STM32
直播中

赵辉

12年用户 850经验值
私信 关注
[问答]

STM32F407ZGT6开发板是如何去实现串口接收的

STM32F407ZGT6开发板是如何去实现串口接收的?
STM32F407ZGT6开发板有哪几种方法可以实现串口接收呢?

回帖(1)

殷夏

2021-12-1 09:20:08
开发环境
STM32CUBMX


  • 正点原子STM32F407ZGT6探索者开发板
  • MDK-ARM 5.31

第一种方式:直接接收



  • 配置外部时钟源




    2.配置时钟树





    3.配置串口一





    生产代码后进入工程
    重定向printf到串口1(建议在usart.c里重定向)
    重定向代码块


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();
  printf("hello wroldrn");
  /* USER CODE BEGIN 2 */


  /* USER CODE END 2 */


  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */


    /* USER CODE BEGIN 3 */
      HAL_UART_Receive(&huart1,receive_buff,10,0xff);// 接收10个字符
      if(receive_buff[0] != 0)
      {
          printf("recive buff is %s rn",receive_buff);
          memset(receive_buff,0,20); // 清除接收内容
      }   
  }
  /* USER CODE END 3 */
}
实验现象





第二种方式:中断方式

时钟准备和串口初始化如上一种方式所示,实例从设置中断开始
设置中断





生成代码
定义相关变量

uint8_t aRxBuffer;                        //接收中断缓冲
uint8_t Uart1_RxBuff[256] = {0};                //接收缓冲
uint8_t Uart1_Rx_Cnt = 0;                //接收缓冲计数
uint8_t Uart1_RxFlag = 0;
uint8_t        cAlmStr[] = "数据溢出(大于256)rn";


在usart.h 中编写回调函数


void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(huart);
  /* NOTE: This function Should not be modified, when the callback is needed,
           the HAL_UART_TxCpltCallback could be implemented in the user file
   */

        if(Uart1_Rx_Cnt >= 255)  //溢出判断
        {
                Uart1_Rx_Cnt = 0;
                memset(Uart1_RxBuff,0x00,sizeof(Uart1_RxBuff));
                HAL_UART_Transmit(&huart1, (uint8_t *)&cAlmStr, sizeof(cAlmStr),0xFFFF);       
        }
        else
        {
                Uart1_RxBuff[Uart1_Rx_Cnt++] = aRxBuffer;   //接收数据转存
       
                if((Uart1_RxBuff[Uart1_Rx_Cnt-1] == 0x0A)&&(Uart1_RxBuff[Uart1_Rx_Cnt-2] == 0x0D)) //判断结束位
                {
                        Uart1_RxFlag = 1;
                }
        }
       
        HAL_UART_Receive_IT(&huart1, (uint8_t *)&aRxBuffer, 1);   //再开启接收中断
}


main函数内内容


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 */
  HAL_UART_Receive_IT(&huart1,&aRxBuffer,1);
  /* USER CODE END 2 */


  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */


    /* USER CODE BEGIN 3 */
    if(Uart1_RxFlag != 0)
    {
        printf("recive buff is %srn",Uart1_RxBuff);
        Uart1_RxFlag = 0;
        Uart1_Rx_Cnt = 0;
        memset(Uart1_RxBuff,0x00,256);
    }
    HAL_Delay(10);
  }
  /* USER CODE END 3 */
}


实验现象





第三种方法:定时器中断判断串口是否传输完成

此方法可以看做是看作中断接收的一种拓展用法,不同于上一种方法介绍的需要特定的格式的数据帧来判定,此方法结合了定时器,以5ms为界限,如果5ms后没有接收新的数据则认为一包数据已经发送完成。下面是配置的具体方法
1.配置时钟和串口中断的同上,然后配置定时器中断
定时器基础配置





打开定时器中断





我们设置的5ms检测串口是否发送完成
我们使用的定时器的主频是84MHZ
那么定时器频率可用下列方式计算
                                    F                         =                                              84                               M                               H                               Z                                                 (                               P                               r                               e                               s                               c                               a                               l                               e                               r                               +                               1                               )                               ×                               (                               C                               o                               u                               n                               t                               e                               r                               P                               e                               r                               i                               o                               d                               +                               1                               )                                            ;                               F = frac{84MHZ}{(Prescaler+1)times (CounterPeriod+1)};                   F=(Prescaler+1)×(CounterPeriod+1)84MHZ;
配置完成后生成代码
程序部分
定义相关变量

uint8_t aRxBuffer;                        //接收中断缓冲
uint8_t Uart1_RxBuff[256] = {0};                //接收缓冲
uint8_t Uart1_Rx_Cnt = 0;                //接收缓冲计数
uint8_t Uart1_RxFlag = 0;
uint8_t        cAlmStr[] = "数据溢出(大于256)rn";
编写串口中断服务函数


void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart -> Instance == USART1)
    {
        if(Uart1_Rx_Cnt == 0)
        {
            __HAL_TIM_CLEAR_FLAG(&htim6,TIM_FLAG_UPDATE);
            HAL_TIM_Base_Start_IT(&htim6);
            Uart1_RxBuff[Uart1_Rx_Cnt] = aRxBuffer;
            Uart1_Rx_Cnt ++;
            
        }
        else
        {
            Uart1_RxBuff[Uart1_Rx_Cnt ++] = aRxBuffer;
        }
        if(Uart1_Rx_Cnt >= 255)
        {
            Uart1_Rx_Cnt = 0;
            Uart1_RxFlag = 0;
            memset(Uart1_RxBuff,0x00,256);
        }
        HAL_UART_Receive_IT(&huart1,&aRxBuffer,1);
    }  
}
编写定时器中断回调函数


void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(htim ->Instance == TIM6)
    {
        HAL_TIM_Base_Stop(&htim6);
        __HAL_TIM_SetCounter(&htim6,0);
        Uart1_RxFlag = 1;      
    }
}


编写主程序


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_TIM6_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  HAL_UART_Receive_IT(&huart1,&aRxBuffer,1);
  /* USER CODE END 2 */


  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */


    /* USER CODE BEGIN 3 */
     if(Uart1_RxFlag == 1)
     {
         printf("rec buff is %srn",Uart1_RxBuff);
         memset(Uart1_RxBuff,0x00,256);
         Uart1_Rx_Cnt = 0;
         Uart1_RxFlag = 0;
     }
     HAL_Delay(10);
  }
  /* USER CODE END 3 */
}
实验现象





第四种方法:串口空闲中断加DMA

使用DMA可以减少CPU负荷,当接收大批量数据的时候,可以防止频繁进入中断。这样有助于提高效率,下面我们介绍STM32带有的串口空闲中断来配合DMA接收数据的例子。
配置部分
1 串口配置
基本部分





配置DMA





中断配置





生产代码
定义宏定义

#define USART1_DMA_REC_SIZE 600
#define USART1_REC_SIZE 1200
编写结构体


typedef struct
{
        uint8_t UsartRecFlag; // 标志位
        uint16_t UsartRecLen; // 接收数据长度
        uint16_t UsartDMARecLEN; // DMA 接收长度
        uint8_t  Usart1DMARecBuffer[USART1_DMA_REC_SIZE]; // DMA 接收数组
        uint8_t  Usart1RecBuffer[USART1_REC_SIZE]; // 接收组
}teUsart1type;
编写打开中断函数


// 打开相关中断
void EnableUsart_It(void)
{
        __HAL_UART_ENABLE_IT(&huart1,UART_IT_RXNE);
        __HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);
        __HAL_UART_CLEAR_IDLEFLAG(&huart1);
        HAL_UART_Receive_DMA(&huart1,Usart1type.Usart1DMARecBuffer,USART1_DMA_REC_SIZE);
}
改写中断服务函数(在stm32f4xx_it.c中)


void USART1_IRQHandler(void)
{

  /* USER CODE BEGIN USART1_IRQn 0 */
        uint16_t temp = 0;
        __HAL_UART_CLEAR_IDLEFLAG(&huart1);
        HAL_UART_DMAStop(&huart1); // 关闭DMA
        temp = huart1.Instance -> SR; // 清除SR状态寄存器
        temp = huart1.Instance -> DR; // 清除DR数据寄存器,用来清除中断
        temp = hdma_usart1_rx.Instance -> NDTR; // 获取未传输的数据个数
        //temp = hdma_usart2_rx.Instance -> NDTR; // F4
        Usart1type.UsartDMARecLEN = USART1_DMA_REC_SIZE - temp;
        HAL_UART_RxCpltCallback(&huart1);
  /* USER CODE END USART1_IRQn 0 */
    HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */
        HAL_UART_Receive_DMA(&huart1,Usart1type.Usart1DMARecBuffer,USART1_DMA_REC_SIZE);
  /* USER CODE END USART1_IRQn 1 */
}
编写中断回调函数


void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
        if(huart -> Instance == USART1)
        {
            if(Usart1type.UsartRecLen > 0)
            {
                memcpy(&Usart1type.Usart1RecBuffer[Usart1type.UsartRecLen],Usart1type.Usart1DMARecBuffer,Usart1type.UsartDMARecLEN);
                Usart1type.UsartRecLen += Usart1type.UsartDMARecLEN;
            }
            else
            {
                memcpy(&Usart1type.Usart1RecBuffer,Usart1type.Usart1DMARecBuffer,Usart1type.UsartDMARecLEN);
                Usart1type.UsartRecLen += Usart1type.UsartDMARecLEN;
            }
            memset(Usart1type.Usart1DMARecBuffer,0x00,600);
            Usart1type.UsartRecFlag = 1;
        }
}
编写主程序


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_DMA_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  EnableUsart_It();
  /* USER CODE END 2 */


  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */


    /* USER CODE BEGIN 3 */
      if(Usart1type.UsartRecFlag == 1)
      {
          printf("rec buff is %srn",Usart1type.Usart1RecBuffer);
          memset(Usart1type.Usart1RecBuffer,0x00,USART1_REC_SIZE);
          Usart1type.UsartRecLen = 0;
          Usart1type.UsartRecFlag = 0;         
      }
      HAL_Delay(20);
  }
  /* USER CODE END 3 */
}
实验现象





END
举报

更多回帖

发帖
×
20
完善资料,
赚取积分