一个关于STM32串口的问题。他想实现接收无限制字符数量的串口信息。
( h: c, P1 ?0 v F6 _$ Q( }! M% p, g
但是他遇到了一个问题,他在主函数中发送循环发送内容(500ms的延时)串口一中断回调函数中如果收到了串口内容,就利用串口发送。* Z/ j' U( G: O; l, b- P; u
0 G1 T, s0 a, `3 q0 \5 y但是他的串口一旦接收到了信息就会导致主循环中的串口发送极快。他的主代码如下
( C1 @" G/ o+ s; C- unsigned char RecieveBuffer;
4 G8 |6 B; G' e/ O' Y* O0 h - void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart), I; q% i o* E8 s; _5 C" `6 a
- {' O: {+ V, X* G
- UNUSED(huart);2 U% c, p9 ]7 d$ r
- HAL_UART_Transmit(&huart1,&RecieveBuffer,8 ,100); // 将接收到的数据再通过串口发送出去9 u! X& A3 p$ o G# @5 k
- HAL_UART_Receive_IT(&huart1,&RecieveBuffer,8); //使能接收中断,RecieveBuffer的类型是uint8_t
$ \6 k U" A- z5 t$ W; c - }
复制代码 / Q! n9 F* I" o: Q0 d
看了他的代码,就这么短短的7行代码,让我汗流浃背。
4 L7 p4 F8 G/ E- J4 D R: _# p- X; v6 I( p6 d
他的发送和接收中有一个参数是8,这意味着当串口接收的寄存器中有8个数据时就会触发中断回调。; f8 R/ {" Z' H/ G6 P0 T$ @
0 c+ e7 J$ k0 H+ G我们需要注意的是,串口寄存器的数据会被存储到缓存区中,这里的缓存区相当于一个队列先进先出,当我们调用HAL_UART_Receive_IT(&huart1,&RecieveBuffer,8);( @ p" S ]1 G
& q# o& O9 O6 B. d会将RecieveBuffer作为缓存区,将串口接收的信息存入缓存区。
7 M; @$ o8 ^" [% l" D4 ?' n
) w( l6 r; L, s那么让我们来试一下这段代码。
/ z/ x% Q/ |) h) N) b! [/ t- m2 j+ N' ^
8 I, Q; M% @, R7 I: \$ p1 d! d* x7 Z1 Y4 }6 R4 [5 [1 G
可以看到,代码死住了。其实不难理解,我们发送数据的时候,由于缓存区只有一个字符的空间,我们发送八个字符的时候会导致缓存区溢出。所以我朋友的代码可以“正常运行”也是一件非常奇怪的事情。
! [4 w; N# x% K$ H( w
1 I) P* X( N# k! b" z. ?所以正确的做法应该是:设置和缓存区一样长的读取字符。
* H: m& O; P8 m! |5 c9 A- Z8 J9 n
' \6 X' O& T. ~" v5 [$ y7 m+ Y- unsigned char RecieveBuffer[8];
* i3 `# R. K) R7 d/ f) k - void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
. E5 @& U) i* d! I' X - {
) z9 y4 g0 H# h. I$ z) t! ] - UNUSED(huart);5 ^( {" b! }4 f
- HAL_UART_Transmit(&huart1,&RecieveBuffer,8 ,100); // 将接收到的数据再通过串口发送出去
& {6 a, H3 W- D9 s+ B - HAL_UART_Receive_IT(&huart1,&RecieveBuffer,8); //使能接收中断,RecieveBuffer的类型是uint8_t" I9 A+ g X9 Q: w
- }
复制代码
- K# U0 \& @; E1 ?0 M& ~, t1 |这样子就可以实现每接收8个字符就调用中断一次2 i3 e, r2 ?% `) ^" X
' {/ ^ l9 A( r
% @/ n# ~: N" P" u, J% Q. q
( J2 F3 X, D3 L可以看到,我们正常的发送了8个字符。
4 J# R% J. ` B( x* U3 i! k- ~( ?" O, n. ?. j9 x, q) P5 d6 S8 u; p
但是这样子有一个非常非常致命的缺点!7 Z) E. s( o* ^& ^0 ~" X
! X* X2 {6 a5 A/ K
由于我们的代码每8个才会接收一次,所以当我们的发送的数量小于8时,必须发送多次才能会触发一次调用。3 z( [7 p0 H' b1 d3 b, e3 ^" i$ Y2 d
9 G1 o6 l' J8 Z# U/ {, {* o
注意,这里的每次我们都是先发送再接收,因为初始化的时候是启用了接收。
- _9 i' L& l" I" @: z$ z$ B4 ]) I" q7 Y; Y* D' g* @
2 w8 w+ e" H9 F' |& B7 `# b
) Z, `& h% K0 B+ x+ Y& I/ R. h9 ~8 B当我们发送3次“123”时才能让接收的字符>=8,我们把前八个发送了出去,此时缓存区剩下了一个字符是“3”
# @5 z' z: m2 s% e" c9 E% z3 ]% F- W, K1 n# T9 E! {
3 T1 R; G* u/ S6 v
d6 d1 Y5 t# D7 a$ |8 `
第二次我们发送了三次“123123123”,再次让字符数量>=8,这时候把缓存区的八个“31231231”发送出去再接收后面的“23”,这时候缓存区的数据为:"23 "。' A' [" v( q: w" y" i) B* s% ~% }
2 w- b# ^; g" |6 S3 H
! N& I" R$ L" t @/ S6 A
+ `& m( c2 @! G; V0 O: o最后我们第三次发送“123”的时候,由于23 + 123 + 123 这时候,虽然这里按理来说正好八个,但是实际测下来,当这时候接收的时候系统就会卡死。
5 r: Y% Q. M8 \( N1 [4 D- Y' _# \ w3 N1 D* n/ m& @
所以,实际上这种方法必须保证发送端的数据是完完整整的八个八个发送,多一个少一个都不行。- i2 k' D0 t* [- F
# R% W2 L1 o0 S2 v
1 ]* }) c7 v* ?1 e: T解法
: F2 c2 C: C/ H, i5 \2 n6 Z事实上最标准的做法是单个字符单个字符处理。定义一个大的缓存区,用来存储接收到的字符并且确立一个结束符来确定数据流的结束。- if((USART_RX_STA&0x8000)==0)//接收未完成2 p, F6 v4 Y9 |' s, E
- {
1 E' T/ ~5 [9 K* ~ - if(USART_RX_STA&0x4000)//接收到了0x0d/ a2 l4 ]; T9 ~. h3 \ W3 R
- {1 O0 R! U7 Z" Y. I9 S7 m) x7 M
- if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始 Y; d# d) _, h+ ?0 f) v8 L/ u, ]
- else USART_RX_STA|=0x8000; //接收完成了
K/ g j, [ F, Q3 l6 n# P$ C - }
2 A$ J I( e5 K' ~# Q% i& \8 s - else //还没收到0X0D+ z! L; n6 u8 {0 j& I8 v2 {
- {
' ~0 G/ t$ s/ H: p, H |. j - if(Res==0x0d)USART_RX_STA|=0x4000;4 ~+ S+ a% \/ b- J$ r' Z0 P
- else4 |4 _; [/ x% D3 t* z
- {
5 f3 A& _7 X* B6 _* ^% q& g0 n - USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ; b$ c, T9 t% p; S0 c
- USART_RX_STA++;2 M9 [1 y2 }8 r9 F& B) ?
- if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收 , p) h. d. v D8 g3 h& [
- }
9 @4 e+ `/ k4 p x, v0 u7 ?+ d: ~5 w - }
/ B: @1 {7 }9 H' |. E - }
复制代码 " Z- ]8 W3 w! \: L# Z: a' V
' w) s1 L& n) @* \- V# a$ R' j. O& E6 o/ O+ k: a' D; p
上述是正点原子的官方例程,其中USART_RX_STA是接收到的字符,即是确定一个结束符\r\n来作为一串字符的结尾并且检测长度是否超出长度。
+ @. U6 [% b8 ~/ I$ v
; l) w/ b$ v0 n3 ]$ ~这样子的代码容错率非常高,也确定了一个规范,并且避免了缓存区溢出的情况。
# p" M& v0 O0 n( U; p3 Z8 d& ^) k
( d0 R: {. `7 H+ k* O2 C' L
转载自:电路小白
1 |# ], e; {) z3 G" {如有侵权请联系删除: ~8 [- { `( M! j/ w- j, S$ W3 D
4 I K* E" ]" c! B9 r+ I
|