STM32串口中断接收不定长报文并解析 , M/ A7 @5 y" F0 W
/ R' x: Z4 C2 J6 {5 f I
功能实现背景介绍
$ l# Z8 v% z# ?本项目中,需要使用STM32的USART6串口与FPGA板(下位机)通信,需要发送和接收数据,有报文应答机制。9 o, r4 M+ z5 S3 O4 M- z. A( L
使用的报文规则如表格所示6 m7 w5 x5 [8 B' g1 J G8 G
: S a: F: ^) b板间报文的通信协议,校验使用的是和校验
: _- l4 E& Z5 c, F6 o O( G- <font size="3">U8 TX_CheckSum(U8 *buf, U8 len) //buf为数组,len为数组长度
: b+ \- b5 w- i+ q - {
: g7 @7 L X4 s/ Y" C! U - U8 i, ret = 0;
+ D+ D+ l G7 _2 h7 H2 L6 p - for(i=0; i<len; i++): @& b* ?; n* p9 Y
- {1 U2 w" U& \9 M. U' H
- ret += *(buf++);5 d6 A( i2 W" W: I. @% G% \
- }
# Y$ C8 O8 F3 A" ~5 y. { - ret = ~ret;
/ p4 S+ F' h/ p( h" k9 q - return ret;
) H6 M8 l. A5 A; z6 a, y - }7 f( x9 o; F& S4 f# G) A
- U8 RX_CheckSum(U8 *buf, U8 len) //buf为数组,len为数组长度
9 ]! Q) g3 P) d# Y9 K - { 7 w4 q3 }8 l, b) N1 e# c
- U8 i, ret = 0;( K9 l% K" P" A: \
- for(i=0; i<len; i++)
& }. n9 X2 G! i# M% x/ G - {
6 _+ Y/ l' j" b2 u - ret += *(buf++);: o G5 u6 q7 X1 q r
- }5 R) P! L9 J4 x4 C: c4 ?; B! Q
- ret = ret;$ b) \5 A1 ]% }; I
- return ret+1;
( `! X. B8 f0 y$ e" L - }</font>
复制代码
# C" S$ Q4 r2 d, Z' o+ E7 `9 k$ z4 G$ N# h4 Y
发送和接收的报文要满足不定长
; I, N: O5 g8 \. Q% A$ |9 T# I! ^HAL库的中断接收函数0 E+ @9 [1 ]) \: ~: t7 {$ z
如果要直接使用HAL库的中断接收函数,也就是HAL_UART_Receive_IT()函数7 _* g9 I2 N2 g4 U B2 C
- HAL_UART_Receive_IT(&huart6,UART6_RxBuffer,5); //下位机FPGA
复制代码 ( j7 m1 G1 f. [0 I) h/ p6 W
: ^5 Y# L) Q( P2 Q在使用时,选择串口,选择接收的缓冲区,选择接收长度。
; \& Z3 \$ p' T) w5 d. i7 V. K
# J) |( [5 f: R; A4 T
- ^/ p; b7 _; S. r+ _! J( W0 X- /**6 g' ^& L5 ?$ n* T# D" |! u1 K
- * @brief Receives an amount of data in non blocking mode.0 H6 u% {9 C* `4 F
- * @note When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),+ ?( ]* C. \' a! u. n" H+ T1 Y
- * the received data is handled as a set of u16. In this case, Size must indicate the number9 b _. x8 x# G$ T' T( M
- * of u16 available through pData.( @+ v( q6 F( P3 e; D/ V
- * @param huart Pointer to a UART_HandleTypeDef structure that contains
* E+ c2 M( S3 b - * the configuration information for the specified UART module.
! d6 n) C" J3 V - * @param pData Pointer to data buffer (u8 or u16 data elements).! j Y+ z# i X) z
- * @param Size Amount of data elements (u8 or u16) to be received.
. @- P8 r" r7 K0 @' V0 e! @( w; d8 p - * @retval HAL status
# j" C3 F+ J j' g" r. s7 Y" b - */4 h1 q$ \( X% o. j, o" W; i
- HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)) P% w: a3 g$ u: ~) p9 Z5 k/ j
- {. j: b: e4 o( L! c
- /* Check that a Rx process is not already ongoing */) M2 o0 d( V5 T) m) T* k% ]/ L$ R
- if (huart->RxState == HAL_UART_STATE_READY)2 U& R* Q% x" Q" h H& v' ?7 Q& _
- {
5 g2 u$ {8 x9 F! X - if ((pData == NULL) || (Size == 0U))
# p3 Y+ q6 ?7 @ - {
m& u6 ~* p* |; q. `7 V - return HAL_ERROR;$ P6 y5 b7 B$ F8 Q' D1 d; R! S
- }
( h- U$ x8 k0 r0 X
2 S/ R# M6 i. I- /* Process Locked */* H0 B$ c& o' ?. u4 K
- __HAL_LOCK(huart);7 f8 A6 _9 T }! ` K
3 y8 s. n* y4 ]2 o6 j- huart->pRxBuffPtr = pData;1 F: p. E) X- L4 v. x2 @; q" ?
- huart->RxXferSize = Size;4 s% e1 q, d+ z1 C
- huart->RxXferCount = Size;' K; u$ e* u2 u: T' l1 c3 B# s
0 O& q% A) P# `- huart->ErrorCode = HAL_UART_ERROR_NONE;/ `! r- I- I5 M" v8 e* K; L, L2 z5 N
- huart->RxState = HAL_UART_STATE_BUSY_RX;$ f5 x6 T3 Q) k3 g& f% M( C( P
- 0 F8 z7 }- K) O5 s! [
- /* Process Unlocked */
) P! R O/ c1 N0 }' }/ `, V - __HAL_UNLOCK(huart);
$ z# ]2 y- U! y - + M* o) M" ?0 T- ^. c* A
- /* Enable the UART Parity Error Interrupt */7 m: q3 s) E/ [
- __HAL_UART_ENABLE_IT(huart, UART_IT_PE);
7 i4 g( D8 r5 C, Q
2 f" e+ h: }5 ^% E7 T- /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */$ U3 p8 i# T$ l3 p
- __HAL_UART_ENABLE_IT(huart, UART_IT_ERR);# V6 g8 M w! |7 P0 \9 Y
- n* Q! e/ x9 j4 ^- Y
- /* Enable the UART Data Register not empty Interrupt */% B) g- C- j9 F- [$ ~8 u$ g; V
- __HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);
+ ]8 k q; Z, V/ L# R - / n5 P" b5 T7 q* C8 W6 [
- return HAL_OK;( Y' I' x5 _6 h2 w
- }
9 @( k4 k5 q3 V8 L9 Q* X6 C! Z - else
7 v5 {8 n& s, y' N1 w$ ^; d# t- q - {/ G# P2 E2 A q- H8 w4 A" G
- return HAL_BUSY;
" |1 T: h+ P3 S6 A- @ - }
2 \" }$ ~( L, G f - }
复制代码 3 B* ^" a9 [ c3 k1 t, g# Y7 V; T
" \/ I- ]% W( _/ I0 C
这个函数本质上其实不是中断接收函数,只是配置函数,配置开启中断的信息,并且接收多少定长的数据结束本数据接收,串口的中断接收还是在中断中进行。
, ~( R1 K! ?6 V我们本次的长度虽然也是定长,但是有两种长度数据的接收,所以还是从设计接收不定长的数据为最终效果。% Z2 ~% R, z+ V4 T
状态机的运用
9 I: U& A+ P F: q7 e# J对于不定长数据的接收,使用了状态机,分两次中断来接收数据
" X {2 E5 J# \. k& @( ]5 {
; I" B( F( Y7 I8 N) q! E
- void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
% C$ |3 y0 ~4 S( c - {4 N0 {' {1 S/ G5 M* S
- if(huart->Instance == USART6) // 判断是由哪个串口触发的中断, H$ T* A2 n3 ~+ r- {
- {# a l ~2 U0 d9 g# F
- if(StateMachine_USART6) //状态机为1,都接收完毕,准备校验
' f9 o( z! \* F - {
1 m$ m1 @' Q* Q; i& N- C, ? - if(re_flag6 == 1)
6 F0 i# Z% Z) E# f - {
; ?' u* m# K9 N& d. @ - UART6_RxCounter = 6;
4 f3 l* e: _2 X$ p7 _: A% s - re_flag6 = 0;6 H8 X7 \4 m+ I, ^# K1 ~2 v
- }
6 d& [" ?3 ?* F7 q v - else* N( q8 \: ^' E" n
- {9 F6 n9 o2 T# c
- len_counter6 = 2+5+UART6_RxBuffer[2]+(UART6_RxBuffer[3]<<8);
' h3 W% }' V4 s( p% M9 R1 s - if(UART6_RxBuffer[len_counter6 - 1] == 0x55 && UART6_RxBuffer[0] == 0xAA) 1 r4 N4 s0 N5 }0 K r* G8 M
- {* @9 `' G' ]! ?' T! D5 O4 `) G
- UART6_RxCounter = len_counter6;
! ?4 c* `! ] u2 \ - }
) x$ z) @, ~1 E) C, h8 g: \ - else
' r+ Y8 P8 I" k3 F( I. W5 z3 E9 Y - {
+ g% u& j F# v8 b! R' i2 `! h% x% ~ - memset(UART6_RxBuffer,0,0x400);" U2 d, c7 F: [
- UART6_RxCounter = 0;
- z) M/ }- h: B( X0 s6 \/ F - } # _0 ^6 I4 p! v s
- } # K. @* x6 }! r6 p) V+ V" H) d
-
5 k0 E! J' ^( D% Z6 | [0 m - StateMachine_USART6 = 0; //状态机为00 E, m4 [ a6 N6 J' h5 L) q4 c$ n
- len_counter6 = 0;
3 o) \- V `! [1 L+ m6 X' r& f! m t7 Y& M - HAL_UART_Receive_IT(&huart6,UART6_RxBuffer,5); * L* v8 J" {: O7 x
- }3 N+ ?, `8 d5 n; `5 g
- else //状态机为0,只接受到了前五个字节,继续接收后面的字节
$ ^3 I, P0 p$ s' J - {
9 d' `! @/ [4 x! o4 [. w4 T$ Q - if(UART6_RxBuffer[0] == 0xAA)6 h* t! k+ {* n. d" A( {! w
- {
9 _) q+ Y6 `" l( i1 d: [0 T9 S - StateMachine_USART6 = 1;
. K' T: \! D- j$ F8 g' b# w9 P, D - UART6_RxCounter = 5;! K2 l5 B8 K& r8 I
- if(UART6_RxBuffer[2] == 0 && UART6_RxBuffer[3] == 0)
1 a/ D& |: I7 N$ F1 h - {
! b5 E- `( D4 @7 ]8 X% _4 ] - HAL_UART_Receive_IT(&huart6,(uint8_t*)&UART6_RxBuffer[5], 1);* ~$ k/ T* x4 C! k
- re_flag6 = 1;
' t3 @) g( e9 |" V - }1 o" U* r: F: C: o; c* z
- else/ z$ o' B; u3 j# E4 ]4 C
- HAL_UART_Receive_IT(&huart6,(uint8_t*)&UART6_RxBuffer[5], 2 + UART6_RxBuffer[2] + (UART6_RxBuffer[3] << 8));2 l$ _# F4 ^0 T W' }9 A- A# @9 o
- }
: d5 @6 P& I0 t- N+ I$ W0 a - else
. v3 R" t& ~/ \' a$ ]% M/ [' M- j6 U8 S - {
* x) C% c0 w9 ?& @ - memset(UART6_RxBuffer,0,0x400);. T5 l( M" h, a F: N+ I3 Q
- UART6_RxCounter = 0;" x* [; P6 M% K e! _
- HAL_UART_Receive_IT(&huart6,UART6_RxBuffer,5);
: {0 v/ d' Z- D% D5 c( ~% L - }
' j/ `7 p; W3 G. P -
8 U4 z# q. G: r6 L - }5 M! r% }, V7 a
- }# K$ l& P. H5 F9 c9 K+ G: [
- }
复制代码
4 Y9 D5 w, i: Q$ j" @7 ]' I g2 m8 A! M: d0 M" a
核心思想就是先接收报文的头,根据头来判断后面的长度,把应答报文和音量数据报文区分开,不合格的报文直接舍去同时开启新的接收。
- w) X' m4 K. L' b+ f7 M2 q$ P
# \) Y2 V" G6 Z* T, B5 h
& q' X8 |3 P! e3 s% @+ @# m% ]3 T9 n+ m
/ ~4 y( ]3 s# m4 p$ E$ {/ B文章出处:Outsider Hub
+ i% h9 b6 y8 B F. h2 Q# f |