STM32串口中断接收不定长报文并解析 ( s8 r) z" \ W: N
2 C# z- d" |0 t* e& f
功能实现背景介绍6 R+ p' ]. T' V: q( ?/ I
本项目中,需要使用STM32的USART6串口与FPGA板(下位机)通信,需要发送和接收数据,有报文应答机制。
" _) P, @) I2 \; b5 ]使用的报文规则如表格所示; E7 f) |7 C( O
1 s' w8 y% ~) w0 r; C' s
板间报文的通信协议,校验使用的是和校验
- G: o0 O, T3 c& ] j3 y- G- <font size="3">U8 TX_CheckSum(U8 *buf, U8 len) //buf为数组,len为数组长度
' R: {( U- D/ [- _ - { 6 x* B9 p4 n! s- Q; L# ~
- U8 i, ret = 0;
- J) ~7 ], e- {( Q - for(i=0; i<len; i++)% z0 w# {) |& m4 m# s5 M7 j
- {
5 a$ } [% {0 d! T4 A6 ` - ret += *(buf++);
: U5 F4 w5 V$ ^7 S - }
0 i( w% M% ^7 U5 b, v' ~9 u P, b - ret = ~ret;
- {6 ]: }9 v% Z' B1 a" v" W5 { - return ret;, n+ e+ N+ @ N; H
- }7 L8 ~/ i- w) Z5 M! C* b
- U8 RX_CheckSum(U8 *buf, U8 len) //buf为数组,len为数组长度
9 d. v, U9 R9 q+ O: ]5 |& I; c - {
& R1 d8 a" [2 f6 Y2 E - U8 i, ret = 0;: Q. Q! D: D+ o" x
- for(i=0; i<len; i++)
N/ b h1 F& L7 K) O - {) P- M) S: ^% [2 B& f& }
- ret += *(buf++); Y! C, R; B+ `% I
- }; e; B7 M+ a! y2 A% |" J
- ret = ret;
8 l6 K0 G4 g! p. [5 j$ J1 g* C - return ret+1;
. L+ u5 q% ^1 r9 e: A7 s - }</font>
复制代码
& ~1 F- M9 b' U' O% {
. y5 o: R3 {7 z9 }发送和接收的报文要满足不定长
~; H4 r( b* c, _- ^6 hHAL库的中断接收函数& O; d. U9 N! F( Y/ @7 k
如果要直接使用HAL库的中断接收函数,也就是HAL_UART_Receive_IT()函数
! z1 g" ]! h' g U9 ~- HAL_UART_Receive_IT(&huart6,UART6_RxBuffer,5); //下位机FPGA
复制代码
- o& Q; a8 U# c. Z4 {
4 g. ~2 u! Y3 G7 \: K" t9 @在使用时,选择串口,选择接收的缓冲区,选择接收长度。( z) s; y8 l% s$ M# Z) h
- t" Y! ~! O* S* m
3 I% |- i" D+ ~4 R- /**
! _9 v# g9 b( W7 l2 _ - * @brief Receives an amount of data in non blocking mode.# h4 V" C- X. g W" [
- * @note When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),* {7 d/ o0 x8 X O( H+ `- l
- * the received data is handled as a set of u16. In this case, Size must indicate the number
+ J+ a: d; p, C6 z - * of u16 available through pData.
! J' M: {& ^8 V; A0 {: i! |- t - * @param huart Pointer to a UART_HandleTypeDef structure that contains
$ S( \5 l C& G* u- d- m1 r) _2 D - * the configuration information for the specified UART module.: u" {2 m5 e% @
- * @param pData Pointer to data buffer (u8 or u16 data elements).' i* `# B3 G4 L! Z" |% a
- * @param Size Amount of data elements (u8 or u16) to be received.
; d/ ~. z' [$ V& |; h1 }2 s: _' X - * @retval HAL status+ `% }9 L7 _( v# C
- */
5 }4 U' H5 t# f! R! Q {# F; J - HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)% a- [5 H4 Q2 Z3 D* Z D
- {8 o, Z- }& F9 f W
- /* Check that a Rx process is not already ongoing */( o7 z P. T' K9 ~1 {3 M* K/ y
- if (huart->RxState == HAL_UART_STATE_READY): [. X c; G: J: _2 F
- {4 ?1 U% k" j' o
- if ((pData == NULL) || (Size == 0U))2 ?5 j! E+ Z E- Y8 ~
- {. K# w6 N7 V* h: r& E6 B5 i
- return HAL_ERROR;6 ?9 D" S: L! C. Z& ~
- }7 y! \& P; \" n6 d6 }
- 8 W' R1 v5 D* y3 q3 j+ _ ?
- /* Process Locked */( p {- N6 t' t3 M8 n# {
- __HAL_LOCK(huart);
, l! F: l* W4 w) H+ n
" c/ h# q! G7 r- A$ E% f/ s( N- huart->pRxBuffPtr = pData;
A& P3 V3 a* A K! ~/ } s - huart->RxXferSize = Size;
4 Y) h- \5 B! s( ^- i: x1 [& Q - huart->RxXferCount = Size;
V2 I" L+ i% f# `: A6 D
+ I2 W f$ H; P: L, @( u- huart->ErrorCode = HAL_UART_ERROR_NONE;
2 W$ ?; P& N; g* L - huart->RxState = HAL_UART_STATE_BUSY_RX;
' r2 B& h# k# t3 B& d - # d! s( h, f6 |
- /* Process Unlocked */
& Z3 Q' c5 f, ~& i - __HAL_UNLOCK(huart);6 G; }9 B( [/ P0 x- _& d
- 9 g# c0 o/ |! Z7 ~4 u) o) x; j
- /* Enable the UART Parity Error Interrupt */
) B5 l3 b M& @& V& F% Z - __HAL_UART_ENABLE_IT(huart, UART_IT_PE);
1 p* V' S6 u% W; ?; O - ! U6 ^, B5 w. F2 f% P
- /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */2 _- {' t# N3 V2 r- `; \ J
- __HAL_UART_ENABLE_IT(huart, UART_IT_ERR);( p$ F, }) n& b9 @5 H/ t
5 ~# I4 Y4 q0 _ A1 ~7 {- /* Enable the UART Data Register not empty Interrupt */0 V9 U2 \' w/ V& p
- __HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);5 C) C/ U2 j9 l, t8 H, a) j
) k) s9 S( |+ U" `9 }4 H" I5 q( V9 M2 k- return HAL_OK;
6 K1 e4 ^/ v; Z( H& n - }' x! D. j+ i j- l
- else
) f3 v$ ]- b+ C4 }+ _3 S - {
+ w. {& o& i2 E! Y6 ?- L - return HAL_BUSY;) ]! V, G* x" i. k4 D- b; e
- }' f! ^( Q6 @ S% @5 T# h: ^
- }
复制代码
$ a9 `/ d7 K% b5 m- Y: R9 I2 i5 J* X W5 U3 N- g/ b
这个函数本质上其实不是中断接收函数,只是配置函数,配置开启中断的信息,并且接收多少定长的数据结束本数据接收,串口的中断接收还是在中断中进行。# K) ]( L, R |) j, F( T( E# x
我们本次的长度虽然也是定长,但是有两种长度数据的接收,所以还是从设计接收不定长的数据为最终效果。
. f0 _. c9 M" | @6 \$ f. k: \状态机的运用
3 \- \' y8 @) Y对于不定长数据的接收,使用了状态机,分两次中断来接收数据% Z$ K! V8 e2 c1 [! w% n
- Z6 r0 ~0 F+ z6 Y" ~( a) E - void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart), z3 U- g9 T% Q
- {
/ F% T1 J- p! c* N8 i$ O/ S - if(huart->Instance == USART6) // 判断是由哪个串口触发的中断* w% x9 i- U( D# R* G5 s2 t7 D
- {2 ~, Y% R8 |3 U9 [! H
- if(StateMachine_USART6) //状态机为1,都接收完毕,准备校验
" }8 i$ Y7 O/ C - { * ?' l- `8 f: z" l: a+ I
- if(re_flag6 == 1)
% H1 z5 u2 z! t; L' M; ?% Y/ y - {
: c; h7 n$ i! e" u. _. A - UART6_RxCounter = 6;+ `+ M- B5 F0 S- [; F
- re_flag6 = 0;
" C: `' V6 {# W. R7 \ - }
: J) J& P+ R K - else$ D7 C% _, I1 p1 v7 J6 `
- {
L c: n) b: n" L - len_counter6 = 2+5+UART6_RxBuffer[2]+(UART6_RxBuffer[3]<<8);
# W, R! y% `- T& U% O4 {/ i - if(UART6_RxBuffer[len_counter6 - 1] == 0x55 && UART6_RxBuffer[0] == 0xAA) . V* {* J+ Q& D0 u# r# |
- {) B6 r/ w* E* H v5 t% [( q
- UART6_RxCounter = len_counter6;
: o% G* [; H" V1 c4 k, o: u - } ; G$ B. l+ Q3 w
- else
7 n9 [3 z+ ]) d! c* b! w- Z! p - {: K5 U: J" r3 `
- memset(UART6_RxBuffer,0,0x400);9 [" c. U3 `: Q; {
- UART6_RxCounter = 0;
6 j( x8 p& M7 p- k" S/ }+ @ - } * }0 T- W4 j7 W+ o! k
- }
D: n! H8 p# Z! P' q -
+ o! ^2 i; e0 c8 P7 e# S7 d - StateMachine_USART6 = 0; //状态机为09 |+ a. J+ o) g Q- w/ I
- len_counter6 = 0;
7 S. s. Q6 i! F2 Q" m - HAL_UART_Receive_IT(&huart6,UART6_RxBuffer,5);
: t: T k4 s% ~ - }
4 H' I" O' E+ f) S - else //状态机为0,只接受到了前五个字节,继续接收后面的字节; R* `, O4 M+ I4 c$ n, f4 j' ]
- {
& Y) ?! _- k9 K* E4 g6 h - if(UART6_RxBuffer[0] == 0xAA)& I' ^3 x" M/ w* l C4 ~; q- F
- {
) q# l3 X& s" h% Z7 ]5 {3 e) x& E/ F - StateMachine_USART6 = 1;$ i& C8 k6 ~$ H5 i
- UART6_RxCounter = 5;( T' e6 I' p- V/ |& |3 N9 ?
- if(UART6_RxBuffer[2] == 0 && UART6_RxBuffer[3] == 0)
. m0 `' x+ j7 o% Q* y - {
' t [, p( N2 L - HAL_UART_Receive_IT(&huart6,(uint8_t*)&UART6_RxBuffer[5], 1);4 }5 E, P6 z `+ q* S
- re_flag6 = 1;
. u0 k2 Q% B) w" t, i# e - }1 {2 T2 P) l# ~2 L
- else4 t! _& D! b& z r2 y# I6 s9 e
- HAL_UART_Receive_IT(&huart6,(uint8_t*)&UART6_RxBuffer[5], 2 + UART6_RxBuffer[2] + (UART6_RxBuffer[3] << 8));
, X! u" K! W: }1 r9 ]- M - }
6 t4 W2 T6 I- [- g5 |. A$ V: n& p - else& K! `4 I+ e' j5 ?9 f: y" V! G t o1 L
- {0 b6 F1 s; ^9 V! E
- memset(UART6_RxBuffer,0,0x400);
# c3 J9 w* p; N6 F - UART6_RxCounter = 0;
4 l' ~$ J* m* M - HAL_UART_Receive_IT(&huart6,UART6_RxBuffer,5);
3 a, a! z; S4 U& b - }8 M+ a8 q9 v6 U/ M0 X& \. c9 |
-
' k& T6 V" N3 I6 ?7 l - }
% L2 Y7 ~5 {+ G1 ^6 Z) y) c - }
0 U4 I- Y5 v: `/ L$ \ - }
复制代码 9 W* i6 w' _+ i0 e
& {/ v" n9 K- K: O# V+ N& n核心思想就是先接收报文的头,根据头来判断后面的长度,把应答报文和音量数据报文区分开,不合格的报文直接舍去同时开启新的接收。
& L% k4 M2 S9 J. `/ p. l' X; Q$ o7 u) a4 w3 M$ f$ A
0 i {) _; ^* Y- b/ o3 {# n) ?" ]3 ^3 N, H( H
% U: Q/ }, z4 Q6 J( j: P- ?文章出处:Outsider Hub* a( W/ g6 a* p8 X! T3 K
|