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);& v# h: ?$ t5 k4 T8 [& W
- HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
! V( C: V" O7 x - HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);9 l& C- ]1 w' h& e; r5 e
- HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);3 ?: @, q2 i( T" O: Y" Q5 I3 v
- HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);" J6 K) u3 H* [. @2 F
- HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
复制代码 7 O4 G1 D: E) s9 y. I$ w1 P
查询方式相对比较占用CPU资源,因此中断和DMA方式使用的比较多。这里不再介绍查询方式的收发程序,只介绍中断和DMA方式。串口发送比较简单,直接调用相关函数即可,如下: - HAL_UART_Transmit_IT(&huart1,"Hello World\r\n",13);! c, V) G2 c/ p8 T9 k
- HAL_UART_Transmit_DMA(&huart1,"DMA Test\r\n",10);
复制代码 2 l1 v: v0 G. d7 N; z4 H. ~$ J/ l$ s Y
HAL库的串口接收只支持接收定长数据,当数据长度不确定时,需要自己处理。 中断方式接收: 首先初始化完成后打开串口接收中断,接收长度为1字节,即当接收到一个字节数据后产生串口接收中断。 - <span lang="EN-US">HAL_UART_Receive_IT(&huart1,&RevByte,1);//</span>打开串口接收中断
复制代码 7 P6 I6 j9 u# h
编写中断回调函数,由于HAL库已经在底层做了处理,串口接收的1字节数据已经存储在RevByte中,因此在中断中直接读取RevByte的值即可。需要注意的是读取完成后要重新打开中断接收。 - //串口接收中断回调函数% |& ?7 m& L# d% L& @+ F8 ~
- void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
; ]8 i @7 O' m' f* @% J8 u+ U% E - {
; E8 C( T! k. j) |( i - if(huart->Instance==USART1)
/ |" n( _$ v( h4 B - {* _/ }, Q. n' o( v
- RevBuf[Revcnt]=RevByte;
! a- n( A! s' c6 N; P9 o - Revcnt++;
) g: i- e6 H9 p' o: c q3 e - if(Revcnt==BUF_LEN)
5 Z5 A- G0 A8 e: {$ e) b - {
* B( L# |9 t5 x - Revcnt=0;+ K" B B; s$ s/ R! ?) P
- }
8 S3 y5 A7 e+ j- v5 Y# ~6 C - HAL_UART_Receive_IT(&huart1, &RevByte, 1); //串口1中断接收数据# l, b/ ]; d; c; T, {
- }
3 F- W2 \$ J! R; J- | - }
复制代码 9 B. Q/ F( r5 v8 e2 L1 Q7 b
DMA方式接收: DMA+空闲中断的方式也可以实现接收不定长的数据。首先初始化完成后打开串口空闲中断和DMA接收。 - __HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);//打开串口空闲中断3 h) c1 q; g7 ^4 u# _+ x
- HAL_UART_Receive_DMA(&huart1, RevBuf, BUF_LEN); //串口1DMA接收数据
复制代码
0 L; g! ]5 o: [$ i( `7 s编写空闲中断函数,在主程序中判断标志位,进行相关处理 - void UART_IDLECallBack(UART_HandleTypeDef *huart)7 E8 {# t5 J7 Q) I0 [
- {4 a( }) X- m' t
- uint32_t temp; + Y- G- T0 w/ m: N" \$ x
- /*uart1 idle processing function*/
4 Q" G/ m& S8 W! m$ H* x - if(huart == &huart1): E5 o; R- S7 h3 i# z; ]
- {! m! u" Z% l" {
- if((__HAL_UART_GET_FLAG(huart,UART_FLAG_IDLE) != RESET))
; [. o, V6 W1 h6 s0 L - {
) ~) B1 g7 l% |9 w7 | - __HAL_UART_CLEAR_IDLEFLAG(&huart1);//清除标志位; ^: W8 i2 T' X
- /*your own code*/6 A' Y5 B7 q& X( B# M
- HAL_UART_DMAStop(&huart1);//停止DMA, J/ }+ P3 I$ g+ P
- DMA_Usart1_RxSize = BUF_LEN - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);// 获取DMA中传输的数据个数
, I. H" v# K. d- r - RevFlag = 1;
$ U, n# ]2 q8 X1 L - HAL_UART_Receive_DMA(&huart1,RevBuf,BUF_LEN); //开启下次接收# }$ i, `7 v6 I9 v6 J2 v
- }
4 @# S Y4 ?9 x( h; L4 l - }: g( i) Z8 x/ y' W
- }; Y6 A$ W. ]3 \6 a/ Y) `
- d' |. {7 w3 {5 a5 W, I8 \3 }; ?7 ?; F- if(RevFlag == 1)
4 I4 g" q7 @! T' R$ ]: s$ B - {4 l' A% U: S. e! n% w3 q$ V$ b4 m
- RevFlag = 0;
5 o/ B3 N' W7 p7 D4 B5 B( u - HAL_UART_Transmit_DMA(&huart1,"DMA RevData\r\n",13);3 \' N! U& \9 n8 s* Z% q
- }
复制代码 * }. L9 B3 d& o
在串口中断函数中调用空闲中断函数。 至此,串口的基本使用就介绍完了。需要注意的是,HAL库需要考虑不同芯片的兼容性,因此程序编写的比较复杂,执行效率低,从串口中断部分可以看出,有时当单片机资源有限且波特率较高时甚至会出现一些错误。所以需要用户根据实际情况对中断部分程序进行优化或重新编写。 文章出处: 嵌入式技术开发 : }+ z7 W0 `( u7 u+ k
|