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); M7 n! I1 X& _4 T6 X' r1 |3 M
- HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
( p; g* c3 w8 K# U5 j' ]) U - HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);6 M% }' i, Q2 l$ ?+ H
- HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);) e) t2 ~/ U# z% }: N+ z9 q/ s0 o
- HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);: A) _! k1 r6 Y' b# u1 g6 D4 D- o5 C
- HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
复制代码 M6 P6 C* s# ^4 L4 z8 \$ q7 l
查询方式相对比较占用CPU资源,因此中断和DMA方式使用的比较多。这里不再介绍查询方式的收发程序,只介绍中断和DMA方式。串口发送比较简单,直接调用相关函数即可,如下: - HAL_UART_Transmit_IT(&huart1,"Hello World\r\n",13); d! I, K6 e' e/ X
- HAL_UART_Transmit_DMA(&huart1,"DMA Test\r\n",10);
复制代码 ( [3 T1 o& q. T) m% p* e
HAL库的串口接收只支持接收定长数据,当数据长度不确定时,需要自己处理。 中断方式接收: 首先初始化完成后打开串口接收中断,接收长度为1字节,即当接收到一个字节数据后产生串口接收中断。 - <span lang="EN-US">HAL_UART_Receive_IT(&huart1,&RevByte,1);//</span>打开串口接收中断
复制代码 , O+ z+ g8 w4 |/ R
编写中断回调函数,由于HAL库已经在底层做了处理,串口接收的1字节数据已经存储在RevByte中,因此在中断中直接读取RevByte的值即可。需要注意的是读取完成后要重新打开中断接收。 - //串口接收中断回调函数# D4 K# O- @& z; G& N1 f) S
- void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)8 ~+ C3 ]1 F, q+ p" \- t* d1 X
- {
& Z, ?" V' B) m5 h. H) \! h( R - if(huart->Instance==USART1)
8 N# R" \- G* I3 [: |% o/ u0 D: | - {
1 ?& S& P& O& D5 Q% |, d7 N) H - RevBuf[Revcnt]=RevByte;3 O/ H6 s+ y/ a7 K b1 {
- Revcnt++;2 n) c0 K A3 R: a7 F/ e
- if(Revcnt==BUF_LEN)
8 \8 M- A. L4 ? - {
7 g; {( K7 g4 @7 w0 s+ E7 t U3 U - Revcnt=0;
/ F" f6 ^' H! z/ I' Y" H4 A, t - }
/ G% B' q6 B$ f( z0 p/ d - HAL_UART_Receive_IT(&huart1, &RevByte, 1); //串口1中断接收数据/ y' U- r0 G3 |% o% K4 k
- }
6 _' ^* i* o6 t; Q: j. g - }
复制代码 - a0 |) g7 m8 L3 @; A/ D+ I
DMA方式接收: DMA+空闲中断的方式也可以实现接收不定长的数据。首先初始化完成后打开串口空闲中断和DMA接收。 - __HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);//打开串口空闲中断
- g) k( ]! g, B - HAL_UART_Receive_DMA(&huart1, RevBuf, BUF_LEN); //串口1DMA接收数据
复制代码 # k7 S: u' p$ u) q# ^4 C* V
编写空闲中断函数,在主程序中判断标志位,进行相关处理 - void UART_IDLECallBack(UART_HandleTypeDef *huart)
6 F: K: d E, ~, U3 A: i% k- | - {
) ]$ W) Y! f7 P; I - uint32_t temp; 1 K0 h% r k# N9 T; u; k
- /*uart1 idle processing function*/4 h2 I% b: S% F9 w9 }
- if(huart == &huart1)& r2 G. K7 O/ }0 l# p
- {4 o; c+ E- K$ A4 D- l
- if((__HAL_UART_GET_FLAG(huart,UART_FLAG_IDLE) != RESET))
/ v- B' c, x6 d( o' |/ w7 @ - {
" t8 h% I% I9 r$ V6 D% |+ J m - __HAL_UART_CLEAR_IDLEFLAG(&huart1);//清除标志位
5 q/ p4 r+ _* E; o - /*your own code*/
+ |7 N g$ h. V5 | - HAL_UART_DMAStop(&huart1);//停止DMA
f, _, e2 E, f9 @ - DMA_Usart1_RxSize = BUF_LEN - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);// 获取DMA中传输的数据个数/ y1 P, N% D8 Y% v$ a" ^
- RevFlag = 1;
: A1 n# I$ a) A: Z# f- {1 e - HAL_UART_Receive_DMA(&huart1,RevBuf,BUF_LEN); //开启下次接收
/ F( H1 G* ?) C8 x y' h) b - }
, s2 R, P! |/ d& j# {, n* a - }
# J. J% H7 F$ \3 w2 u - }
5 a7 z& J4 n$ K$ @
6 F& d2 O7 f6 z, j- r/ O% S7 _. g- if(RevFlag == 1)
4 t b# w9 n7 n$ a - {# z' K4 ~, X2 [
- RevFlag = 0;
% C! \# Q/ J f G2 }+ r# ~ - HAL_UART_Transmit_DMA(&huart1,"DMA RevData\r\n",13);3 P3 _' T7 x, J- X6 I2 s G: j
- }
复制代码
. _1 R3 Y' R% i0 E* [9 q在串口中断函数中调用空闲中断函数。 至此,串口的基本使用就介绍完了。需要注意的是,HAL库需要考虑不同芯片的兼容性,因此程序编写的比较复杂,执行效率低,从串口中断部分可以看出,有时当单片机资源有限且波特率较高时甚至会出现一些错误。所以需要用户根据实际情况对中断部分程序进行优化或重新编写。 文章出处: 嵌入式技术开发 & a8 Z( L4 \$ |
|