一个关于STM32串口的问题。他想实现接收无限制字符数量的串口信息。
& k; }: E* p8 o$ v5 P6 y( [- @7 w* ]8 F. w5 q2 Y- t6 y* l
但是他遇到了一个问题,他在主函数中发送循环发送内容(500ms的延时)串口一中断回调函数中如果收到了串口内容,就利用串口发送。
9 i0 m9 O9 z( ~$ t* N
. u+ B5 Z( Z( n8 a但是他的串口一旦接收到了信息就会导致主循环中的串口发送极快。他的主代码如下
5 ~ f; s. v; F1 V) }+ a/ \! d% W- unsigned char RecieveBuffer;
1 W& T4 b8 X1 d3 N* \ - void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
& b0 e( m) f- p- z/ X; n1 g - {, r/ a. R! M k, I
- UNUSED(huart);
6 r2 I" o: w o8 y - HAL_UART_Transmit(&huart1,&RecieveBuffer,8 ,100); // 将接收到的数据再通过串口发送出去% H: l" f# e* F& K9 ~; y
- HAL_UART_Receive_IT(&huart1,&RecieveBuffer,8); //使能接收中断,RecieveBuffer的类型是uint8_t
, k1 B. L7 h: c7 C- i( f, Y - }
复制代码
6 l" n8 m9 V7 o. d* p# W/ F看了他的代码,就这么短短的7行代码,让我汗流浃背。3 B! J! S: b5 {; Z' T" t9 A& h
a& s/ s' e8 n" K" g a他的发送和接收中有一个参数是8,这意味着当串口接收的寄存器中有8个数据时就会触发中断回调。: d. L' ` o9 _
$ ^8 K- n. W5 S; s! {我们需要注意的是,串口寄存器的数据会被存储到缓存区中,这里的缓存区相当于一个队列先进先出,当我们调用HAL_UART_Receive_IT(&huart1,&RecieveBuffer,8);: l) i3 g E) @$ ^( G7 P+ F
7 Z& s. [( n% W k" h2 m
会将RecieveBuffer作为缓存区,将串口接收的信息存入缓存区。5 j* y( h) C o# W3 X+ K2 e
2 T1 B1 z; T% @4 D那么让我们来试一下这段代码。
( A. P5 I" n/ b; l
- Y5 p4 ?$ L% P) R
. [+ A4 M3 k x* ]" W* f- W6 d' }$ q" H9 x" K4 w
可以看到,代码死住了。其实不难理解,我们发送数据的时候,由于缓存区只有一个字符的空间,我们发送八个字符的时候会导致缓存区溢出。所以我朋友的代码可以“正常运行”也是一件非常奇怪的事情。
& f ?* l! l0 `. B9 K
* B! Z- H( b7 |所以正确的做法应该是:设置和缓存区一样长的读取字符。
7 r4 z$ T3 ^. [8 u# {) p, D. J6 I& v0 C9 F9 ^ E
- unsigned char RecieveBuffer[8];
# }; i" S! T' Y; Y5 D8 X - void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
V/ p: K5 F4 [3 H* e- X - {
: b) c8 {) e9 J+ g! D - UNUSED(huart);: ~ X* a' Z' G/ |/ q
- HAL_UART_Transmit(&huart1,&RecieveBuffer,8 ,100); // 将接收到的数据再通过串口发送出去& B \* g7 ?' }; Z/ h
- HAL_UART_Receive_IT(&huart1,&RecieveBuffer,8); //使能接收中断,RecieveBuffer的类型是uint8_t
5 f( q' G- k& ?7 a$ |- m3 y, t - }
复制代码
; L+ b- X, N, ] S/ m% t7 ~$ a这样子就可以实现每接收8个字符就调用中断一次 L2 _% C/ g1 H, u' ^- o* W4 G
, W% \9 T0 l J. J. ]0 o) M0 Y+ x, h& ^
4 o, T! e, K- C
. F" R; [# m( |3 x* ~% m |可以看到,我们正常的发送了8个字符。
0 K* B( R0 {# F1 A
6 d6 z4 E8 F/ S. \# W但是这样子有一个非常非常致命的缺点!1 c9 L, f4 l1 u2 X* T' U/ M, {# u+ u3 P
+ A1 e! G9 T* O4 K/ E% |& y
由于我们的代码每8个才会接收一次,所以当我们的发送的数量小于8时,必须发送多次才能会触发一次调用。
0 U; p, c3 d ?* N* L' a, G3 P Y+ b6 Y4 w" T/ c0 E3 A
注意,这里的每次我们都是先发送再接收,因为初始化的时候是启用了接收。
" L" A" C8 k5 H+ j4 t) c1 W
# [+ j+ a& _' D. ^$ Q. @
4 [9 a& z& c$ F E7 t# G1 h
& E& J' V$ f/ ?2 h G当我们发送3次“123”时才能让接收的字符>=8,我们把前八个发送了出去,此时缓存区剩下了一个字符是“3”
4 P' I- D- B. M: U) z2 J% Z
! Z C$ `$ x' t$ n1 W
; h) G5 @1 `& ` A' X1 e! t1 z9 U
0 A0 t& H6 y: u( @6 X4 s# P7 i! [* p第二次我们发送了三次“123123123”,再次让字符数量>=8,这时候把缓存区的八个“31231231”发送出去再接收后面的“23”,这时候缓存区的数据为:"23 "。
6 |( m/ [) \# L5 ~- m* V+ p1 F8 M4 O
# ~% P1 F. E7 Y. |( a+ }
; P# [% j& U( {, x- q, M最后我们第三次发送“123”的时候,由于23 + 123 + 123 这时候,虽然这里按理来说正好八个,但是实际测下来,当这时候接收的时候系统就会卡死。
% _8 G' A" Y5 N
0 s$ Z5 ^% @( s1 j所以,实际上这种方法必须保证发送端的数据是完完整整的八个八个发送,多一个少一个都不行。
) [) r: j! L. _# j% V5 U$ T- A$ C" w- [* `
# b5 U0 o2 n# s, M解法' F1 e: S. X- Y- _" w
事实上最标准的做法是单个字符单个字符处理。定义一个大的缓存区,用来存储接收到的字符并且确立一个结束符来确定数据流的结束。- if((USART_RX_STA&0x8000)==0)//接收未完成( N, U) L: M8 `! `: H+ U9 L
- {- R+ `9 F6 y% J1 O. _ q
- if(USART_RX_STA&0x4000)//接收到了0x0d$ Y& R0 ~: i* u- }
- {
# V9 Q3 W4 Q9 v2 g. B - if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始 M/ n" j% { p( N7 R2 k
- else USART_RX_STA|=0x8000; //接收完成了 / ]( `' O" o& d7 t% L( B; q" w
- }, Z! Y& T4 @ x7 y8 m8 S
- else //还没收到0X0D
& z: l- H) G9 P- |" t0 ` - { 0 ?5 b3 j1 O( y1 J) o" I3 X
- if(Res==0x0d)USART_RX_STA|=0x4000;, v4 n0 I& l7 s
- else
; }9 v% y. j$ p ]/ m, o6 ], o - {' D: k1 e M* H, r0 U
- USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;0 @8 X- d5 i) s" w4 y" u
- USART_RX_STA++;
7 z9 @% J/ `$ D' T# p - if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收
1 T; X) f! |# `5 x# R# K1 g; T ` - } 5 _" p, y9 r, U$ P. g; q
- }& `6 _. X' L2 `, p$ y6 Q! w
- }
复制代码
z2 `0 C. Q& y2 A* X# o6 K2 V8 b& @6 _ V$ Z& i' P9 t
4 d7 x1 {, t( o# Y6 w2 v0 e0 y6 Q, S
上述是正点原子的官方例程,其中USART_RX_STA是接收到的字符,即是确定一个结束符\r\n来作为一串字符的结尾并且检测长度是否超出长度。
; S/ S1 ?* M% }2 _/ ?! b% f+ K8 }4 _5 X. Q' s# x1 K6 a" Q
这样子的代码容错率非常高,也确定了一个规范,并且避免了缓存区溢出的情况。
9 P4 }! {4 E L5 b
/ y _5 h8 Q2 T# ]4 o
3 l0 S- M- r8 _4 E/ m, z转载自:电路小白
! M9 k( I y# p如有侵权请联系删除
; E, q% b9 f5 y7 ~) p
% N! s! C+ r( I# o3 t |