你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

如何STM32 串口代码实现更高效的接收消息

[复制链接]
STMCU小助手 发布时间:2023-2-26 16:31
这段时间一直在研究多旋翼飞行器,以及其它的事情,博客好外没更新,再不坚持怕真荒废了哦。0 ^. f- \9 V& e6 C/ s
  |9 D: q3 b1 D; n% X
在上篇简单实现 MAVLink 协议的解析,并演示按照设计好的命令执行对应的事件处理,以及又加入 CRC 校验,实现更稳定的通信,但在上文结束时也提到当对一个包进行解析及对应事件处理时,是不能接收新的数据,直到事件处理完成,Msg_Rev.Get 状态设置为 RECEIVING 后方能再接收新的数据。这时,当事件处理需要一定时间,而又有新的数据不断发送过来时,很容易造成数据丢失现象。

2 Q) ^, D6 N: b" l
如何提高串口通信效率,并避免丢包现象了?

: X: a" t/ }3 }% o6 e# d8 S! r
为提高效率,首先想到采用 DMA 方式,然而考虑下发现,接收的数据包是不固定的;并且即使采用 DMA,若 MAVLink 接收缓存仍设计成只接收一条消息大小,丢包问题仍然还是会有滴。
, ]# Y$ s  [% ?* E7 ]
这样就想有没方法软件来实现,就相到如果开辟一个缓存空间,不断接收的数据都放到那儿,而包的解析处理函数可从这里面依次取出一定数据,来作处理。这样只要设计比较合理,因软件阻塞造成的丢包现象就容易解决了。那么要设计一个怎样的缓存呢 ? 其实很容易想到队列(先进先出的特性),而为了更有效且合理的利用空间,又就会想到环形队列这种数据结构 。( X3 o  i, n3 Y, j) v
. ?0 ?, {* n; T) c. u  m0 q
首先是其数据结构设计,以及插入删除操作,不多说,如下代码:
  1. #define MAX_QUEUE_LEN  (4096) // 4K% H9 J* \' S" B1 V, Z0 H
  2. #define RW_OK   0) S( J9 m9 d, h% X. q* l
  3. #define FULL_ERROR    1
    , A) N/ M& ]/ B
  4. #define EMPTY_ERROR   2( z' Z2 }6 }1 W5 n2 ?" j: o
  5. , q, M$ J5 I% M* K& l- ^
  6. typedef uint8_t boolean;
      M6 ^( p  j& c. _7 s' w! n# U
  7. * a+ Y( Q% y, x, B5 {' F( b! \
  8. typedef struct
    ' c2 R8 b0 A" ]: Q+ Z7 G+ r
  9. {
    ( c5 S" f+ O1 C4 s1 ^
  10.     u16 MemFrontSendIndex ;% G# a$ o, l& @4 O' [! w" W
  11.     u16 MemRearRecvIndex ;
    ' v& W+ u( k( `3 g
  12.     u16 MemLength ;( C9 t4 t5 ~, [( P; U/ `
  13.     u8  MemDataBuf[MAX_QUEUE_LEN];
    ! {/ q3 R% l9 ~5 ~
  14. } Queue_Mem_Struct , * Queue_Mem_Struct_p ;
    " s" H; `  ~# S6 y, M
  15. 5 \& _1 u1 }2 o! J" X" C% ^
  16. Queue_Mem_Struct Queue_Recv ;
    , a* Z% k' I) \) V# E* h
  17. 1 g' V! S3 {9 n2 Q0 h9 T+ [
  18. boolean QueueMemDataInsert(u8 data)
    ( ^+ ~4 i6 e# g- l: p! w1 y
  19. {
    % J8 g" N# r: x; X' M- H5 q
  20.     if (MAX_QUEUE_LEN == Queue_Recv.MemLength), x/ y, g  f# s, w; W9 Q$ m
  21.     {8 M/ v+ v+ v( o+ @
  22.         return FULL_ERROR;6 D$ z7 E" o- v5 g" ?
  23.     }+ [7 O( D! Q) K" p& k5 o; I2 g
  24.     else
    # b/ s8 B( D# T9 `' C2 D0 ]- v
  25.     {
    6 U0 E! v5 B- r1 \2 j
  26.         Queue_Recv.MemDataBuf[Queue_Recv.MemRearRecvIndex] = data ;8 k" X  L, `3 W5 d1 _
  27.         //        if(++Queue_Recv.MemRearRecvIndex >= MAX_QUEUE_LEN){Queue_Recv.MemRearRecvIndex = 0;}# ^+ G' E+ e7 H, s
  28.         Queue_Recv.MemRearRecvIndex = (Queue_Recv.MemRearRecvIndex + 1) % MAX_QUEUE_LEN;
      \0 n1 L5 B5 x1 X0 H9 u
  29.         Queue_Recv.MemLength ++ ;) E, g& g. K* M" B* Q7 c1 q
  30.         return RW_OK;2 ~: x6 Y! y) D- J
  31.     }
    $ N) @8 U  S$ {  u( q
  32. }
    * z3 p  ~% g# _2 O2 S. y! {( X
  33. 3 r2 y7 b5 Q3 {' ^
  34. boolean QueueMemDataDel(u8 *data)
    * [$ B6 Y9 V& t+ X
  35. {
    ; `2 g1 k" j3 g
  36.     if (0 == Queue_Recv.MemLength)
    . o! p7 Y' ^% l
  37.     {
    ; i1 z6 S6 e# g  c, ~* t+ d9 m
  38.         return EMPTY_ERROR;
    . F' V% k. i4 G8 K# C- v) w( [. q
  39.     }
    1 ]0 A7 H6 a$ G. V
  40.     else3 T: _) n: ]; ?- s! t7 x
  41.     {
    7 M, c2 }( i7 |0 M- }2 }/ I3 v
  42.         *data = Queue_Recv.MemDataBuf[Queue_Recv.MemFrontSendIndex]  ;
    % g: t0 ], a- d
  43.         Queue_Recv.MemFrontSendIndex = (Queue_Recv.MemFrontSendIndex + 1) % MAX_QUEUE_LEN;
    6 }0 ~( T! v1 H) [/ t# D( {
  44.         Queue_Recv.MemLength -- ;2 Y9 V+ M& }6 }/ o/ C# L
  45.         return RW_OK;
    8 u! `/ S6 m  _
  46.     }8 @& q6 O( }2 ?) I0 {% _7 a4 W  E/ B
  47. }
复制代码

; y! \  j# }5 ?$ b) z) F
这样,只需通过 QueueMemDataInsert 函数把串口接收的数据依次填充到缓冲区 Queue_Recv.MemDataBuf 中去。而在处理时调用 QueueMemDataDel 函数取出对应个数的数据来处理。这样就避免整个处理过程中无法同时接收数据而产生丢包的问题。当然此时要保证缓冲区的数据及时处理完,否则,尤其当数据量很大时队列填充满后,又会造成数据无法再填充进来。

% N/ y* F, P2 @- T' u0 ^
另外至此又会发现,如上设计可结合采用 DMA 方式。设计的好的话,可以进一步大幅度提升 STM32 利用率及系统运行效率!

* s7 x5 H1 X7 J! v5 W( F
转载自:以太快跑

3 Z* b- A2 Y/ E
收藏 评论0 发布时间:2023-2-26 16:31

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版