一个关于STM32串口的问题。他想实现接收无限制字符数量的串口信息。
6 q! g, Z! F- }/ u" a, @# } d
: s" X9 J0 ^& C! w但是他遇到了一个问题,他在主函数中发送循环发送内容(500ms的延时)串口一中断回调函数中如果收到了串口内容,就利用串口发送。; z& M8 i9 _- I0 O
& u: D1 w" F* y但是他的串口一旦接收到了信息就会导致主循环中的串口发送极快。他的主代码如下7 m. h# y: H% p* e g
- unsigned char RecieveBuffer;
% n9 H& H8 v" } b* f) Q - void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart). a1 V& G' z/ S4 u6 p5 A* ?( O
- {0 s, ^" v ~ d; `+ k0 z4 c
- UNUSED(huart);" \/ h% j6 |! W
- HAL_UART_Transmit(&huart1,&RecieveBuffer,8 ,100); // 将接收到的数据再通过串口发送出去
/ j. l2 e1 e. D3 W0 c - HAL_UART_Receive_IT(&huart1,&RecieveBuffer,8); //使能接收中断,RecieveBuffer的类型是uint8_t
* ?3 E+ ?6 H6 k% C" j0 D. o* g" j9 I- o: d - }
复制代码 . R# B3 a0 g" }" T
看了他的代码,就这么短短的7行代码,让我汗流浃背。 c6 G L5 [4 m1 {( U6 l1 @7 f! b
# N4 k: F# a; J# w9 {9 j3 H
他的发送和接收中有一个参数是8,这意味着当串口接收的寄存器中有8个数据时就会触发中断回调。% {- N: d0 I/ z" d( v4 S
4 @ [9 g' V) x' N$ S我们需要注意的是,串口寄存器的数据会被存储到缓存区中,这里的缓存区相当于一个队列先进先出,当我们调用HAL_UART_Receive_IT(&huart1,&RecieveBuffer,8);
9 F- \6 }9 H7 A" v8 n: }1 w1 ~4 S- ^. r& H5 V
会将RecieveBuffer作为缓存区,将串口接收的信息存入缓存区。
% I: @- Q! U# g7 y, _, V
# v I J* }) m: x _那么让我们来试一下这段代码。
' E( j/ l3 x" ~" @8 `
3 x8 x& j5 ~0 J7 f) i9 u
: M: v8 p+ ]7 T" } |' v& r1 {- C) _2 \( f+ s+ b* P9 q
可以看到,代码死住了。其实不难理解,我们发送数据的时候,由于缓存区只有一个字符的空间,我们发送八个字符的时候会导致缓存区溢出。所以我朋友的代码可以“正常运行”也是一件非常奇怪的事情。
# E% Z* U- z7 n$ h6 L9 |7 Y# b, `) i% T! n" J. ^. {
所以正确的做法应该是:设置和缓存区一样长的读取字符。
' `" K* Q, ]; k( n. D$ }
3 T& }% v8 N6 g4 @( l2 z% O- unsigned char RecieveBuffer[8];: ] z0 B( T* e, c- f. y
- void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)& U( B9 z& M+ s- M# O2 v1 s! n" o
- {; S8 E8 A u" @; a4 Z0 G9 _4 O
- UNUSED(huart);; V5 M3 S% W* G4 {) `% D
- HAL_UART_Transmit(&huart1,&RecieveBuffer,8 ,100); // 将接收到的数据再通过串口发送出去; q$ f7 t( V" m3 t' |4 e# Y
- HAL_UART_Receive_IT(&huart1,&RecieveBuffer,8); //使能接收中断,RecieveBuffer的类型是uint8_t5 i1 S; t! k; ^* b: A# ^' \
- }
复制代码 6 c# f- a( f8 g- s/ K( X
这样子就可以实现每接收8个字符就调用中断一次
" k0 I1 }6 Z& v% z) Y
, ]; ]6 Y1 h! {- }/ e
( H; V0 \" |. E+ f; t- r# ?; \7 T' @4 j( U3 T1 p( s
可以看到,我们正常的发送了8个字符。4 }$ I5 c* B5 Q3 e: }
9 H; i6 @3 E5 I& f
但是这样子有一个非常非常致命的缺点!
1 {$ ]! F( P/ ]" s {( n- X
5 x, h0 p& G: p由于我们的代码每8个才会接收一次,所以当我们的发送的数量小于8时,必须发送多次才能会触发一次调用。( K* @. t3 E. \
& J" X; _# N, d1 [: [3 y: W6 u注意,这里的每次我们都是先发送再接收,因为初始化的时候是启用了接收。$ W. E: }) i3 v5 p! K1 X
8 Z* d& u* f$ U q" h- F& H* p
9 r3 ^- g! K& {; v3 j
/ O- n4 H) G; \2 H" H$ V9 O
当我们发送3次“123”时才能让接收的字符>=8,我们把前八个发送了出去,此时缓存区剩下了一个字符是“3”9 \% `( Q3 H( e' F/ a/ H# t8 E
! z+ Y8 L- R5 }7 R7 J
6 I3 P% L" ?( |+ C2 _. G K% @
0 I2 ?! W! J$ z! G" n7 r' F6 @! X第二次我们发送了三次“123123123”,再次让字符数量>=8,这时候把缓存区的八个“31231231”发送出去再接收后面的“23”,这时候缓存区的数据为:"23 "。
, n$ f. p; j) r/ E" f: [+ O* ^, Q* B8 W" w4 a6 S
6 J3 s& t1 L" F; e: g
! F: f: d1 U5 S: O4 V! i
最后我们第三次发送“123”的时候,由于23 + 123 + 123 这时候,虽然这里按理来说正好八个,但是实际测下来,当这时候接收的时候系统就会卡死。# R! n; n" a( {4 b3 L. |! @
$ O5 G" ^. f& @2 S. |* y% B" v2 D
所以,实际上这种方法必须保证发送端的数据是完完整整的八个八个发送,多一个少一个都不行。
( ]$ x* k% z# X$ v: U M
: r& O6 ~5 ^* o+ l8 A
& S- _0 h! d1 @, | b解法: X4 ^' d2 A3 F" w6 W
事实上最标准的做法是单个字符单个字符处理。定义一个大的缓存区,用来存储接收到的字符并且确立一个结束符来确定数据流的结束。- if((USART_RX_STA&0x8000)==0)//接收未完成( F( R3 C; }* Y& n7 h
- {
* k$ X3 i4 l0 w+ R' F - if(USART_RX_STA&0x4000)//接收到了0x0d6 t8 M6 K9 j8 v5 d Z2 V8 j! O9 o
- {1 E2 j; u" K! i& S `. b
- if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始0 q# {& D! _) U0 @1 l1 o
- else USART_RX_STA|=0x8000; //接收完成了 : n2 w5 V. U5 x$ }
- }
2 n+ e( R- e5 c* Y) K - else //还没收到0X0D5 O- w6 y0 y3 j" V: @! @% a, ~
- {
$ K9 R& u4 Q, Q* _4 E. }8 I1 ~ - if(Res==0x0d)USART_RX_STA|=0x4000;
* I4 w7 n! i/ [+ ^ - else
3 c. _. ?# S. v7 f' G/ @' | - {' ]0 h- y$ g. K3 j2 x* G3 p
- USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
* P) Z v7 @2 W - USART_RX_STA++;
- M" l) Q$ R9 Y5 D% p3 m1 O - if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收 - B# v5 `6 _7 U+ [
- } - N/ m; C5 |/ {+ }/ Z3 N/ C/ L s
- }: K2 I. m1 a: b- D
- }
复制代码
# u& ~' E k1 i. k$ @4 d: y$ O1 g4 o
- a& f a, ~2 c/ F5 I0 X8 L
上述是正点原子的官方例程,其中USART_RX_STA是接收到的字符,即是确定一个结束符\r\n来作为一串字符的结尾并且检测长度是否超出长度。0 ~5 `) @* v" W
6 D M/ K: C" q! \! E这样子的代码容错率非常高,也确定了一个规范,并且避免了缓存区溢出的情况。# o6 `; ?. S. N F' S+ a
$ t {4 |" x( l% c+ U2 k t- r! k/ K" d- |2 Q- ]& h
转载自:电路小白
$ G& a8 K& ~3 T如有侵权请联系删除
; |% t' ]9 r' n2 y# @1 S4 L5 B+ s! t. \$ ^" w
|