你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】基于STM32F103C8T6和STM32CubeMX实现UART串口通信数据收发

[复制链接]
STMCU小助手 发布时间:2022-4-15 11:00
前言
这次我用的板子是一个用STM32F103C8T6作为主控芯片的一个数据采集卡,两个LED灯连接的引脚是PB3与PB4,TX与RX引脚分别是PA9和PA10。

5]{B4~8{`U1E9]{KV)1P5%I.png
Z}QVG)L}6`41VSN1_J)]39B.png

一、配置CubeMX
1、新建工程;
2、配置时钟源,在RCC里面的HSE配置的是晶振时钟;
3、配置程序烧录引脚SYS为SWD模式;
4、配置GPIO口,配置一个LED灯(我的板子是PB3),起到串口成功接收到数据时的指示作用;
5、配置串口收发引脚

此处我们采用的通信方式为UART通信(异步全双工串口通信),PA9作为TX,PA10作为RX使用。直接在可视框图里点击相应的引脚进行配置。

配置到目前,效果图为:

2)WLE5206B@5M4D%)L5_5DH.png

可以发现,TX和RX两个引脚配置完之后是黄色的,代表还没有配置完毕,下面继续进行配置。

6、在左边的"Connectivity”里面的USART1模式里选择异步全双工通信模式asynchronous
⮚点击USATR1
⮚设置MODE为异步通信(Asynchronous)
⮚基础参数:波特率为115200 Bits/s。传输数据长度为8 Bit。奇偶检验无,停止位1,接收和发送都使能
⮚GPIO引脚设置 USART1_RX/USART_TX
⮚NVIC Settings 一栏使能接收中断

这里简单扩展一下:
STM32F103系列单片机共有5个串口,其中1-3是通用同步/异步串行接口USART(Universal Synchronous/Asynchronous Receiver/Transmitter),4,、5是通用异步串行接口UART(Universal Asynchronous Receiver/Transmitter)。

P{8HHQ98I2B{EZ40B6D%@IQ.png

1e5624c57d13495db50aacb1703f5f33.png

LP)LH7Q[)EF$JCO1(3M2HQ3.png


7、配置时钟树,我还是开到最高的72MHz
8、进行项目设置,最后生成代码,CubeMX部分就大功告成了

二、HAL库UART相关函数简介
2.1 串口发送/接收函数
  1. HAL_UART_Transmit();//串口发送数据,使用超时管理机制
  2. HAL_UART_Receive();//串口接收数据,使用超时管理机制
  3. HAL_UART_Transmit_IT();//串口中断模式发送  
  4. HAL_UART_Receive_IT();//串口中断模式接收
  5. HAL_UART_Transmit_DMA();//串口DMA模式发送
  6. HAL_UART_Transmit_DMA();//串口DMA模式接收
复制代码

这六个函数参数基本一致,发送/接收各挑一个常用的函数进行简单介绍:

串口发送数据:

  1. HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
复制代码

功能:

串口发送指定长度的数据。如果超时没发送完成,则不再发送,返回超时标志(HAL_TIMEOUT)。

参数:

⮚ UART_HandleTypeDef *huart UART的别名 如 : UART_HandleTypeDef huart1; 别名就是huart1
⮚ *pData 需要发送的数据
⮚ Size 发送的字节数
⮚ Timeout 最大发送时间,发送数据超过该时间退出发送
举例: HAL_UART_Transmit(&huart1, (uint8_t *)ZZX, 3, 0xffff); //串口发送三个字节数据,最大传输时间0xffff

串口接收数据:

  1. HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
复制代码

功能:

串口中断接收,以中断方式接收指定长度数据。
大致过程是,设置数据存放位置,接收数据长度,然后使能串口接收中断。接收到数据时,会触发串口中断。再然后,串口中断函数处理,直到接收到指定长度数据,而后关闭中断,进入中断接收回调函数,不再触发接收中断。(只触发一次中断)

参数:
⮚ UART_HandleTypeDef *huart UART的别名
⮚ *pData 接收到的数据存放地址
⮚ Size 接收的字节数
举例: HAL_UART_Receive_IT(&huart1,(uint8_t *)&value,1); //中断接收一个字符,存储到value中

2.2 串口中断函数
  1. HAL_UART_IRQHandler(UART_HandleTypeDef *huart);  //串口中断处理函数
  2. HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart);  //串口发送中断回调函数
  3. HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart);  //串口发送一半中断回调函数(不常用)
  4. HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);  //串口接收中断回调函数
  5. HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart);//串口接收一半回调函数(不常用)
  6. HAL_UART_ErrorCallback();//串口接收错误函数
复制代码

串口接收中断回调函数:

  1. HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);  
复制代码

功能:

HAL库的中断进行完之后,并不会直接退出,而是会进入中断回调函数中,用户可以在其中设置代码,串口中断接收完成之后,会进入该函数,该函数为空函数,用户需自行修改。

参数:

⮚ UART_HandleTypeDef *huart UATR的别名
举例: HAL_UART_RxCpltCallback(&huart1){ //用户设定的代码 // }

串口中断处理函数:
  1. HAL_UART_IRQHandler(UART_HandleTypeDef *huart);  
复制代码

功能:

对接收到的数据进行判断和处理,判断是发送中断还是接收中断,然后进行数据的发送和接收,在中断服务函数中使用。

如果接收数据,则会进行接收中断处理函数

  1. /* UART in mode Receiver ---------------------------------------------------*/
  2.   if((tmp_flag != RESET) && (tmp_it_source != RESET))
  3.   {
  4.     UART_Receive_IT(huart);
  5.   }
复制代码

如果发送数据,则会进行发送中断处理函数

  1.   /* UART in mode Transmitter ------------------------------------------------*/
  2.   if (((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))
  3.   {
  4.     UART_Transmit_IT(huart);
  5.     return;
  6.   }
复制代码

2.3 串口查询函数

  1.   HAL_UART_GetState();  判断UART的接收是否结束,或者发送数据是否忙碌
复制代码

举例:

  1. while(HAL_UART_GetState(&huart4) == HAL_UART_STATE_BUSY_TX) //检测UART发送结束
复制代码

三、逻辑代码部分
3.1 UART接收中断

因为中断接收函数只能触发一次接收中断,所以我们需要在中断回调函数中再调用一次中断接收函数。

具体流程:

1、初始化串口

2、在main中第一次调用接收中断函数

3、进入接收中断,接收完数据 进入中断回调函数

4、修改HAL_UART_RxCpltCallback中断回调函数,处理接收的数据,

5、回调函数中要调用一次HAL_UART_Receive_IT函数,使得程序可以重新触发接收中断

函数流程:

①HAL_UART_Receive_IT (中断接收函数) ->
②USART2_IRQHandler(void) (中断服务函数) ->
③HAL_UART_IRQHandler(UART_HandleTypeDef *huart) (中断处理函数) ->
④UART_Receive_IT(UART_HandleTypeDef *huart) (接收函数) ->
⑤HAL_UART_RxCpltCallback(huart) (中断回调函数)

HAL_UART_RxCpltCallback函数就是用户要重写在main.c里的回调函数。

代码实现:

在main.c中添加下列定义:

  1. #include <string.h>

  2. #define RxBuffer_MaxSize  256     //最大接收字节数
  3. char RxBuffer[RxBuffer_MaxSize];   //接收数据
  4. uint8_t aRxBuffer;                        //接收中断缓冲
  5. uint8_t UART1_Rx_Cnt = 0;                //接收缓冲计数
复制代码

在main()主函数中,调用一次接收中断函数

  1. /* USER CODE BEGIN 2 */
  2.         HAL_UART_Receive_IT(&huart1, (uint8_t *)&aRxBuffer, 1);
  3. /* USER CODE END 2 */
复制代码

在main.c下方添加中断回调函数

  1. /* USER CODE BEGIN 4 */

  2. void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
  3. {

  4.   UNUSED(huart);

  5.          if(UART1_Rx_Cnt >= 255)  //溢出判断
  6.         {
  7.                 UART1_Rx_Cnt = 0;
  8.                 memset(RxBuffer,0x00,sizeof(RxBuffer));
  9.                 HAL_UART_Transmit(&huart1, (uint8_t *)"数据溢出", 10,0xFFFF);         
  10.   }
  11.         else
  12.         {
  13.                 RxBuffer[UART1_Rx_Cnt++] = aRxBuffer;   //接收数据转存
  14.                         if((RxBuffer[UART1_Rx_Cnt-1] == 0x0A)&&(RxBuffer[UART1_Rx_Cnt-2] == 0x0D)) //判断结束位
  15.                         //此处条件可以改写为if(RxBuffer[UART1_Rx_Cnt-1] == '\n') 因为上面的条件就是表示回车
  16.                         {
  17.                                         HAL_UART_Transmit(&huart1, (uint8_t *)&RxBuffer, UART1_Rx_Cnt,0xFFFF); //将收到的信息发送出去
  18.           while(HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX);//检测UART发送结束
  19.                                   HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_3);//LED指示灯状态翻转
  20.                                         UART1_Rx_Cnt = 0;
  21.                                         memset(RxBuffer,0x00,sizeof(RxBuffer)); //清空数组
  22.                         }
  23.         }
  24.                 HAL_UART_Receive_IT(&huart1, (uint8_t *)&aRxBuffer, 1);   //再开启接收中断
  25. }
  26. /* USER CODE END 4 */
复制代码

现象:

使用USB转TTL(CH340)进行数据发送,XCOM V2.6串口助手进行调试,发送“1”(这里要注意波特率等参数要设置的和之前配置的相同)

9C7`95@PL$(0TYC1DMJ@J@3.png

在debug模式下,将缓冲计数值UART1_Rx_Cnt加入监视器,串口接收到发来的数据后,计数值+1.

Q8LP`T_RZX28MYTO2RKWT}N.png

同时也可以看到LED灯状态翻转

3.2 UART发送
重新定义printf函数


在 stm32f1xx_hal.c中包含#include <stdio.h>

  1. #include "stm32f1xx_hal.h"
  2. #include <stdio.h>
  3. extern UART_HandleTypeDef huart1;   //声明串口
复制代码
在 stm32f1xx_hal.c 中重写fget和fput函数

  1. /**
  2.   * 函数功能: 重定向c库函数printf到DEBUG_USARTx
  3.   * 输入参数: 无
  4.   * 返 回 值: 无
  5.   * 说    明:无
  6.   */
  7. int fputc(int ch, FILE *f)
  8. {
  9.   HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
  10.   return ch;
  11. }

  12. /**
  13.   * 函数功能: 重定向c库函数getchar,scanf到DEBUG_USARTx
  14.   * 输入参数: 无
  15.   * 返 回 值: 无
  16.   * 说    明:无
  17.   */
  18. int fgetc(FILE *f)
  19. {
  20.   uint8_t ch = 0;
  21.   HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
  22.   return ch;
  23. }
复制代码

在main.c中添加

  1. #define RxBuffer_MaxSize  256
  2. char RxBuffer[RxBuffer_MaxSize];
复制代码
  1. while (1)
  2.   {
  3.     /* USER CODE END WHILE */
  4.                         printf("hello world\r\n");//这里博主只写\n的时候无法换行,百度了一下用\r\n就可以了,估计是编译系统的问题
  5.                         HAL_Delay(1000);
  6.     /* USER CODE BEGIN 3 */
  7.   }
复制代码

现象:



注意:

重定义printf后,必须在target里面勾选上MicroLIB,调用一下这个微型库,不然一直卡在里面。

H[76W`UJY`A_2%W)[(M~RB2.png




收藏 评论0 发布时间:2022-4-15 11:00

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版