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

基于STM32与FreeRTOS的消息传递详解(HAL库)

[复制链接]
STMCU小助手 发布时间:2022-12-1 18:00
引言9 B$ H! Z1 l% f/ s
我们在裸机开发中,每个函数之间进行数据通信往往采用全局变量。而在嵌入式开发中。我们在进行进程间通信的时候,往往采用消息队列。对于操作系统来说,消息队列是非常重要的一个数据结构。本文将介绍一下,如何使用消息队列进行通信。! l- G! b& D. Q% L1 d

# S. l; }+ A" q( B6 b' D' u介绍
1 w* p2 Z  N. F0 ]# C消息队列概念
! w6 Z- R! r, ^( Q1 [. n
队列又称消息队列,是一种常用于任务间通信的数据结构,队列可以在任务与任务间、中断和任务间传递信息,实现了任务接收来自其他任务或中断的不固定长度的消息,任务能够从队列里面读取消息,当队列中的消息是空时,读取消息的任务将被阻塞,用户还可以指定阻塞的任务时间 xTicksToWait,在这段时间中,如果队列为空,该任务将保持阻塞状态以等待队列数据有效。当队列中有新消息时,被阻塞的任务会被唤醒并处理新消息;当等待的时间超过了指定的阻塞时间,即使队列中尚无有效数据,任务也会自动从阻塞态转为就绪态。消息队列是一种异步的通信方式。
. i6 m& C8 h! G: t/ Y
3 T# Z( f1 d2 w在FreeRTOS中的消息队列函数
: D! b* I. h. z3 u8 \# ?" |1.设定消息队列的格式:osMessageQDef(myQueue, len, size);
) K: I" E& A4 u0 {' N( hmyQueue是消息队列的名称。
8 S; L; C) m) P% qlen是消息队列的长度(有几个消息), o6 l# n( e& \* K/ j; f6 u
size是每个消息的大小,也就是每个元素的格式
/ j3 u) u: b  s. ~& ?. O! g# [& X% W0 Y  y8 _0 y/ p6 q0 h
2.创建消息:osMessageCreate(osMessageQ(myQueue01), NULL);1 V9 f4 K) [4 M: R4 f0 h* T' y
创建消息的函数,实际上是调用了FreeRTOS的osMessageCreate()函数,只不过HAL库进行了封装。
8 n' N" [( v& L- |1 n" p
# s8 l" i9 [( b3.向消息队列发送消息
$ G2 e6 T0 T: I# q6 Y7 S& I( Z4 C我们这里来介绍在中断中发送消息。使用函数xQueueSendFromISR(QueueHandle,&Res,time);1 G! }- @# x1 v, T4 R
其中:+ s& J) x: J4 R
QueueHandle:消息队列的句柄5 B$ S5 W9 \* m$ R
&Res:要发送的数据的地址
6 U% u' Y" g; y" x7 L1 ktime:阻塞时间,就是如果消息队列满的时候,任务应该阻塞多久
. B" _" a) |3 }9 H5 D9 b3 E
3 r. H/ C" Z: F4.接收消息队列中的消息
8 \. a  }+ \1 s3 H  m  O9 yxQueueReceive(QueueHandle,&queue_buffer,time);$ z1 N4 ~2 K% I5 C% S! T2 z8 H9 h
QueueHandle:消息队列的句柄
2 X" e' w5 r# j2 H: p: O&queue_buffer:接收的消息要存放在的地址
( `8 F7 P, z1 s5 Y. A5 h- btime:阻塞时间,就是如果消息队列空的时候,任务应该阻塞多久
- L- I1 T+ Q1 R5 s. x9 F1 v' A/ t9 e& l; f& T9 q
5.查询消息队列中消息的数量( j6 _# U) U" ]+ o3 w
uxQueueMessagesWaiting(myQueue01Handle),可以返回消息队列(句柄为myQueue01Handle)中消息的数量,返回值为整数。
- j! X; d9 A* k/ N  t# S( g; Z- @" Y. A0 I, S6 Y% u5 b
实例
8 D2 Q7 j& H5 Y0 J+ Z0 T1 D' M需求分析
+ Y, p3 ~0 M( g2 {, p
此样例我们使用PC充当上位机,上位机发送数据后,在串口中断函数中将接收到的PC数据发送在消息队列myQueue01Handle中,之后在一个接收线程中接收这个消息的内容,并通过串口将接受到的消息的大小和内容输出出来。
- f  W# A$ Y- r! R7 k. O9 C: m; \+ {, f  q; `1 m7 e
发送消息. A/ s# R7 Z6 F8 ?! ]
当上位机PC下发数据后,串口中断函数将接收到的数据发送在消息队列中。& m7 F) A/ M! A1 P8 t+ b

( s4 R$ P0 h  s% X4 v1 h
  1. void USART3_IRQHandler(void)
    . {8 K4 R. m+ \  g6 E* U# D& m! |
  2. {
    % a# z/ `# t, y3 E
  3.         uint8_t Res;
    3 ?1 M$ q& J1 I- n( u4 r
  4. if(__HAL_UART_GET_FLAG(&huart3,UART_FLAG_RXNE)!=RESET)//检测到有单个字节的中断8 o" D- J# c, e/ m2 m4 |6 B& C
  5. {
    , ]3 x0 {9 a7 k6 m% D& ^5 u
  6.         HAL_UART_Receive(&huart3,&Res,1,0Xffff); " b) Y$ @0 ]9 H$ b; T
  7.         xQueueSendFromISR(myQueue01Handle,&Res,0)//发送消息
    9 b) @' T+ I+ z: [- x# G- m
  8. }* Y4 Z% a* r# [) z
  9. else if(__HAL_UART_GET_FLAG(&huart3,UART_FLAG_IDLE)!=RESET)//空闲中断(代表这一帧数据传输完了)
    : I+ ]* s/ k" y% r6 \  I# ?( p: e
  10. {
    & b) w% E. K5 u( e/ L
  11.         printf(" Receive a frame data.");9 ]# n1 q* Y9 o0 N
  12.         __HAL_UART_CLEAR_IDLEFLAG(&huart3)
    3 n9 p5 y3 f, Y( L% p& r6 f8 T
  13. }
复制代码
7 ^5 q5 q# d2 \, F& W
接收消息- C; b% _) d2 u7 p4 `) W
我们创建一个任务,此任务的重要功能就是接收消息队列中的消息。我们将接受到的消息的大小和内容通过串口发送出来。没有消息的时候,一直实现LED的闪烁。+ d9 i6 ~( W/ e- e, A/ v) g
4 p* h7 z' L; b/ i
  1. void LEDToggleTesk(void const * argument)
    1 D, e6 O1 `& y& n! X
  2. {( B/ a( ]7 k( h" A& B+ g# F; }, G
  3.   /* USER CODE BEGIN LEDToggleTesk */
    1 i* \9 |0 z2 o0 q0 ^
  4.   BaseType_t xReturn=pdTRUE;//定义一个创建消息返回值,默认为pdTRUE
    0 V) {" ~4 l, ]" g# {
  5.   UBaseType_t num_queue ;
    7 C& c* E$ p( }2 t0 Y+ _9 f
  6.   uint8_t Res[20];//存放我们接收到的一包数据
    . G  j1 S( E+ C5 x! h
  7.   uint8_t queue_buffer;: J7 O! W6 a( T9 b1 S' @# ]; c2 V! {
  8.   int i=0;//接收数组下标
    + s' W9 P* O$ h: U1 P1 B8 N. y
  9.   for(;;)- M( i8 e% e8 v8 k' e3 k
  10.   {& o+ N' d* }  m) b1 P( q9 l
  11.     i=0;6 A" v8 |5 h) i0 F
  12.     HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_5);- x' E$ T. U+ S$ f1 C: ^" l; v7 r
  13.     num_queue=uxQueueMessagesWaiting(myQueue01Handle);//获取消息队列中有多少数据
    / i# \2 w/ q; Q. \# _& [
  14.     while(num_queue--)( B/ \8 h* W+ k  m2 g4 h% V% a
  15.     {
    4 h; P2 v( B4 r5 ?: ]
  16.       xReturn=xQueueReceive(myQueue01Handle,&queue_buffer,0);//将消息队列中的数据放在queue_buffer中" n9 h' T# u# [# I& g, H" i5 x$ D/ k
  17.       if(xReturn): d" d6 y- K$ j7 E. \# y
  18.       Res[i++]=queue_buffer;  6 b7 x) }2 f8 t$ r1 f
  19.     }
    / g1 E& p: \+ f  _
  20.     if(i!=0)8 j, t+ w) E' O1 S# j2 n+ t- a' P
  21.     printf(" count %d,LEDTask Receive %s",i,Res);//输出接收消息的大小和内容
    1 ^: _) T% @* `
  22.     osDelay(500);1 u5 S+ k7 I. g
  23.   }$ o3 i# h2 \. l0 {7 V/ r
  24. }
复制代码
4 r& @2 `. m; M& b' B1 q% T
现象

7 I) L8 b9 t9 ]# r3 o( H* kPC端发送123456789,MCU回复Receive a frame data# _* `) s( x' }  {' F" {7 p1 x
count 8,LEDTask Receive 12345678
4 N& G7 ?  {) ?2 x% f- }7 d( D/ Z2 j: B+ r' O( w

' q* l3 t9 [: e' _! B 640.png + t/ ^5 V  u1 {6 G( I4 a
/ Y) [6 a' g, V  i2 j1 |
转载自: 跋扈洋
1 l; W! u9 Z- G8 t
收藏 评论0 发布时间:2022-12-1 18:00

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版