|
STM32串口中断接收不定长报文并解析 e# a+ y0 {5 F/ F+ `; ~8 ?* H
) `8 _# o9 x! A! t/ L& X9 V+ ~
功能实现背景介绍
8 H( ~5 k f) X/ C3 `( \8 f5 y. O本项目中,需要使用STM32的USART6串口与FPGA板(下位机)通信,需要发送和接收数据,有报文应答机制。- _, I0 S# _9 d* Q% y' V
使用的报文规则如表格所示' N y" A* c+ e F4 x% f+ q9 v" n
3 k: F1 J( ]5 Z7 |, P7 v板间报文的通信协议,校验使用的是和校验
. c4 j: h% B& [ M& z$ c- <font size="3">U8 TX_CheckSum(U8 *buf, U8 len) //buf为数组,len为数组长度. x; C& l+ m8 T7 Z' _
- {
Q8 t9 [4 Z5 ^# V, L - U8 i, ret = 0;3 z0 a5 `7 z+ M- h6 J
- for(i=0; i<len; i++): f) l/ Z8 C; n/ n
- {
: \% M* V1 J% a - ret += *(buf++); h `. t- q }: Z I5 l+ K- F& k9 g
- }0 e `+ V/ P* q
- ret = ~ret;
# \- w; F; o7 W6 ^- ?: `# @' r - return ret;
c/ l1 @& D) R' `) O$ I - }4 W$ A1 `6 h0 b. g
- U8 RX_CheckSum(U8 *buf, U8 len) //buf为数组,len为数组长度
/ s8 M8 h, {- z7 m8 S/ e2 u - { # h0 @1 ?8 N$ @
- U8 i, ret = 0;2 i; Q9 j. A( m: a( o
- for(i=0; i<len; i++)7 w7 i9 k5 i+ L% }7 ~# \
- {4 S1 s3 K$ @! ~
- ret += *(buf++);: ~- w9 @" o" G* S+ `0 K) V2 E
- }
; \. g f& _% F; ] - ret = ret;3 W N5 E- |# V0 B6 O& x1 I
- return ret+1;
" N6 ?5 I7 A" S9 o9 D7 v - }</font>
复制代码 9 ]* Z3 Z) @+ L* ?# [; U; x% k0 N
1 K5 F6 ?* c( s! z1 S8 K发送和接收的报文要满足不定长
# f8 {# m* y$ V' q0 N3 lHAL库的中断接收函数5 o( o% e" Z! G7 a+ C- Q
如果要直接使用HAL库的中断接收函数,也就是HAL_UART_Receive_IT()函数
7 O# ^/ M) Y& i/ {- HAL_UART_Receive_IT(&huart6,UART6_RxBuffer,5); //下位机FPGA
复制代码
2 g: U. ]9 P3 J! k+ T0 R8 ?# q0 y' x+ o0 F* x3 R2 v
在使用时,选择串口,选择接收的缓冲区,选择接收长度。
$ r: Y# g" A# h: R4 v: O5 E! o
3 M0 |( `: r' `1 R1 e
8 D0 E; {) x. _% D5 s" `- ]! Q9 `- /**
" Z9 a% \5 d9 M1 R9 k' Y - * @brief Receives an amount of data in non blocking mode.
7 j; Z5 K; w7 x$ Y7 E - * @note When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),. ^1 M& [9 _: H* u8 {' W- f+ I/ A9 q
- * the received data is handled as a set of u16. In this case, Size must indicate the number) u3 ^) l& C. T
- * of u16 available through pData.8 E6 z0 J2 Y& Z" H2 v9 p- T1 n* u$ W
- * @param huart Pointer to a UART_HandleTypeDef structure that contains
- N1 U5 p/ V3 v9 |. v - * the configuration information for the specified UART module.
" c! H6 b8 E4 X. i1 }; S - * @param pData Pointer to data buffer (u8 or u16 data elements).3 g. J4 s4 j/ f$ l: H/ k
- * @param Size Amount of data elements (u8 or u16) to be received.
" C `4 p6 K# f: N - * @retval HAL status1 b8 |6 ]5 n% {2 f
- */
5 ]) N1 I( M* S - HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
7 Z( q1 M5 ]. J' y# B - {1 d0 K( j1 w* w: U
- /* Check that a Rx process is not already ongoing */
1 ?; b- @ Z, c/ D, W - if (huart->RxState == HAL_UART_STATE_READY) d8 S% G- H0 D, S9 I' B! J
- { c U& r" u, d9 Q( J6 k7 ^% T
- if ((pData == NULL) || (Size == 0U))& \) A& b# z9 Y+ P
- {' v7 _' g2 S0 W4 d) Q/ b
- return HAL_ERROR;- ^. @$ _" c; H
- }
) L9 Z# B* P8 g1 L' x ?: M% X' ?
$ ?0 _( g+ I0 w/ x8 ~- /* Process Locked */6 \& G7 f" b+ R- Z3 A2 [; [) O
- __HAL_LOCK(huart);+ C. Z3 f6 O3 F$ v5 @6 g/ B; e1 M
- " Z3 Z8 ` g9 k4 ~% e }# R
- huart->pRxBuffPtr = pData;
8 E! ^2 u4 n w0 |1 a - huart->RxXferSize = Size;
4 r4 U- P( o! [8 S* s& B3 p - huart->RxXferCount = Size;
) L# s% b+ ]; o - 2 a1 R- c5 t( \1 w" Q1 @9 l
- huart->ErrorCode = HAL_UART_ERROR_NONE;
, n. X3 R9 v* u$ g1 k- ` - huart->RxState = HAL_UART_STATE_BUSY_RX;
6 u9 N& I& |% d% K0 N - # w6 w) h) i8 s0 X8 G) h
- /* Process Unlocked */
9 e) I* U0 c( t9 a- A2 L" J - __HAL_UNLOCK(huart);6 K$ a* U! G/ s" J2 D* M; @: ]
- m2 j; s: U# y1 \* f0 W1 o4 l- /* Enable the UART Parity Error Interrupt */
. G4 n. K: c8 f7 p4 S8 Y - __HAL_UART_ENABLE_IT(huart, UART_IT_PE);1 G: ^" ?) d3 `4 X. A& ~; `
; e. c* N- A" I" F- /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */! B+ @0 ~: s) ^0 P) \" O v- `! j8 E
- __HAL_UART_ENABLE_IT(huart, UART_IT_ERR);
; l# p9 Q# @+ a% B( C
' _ F, z1 |" f' y1 {8 x- /* Enable the UART Data Register not empty Interrupt */: Z5 W: h& J8 U( ~" L
- __HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);3 ?; F6 y7 L1 z; [: Q/ P. ]: a/ Q, z
9 w; k+ }- B* q9 s! F) ~2 J- return HAL_OK;
0 l5 i: W6 D5 c - }8 I# i! J1 c% ]1 J- k( X
- else
; I* K' }. U/ [# L - {/ }3 x' A% B" g. m
- return HAL_BUSY;
" l6 a7 y1 v& \& z! @) z& N - }
6 ^9 e& K4 I. {. e - }
复制代码
# e- T+ E1 T! N" ]0 W- t7 M: G9 p
这个函数本质上其实不是中断接收函数,只是配置函数,配置开启中断的信息,并且接收多少定长的数据结束本数据接收,串口的中断接收还是在中断中进行。# d4 ^6 s, W X0 e5 r5 B& w7 d
我们本次的长度虽然也是定长,但是有两种长度数据的接收,所以还是从设计接收不定长的数据为最终效果。
" x, Z" k4 [% R; W& e2 K$ d状态机的运用
+ X$ T+ B/ w8 z对于不定长数据的接收,使用了状态机,分两次中断来接收数据; z! `" F7 [2 v6 F& v
- u& L2 @$ B( ^ p! s! d
- void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)' H X/ X* V% \' \9 d
- {
/ e% G( H& q0 {& d1 H - if(huart->Instance == USART6) // 判断是由哪个串口触发的中断
% M: f; ~' p5 ~" D/ H - {
! S+ k" s. _5 r+ L1 i - if(StateMachine_USART6) //状态机为1,都接收完毕,准备校验
5 a+ N7 Z5 b* H7 U, F0 _ o - {
( e' ]9 h/ z! G% v - if(re_flag6 == 1)' W( ~9 K5 A" r/ A. x& R
- {
8 p$ p8 c4 {+ B* E - UART6_RxCounter = 6;
s- A. ?' A$ h: t2 e5 x6 d - re_flag6 = 0;
4 P6 H0 {! s$ n5 Y4 n - } : W5 w/ n" @1 G5 J$ q- F1 G" I
- else
5 W' o. Z- Y' b: a - {, D* |" n/ Z3 L5 u. G( f$ V
- len_counter6 = 2+5+UART6_RxBuffer[2]+(UART6_RxBuffer[3]<<8); # x, K- A4 @8 E4 b5 D q: k! q9 M/ \
- if(UART6_RxBuffer[len_counter6 - 1] == 0x55 && UART6_RxBuffer[0] == 0xAA) 1 Z- B- h5 A# R9 s% X# d$ I+ S% B
- {* m* D, \! i. j- f0 [
- UART6_RxCounter = len_counter6;! O; n K2 x8 H4 c8 b! p$ e
- } & V4 s3 M9 V4 ~' @
- else% s/ d& A' x% i- j% f: f
- { q* m) A! W& Q: o' v
- memset(UART6_RxBuffer,0,0x400);
. q+ k3 L. _0 P' p9 C. j2 a - UART6_RxCounter = 0;8 H9 [" F0 |; R
- } 4 i8 P9 [- T, Z% M; j9 N
- }
) X& h" G! f/ E B, |" e) \8 G! i -
" s5 d' X7 P4 p% ], _- F/ w2 s% s& l - StateMachine_USART6 = 0; //状态机为0' g6 e0 T" q2 {
- len_counter6 = 0; * D. A, G! {# l" t9 M" f
- HAL_UART_Receive_IT(&huart6,UART6_RxBuffer,5);
' {% E& a! e6 V7 ]8 s - }
3 s' B) I$ @3 }: U3 e$ Y3 R - else //状态机为0,只接受到了前五个字节,继续接收后面的字节
1 I( E3 I9 C9 v+ }4 a$ [" J3 U2 `' \ - {
4 C s j. [* } - if(UART6_RxBuffer[0] == 0xAA)! ~/ g. \0 P7 p2 c2 w
- {
* F3 z3 f5 f; z1 B' @ - StateMachine_USART6 = 1;
: g0 e1 z1 V4 O$ H. k# h) e4 k - UART6_RxCounter = 5;, z6 _2 t& j9 g, b- w* K
- if(UART6_RxBuffer[2] == 0 && UART6_RxBuffer[3] == 0)
" L4 Z+ _/ \8 K/ x- L3 g - {4 a6 z7 @9 [2 \5 Y" f! ~9 R
- HAL_UART_Receive_IT(&huart6,(uint8_t*)&UART6_RxBuffer[5], 1);- O8 f; g9 r! d8 f/ u7 f
- re_flag6 = 1;
0 r: F' ?7 Z3 s8 n7 V$ U% l - }# I ^' p- U/ [" @8 Z% k6 b
- else
. O8 r* L; Y/ M. c( a7 k - HAL_UART_Receive_IT(&huart6,(uint8_t*)&UART6_RxBuffer[5], 2 + UART6_RxBuffer[2] + (UART6_RxBuffer[3] << 8));
, }( W& X8 r4 |. b5 U) w$ E( _ - }) ^! J( ]/ t8 V! a
- else
1 v8 T* W. H: m/ ~% [, l - {! o5 f) ?# n, x" e( B5 G' C6 h; ]
- memset(UART6_RxBuffer,0,0x400);
k5 z6 _8 |2 I# t- |. Q - UART6_RxCounter = 0;
: u) x' E. m0 N+ R% o4 G - HAL_UART_Receive_IT(&huart6,UART6_RxBuffer,5);
" r" Y; ~. `* O, S8 {1 U - }* l5 A5 d- H' ?. P; {) k; [1 y
-
0 }0 `! P% x1 C" y! u9 b5 ` - }4 @' Y1 J3 V& N0 \
- }7 B# e. ?- c( S; j, F. f6 ]
- }
复制代码
$ @; I3 Q7 o2 h4 B) x$ y
0 Q# o! I& p& D& ?) G7 L0 G核心思想就是先接收报文的头,根据头来判断后面的长度,把应答报文和音量数据报文区分开,不合格的报文直接舍去同时开启新的接收。
3 b6 Y$ P- Z, w7 z& q# N$ m
y( B6 h4 b) E4 z; v" y6 Q1 q
8 B2 [3 y; a" S& D- S: Y ^ h( @3 ~& Q* D, T6 v: D( c9 R8 f
- Z8 O4 B4 D% Q: a文章出处:Outsider Hub
8 M) M' \8 z' | |