一个关于STM32串口的问题。他想实现接收无限制字符数量的串口信息。. r/ x( l, E& t! `
* F7 E2 M: m% ]: t
但是他遇到了一个问题,他在主函数中发送循环发送内容(500ms的延时)串口一中断回调函数中如果收到了串口内容,就利用串口发送。
7 i$ t! M0 n( {4 ]" V
, r) d- l6 V1 |+ _5 X0 F但是他的串口一旦接收到了信息就会导致主循环中的串口发送极快。他的主代码如下
) J* V3 u* z$ @1 Z- a" J$ E2 L M7 F- unsigned char RecieveBuffer;
- h0 B3 p0 }6 _( I1 P& r8 h - void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
A7 y. l5 r5 L8 i" @( p3 O" S - {, N2 F1 _9 a) l' H
- UNUSED(huart);3 E- N" E1 b& P7 i, [' I d
- HAL_UART_Transmit(&huart1,&RecieveBuffer,8 ,100); // 将接收到的数据再通过串口发送出去
, [& s: K. X0 \' ^5 r: r - HAL_UART_Receive_IT(&huart1,&RecieveBuffer,8); //使能接收中断,RecieveBuffer的类型是uint8_t" m. T! C' j) C4 l
- }
复制代码
# V6 {7 `* A: n6 }' _# b看了他的代码,就这么短短的7行代码,让我汗流浃背。
" C% e! B# Z( t) T' {3 p5 G/ h+ x1 U4 W2 {/ P6 c- R. [
他的发送和接收中有一个参数是8,这意味着当串口接收的寄存器中有8个数据时就会触发中断回调。
9 V+ _( K" ]5 ]
) f: p5 ]8 o6 x( k N# S我们需要注意的是,串口寄存器的数据会被存储到缓存区中,这里的缓存区相当于一个队列先进先出,当我们调用HAL_UART_Receive_IT(&huart1,&RecieveBuffer,8);( x& U+ S6 {( H+ p# x: Q1 o
+ S) J" B6 _9 ^
会将RecieveBuffer作为缓存区,将串口接收的信息存入缓存区。
7 X' R8 u1 C& s1 H. {" O* L A' ` Y6 [8 z$ Q5 h; m
那么让我们来试一下这段代码。6 e( @6 E& a) C- f3 I
1 j) J9 d% z- o, x: n5 o
- x2 H: b/ d4 S3 ^' U( I( a9 t3 G' ~2 ]2 f) I) {
可以看到,代码死住了。其实不难理解,我们发送数据的时候,由于缓存区只有一个字符的空间,我们发送八个字符的时候会导致缓存区溢出。所以我朋友的代码可以“正常运行”也是一件非常奇怪的事情。
8 B% m3 N8 I: h$ G5 p" Y4 l. q2 x2 ?% B1 C* m
所以正确的做法应该是:设置和缓存区一样长的读取字符。, g: k* y b6 u/ x
' Y3 C5 Q- ]/ w% n
- unsigned char RecieveBuffer[8];5 f2 F6 C9 S0 C( x8 ~5 i5 _& y1 d
- void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
8 o, O5 V0 q4 z) \9 Q - {
, F# Y- G9 v; u/ l% p - UNUSED(huart);* J1 d9 F' U+ m# u# b4 H
- HAL_UART_Transmit(&huart1,&RecieveBuffer,8 ,100); // 将接收到的数据再通过串口发送出去$ J4 ?: u' z/ Y/ K
- HAL_UART_Receive_IT(&huart1,&RecieveBuffer,8); //使能接收中断,RecieveBuffer的类型是uint8_t k @7 Z% ], Z8 {4 y, B% l3 G
- }
复制代码 # y/ ~2 P8 e1 h# S
这样子就可以实现每接收8个字符就调用中断一次
7 a& q: ?& v6 N: b9 X- e- T" t& p; v5 Z) s8 J
3 V+ q7 n8 }3 \2 j; _
$ b! A3 q- h; C& N* a0 T
可以看到,我们正常的发送了8个字符。
4 e2 X x$ ^: |/ | N& M0 N/ L$ K; L
但是这样子有一个非常非常致命的缺点! `6 l' C" k* h7 r
8 t2 ]- _$ W& J) o1 Z6 Q由于我们的代码每8个才会接收一次,所以当我们的发送的数量小于8时,必须发送多次才能会触发一次调用。
2 x% L& D) M! V8 k8 Q7 x P) i! A7 [2 M
注意,这里的每次我们都是先发送再接收,因为初始化的时候是启用了接收。
; O X# K! E, `% Z, M8 ~; L, J* j2 ]
$ L5 G' |/ V- j3 X9 @+ V: m. E; G
" }6 q) k1 n3 Y+ [$ P# C; b9 q. w' Z( T }
当我们发送3次“123”时才能让接收的字符>=8,我们把前八个发送了出去,此时缓存区剩下了一个字符是“3”: |6 @+ y* U3 W0 G
) K2 i9 \% j' |
/ \$ c" R8 Y7 A5 g0 H! L/ E" y8 D
8 P' ?& _+ I# g/ B0 g( C7 I第二次我们发送了三次“123123123”,再次让字符数量>=8,这时候把缓存区的八个“31231231”发送出去再接收后面的“23”,这时候缓存区的数据为:"23 "。2 D- f7 m7 M5 }# N5 n6 T4 B. N
j$ F( _( e2 T0 A
! l6 A& u; R5 _6 _, A! R$ P) p
! p# q% O1 q& C4 c- l
最后我们第三次发送“123”的时候,由于23 + 123 + 123 这时候,虽然这里按理来说正好八个,但是实际测下来,当这时候接收的时候系统就会卡死。
( F& N4 D8 H3 [3 U* X1 b
8 l- m: l! w3 D# F所以,实际上这种方法必须保证发送端的数据是完完整整的八个八个发送,多一个少一个都不行。
# {* c# [0 \# h8 J5 C% y, P( w' o1 l/ w# G
2 m! y% b- E; x7 A
解法( Z" S8 i5 Y; v! d- U' s0 S
事实上最标准的做法是单个字符单个字符处理。定义一个大的缓存区,用来存储接收到的字符并且确立一个结束符来确定数据流的结束。- if((USART_RX_STA&0x8000)==0)//接收未完成3 ?& p# @' W+ j0 `4 K+ y8 {: P$ i7 U, [4 W
- {
: t& g% M3 m7 \ - if(USART_RX_STA&0x4000)//接收到了0x0d6 X$ o5 f5 B+ q7 D# D" Y
- {
$ _: A1 R6 \9 k6 w4 V- H; `! } - if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始, e0 ^) p: c- V) n# i# d0 d" O! p
- else USART_RX_STA|=0x8000; //接收完成了
/ @* p: {$ P5 _( o5 W - }9 `) q. V( J9 s+ \! d
- else //还没收到0X0D d7 f, A! h& k) }$ | c
- {
& o3 Z$ Y* y) s - if(Res==0x0d)USART_RX_STA|=0x4000;
; n3 s4 f" w6 F ]" R. E - else
7 G9 Y8 ^( e7 n5 b - {
7 O! }! G8 c: C0 B1 C# j - USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ; [6 S6 O+ j2 E8 ?
- USART_RX_STA++;4 p8 [" D) ~$ d/ e7 {/ S( O
- if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收
7 P4 n4 n7 x. p2 g( ] - } ) M" \! s/ R% U0 \
- }
& X3 x( B1 z6 ` - }
复制代码 / L) @; g8 L% n" H: O+ v$ @
3 q/ R. Y h) d, u
7 r* V6 K! |" y6 I4 S4 D8 K上述是正点原子的官方例程,其中USART_RX_STA是接收到的字符,即是确定一个结束符\r\n来作为一串字符的结尾并且检测长度是否超出长度。
* s& z3 }' M0 \5 S* j0 G- {5 ^$ t- t7 }' I% l; O7 K
这样子的代码容错率非常高,也确定了一个规范,并且避免了缓存区溢出的情况。
" D' ]/ g+ t9 i, u7 C- {( I
) z" s5 \/ s P2 W5 B; A% S4 H' ~9 Y% B6 \+ }* n7 P: a+ T* G
转载自:电路小白3 Z- u9 F* j$ d( l% S( }0 m
如有侵权请联系删除
2 V5 x# |- h3 y3 t, |, q9 T
1 b* Q: A: ` g" p) v |