在使用1.2版本的HAL库开发STM32H743的串口7设备的时候,遇到了如下问题:
~5 Z; b) G+ d: l+ \数据发送使用HAL_UART_Transmit进行发送,单独测试发送的时候,发送正常。
% Y; w: [, t. [2 K9 ?5 f0 Q T接收则是HAL_UART_Receive_IT,逐字节进行接收并存放至数组,配合定时器进行不定长数据接收,单独测试接收的时候,接收也正常。: x+ p; ?( \- l! e, R
然后博主这里就把TX和RX短接,按理说在发送完成后的50ms以内就会打印接收到的数据(定时器设置的50ms溢出,即不定长数据间隔为50ms),但是这里并没有看到输出。
& k. d7 |' v* t+ m' u& D% l p1 J
研究了下源码,可以发现,发送的时候,会把串口状态huart->gState标记为发送忙HAL_UART_STATE_BUSY_TX并上锁。2 V) t" F4 k v. R! @" Q0 R/ a1 F
- HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)- B" G$ D' e, l' l
- {$ Y1 {8 E$ ?' R/ x4 H3 \; A
- uint16_t* tmp;6 B+ E$ C- i2 w; j6 m D* U
- uint32_t tickstart = 0U;
# E8 T3 H5 m7 T O - : B( k9 ^, v \, z. G- m" |; U
- /* Check that a Tx process is not already ongoing */
+ a f9 v. {* N/ t$ } - if(huart->gState == HAL_UART_STATE_READY)$ T2 a+ [3 l' S4 Z5 j
- {
. q% \2 {, |# b8 [ - if((pData == NULL ) || (Size == 0U))3 @, v2 x3 P; W0 S. ^
- {: ]' x- X8 F# ]5 {$ ~) p
- return HAL_ERROR;
( I5 {" t G$ {3 q& n* z0 I0 L - }8 k$ e1 u, x, M$ u
) h5 V) y' e- @! y, s0 C) b& Q- /* Process Locked */
: w! W2 v) O1 p- C - __HAL_LOCK(huart);
* W+ R" O* w4 I* @# D* W9 ]
; b9 ]( Z' \4 o* h% b% ^3 K- huart->ErrorCode = HAL_UART_ERROR_NONE;
' c. Q4 \, P& ~% Q5 ]! X - huart->gState = HAL_UART_STATE_BUSY_TX;
) K4 x, N2 i" [5 C
: t# Z+ I# d1 a! R1 Z& Z- /* Init tickstart for timeout managment*/+ L" |' ^( w4 U& @) _$ |5 R# s- Q
- tickstart = HAL_GetTick();
; Z1 q" Y6 ?- l! c& ~$ U. }9 v - 0 y- S7 n) Y9 O3 V4 } s( t
- huart->TxXferSize = Size;
$ l2 c/ v: R( G5 v1 Y; y; e& I- e9 [ - huart->TxXferCount = Size;1 C& }- F' \; p' K* _, k7 h. H& G
- while(huart->TxXferCount > 0U), C" d1 T( y$ q3 S u _
- {. q: v5 n" v7 \2 W' v2 V
- huart->TxXferCount--;
! @. P! c9 q, T1 } - if(UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TXE, RESET, tickstart, Timeout) != HAL_OK)) N4 g* a n+ c5 F3 n
- {; U9 x. r# f* g) c
- return HAL_TIMEOUT;
* k O9 M" p6 V X. A - }/ F3 \( H) Z1 A" _: h5 Z& n
- if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE))- }/ _+ P+ c+ w" c; v
- {
& B5 [$ @* y( n$ o% n4 G. o - tmp = (uint16_t*) pData;/ L! B$ W8 F* O7 V1 D! V
- huart->Instance->TDR = (*tmp & (uint16_t)0x01FFU);
" ]3 i H' N0 a - pData += 2U;. u( i D; y6 c/ |
- }( V) v5 B' k2 E& E
- else1 w- _9 V' \; Z/ S5 f
- {! @8 V* J! p6 l7 l7 H2 p1 k: z4 s
- huart->Instance->TDR = (*pData++ & (uint8_t)0xFFU);
$ W1 S- |, D, S - }
+ @* f+ h a# n8 c - }( ]( a' g$ H6 w1 m
- if(UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TC, RESET, tickstart, Timeout) != HAL_OK)
- x3 Z$ b- X O: u5 I, i/ y - {
7 b/ ~9 e+ F) P, r0 Q# N - return HAL_TIMEOUT;
7 K; Y! B' X& C- ~" \4 Y+ y - }
6 J) b b4 e6 N m( K( R+ y0 B - 3 Z% R8 s( E5 P, p: _) W
- /* At end of Tx process, restore huart->gState to Ready */
# U" d- a# i. n7 U( {. j - huart->gState = HAL_UART_STATE_READY;
# s& x- ?0 T1 T8 A# K5 V7 r - ! `/ w, A5 @& V/ ^* s0 m# E
- /* Process Unlocked */
% q$ p7 z# f& ?7 o0 ~6 A0 [ - __HAL_UNLOCK(huart);
9 L9 m0 P6 N' o! v& R - 7 _. f- i$ J" S4 {; f
- return HAL_OK;
% O M0 [% Y0 e6 W j1 | - }
5 v( r7 k2 F" S' m: ?( Q9 U" u - else
" F( T% ~- o( _9 T& h( o6 M7 b - {2 W+ f B8 d* p4 J
- return HAL_BUSY;7 _8 ~ K0 Z ~! I3 _ h4 o2 y
- }1 x. K/ M7 R1 j' J! t- k. z
- }
' z' q( L( _2 J( m2 J
复制代码
0 H( d0 l0 Z0 f; t: x: L而接收中断触发后,中断向量入口UART7_IRQHandler会直接调用HAL_UART_IRQHandler(&huart7)分析中断请求,根据接收数据完成请求函数调用UART_Receive_IT(huart),注意这里会把huart->RxState设置为准备接收HAL_UART_STATE_READY并上锁。
+ g) P+ ?! r6 E6 I4 o- HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)2 M& }& q( y+ E @8 ]# D
- {
0 |: _0 F" X9 r7 v6 v; {( b - /* Check that a Rx process is not already ongoing */( X6 e6 d$ L4 X% X7 \2 I
- if(huart->RxState == HAL_UART_STATE_READY)
' P% }! J& [8 W( A0 k* d - {
$ [) G# K; e2 a - if((pData == NULL ) || (Size == 0U))
0 V* q: d. K' |& e# W/ N - {; ~. K7 K. B! }; |
- return HAL_ERROR;
- _- x9 l! p9 f - }& {: \' o2 o7 f5 M4 N7 \3 L
' f7 l" L& ^4 c- h# M* S- /* Process Locked */8 G' q# l2 w2 F3 e h/ K
- __HAL_LOCK(huart);
7 ~% s n0 F- R9 o5 n# J" g
) k2 B- o" f" \" C9 j+ \9 P- huart->pRxBuffPtr = pData;& r! v- b& N# f2 [4 j% I
- huart->RxXferSize = Size;% ]/ G; {# R l2 a, ]/ o
- huart->RxXferCount = Size;
: o% _+ u4 z( R8 E( y
& B! U6 W9 r4 S! c9 R3 N$ l/ |- /* Computation of UART mask to apply to RDR register */. O7 z7 @1 n H' k
- UART_MASK_COMPUTATION(huart);% r* o, ]3 R f9 h+ [. r, t
- , _% ^9 J" D, ^: K8 s5 G) j
- huart->ErrorCode = HAL_UART_ERROR_NONE;; F `2 k( N8 I% j n, r
- huart->RxState = HAL_UART_STATE_BUSY_RX;! k" q2 B8 d( q( ]& y. ~
- : a3 X2 v. K/ P/ T+ V) x
- /* Process Unlocked */
6 j, E4 @9 X. `6 v6 w - __HAL_UNLOCK(huart);9 \8 t. j7 L$ h' m& V2 D
- * q# g0 g6 @/ `1 b
- /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */
4 ?' Z. l/ E2 z# {5 |- U, h& M - SET_BIT(huart->Instance->CR3, USART_CR3_EIE);
+ s3 Z1 @; C( ^
1 M$ O' K" }. r6 r l5 Z6 N# v, L- /* Enable the UART Parity Error interupt and RX FIFO Threshold interrupt
, ^ h( p- b4 m3 s6 \0 U# C - (if FIFO mode is enabled) or Data Register Not Empty interrupt
+ U0 z7 t8 V u7 | S - (if FIFO mode is disabled).
& z5 o) b5 n) V4 [; o7 \ - */
( _2 ?' ?0 v5 {# u7 `/ m% H - if (READ_BIT(huart->Instance->CR1, USART_CR1_FIFOEN) != RESET)
5 b. U k2 s6 _# R - {
6 l6 f: ~# N! c( l6 v* d) N - SET_BIT(huart->Instance->CR1, USART_CR1_PEIE);) U% @ G8 A9 n! o1 }
- SET_BIT(huart->Instance->CR3, USART_CR3_RXFTIE);* s5 y" E( [6 `: F! h) k# o B
- }: ~5 Z1 k0 _6 j' p# K. x2 S7 _
- else
$ u' k! C8 S$ h2 W - {
5 O! f4 a- m( Y S9 P A - SET_BIT(huart->Instance->CR1, USART_CR1_PEIE | USART_CR1_RXNEIE);0 c4 d. _* @4 K# Q6 y
- }1 Y$ T. @9 [( j7 r2 }2 h- ^
1 d9 c) I' p) h' o- return HAL_OK;+ l8 `; O% i- E9 u) n5 G
- }, P* z4 @+ P) c* n
- else+ I u" v F% @, L7 x
- {
/ E0 Y- @* w* H: B - return HAL_BUSY;5 D. I3 X# ` w& {7 p' B7 ]9 C$ |
- }
# v" F V; ?1 p. C) l0 y1 n - }' C T5 q( ~/ `5 h
复制代码 % Q- H4 B9 _7 _
查看一下定义,可以发现这里的一个设计缺陷,gState代表发送状态,RxState代表接收状态,通过这个状态机来保证接收和发送过程的完整性,但是,只设计了一把锁Lock,而锁是用来保护发送或者接收单个字节的完整性的,这样就导致了在连续发送的过程中,处理接收来的数据发现串口设备被上锁了,返回busy,从而丢失了发送的数据。# x& z- |; ?7 Q; G: D' X. R, G
- typedef struct4 w5 l# U) L4 K) w) K- a
- {
* ]( q1 z' u+ E% R! V - USART_TypeDef *Instance; /*!< UART registers base address */
$ N- m+ s7 N- w% T3 _2 E
' z4 @3 w1 R+ B% Q" `" k! D- UART_InitTypeDef Init; /*!< UART communication parameters */
" H4 @* b* \& T9 X - ( h N' U( \2 H" h
- UART_AdvFeatureInitTypeDef AdvancedInit; /*!< UART Advanced Features initialization parameters */
& a$ `7 l, F9 c3 p& I - - t& O9 u# e) x. @7 t* d
- uint8_t *pTxBuffPtr; /*!< Pointer to UART Tx transfer Buffer */
6 p9 q+ F( [( X+ K
! x% I$ j7 k9 j& N5 E$ n4 _% o9 x: [- uint16_t TxXferSize; /*!< UART Tx Transfer size */ w1 i+ e3 _+ B! q
3 ]) j- t+ p* _- __IO uint16_t TxXferCount; /*!< UART Tx Transfer Counter */0 z" V9 u: l! R! n7 g
- / m8 v7 a% {3 ?- a9 j
- uint8_t *pRxBuffPtr; /*!< Pointer to UART Rx transfer Buffer */
+ o! i, N5 ]1 [: c; r# D - I& I& v: F: e: q! @
- uint16_t RxXferSize; /*!< UART Rx Transfer size */
V b' |+ h9 v: y: ^4 U - 5 x$ e3 F2 E) u) c2 f
- __IO uint16_t RxXferCount; /*!< UART Rx Transfer Counter */
$ _% R& ]) f- R - - m! D) G& ]: T# G
- uint16_t Mask; /*!< UART Rx RDR register mask */. E& y$ w& j* x1 m6 E( [/ ^
- & I; J# l2 |: B
- DMA_HandleTypeDef *hdmatx; /*!< UART Tx DMA Handle parameters */' q0 J3 r' I3 I. u- w! h4 C/ b- h
% g+ v* I2 Y% s% k( ?- DMA_HandleTypeDef *hdmarx; /*!< UART Rx DMA Handle parameters */ E$ ~0 w% ` w. l, T
- 9 @2 U$ Z0 D- \1 o/ C
- HAL_LockTypeDef Lock; /*!< Locking object */
- V! a/ Q6 s1 n: V0 p5 c' O - ( J, A, H. g6 p2 l ]/ o
- __IO HAL_UART_StateTypeDef gState; /*!< UART state information related to global Handle management
: L4 J- r/ `9 _1 s I. u# R - and also related to Tx operations.; X ?$ F6 |( O4 d: u# e' s
- This parameter can be a value of @ref HAL_UART_StateTypeDef */" u9 N3 a$ j& M" I% T1 O
/ T1 {- }5 O' Y- __IO HAL_UART_StateTypeDef RxState; /*!< UART state information related to Rx operations., y9 p* ~. v; Q4 y8 O
- This parameter can be a value of @ref HAL_UART_StateTypeDef */6 t# P, E' p" b) Q5 ^. w6 Q" ^
1 @7 L9 L4 s8 v) O& C- M" `* L- __IO uint32_t ErrorCode; /*!< UART Error code */
" U/ O0 h# n7 W! X1 e
: r$ t" X/ ]; F) y( c- }UART_HandleTypeDef;& F- ^# w1 O! ]# V0 l( k
复制代码
7 B/ O0 |7 _: E4 `+ y6 ?因为串口本身是全双工,一个比较合理的设计方法就是再设计一把锁进行保护,而网上的大部分解决方案是注释掉调用锁这个过程,个人是不想改动HAL库的,于是自己写发送函数和接收函数。
+ v8 C- t: P# v6 E3 O4 B' ~7 {# e d7 O6 t! s% L# W
+ c3 E5 Q' K" }- N+ \" M
首先是串口初始化,没有使用HAL_UART_Receive_IT设置接收buffer,而是直接使能接收中断。4 S/ B, c* p4 e
- void MX_UART7_Init(void)
+ G' e! X+ C# t/ Z* N - {) ?, w( }: a+ ~8 E: c' g9 h
- 2 f+ r0 v, ^. t$ M1 k0 e3 o1 _
- huart7.Instance = UART7;
0 c* y7 T; S1 R( t. q6 N0 D6 {2 e - huart7.Init.BaudRate = 115200;1 c0 x. O Z2 O' V/ t: W* i& Y
- huart7.Init.WordLength = UART_WORDLENGTH_8B;8 p4 [0 M* b& v- g* K8 {
- huart7.Init.StopBits = UART_STOPBITS_1; ]4 X' a9 z1 x# R
- huart7.Init.Parity = UART_PARITY_NONE;
- W# q) r) n$ B% W# O - huart7.Init.Mode = UART_MODE_TX_RX;0 y: x, q7 |9 Z+ x
- huart7.Init.HwFlowCtl = UART_HWCONTROL_NONE;" E/ O. t( I1 G( M% P
- huart7.Init.OverSampling = UART_OVERSAMPLING_16;
0 H# L$ Q9 b2 a4 j* M - huart7.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;6 D& v/ C4 Y9 U$ f
- huart7.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
, H9 L! m! @9 x6 f - if (HAL_UART_Init(&huart7) != HAL_OK)
+ z, X# J) r( T( x7 V( h - {/ s8 r8 [) n; z! b( W
- Error_Handler();
8 o% C! [$ k! ?4 i& i- F. r - }
+ C$ y8 ^$ G4 E) L! {, b - __HAL_UART_ENABLE_IT(&huart7, UART_IT_RXNE); //使能接收中断5 D, I0 F0 E! a. ?- g9 r
复制代码 . u, ~" M5 d' i+ m: }
中断服务函数这里,因为我只使能了接收中断,所以只对接收中断进行处理,其他中断源直接清除。
3 W" w$ K' p' E7 v G- void UART7_IRQHandler(void)
6 G0 w- E7 u( ]4 y% } - {
5 R! V: l3 C4 D* ^4 J; R! W$ ]1 f+ r - char ch;9 Z* p! J$ j6 S6 {1 t
- if ((__HAL_UART_GET_FLAG(&huart7, UART_FLAG_RXNE) != RESET) &&
1 D6 R6 ^, ? ^ - (__HAL_UART_GET_IT_SOURCE(&huart7, UART_IT_RXNE) != RESET))
2 U; b! m: W* M9 k - {* m5 P7 N$ N) f* P+ F6 F9 a; }7 N
- ch = huart7.Instance->RDR;
W) B A$ @- Q2 |) n+ @* g - __HAL_TIM_SET_COUNTER(&htim6, 0);/ Y, g, \. ?* ?& p
- if (USART7_RX_STA & 0x8000) return; //上次接收完成的未处理,直接退出
' g8 a; ^/ E7 V) |: i4 g2 _# z& f+ M - if (USART7_RX_STA == 0) //长度为0,接收到的是第一个字节,启动定时器
9 t3 K* S0 B$ M. ^$ x7 I - {
+ m7 e! J2 a; d - __HAL_TIM_CLEAR_FLAG(&htim6, TIM_FLAG_UPDATE);$ L1 s t) P! j! s8 p) c
- HAL_TIM_Base_Start_IT(&htim6);& c% `/ i f% F! T
- }
, \5 Y p9 d9 N! |) W: h7 z - USART7_RX_BUF[USART7_RX_STA & 0x3FFF] = ch; ~% o7 {; P' \1 w- X7 h
- USART7_RX_STA++;6 q& N, D* m" ]
- if (USART7_RX_STA > (USART_REC_LEN - 1))USART7_RX_STA = 0;1 T% K q/ h: s+ L: `
- }
% k: K* a, {0 j" j - else
# v3 m' V+ y5 ?6 w- U* b" n - {
: a8 W$ C' [4 w8 F- D$ V5 z# K - if (__HAL_UART_GET_FLAG(&huart7, UART_FLAG_ORE) != RESET)2 O6 A* @( h+ {% e% p
- {
v, o6 T! t9 T4 ?# U+ q. | - __HAL_UART_CLEAR_OREFLAG(&huart7);$ w( `& x' ~+ }& u5 `
- }
; _$ f" I) |- W3 I/ q1 U - if (__HAL_UART_GET_FLAG(&huart7, UART_FLAG_NE) != RESET)
$ b9 t9 e9 Z% h/ {* w/ p - {, H: ^9 u) C5 [' l8 P
- __HAL_UART_CLEAR_NEFLAG(&huart7);, Z, D/ \7 h$ N8 O: ^5 S
- }2 n" o8 C# \! E, K. g7 t
- if (__HAL_UART_GET_FLAG(&huart7, UART_FLAG_FE) != RESET)
" S4 N, q, i/ ~$ |3 n$ u - {3 _3 H6 l6 _# @
- __HAL_UART_CLEAR_FEFLAG(&huart7);
# o0 d0 I, p5 V! R4 c - }8 t9 k. `2 t$ B
- if (__HAL_UART_GET_FLAG(&huart7, UART_FLAG_PE) != RESET)1 v8 J+ y- }: M0 p
- {
4 V' {# ^% q! q" ~ - __HAL_UART_CLEAR_PEFLAG(&huart7);* U4 Q- t' p. C# P H" o! x
- }2 b) |! X1 D3 i7 d0 }
- if (__HAL_UART_GET_FLAG(&huart7, UART_FLAG_CTS) != RESET)$ Z5 ?& E: V& J0 G0 k
- {" z) b. L4 z) L5 C+ M
- __HAL_UART_CLEAR_IT(&huart7, UART_FLAG_CTS);
C" }" Q3 u1 J+ ~) f) P/ ^4 j - }
, g m5 ~; X; ~ - if (__HAL_UART_GET_FLAG(&huart7, UART_FLAG_TXE) != RESET)1 n$ R& f% p; h/ E" x
- {
9 f6 i2 J J; c; I( D! X - __HAL_UART_CLEAR_IT(&huart7, UART_FLAG_TXE);9 b1 q% K p: q" e# R
- }
& `3 s2 B: T/ K4 N - if (__HAL_UART_GET_FLAG(&huart7, UART_FLAG_TC) != RESET)
8 @3 J9 |0 D3 D, O - {
1 e; N7 D" w+ x: f8 w; w) x3 p - __HAL_UART_CLEAR_IT(&huart7, UART_FLAG_TC);
/ ^$ p, [- n, e0 X - }+ ~% O8 [+ x+ F' O& W; K
- if (__HAL_UART_GET_FLAG(&huart7, UART_FLAG_RXNE) != RESET)
+ D1 H$ v/ g& Q* N2 j" l - {
/ y& H( ?' i& Q# U1 }; S - __HAL_UART_CLEAR_IT(&huart7, UART_FLAG_RXNE);
' [5 \, {% H+ H0 O1 P' ^+ y# A - }7 L( j s; j( e
- }' k. U3 o# h% s% B1 h
- }$ U% q F# W* P: \6 \2 Q1 o1 g% e" D' a
复制代码 : a) ^3 n& U( G' O- N$ f5 Q
发送过程就比较简单了,等待发送完成继续发送就行了。
3 a. A+ H" M4 I; x# Z; i0 u4 ]$ u- void u7_printf(char* s)2 B$ K: F5 V \- ~
- {( l0 z- O7 T2 S2 g* G
- int i=0;
: Z$ D; Y! |9 l - while(s[i])
6 K- Q- V/ N3 h/ @ - {3 ? J2 i6 E: O+ r: n
- huart7.Instance->TDR = s[i];+ E$ V" r# N$ w8 a
- while (__HAL_UART_GET_FLAG(&huart7, UART_FLAG_TC) == RESET);
% f) y2 o4 n$ ?# `1 W2 u4 y - i++;
5 U9 Q! ]" G8 {( Z: H( x- ` - }
6 }2 K. o' E8 V$ Q( g8 x& j - }
复制代码 ————————————————) p. h5 O! y3 y# `0 i) q# Q' U
版权声明:小盼你最萌哒如有侵权请联系删除
% X# T) J, |3 U7 k9 N
! M( m% s6 k1 L$ k3 Q' }
4 V0 k9 L' y% b$ Y& B/ q4 L: r( C! K: h6 {1 @
|