|
STM32串口中断接收不定长报文并解析
0 S# R* t0 V; e( e" t6 G4 R- E9 p) P# c4 z6 M3 g( W" M
功能实现背景介绍
8 }8 n6 n" y4 S# `; ]7 q7 Z( b! d( {本项目中,需要使用STM32的USART6串口与FPGA板(下位机)通信,需要发送和接收数据,有报文应答机制。7 f) N$ w, Q( T
使用的报文规则如表格所示0 a1 B s% w; r! N7 o( i
, `: h0 {) |2 j4 q9 L
板间报文的通信协议,校验使用的是和校验
9 N% D) h% h5 P: c% [+ G" c/ d7 z4 r- <font size="3">U8 TX_CheckSum(U8 *buf, U8 len) //buf为数组,len为数组长度
0 H1 h2 O: D- n8 s! ^& E7 L - {
9 Q/ |1 |! @: F - U8 i, ret = 0;
[9 l6 c9 B; A - for(i=0; i<len; i++)
& j$ V; x/ h l5 e - {
T! e0 j' ~5 A- {( y; a; U - ret += *(buf++);
' U; h' s* B3 V9 ~3 U$ V - }% [& V8 }* D- ~/ ~# c. L6 l
- ret = ~ret;; P% R/ n6 S* g8 ^. M& @$ J
- return ret;1 L, J# N* O' A( ~3 s7 i
- }: h: E* I/ e# a! N" y) h
- U8 RX_CheckSum(U8 *buf, U8 len) //buf为数组,len为数组长度0 K) e# C5 W2 i, v
- { ( ~+ u3 V/ A7 P0 o- X; Y2 I! h
- U8 i, ret = 0;, g! S v& ~6 u3 U
- for(i=0; i<len; i++)# Y4 O. m& Q! @
- {5 p! B1 v& U h* }5 L% |4 A% i
- ret += *(buf++);. K! `' [" p5 O
- }
' V/ Z9 M1 u5 l - ret = ret;# A6 K! l. m8 ~9 k# o
- return ret+1;
. ]2 J2 w& ^4 X* u7 x$ r - }</font>
复制代码
; g0 y8 S+ t' P0 W1 H" `+ N; x
9 ?- F/ H% v, n7 L4 ` `( h发送和接收的报文要满足不定长
. s; a4 t3 { L: p' e) eHAL库的中断接收函数
. I3 u# ^7 Z: x# J6 @如果要直接使用HAL库的中断接收函数,也就是HAL_UART_Receive_IT()函数' R0 v0 G( |# _5 {* |3 J8 {" R
- HAL_UART_Receive_IT(&huart6,UART6_RxBuffer,5); //下位机FPGA
复制代码 - _5 E1 c7 ]0 u( g
( ?4 _% F$ u: F0 S- I在使用时,选择串口,选择接收的缓冲区,选择接收长度。
2 N5 B- g3 W! \3 n. N( h& ~2 d( W2 M% o; r- y
: W- a- n) S' p6 z$ d- /**
5 K5 R' S2 y6 K - * @brief Receives an amount of data in non blocking mode.
' Z% h" k' l9 E4 S, l* S - * @note When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),7 ?; j% h5 Q) o- P0 i. }
- * the received data is handled as a set of u16. In this case, Size must indicate the number
$ Q; A9 G8 d( f0 Q0 y - * of u16 available through pData.
% R- m2 I/ F2 ]7 a& D - * @param huart Pointer to a UART_HandleTypeDef structure that contains1 L f! A! K' P/ A' X" k
- * the configuration information for the specified UART module.
* ?, D, \" h9 n1 D* n) A - * @param pData Pointer to data buffer (u8 or u16 data elements).
1 z$ i* n7 [4 @6 N5 F& i+ @# D4 ^ - * @param Size Amount of data elements (u8 or u16) to be received.1 l/ I+ M0 s! H3 G; _
- * @retval HAL status
) D7 V# p |5 b; t) R- C - */1 F" a4 M& C9 v8 ?
- HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)6 }" ^: o+ O3 W5 z$ v
- {* N# m6 L. C/ ~$ o' [2 e7 g
- /* Check that a Rx process is not already ongoing */
8 K) v) J; X; x3 D. a1 A - if (huart->RxState == HAL_UART_STATE_READY)
4 V: g4 W* r9 A - {8 {3 A3 C% s$ z. I- C1 [
- if ((pData == NULL) || (Size == 0U))
b I( j8 q6 M2 d0 s - {7 N/ ]$ n ~3 P' q f
- return HAL_ERROR; l% L' @& I* }: D* h
- }
l' G4 \9 p3 O' O6 ~5 f( W
$ g3 f% j3 F' t& t; T- /* Process Locked */$ [: [ m0 F0 C) Q# S# Y
- __HAL_LOCK(huart);
?6 T1 T4 N M* k1 k' S9 Q - # O4 \2 k5 n7 B( X$ s' |$ G7 v6 Y# z
- huart->pRxBuffPtr = pData;% z o! B9 w% q w3 d
- huart->RxXferSize = Size; \7 _2 E3 }: I7 @
- huart->RxXferCount = Size;
' w( r) i, ^9 w7 J3 t# P( Y4 S9 s
. ]4 P& F- ~6 |5 r0 {5 `0 d- huart->ErrorCode = HAL_UART_ERROR_NONE;# g0 |: F% w% z# B# `" a# b
- huart->RxState = HAL_UART_STATE_BUSY_RX;1 a* @" J- p* O+ i
- 4 H, W2 \! K7 Q9 ^
- /* Process Unlocked */0 Z; ~: ?( e. x D* v3 U' h( I6 w
- __HAL_UNLOCK(huart);
2 n T% |& W; U5 c# V" T+ s& z - ) G3 _; h" z, z' z6 \% i
- /* Enable the UART Parity Error Interrupt */, @: b' ]' Q+ `7 ~$ [
- __HAL_UART_ENABLE_IT(huart, UART_IT_PE);" O; U3 M5 I6 j+ }0 c, c
4 W; i9 Q1 D: B: \9 J8 u- /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */% S' Z& T& z( \) k
- __HAL_UART_ENABLE_IT(huart, UART_IT_ERR);
3 l( u8 f5 L* Y# U - , P8 E9 `% w; ?5 M; d& P' l5 a9 K, B6 a
- /* Enable the UART Data Register not empty Interrupt */
+ _/ ?9 U5 ^% \2 M - __HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);% {$ \: k) Z) n2 x
- 1 n/ Z8 V/ D& |6 S
- return HAL_OK;
* L: G" [4 C+ B( b K+ [+ z - }
2 Z- ~; ?1 ?- }7 P - else
5 X7 M( K3 m: I+ @8 E: { - {
# y' E# D! i' N- M1 n - return HAL_BUSY;2 ~. ?+ D* s8 _% \0 r
- } Z# z. n. v4 R- o/ h
- }
复制代码
4 x1 d1 O4 }) F: M+ V# V$ J$ c" u" _. p2 l* e* a0 Q# f! F' k
这个函数本质上其实不是中断接收函数,只是配置函数,配置开启中断的信息,并且接收多少定长的数据结束本数据接收,串口的中断接收还是在中断中进行。* e$ ?% V! t. \
我们本次的长度虽然也是定长,但是有两种长度数据的接收,所以还是从设计接收不定长的数据为最终效果。
4 \9 M; @; \- k: k. Z% m- P' I状态机的运用* @' d& O, ^& F2 z' a
对于不定长数据的接收,使用了状态机,分两次中断来接收数据
) H9 I% _7 |: p
& T2 j" C7 }& G) A - void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
, M' P& o' a2 ]! p) y: l - {' o" o2 f" [4 w4 ?% ~4 n$ d' e6 n
- if(huart->Instance == USART6) // 判断是由哪个串口触发的中断( K! e# a R9 g1 k' j
- {) x' h) E6 `' ^2 \
- if(StateMachine_USART6) //状态机为1,都接收完毕,准备校验
! a O8 T- A m5 p; r0 a) F) K% ~+ ~ - { 4 V6 J/ T8 ?" v* D! e
- if(re_flag6 == 1)
2 a7 D. c3 C/ P) c6 | - {5 s/ X% s; ]9 ?1 z0 @$ G
- UART6_RxCounter = 6;
* P& m5 ~" ^6 x- y* j - re_flag6 = 0;
v' W' e5 O9 B - }
/ \2 r5 O8 a5 Q( B4 L - else/ q" ?5 V1 ]+ w, o6 |# ?% `
- {' h: u& i- D- x( \, W7 }
- len_counter6 = 2+5+UART6_RxBuffer[2]+(UART6_RxBuffer[3]<<8); 4 U' j5 O+ x3 t+ e! A' g
- if(UART6_RxBuffer[len_counter6 - 1] == 0x55 && UART6_RxBuffer[0] == 0xAA) 9 K% f! y2 ~# U
- {
, t4 [' o' f+ u0 o- [4 B" k1 o% m: m - UART6_RxCounter = len_counter6;. Y5 h' k% ?& f+ R3 E% h
- } ( u+ n/ Y5 b; }' R& x- ?
- else5 T) H. T+ r8 c: I5 j% J" B
- {7 P- E& ~7 j1 H/ z- Q
- memset(UART6_RxBuffer,0,0x400);* k/ `3 w2 c6 K2 H9 v
- UART6_RxCounter = 0;: M* i+ _# u V) ~8 R5 I, Q
- } + V( u7 b( F+ M8 }: s" s; g. K5 _
- }
1 C! G/ P' n4 B. J, j - ?+ M+ F. c- W7 A, g
- StateMachine_USART6 = 0; //状态机为0
, S0 u$ q5 G) I0 \ - len_counter6 = 0; : C" w. L- s0 @- |
- HAL_UART_Receive_IT(&huart6,UART6_RxBuffer,5);
3 y4 C/ K, O/ L8 U1 F% l5 d6 w - }
: }% X2 D, f ^% h4 R3 H' d7 T8 h" [( K - else //状态机为0,只接受到了前五个字节,继续接收后面的字节+ U6 D/ \+ ~) j6 U( u* W
- { 2 q3 q. M# V8 ?( ]$ X* a9 V, ~: C
- if(UART6_RxBuffer[0] == 0xAA)" ?0 l: M+ C' p+ ?
- {- r4 U$ t/ c! M- D+ u, a
- StateMachine_USART6 = 1;. R; x6 w" Q: H
- UART6_RxCounter = 5;6 B1 v+ ^! G! C- }; B! V. C
- if(UART6_RxBuffer[2] == 0 && UART6_RxBuffer[3] == 0)
0 ?- S( O. C3 v9 L - {1 Z, y0 U. d2 \
- HAL_UART_Receive_IT(&huart6,(uint8_t*)&UART6_RxBuffer[5], 1);
. R& L" Z, J% { - re_flag6 = 1;
+ [. V& w' v' I5 c4 E2 m# I - }
+ w$ h& B8 A7 F3 `# A - else
1 o2 @5 h% L7 y: |9 \2 P- n - HAL_UART_Receive_IT(&huart6,(uint8_t*)&UART6_RxBuffer[5], 2 + UART6_RxBuffer[2] + (UART6_RxBuffer[3] << 8));6 g) q3 R5 N3 P6 _- I: d0 C
- }
, u+ I" N7 j3 f; k6 r; F2 ^8 v - else# n/ ~# g% |0 @8 |7 f) {5 `9 ^
- {' a! Q& M# X+ m: ] L. `
- memset(UART6_RxBuffer,0,0x400);
, Y* _/ c; k0 I8 J# D - UART6_RxCounter = 0;
; G( _# r, k7 r" |4 { - HAL_UART_Receive_IT(&huart6,UART6_RxBuffer,5);% R+ F+ s; E1 s* y
- }
2 _- T4 e3 g$ d h2 t; ? - ' [ K9 ^& Q/ i4 n6 \1 t$ S
- }# K: W: @. H$ r; Z; E0 R, C4 h
- }
& ]7 A5 m1 \- z - }
复制代码 4 z' Q5 k! [2 y
" _+ V3 r: A% F# t) t- ]
核心思想就是先接收报文的头,根据头来判断后面的长度,把应答报文和音量数据报文区分开,不合格的报文直接舍去同时开启新的接收。8 i3 u: y0 s5 N) F- g
) N) v' g6 U- S6 G, D. V
' a6 K+ y2 Z! w+ e/ }: f) w4 r0 J
- T+ P0 \7 O! `8 Z5 E z5 s* Q' R, C* G" |+ h2 d( ]; Z, K
文章出处:Outsider Hub( I& f& z2 C% K. J( y! K6 T
|