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);+ Z2 N6 q& `7 S; ?2 A
- HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);$ G1 Y& e3 A4 F) w
- HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);. {0 j: ^* a9 _
- HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
6 h" [9 m" _' H( P: c! m; N! q - HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);: E3 x! f5 ` e V, L
- HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
复制代码
; T+ h9 z$ Z- ]; v/ X查询方式相对比较占用CPU资源,因此中断和DMA方式使用的比较多。这里不再介绍查询方式的收发程序,只介绍中断和DMA方式。串口发送比较简单,直接调用相关函数即可,如下: - HAL_UART_Transmit_IT(&huart1,"Hello World\r\n",13);
8 Y$ x9 q, g- t2 q4 z: ^ - HAL_UART_Transmit_DMA(&huart1,"DMA Test\r\n",10);
复制代码
8 k4 `/ c( E/ g9 \+ wHAL库的串口接收只支持接收定长数据,当数据长度不确定时,需要自己处理。 中断方式接收: 首先初始化完成后打开串口接收中断,接收长度为1字节,即当接收到一个字节数据后产生串口接收中断。 - <span lang="EN-US">HAL_UART_Receive_IT(&huart1,&RevByte,1);//</span>打开串口接收中断
复制代码
: x5 E! ` `/ {0 j编写中断回调函数,由于HAL库已经在底层做了处理,串口接收的1字节数据已经存储在RevByte中,因此在中断中直接读取RevByte的值即可。需要注意的是读取完成后要重新打开中断接收。 - //串口接收中断回调函数
1 x+ c, ]( r+ V$ u# W - void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
' c7 _; e& C, J6 F. Z3 l - {1 |4 ~3 D U# R% ^0 ^6 W: G0 v A6 g
- if(huart->Instance==USART1)9 k9 p9 w' O9 T& F
- {
7 }, H% o. X- _7 L) _& m) Q - RevBuf[Revcnt]=RevByte;
& P7 x- ?3 |7 _) W ~ - Revcnt++;
& ?8 Q& H5 M$ _, T9 @ - if(Revcnt==BUF_LEN)
0 r3 w8 C5 e$ ~, N+ I7 g - {
% d2 G( n/ }6 ~5 \6 a; n - Revcnt=0;
' [4 D( L) m2 g - }
$ ~5 i5 O1 F+ \' s! s7 L - HAL_UART_Receive_IT(&huart1, &RevByte, 1); //串口1中断接收数据
) ~4 ~/ t/ S% [ - } J* X* \& z( }. @
- }
复制代码 ; T+ W" j& f2 H
DMA方式接收: DMA+空闲中断的方式也可以实现接收不定长的数据。首先初始化完成后打开串口空闲中断和DMA接收。 - __HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);//打开串口空闲中断. _8 v& w# @! M# H! M7 H
- HAL_UART_Receive_DMA(&huart1, RevBuf, BUF_LEN); //串口1DMA接收数据
复制代码
; I6 y5 W3 I7 S/ k3 J; P+ p编写空闲中断函数,在主程序中判断标志位,进行相关处理 - void UART_IDLECallBack(UART_HandleTypeDef *huart)
# _2 V) i! D& C5 e! s, M2 c( S - {
5 d/ P1 j. |9 k+ |. Q+ V- P - uint32_t temp; : L* D1 g# d' r- w% @
- /*uart1 idle processing function*/
. ]0 F6 H- v0 e - if(huart == &huart1), y7 P5 ~: Y$ H$ R1 H1 T2 ]
- {
* o' `: z* E" e& D' G6 s - if((__HAL_UART_GET_FLAG(huart,UART_FLAG_IDLE) != RESET)) , Q8 f' m t/ R! K, S' A: V
- {
! h1 f+ L0 `, ]% \6 d - __HAL_UART_CLEAR_IDLEFLAG(&huart1);//清除标志位) o8 e: [8 R5 d0 f) R3 G c
- /*your own code*/# `, G. v: b$ S" }" S
- HAL_UART_DMAStop(&huart1);//停止DMA
5 a$ G; r+ g# ]& ?5 z - DMA_Usart1_RxSize = BUF_LEN - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);// 获取DMA中传输的数据个数
7 w4 p2 f) g5 P+ I' V - RevFlag = 1;
) r: G& l, w6 x- e' O) w% F - HAL_UART_Receive_DMA(&huart1,RevBuf,BUF_LEN); //开启下次接收/ k/ m0 e7 B# }# g
- }9 L. @3 u# L1 o. `9 g
- }
5 I* g% R& g' m# A% u1 J+ Z9 J - }
2 N; a0 b4 s, E# b2 n
' B( T5 B4 r7 o: d' }; \" \/ K% O- if(RevFlag == 1)
& L. J' a7 B! T' j* D - {$ m& A" v% c7 z) E: i
- RevFlag = 0;
9 N( m8 c( Q2 T8 e! `7 C. g - HAL_UART_Transmit_DMA(&huart1,"DMA RevData\r\n",13);
) X- X$ l: [5 X c. ] - }
复制代码 & t2 ~6 J7 E! J1 o2 k6 y8 v9 S
在串口中断函数中调用空闲中断函数。 至此,串口的基本使用就介绍完了。需要注意的是,HAL库需要考虑不同芯片的兼容性,因此程序编写的比较复杂,执行效率低,从串口中断部分可以看出,有时当单片机资源有限且波特率较高时甚至会出现一些错误。所以需要用户根据实际情况对中断部分程序进行优化或重新编写。 文章出处: 嵌入式技术开发 $ z. K8 q* D5 a1 ^7 y8 o. E' z
|