STM32CubeMX之串口通信 串口通信的基本概念可参考下面的一篇文章,本章将介绍如何使用STM32CubeMX工具快速编写串口通信的程序。 前期准备 (1) STM32硬件电路板及仿真器(以STM32F407单片机为例) (2) Keil v5以上版本(MDK-ARM) (3) USB转串口工具及驱动 (4) 串口调试助手 STM32CubeMX配置 首先,时钟等的配置参考之前文章的介绍(STM32CubeMX之GPIO的使用)。串口部分配置如下: 选择Mode为常用的异步串口Asynchronous,不使能RS232硬件流控制。波特率设置为115200,数据长度8位,无校验位,1位停止位。 打开中断和添加发送和接收的DMA,DMA参数设置为默认即可,如下图。 编写程序 设置完成后生成代码。初始化部分已经自动生成,用户只要添加发送和接收的代码就行。串口发送和接收的函数包括三种方式:查询、中断和DMA方式,函数如下: - HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
9 F. j0 T. X) p0 c2 B - HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);5 u& m3 S& i( y! g& w, r3 F
- HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
+ R0 A; [! ~% ~# r! k% r( E, N - HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);* `7 F# Z, c6 J; A3 u0 S
- HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
' V* V1 K# ?8 P+ H _ - HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
复制代码
t) f) E/ @& y8 {查询方式相对比较占用CPU资源,因此中断和DMA方式使用的比较多。这里不再介绍查询方式的收发程序,只介绍中断和DMA方式。串口发送比较简单,直接调用相关函数即可,如下: - HAL_UART_Transmit_IT(&huart1,"Hello World\r\n",13);
z0 b! ]$ ?9 X0 a9 S- l+ {0 Z - HAL_UART_Transmit_DMA(&huart1,"DMA Test\r\n",10);
复制代码 9 M% M0 e2 L: w
HAL库的串口接收只支持接收定长数据,当数据长度不确定时,需要自己处理。 中断方式接收: 首先初始化完成后打开串口接收中断,接收长度为1字节,即当接收到一个字节数据后产生串口接收中断。 - <span lang="EN-US">HAL_UART_Receive_IT(&huart1,&RevByte,1);//</span>打开串口接收中断
复制代码 + G* X. [ b7 ^& ~" n! z
编写中断回调函数,由于HAL库已经在底层做了处理,串口接收的1字节数据已经存储在RevByte中,因此在中断中直接读取RevByte的值即可。需要注意的是读取完成后要重新打开中断接收。 - //串口接收中断回调函数
# B: Y F5 @* F) M2 B. i6 _% z/ O6 S1 D - void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
Y3 G- T% l5 b; ] - {
1 b1 X0 Z( @) m - if(huart->Instance==USART1), C9 Y. r! p# `% D6 s% W& M5 k, A
- {
! l% P8 h! b0 o1 D - RevBuf[Revcnt]=RevByte;
9 `: Y5 c# j4 l% X$ z! Y5 q - Revcnt++;: Y4 V/ l2 h! d; T
- if(Revcnt==BUF_LEN), L4 J; h3 w5 Y( t
- {% ]) y8 ~4 }" k5 s7 G
- Revcnt=0;' k0 V9 ]$ j: b% s% \+ ~$ R8 J
- }; A, M( g* j% U/ A- |
- HAL_UART_Receive_IT(&huart1, &RevByte, 1); //串口1中断接收数据' C7 G) d3 ]! D! N8 n* {8 ^
- }' L9 q0 e" d" S4 N% t6 ~9 z
- }
复制代码 / D( u! p% Q# J7 {) @
DMA方式接收: DMA+空闲中断的方式也可以实现接收不定长的数据。首先初始化完成后打开串口空闲中断和DMA接收。 - __HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);//打开串口空闲中断
# \. x: g4 D- [: [6 t - HAL_UART_Receive_DMA(&huart1, RevBuf, BUF_LEN); //串口1DMA接收数据
复制代码 9 \! y$ v/ E6 v' ~
编写空闲中断函数,在主程序中判断标志位,进行相关处理 - void UART_IDLECallBack(UART_HandleTypeDef *huart). w- R6 }# Y8 }' @# @
- {
0 G0 c% y5 i9 |3 u5 y R - uint32_t temp;
1 p, S7 z$ k4 u2 o0 w& D - /*uart1 idle processing function*/
; ]8 u3 |) [4 d# m: y - if(huart == &huart1)! l/ \* s2 e6 b1 B7 j A; b* k& F! Z
- {
- U8 X+ p; K, E0 d7 v' ` - if((__HAL_UART_GET_FLAG(huart,UART_FLAG_IDLE) != RESET))
. V8 r! W8 E( W) ?0 k$ u - {& S! P% K8 A% |% U" b
- __HAL_UART_CLEAR_IDLEFLAG(&huart1);//清除标志位' W, d- {) I/ @% W
- /*your own code*/8 w1 J7 ~9 a9 T- J( R
- HAL_UART_DMAStop(&huart1);//停止DMA& z) s0 ^0 @. d, F2 a5 n; O
- DMA_Usart1_RxSize = BUF_LEN - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);// 获取DMA中传输的数据个数2 |% x4 A8 n# k9 h/ x
- RevFlag = 1;
# Y8 L: d# k& }% c) j- W& n - HAL_UART_Receive_DMA(&huart1,RevBuf,BUF_LEN); //开启下次接收
8 e& y* J# ]" i3 f* y - }
8 x5 _! \6 P; }' K1 |; ~ - }
/ M/ ^( D$ |/ H: ~, I$ h - }" ?- J! {% Q) O, A4 q# V! [
- " m" R, {1 H8 Y% s
- if(RevFlag == 1), i. e1 T: [2 _' R
- {/ [+ w8 n3 o; ?* g% T: W- @3 O
- RevFlag = 0;& _- G/ H' k1 M
- HAL_UART_Transmit_DMA(&huart1,"DMA RevData\r\n",13);. J1 l, J' R/ O4 k* t
- }
复制代码 Q8 A; a& v/ v( V4 r/ P3 i% s5 i
在串口中断函数中调用空闲中断函数。 至此,串口的基本使用就介绍完了。需要注意的是,HAL库需要考虑不同芯片的兼容性,因此程序编写的比较复杂,执行效率低,从串口中断部分可以看出,有时当单片机资源有限且波特率较高时甚至会出现一些错误。所以需要用户根据实际情况对中断部分程序进行优化或重新编写。 文章出处: 嵌入式技术开发 3 `* I$ G# a# Q! X' z0 c. Q. `
|