STM32对HAL库的串口不定长度的读写操作(一)

这几天终于开始接触HAL库,随着固件库被逐渐淘汰,尽管很多人说用STM32CUBEMX不能很好地学习stm32,但这肯定是一个趋势,所以用好HAL库十分得重要。

   这几天也学到了简单地操作cubemx这个软件,这里不做教学,因为百度很多,虽然很杂乱,但是总能找到的。HAL库的应用与固件库在一些特定函数上不一样。举几个我目前遇到的例子。

  

 再弄跑马灯时需要用到翻转的程序,HAL库有自带的翻转函数,使用方便。

 延时函数也有自带。

串口读写,个人理解来说,串口分为三种,1、普通的串口写入 2、串口中断的读和写 3、串口中断与DMA

现在还没接触到DMA,后续再补上。

1、普通的串口写入,

 HAL库有特定函数将数据传入特定的串口,用上位机软件即可读到函数传输的数据。

2、串口中断的读和写

  

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef huart1;

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
            uint8_t dd[10];
            //uint8_t dd;
            uint8_t ff[]="send!";
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */
  

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
            uint8_t aa[] = "key0";
            uint8_t bb[] = "key1";
            uint8_t cc[] = "wkup_pres";
            //uint8_t dd[20];
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
    HAL_UART_Receive_IT(&huart1, dd, 1);
  while (1)
  {
     
        int key = 0;
        key=KEY_Scan(0);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
        switch(key)
        {                 
            case KEY0_PRES:
                //LED0=!LED0;
            HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_8);
            HAL_UART_Transmit(&huart1, aa, sizeof(aa), 0xffff);
                break;
            case KEY1_PRES:
            //    LED1=!LED1;
                HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_2);
            HAL_UART_Transmit(&huart1, bb, sizeof(bb), 0xffff);
                break;
            case WKUP_PRES:                
            //    LED0=!LED0;
            //    LED1=!LED1;
                HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_8);
                HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_2);
            HAL_UART_Transmit(&huart1, cc, sizeof(cc), 0xffff);
            //HAL_Delay(100);
            //HAL_UART_Transmit(&huart1, cc, sizeof(cc), 0xffff);
//            HAL_UART_Transmit(&huart1, aa, sizeof(aa), 0xffff);
//            HAL_UART_Transmit(&huart1, bb, sizeof(bb), 0xffff);
                break;
            default:
                HAL_Delay(10);
        }
        //HAL_UART_Receive_IT(&huart1, dd, 1);
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief USART1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_USART1_UART_Init(void)
{

  /* USER CODE BEGIN USART1_Init 0 */

    
  /* USER CODE END USART1_Init 0 */

  /* USER CODE BEGIN USART1_Init 1 */

  /* USER CODE END USART1_Init 1 */
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 9600;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART1_Init 2 */

  /* USER CODE END USART1_Init 2 */

}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOD_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOC_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);

  /*Configure GPIO pin : WK_UP_Pin */
  GPIO_InitStruct.Pin = WK_UP_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_PULLDOWN;
  HAL_GPIO_Init(WK_UP_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pin : KEY0_Pin */
  GPIO_InitStruct.Pin = KEY0_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  HAL_GPIO_Init(KEY0_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pin : PA8 */
  GPIO_InitStruct.Pin = GPIO_PIN_8;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pin : KEY1_Pin */
  GPIO_InitStruct.Pin = KEY1_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  HAL_GPIO_Init(KEY1_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pin : PD2 */
  GPIO_InitStruct.Pin = GPIO_PIN_2;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

}

/* USER CODE BEGIN 4 */
int KEY_Scan(int mode)
{     
    static int key_up=1;//按键按松开标志
    if(mode)
     key_up=1;  //支持连按          
    if(key_up&&(KEY0==0||KEY1==0||WK_UP==1))
    {
        HAL_Delay(10);//去抖动 
        key_up=0;
        if(KEY0==0)return KEY0_PRES;
        else if(KEY1==0)return KEY1_PRES;
        else if(WK_UP==1)return WKUP_PRES; 
    }else if(KEY0==1&&KEY1==1&&WK_UP==0)key_up=1;          
    return 0;// 无按键按下
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
        UNUSED(huart);
        HAL_UART_Transmit(&huart1, dd, 1, 0xffff);
        HAL_UART_Receive_IT(&huart1,dd, 1);
     //memset(dd, 0x00, sizeof(dd));
}
/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */

  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{ 
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     tex: printf("Wrong parameters value: file %s on line %d
", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
main.c

这里插入串口读写的main文件,程序先无视按键KEY的作用,直接看到

 在串口接收外部如上位机发送的数据时需要用HAL库的这个函数接收数据,可设置特定的串口和接收到哪个位置,以及接收数据的长度。若你直接把接收的数据transmit 出去,也可以做到,但是得是定长度的读写操作,不然会出现溢出或者是数据缺失的现象。

今天遇到这个问题,百度找了很多相关的,大多方法都特别复杂,很多也是通过DMA来解决的,后来发现一中方法。在receive_IT执行完毕后,会进入一个回调函数(需要自己重新声明出来),

 若在回调函数中发送其中一个字节,在接收,又会调用这个回调函数,反复之后就可以把读到的数据全部放入dd 中,最后发给串口。这种递归思想很好,实现了不定长度的读写。

对于这个回调函数和中断函数的区别没怎么分清,串口中断函数可能多用于执行其他操作吧,回调函数多用于此读取操作吧,个人猜测。

在(二)中简单解析个人写的C#上位机软件,与stm32实现数据读写操作。

原文地址:https://www.cnblogs.com/zjx123/p/11861964.html