使用STM32 HAL库实现串口中断接收数据包功能

目录

一、CUBEmx配置

1.设置系统时钟,配置SYS,配置时钟树

 ​编辑

 2.配置串口USART1

3.配置NVIC,开启串口中断

​编辑4.点击GENERATE CODE输出文件即可

二、代码部分

0.串口重定向——printf

1.关于舵机

2.开启串口中断函数

3.编写串口回调函数

4.主函数部分

三、实验现象:

四、总结


 

        刚从标准库转到HAL学习,最近需要做一个机械臂控制,打算用USART1串口中断的方式控制四个舵机运行,现在记录一下过程,主控使用STM32F103ZET6。(本文只讲中断的接收,舵机控制暂时不涉及)

一、CUBEmx配置

1.设置系统时钟,配置SYS,配置时钟树

d930e98adeeb420ab157db1588c24f0e.png

f02f3bcf46cb407ab230f43ae3ffd55e.png

 14185f53defc4b57be83a55849d1e199.png

 2.配置串口USART1

a73f50c94aa74ab3ad868d234065de87.png

3.配置NVIC,开启串口中断

这里我将中断的优先级设置为12(单独学习串口中断并不需要修改优先级配置,按照0级即可)

8bee212e58fc40ac8d1226c61be27aee.png4.点击GENERATE CODE输出文件即可

二、代码部分

我使用CLION进行编写,使用keil的方式也是一样的。

0.串口重定向——printf

在用户自定义区加上如下代码即可使用:

70b9a9980b254ee89a99d966d97d53b3.png

#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE
{
    HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);
    return ch;
}

1.关于舵机

舵机使用了两个180°舵机和两个270°舵机,由于uint8_t最大到255,所以打算使用两个八位去存储舵机旋转的角度。

数据包采用如下形式,通过定义一个数组去存放数据包

uint8_t Rx_data[5];//数据包加上包头一共5个byte
uint8_t Rx_flag=0;//设置一个中断完成的标志位

1c4df32d3a81411184f4bdacf2eb8d66.png

2.开启串口中断函数

  HAL_UART_Receive_IT(&huart1,(uint8_t*)Rx_data,5);//开启串口接收中断函数

函数的三个参数,第一个指定是USART1的串口中断,第二个参数指定接受数据的位置,第三个指定数据接收的长度,当串口接收到5个字节的数据时,才会触发中断回调函数。 

3.编写串口回调函数

回调函数仅仅负责将接受完成的标志位置1,处理工作再主函数while循环中进行。 

 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance==USART1)//首先判断是否是USART1触发的中断
    {
        Rx_flag=1;
    }
}

4.主函数部分

首先判断标志位,即是否接受完5个字节的数据,判断完成后,先将标志位即Rx_flag清零,否则会一直卡在主循环中,接着开启下一次的串口中断。

 if(Rx_flag==1)
      {
          Rx_flag=0;
          HAL_UART_Receive_IT(&huart1,(uint8_t*)Rx_data,5);
  
       }

接着就是对数据包中的数据进行解析了:

1.首先判断包头包尾是否满足协议规范。然后在处理里面的数据:这里我通过switch语句对舵机的ID进行判断:0x01-0x04代表着四个舵机。

2.关于度数的转换:angle=Rx_data[2] * 256 + Rx_data[3],即高位为Rx_data[2] ,低位为Rx_data[3]。

switch (Rx_data[1]) {
                  case 0x01: {
                      printf("Servo_1 turn\r\n");
                      printf("angle=%d\r\n", Rx_data[2] * 256 + Rx_data[3]);
                  }
                      break;
                  case 0x02: {
                      printf("Servo_2 turn\r\n");
                      printf("angle=%d\r\n", Rx_data[2] * 256 + Rx_data[3]);
                  }
                      break;
                  case 0x03: {
                      printf("Servo_3 turn\r\n");
                      printf("angle=%d\r\n", Rx_data[2] * 256 + Rx_data[3]);
                  }
                      break;
                  case 0x04: {
                      printf("Servo_4 turn\r\n");
                      printf("angle=%d\r\n", Rx_data[2] * 256 + Rx_data[3]);
                  }
                      break;
                  default:
                      printf("data_error!");
              }

 3.处理完数据后需要把Rx_data[]中的值全部清零以便下一次的接收:

          for (int i = 0; i < 5; ++i) {
              Rx_data[i]=0;
          }

4.主循环全部函数

  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
      if(Rx_flag==1)
      {
          Rx_flag=0;
          HAL_UART_Receive_IT(&huart1,(uint8_t*)Rx_data,5);
          if(Rx_data[0]==0xaa&&Rx_data[4]==0xff) {
              switch (Rx_data[1]) {
                  case 0x01: {
                      printf("Servo_1 turn\r\n");
                      printf("angle=%d\r\n", Rx_data[2] * 256 + Rx_data[3]);
                  }
                      break;
                  case 0x02: {
                      printf("Servo_2 turn\r\n");
                      printf("angle=%d\r\n", Rx_data[2] * 256 + Rx_data[3]);
                  }
                      break;
                  case 0x03: {
                      printf("Servo_3 turn\r\n");
                      printf("angle=%d\r\n", Rx_data[2] * 256 + Rx_data[3]);
                  }
                      break;
                  case 0x04: {
                      printf("Servo_4 turn\r\n");
                      printf("angle=%d\r\n", Rx_data[2] * 256 + Rx_data[3]);
                  }
                      break;
                  default:
                      printf("data_error!");
              }
          }
          else
          {
              printf("Data——error!\r\n");
          }
          for (int i = 0; i < 5; ++i) {
              Rx_data[i]=0;
          }
      }
  }

三、实验现象:

多数厂家的ZET6带有ch340芯片,不需要单独使用usb转串口的工具,直接使用USB连接电脑即可。

bfcdeb1636e348a7828e6c869daf043a.png

5e17bac494984d45becad2b4a4648e42.png

c04ab60d5d67456da97035acc1eacf08.png

四、总结

        这仅仅是串口中断接收的部分,关于舵机控制会在下一篇文章给出,第一次写文章,能力不足,有许多改进的地方,希望大家批评指正!

 

 

物联沃分享整理
物联沃-IOTWORD物联网 » 使用STM32 HAL库实现串口中断接收数据包功能

发表评论