前言# V: c3 o( L& a% P" h) R. i/ ]
串口在单片机中是使用比较频繁的一部分,一般我们人机交互就会使用到串口。串口的输出比较简单直接调用发送函数即可,接收数据就要稍微麻烦一些,因为我们接收的一般是不定长的数据。但是最近使用到了stm32的串口接收的时候,发现hal库竟然有提供串口空闲中断接收函数,无需配置和自己写中断函数。
8 Z0 m" `, Z/ N, v+ N/ \
0 O2 g; s, m. i2 L p9 x% [一、串口空闲中断是什么?
1 _5 G( \1 V2 {0 n$ L6 X6 `一般我们串口接收的时候都是使用的RXNE,接收到一个字节数据就进入一次中断,然后把它放入缓存,但是数据量很大的时候会频繁进入中断影响单片机的时效性。这时就可以使用到IDLE空闲中断,即在接收到一段数据后在一定的时间检测到没有数据到来,就认为此时串口总线空闲便产生一个空闲中断。
3 B1 Z' l4 G8 y4 m0 ~8 _) Y/ F% W1 t9 P i' ?
二、使用步骤
, ]6 b! ^& j' q1.hal库空闲中断接收函数:" H7 E/ }& ]6 d0 ]' R7 d# T3 @
在stm32f1xx_hal_uart.h中9 w6 B' U, q7 s
5 m5 e* S; A- v5 S5 c0 s
- //在阻塞模式下接收一定数量的数据,直到接收到预期数量的数据或发生空闲事件。
& n4 c% M5 Q( |! A - HAL_StatusTypeDef HAL_UARTEx_ReceiveToIdle(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint16_t *RxLen, uint32_t Timeout);, I5 v% d+ o0 d# B, G
- //在中断模式下接收一定数量的数据,直到接收到预期数量的数据或发生空闲事件。' ]# K' n) g, e1 r
- HAL_StatusTypeDef HAL_UARTEx_ReceiveToIdle_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);4 e+ @& C. b, c
- //在DMA模式下接收一定数量的数据,直到接收到预期数量的数据或发生空闲事件。
* g9 N$ j" z" r4 L - HAL_StatusTypeDef HAL_UARTEx_ReceiveToIdle_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);! [" D: X% k. m! b" L0 D3 B2 p$ y$ Q
- //使用空闲中断时的接收回调函数
/ r7 Z$ e& v% u6 A; X1 g2 [* E - void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size);
复制代码
! d8 C8 F4 P% F. x: G! f% E( @% s( iHAL_UARTEx_ReceiveToIdle_IT()0 a# V! C( o l" X6 l* `
+ Q2 y0 k" K- B4 g& A; H1 Z- /**$ ^4 {6 ~' t, Z% Y' h
- * @brief 在中断模式下接收一定数量的数据,直到接收到预期数量的数据或发生空闲事件。
3 E9 v$ @' C4 i, Y, v2 }/ D1 x6 x1 I) s - * @note 接收由此功能调用启动。由于RXNE和空闲事件引发的UART中断,接收的进一步进展得以实现。在接收结束时调用Callback,指示接收到的数据元素的数量。
$ |) ?( Y6 _0 f8 Q - * @param huart UART handle.: l; s+ x4 Z3 X8 v d- N1 ~
- * @param pData 指向数据缓冲区(uint8_t或uint16_t数据元素)的指针。' o% n. t/ X2 ^! ~# k
- * @param Size 要接收的数据元素的大小(uint8_t或uint16_t)。
/ J, @( i6 ~9 D) `2 k7 u - * @retval HAL status; b; a5 g$ I- P V' q% h6 d
- * */9 B+ _; a3 R# V8 n8 P7 Y8 ?1 p
- HAL_StatusTypeDef HAL_UARTEx_ReceiveToIdle_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
复制代码 / y# m& Q8 n0 ^1 N8 O; S0 v
2.使用方法
* X q- F0 o ?7 f1.在主函数中调用HAL_UARTEx_ReceiveToIdle_IT(). B' y( [ a$ n8 S
2.然后在回调函数 HAL_UARTEx_RxEventCallback()中做相应处理。8 i: C* {$ v. d/ J3 O
- int main(void)
' E7 R6 j) F. R& `+ E - {$ {. {/ y# y" ]# a. j5 H0 ]' n6 `6 n8 U' X
- /* USER CODE BEGIN 1 */
* ]- U9 @' V- [9 i2 } - //__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);
& U& d' h5 p. U7 c& }* n - /* USER CODE END 1 */) W. ?# L$ U% F4 c# ~
" x: ?1 ~9 A0 @# }8 j" u% C- /* MCU Configuration--------------------------------------------------------*/
$ c3 }. D" b t - . g2 y# H) g$ _- K4 e: p- o1 W
- /* Reset of all peripherals, Initializes the Flash interface and the Systick. */- t6 v: q& A( a: b, _
- HAL_Init();4 s0 ^1 P) v( B3 A: n
- : L7 T$ J, k3 N$ a U' C8 l- Z
- /* USER CODE BEGIN Init */' G& C s% ~ }/ ~0 ?+ q/ O
& ~) k# ], v" `" u! t. G- /* USER CODE END Init */, A! s' v3 P) s, Y: O/ r+ `
- 1 _5 ?" _8 I6 U* V; ~0 B* b2 V
- /* Configure the system clock */
2 o) j+ Y# h$ F, a' o - SystemClock_Config();
& h4 M. {8 \9 o1 R! ^ - ' a+ v- Y* d( L8 D0 X
- /* USER CODE BEGIN SysInit */
" ]3 j& M3 {/ k9 K8 X! P4 q# ] - 7 E4 U4 w: G. ^: J3 }% N9 u. S$ t- F
- /* USER CODE END SysInit */
8 O4 c0 o+ g6 Z3 Q+ o: \2 S
0 A$ T4 @* a8 o, h' n- /* Initialize all configured peripherals */' j' Z2 y2 d, w2 |4 r/ [
- MX_GPIO_Init();- s" a, ~* u' {! |! C$ Z& X' ^
- MX_USART1_UART_Init();& S9 ?# A$ J+ F1 P8 P9 q3 n* A
- /* USER CODE BEGIN 2 */
2 `- E( R+ |5 W& B2 N - //空闲中断接收. i% G1 H3 A. o& h
- HAL_UARTEx_ReceiveToIdle_IT(&huart1,Uart_ReadCache,410);, T5 O3 h' l. M! D
- /* USER CODE END 2 */
3 g: y! H% X4 Z' ~ - 0 H. h ]* s8 N
- /* Infinite loop */1 |( A5 X9 b1 O
- /* USER CODE BEGIN WHILE */
- g% ?$ [, Q$ J- v# p# C. i - while (1)
$ A7 M. F: x/ A1 x+ K( u4 t - {, |1 d( N* y8 V+ t( m) q$ U+ C( n
- /* USER CODE END WHILE */
" _. H6 k/ s5 p9 J- v - 8 G3 w5 ?4 C+ T) L2 c
- /* USER CODE BEGIN 3 */
" Q) O8 d- Z' f% I) i - }
; M0 C, b' E4 |5 u# j# e - /* USER CODE END 3 */! I$ \4 V. |$ f
- }
) ]- {! [- e5 V2 c
复制代码
( r) M4 X/ p) o' }& E5 a, R- //空闲中断回调函数,参数Size为串口实际接收到数据字节数
( _! n! K) I/ k, S; I2 ] - void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
7 F, h- n3 S* l- b - {
s4 d* p: Z) E, k/ @( J' f' ^ - if(huart->Instance==USART1)1 ~1 w: d {' o1 F
- {
2 p; {2 Q P/ @- F - //把收到的一包数据通过串口回传2 f' J' s ^" u5 P o: t. _
- HAL_UART_Transmit(&huart1,Uart_ReadCache,Size,0xff);
: x- H% z1 `: } l - //再次开启空闲中断接收,不然只会接收一次数据- q5 ~! t% _# l! Y+ R
- HAL_UARTEx_ReceiveToIdle_IT(&huart1,Uart_ReadCache,410);$ ]! a! o# c* t7 N4 J2 }. Y6 |, }
- }
+ U+ [( v4 f' m" g+ Q: j - }
复制代码
; }/ }. a1 A! T3 ]3.最终效果
. Z) p- _" U6 S) c& e( V }
% y% Y; ^9 V0 d; H) d) k. ?
2 Y5 c* H4 R2 ]+ e! m$ s& f
* w, J* ]# o- S9 h+ r总结5 |% G0 z Y3 E& b; ?
使用stm32 hal自带的空闲中断函数后我们通过串口接收不定长的数据变得十分的方便了,只需要调用两个函数即可。不像刚开始的时候使用串口空闲中断还的自己开启中断和自己编写中断回调函数,大大地提高了我我们开发的效率。
4 O( ^4 V, R" {& O% ]' _————————————————) a" n) @) Q- O0 T
版权声明:北世安2 _0 z3 ]+ _( I+ e/ Z v) j7 k
h5 g5 R( A- b% g
|