|
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 ^9 A4 L0 B5 ^" n
- HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);# Y- L, f( P8 a
- HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);& }* `& ^6 s: _- h8 J- x" J8 ~' U
- HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
+ M$ u) S8 \8 q, k ~ - HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
% E* F2 C& V% y0 b7 _ - HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
复制代码 ]5 G' g8 D' P2 Y$ U3 B
查询方式相对比较占用CPU资源,因此中断和DMA方式使用的比较多。这里不再介绍查询方式的收发程序,只介绍中断和DMA方式。串口发送比较简单,直接调用相关函数即可,如下: - HAL_UART_Transmit_IT(&huart1,"Hello World\r\n",13);
% z1 `. h2 K+ |3 r - HAL_UART_Transmit_DMA(&huart1,"DMA Test\r\n",10);
复制代码
5 P; z; |8 t7 P$ |4 y2 b0 G' ?HAL库的串口接收只支持接收定长数据,当数据长度不确定时,需要自己处理。 中断方式接收: 首先初始化完成后打开串口接收中断,接收长度为1字节,即当接收到一个字节数据后产生串口接收中断。 - <span lang="EN-US">HAL_UART_Receive_IT(&huart1,&RevByte,1);//</span>打开串口接收中断
复制代码 % N( @! V0 p* _
编写中断回调函数,由于HAL库已经在底层做了处理,串口接收的1字节数据已经存储在RevByte中,因此在中断中直接读取RevByte的值即可。需要注意的是读取完成后要重新打开中断接收。 - //串口接收中断回调函数( h5 F j5 |% |$ {
- void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
/ }9 k; m7 ^: R( a e0 E% e: U - {- X" n+ T, B$ S* Y. j/ Y! I3 s
- if(huart->Instance==USART1)4 u5 {& Q) j9 E1 U6 Z" M$ e
- {
' A) p2 T6 y9 S. |" d - RevBuf[Revcnt]=RevByte;+ q' Q! Q. G+ `. ~
- Revcnt++;7 W1 F7 O) T; w* Y. d j
- if(Revcnt==BUF_LEN)
3 X6 r5 ]" l, \8 i g - {: a! I- @6 ^ M) D
- Revcnt=0;
7 S3 u' b3 J, }/ g - }7 w, u$ T6 p7 y& H
- HAL_UART_Receive_IT(&huart1, &RevByte, 1); //串口1中断接收数据0 g5 _9 E; o1 B' M; A1 e( ~
- }; w; X, o" h/ d6 B9 V
- }
复制代码 ! p* X% L* V% j( S& z3 I3 ]
DMA方式接收: DMA+空闲中断的方式也可以实现接收不定长的数据。首先初始化完成后打开串口空闲中断和DMA接收。 - __HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);//打开串口空闲中断
3 q; q$ j' }& g$ R& }' a$ y - HAL_UART_Receive_DMA(&huart1, RevBuf, BUF_LEN); //串口1DMA接收数据
复制代码
( u4 N9 f, j, R4 [9 z编写空闲中断函数,在主程序中判断标志位,进行相关处理 - void UART_IDLECallBack(UART_HandleTypeDef *huart)
1 C. i( B' } c4 G - {
0 B- }3 ] M$ i8 Q; c! ] - uint32_t temp; & J) l: q# i7 O g! K
- /*uart1 idle processing function*/
1 x( e6 A0 h A- x& i - if(huart == &huart1)
& J$ G+ }2 v3 m" B( R - {
1 \1 E5 E, N9 p. H9 r - if((__HAL_UART_GET_FLAG(huart,UART_FLAG_IDLE) != RESET)) 0 B8 d* C2 V- G- G& u
- {
2 u! ?: t; p( o - __HAL_UART_CLEAR_IDLEFLAG(&huart1);//清除标志位
/ c; q5 s& A. l) k9 `* y* C - /*your own code*/
2 e2 q* w7 c7 K" }+ o- j6 [ - HAL_UART_DMAStop(&huart1);//停止DMA
" C5 W. S, t' M/ f) I8 x - DMA_Usart1_RxSize = BUF_LEN - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);// 获取DMA中传输的数据个数$ A7 o" _# S9 P3 b ?
- RevFlag = 1;
: r) p# I: O0 a/ x4 K, U) W - HAL_UART_Receive_DMA(&huart1,RevBuf,BUF_LEN); //开启下次接收
4 j" \$ q2 o7 o' D$ k: c - }
& F/ f0 I/ D6 X- P- ]+ K; W - }
! A( U* ^3 k5 o% F - }! x. }5 M; i0 p" M" _: E, Q% R% b! s" \
- ; j; N& N. h1 M, R
- if(RevFlag == 1) c% A K! g x; c" h- G
- {' D0 ?) C: {6 r) J' a$ ~6 z
- RevFlag = 0;
( p, H0 U1 d8 t! R1 G. Y: r - HAL_UART_Transmit_DMA(&huart1,"DMA RevData\r\n",13);) X2 @" |! |" Q8 }
- }
复制代码 5 H) g1 l/ u0 h/ Q! ^9 M
在串口中断函数中调用空闲中断函数。 至此,串口的基本使用就介绍完了。需要注意的是,HAL库需要考虑不同芯片的兼容性,因此程序编写的比较复杂,执行效率低,从串口中断部分可以看出,有时当单片机资源有限且波特率较高时甚至会出现一些错误。所以需要用户根据实际情况对中断部分程序进行优化或重新编写。 文章出处: 嵌入式技术开发
# H- X6 d9 N4 [1 A6 a0 ] |