一个关于STM32串口的问题。他想实现接收无限制字符数量的串口信息。
3 x; G5 \% D/ f: G1 Y2 O' W6 a; x. e: V7 `2 u7 l* c
但是他遇到了一个问题,他在主函数中发送循环发送内容(500ms的延时)串口一中断回调函数中如果收到了串口内容,就利用串口发送。
! `: a7 E2 s, R4 v7 p* J" ~9 S+ W6 X- b0 U1 | M2 i- s) c
但是他的串口一旦接收到了信息就会导致主循环中的串口发送极快。他的主代码如下
. m; I: K6 t2 E. a- unsigned char RecieveBuffer;9 O' J. W& M" k- y5 r* x. ~
- void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart): U3 t. } ?8 F: e
- {% o5 u* i2 U s8 p! t, j8 n
- UNUSED(huart);- o" @, z- l# u4 k, o1 D5 f5 Y
- HAL_UART_Transmit(&huart1,&RecieveBuffer,8 ,100); // 将接收到的数据再通过串口发送出去
, \7 ]8 i6 h- r% ^ Q! H( J& i - HAL_UART_Receive_IT(&huart1,&RecieveBuffer,8); //使能接收中断,RecieveBuffer的类型是uint8_t9 i+ e) z6 [ C
- }
复制代码 + }! l1 W* N, P& E! K
看了他的代码,就这么短短的7行代码,让我汗流浃背。- v: y+ i7 Y- j( m3 X4 q. E
# l B6 `- p2 L( L8 K' L4 }6 @
他的发送和接收中有一个参数是8,这意味着当串口接收的寄存器中有8个数据时就会触发中断回调。( ^. y: n, A, }
6 z& x8 W5 z1 @, ~+ E2 q
我们需要注意的是,串口寄存器的数据会被存储到缓存区中,这里的缓存区相当于一个队列先进先出,当我们调用HAL_UART_Receive_IT(&huart1,&RecieveBuffer,8);& q) f$ @. R6 S1 |% h, l
7 O& p$ U, Q5 o) _3 X会将RecieveBuffer作为缓存区,将串口接收的信息存入缓存区。
3 ~- v$ a4 J) M; o: L8 }$ N; N5 c7 c/ \1 F/ t5 V+ c2 O
那么让我们来试一下这段代码。
5 [. c3 w; v9 v$ }
* p1 O* @6 g* k
+ k$ S+ b) M0 g. B8 B! d8 h& C: g2 {- z9 D8 O, q
可以看到,代码死住了。其实不难理解,我们发送数据的时候,由于缓存区只有一个字符的空间,我们发送八个字符的时候会导致缓存区溢出。所以我朋友的代码可以“正常运行”也是一件非常奇怪的事情。9 r& R# G3 x" O* `5 _ C! k2 `
! I- P/ p% U6 Z* ^所以正确的做法应该是:设置和缓存区一样长的读取字符。$ N* m1 D) `; b% i( `
2 m* p9 ?3 U2 {' y* F6 Z0 J
- unsigned char RecieveBuffer[8];1 e" h. u5 `- t3 y9 Y
- void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
9 c2 _8 n }7 i - {
2 I5 M2 \" J! n- }. B" E# w# l - UNUSED(huart);7 q }+ s' E* M& D
- HAL_UART_Transmit(&huart1,&RecieveBuffer,8 ,100); // 将接收到的数据再通过串口发送出去+ w c5 o* S4 C7 E1 a q; H9 W
- HAL_UART_Receive_IT(&huart1,&RecieveBuffer,8); //使能接收中断,RecieveBuffer的类型是uint8_t! P' h. y" i" C/ }; V) w, _* y* o
- }
复制代码
$ {5 G" i+ e" q1 j2 S+ |" @这样子就可以实现每接收8个字符就调用中断一次
% Q- S, o2 [$ n- E
+ L% }& W4 X2 X3 P! `% T
3 M, j4 p4 }# i" l+ Z$ b7 b* ^6 l
可以看到,我们正常的发送了8个字符。1 G+ |; `4 @ ~, f h& k' E
4 U- d; Q2 ]3 _: d6 @$ I但是这样子有一个非常非常致命的缺点!
- @/ `1 j2 U7 c9 J* B4 h9 h" H! Z6 ]/ ?
由于我们的代码每8个才会接收一次,所以当我们的发送的数量小于8时,必须发送多次才能会触发一次调用。
8 y) }' O$ V% x. O5 O
# q0 a9 ^4 t0 G0 d注意,这里的每次我们都是先发送再接收,因为初始化的时候是启用了接收。
0 S% \7 G3 `: G2 ]: s* M& Z! B2 `$ ~9 q; C2 j' \
; A$ Q, D- I, Q6 u* @! e. y
}7 ~: v& e/ m/ s当我们发送3次“123”时才能让接收的字符>=8,我们把前八个发送了出去,此时缓存区剩下了一个字符是“3”: L6 x* q& H8 C' T
: b9 f: {8 E" i$ Y5 e7 {- d& A
, ~5 K2 B( j: d y# H9 ]9 Y
% g ?& ?( ~6 |3 G8 o第二次我们发送了三次“123123123”,再次让字符数量>=8,这时候把缓存区的八个“31231231”发送出去再接收后面的“23”,这时候缓存区的数据为:"23 "。
% ^ B4 p* [# f# p3 L( z! k! t) B9 C, t- s6 ], K7 Y0 C0 x! a9 H% W) q9 Q% Y
0 S4 n$ q, P/ @
! C' s0 |% H x! c1 f/ ?最后我们第三次发送“123”的时候,由于23 + 123 + 123 这时候,虽然这里按理来说正好八个,但是实际测下来,当这时候接收的时候系统就会卡死。
% `! ~, e+ c# y1 u" S/ M
, r8 @2 \' N* ?: j7 e% V所以,实际上这种方法必须保证发送端的数据是完完整整的八个八个发送,多一个少一个都不行。4 y- e( T( N. ]
2 _ X8 q' N9 j7 i
2 C! @; n5 W5 F0 q) p$ S解法, e; R) b& S" r/ {4 z8 k' ~: \8 Z# D
事实上最标准的做法是单个字符单个字符处理。定义一个大的缓存区,用来存储接收到的字符并且确立一个结束符来确定数据流的结束。- if((USART_RX_STA&0x8000)==0)//接收未完成 a1 v' s% \9 t9 t
- {
% B5 H3 c5 F8 Q' Z: o6 } - if(USART_RX_STA&0x4000)//接收到了0x0d3 p+ w2 I$ }7 O5 j
- {
5 j! Y2 S$ A* c' Q; v5 C6 R - if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始. r7 ?0 X, o( e; A8 {5 k9 h& l7 D. _
- else USART_RX_STA|=0x8000; //接收完成了
$ l$ X/ N) a9 A - }
, n1 Q- l9 D" ]. O! @, V9 v4 L - else //还没收到0X0D
M2 Y/ ^/ d4 q* j, C - {
$ m" O; K3 _( H, _ T - if(Res==0x0d)USART_RX_STA|=0x4000;) v6 j3 ~. v0 d B+ r
- else
5 N% n2 | x+ @0 i. y - {
, ` ^" ?( V* \9 f2 W! P - USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;0 E i i1 d9 x8 w. j/ x1 c' \' A
- USART_RX_STA++;
: c8 i* L( q( O - if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收 0 P! a% @/ K" g+ T2 }# b# i* q2 m
- } $ q J: j" N( b9 o
- }
4 R6 M% k7 _( U- ]. K+ ^( N - }
复制代码 ' S" C3 E/ S+ ]$ O
( H0 a" c+ k% r. B1 W
* K; u. I( j" E上述是正点原子的官方例程,其中USART_RX_STA是接收到的字符,即是确定一个结束符\r\n来作为一串字符的结尾并且检测长度是否超出长度。
7 D6 K! v- E7 O/ l4 H2 Z) u
. H7 |4 v/ ^' J1 s m4 M这样子的代码容错率非常高,也确定了一个规范,并且避免了缓存区溢出的情况。
4 [3 x" y( x9 w R8 `
3 w: Y% e; U) P0 R. k r3 X5 v1 C( F! Q" K6 Z R$ z# U
转载自:电路小白: Q9 {9 `% z8 M- r2 ^% D2 b% F
如有侵权请联系删除
/ n$ ~! G+ ~1 _! o! w" n" k
. q: H4 U; X* T: T3 F Z/ N0 o A |