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

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

[复制链接]
STMCU小助手 发布时间:2022-12-1 18:00
引言, G! n" O; E' N. Q" y
我们在裸机开发中,每个函数之间进行数据通信往往采用全局变量。而在嵌入式开发中。我们在进行进程间通信的时候,往往采用消息队列。对于操作系统来说,消息队列是非常重要的一个数据结构。本文将介绍一下,如何使用消息队列进行通信。0 [  D& \# d4 {8 `% ^* S' ^7 Q. q5 Q
; h! A4 T: F" \3 w+ B; A
介绍
, N" g1 A  q. |3 ], M5 o; b, c- f& X消息队列概念
7 H; R. c$ r- w$ p
队列又称消息队列,是一种常用于任务间通信的数据结构,队列可以在任务与任务间、中断和任务间传递信息,实现了任务接收来自其他任务或中断的不固定长度的消息,任务能够从队列里面读取消息,当队列中的消息是空时,读取消息的任务将被阻塞,用户还可以指定阻塞的任务时间 xTicksToWait,在这段时间中,如果队列为空,该任务将保持阻塞状态以等待队列数据有效。当队列中有新消息时,被阻塞的任务会被唤醒并处理新消息;当等待的时间超过了指定的阻塞时间,即使队列中尚无有效数据,任务也会自动从阻塞态转为就绪态。消息队列是一种异步的通信方式。! b& `: Y4 O: v" N; k
8 k; a1 K" Q! J" n' J
在FreeRTOS中的消息队列函数" E& U; \* Z  L' \+ r: H) A
1.设定消息队列的格式:osMessageQDef(myQueue, len, size);
4 y  w/ b8 R0 B' g3 wmyQueue是消息队列的名称。
: B; V0 v6 j0 Ulen是消息队列的长度(有几个消息)4 L% ^4 P2 s8 N; I6 z( i# k
size是每个消息的大小,也就是每个元素的格式/ R7 k6 q3 f! r- }

" W9 r9 y" _  m5 h* Y) V2.创建消息:osMessageCreate(osMessageQ(myQueue01), NULL);, t  J- g4 X" `/ r% s, F
创建消息的函数,实际上是调用了FreeRTOS的osMessageCreate()函数,只不过HAL库进行了封装。
+ e( s  G7 C0 P+ ~+ g, h; }1 b- {2 b" b4 F! V
3.向消息队列发送消息
. F. M! E% ?! ]# O8 `7 v我们这里来介绍在中断中发送消息。使用函数xQueueSendFromISR(QueueHandle,&Res,time);
$ p3 N7 E4 l( c8 d& e其中:) ~  [* r1 n, I# K
QueueHandle:消息队列的句柄
6 ~. z7 L6 C8 H8 k  S2 Z2 E% l&Res:要发送的数据的地址
% @; m% w2 Q+ l6 H* b( q1 }* n# Jtime:阻塞时间,就是如果消息队列满的时候,任务应该阻塞多久$ l. A7 F5 D+ h: J
/ }1 b% g- |' l/ t, {
4.接收消息队列中的消息
2 G; P. _) G$ P" {xQueueReceive(QueueHandle,&queue_buffer,time);
, ^( }5 r# H! w+ O( E# IQueueHandle:消息队列的句柄
; T$ ^, C+ B; u; i" C4 d&queue_buffer:接收的消息要存放在的地址* V5 n  p5 {1 K8 B6 A
time:阻塞时间,就是如果消息队列空的时候,任务应该阻塞多久' [6 B0 N6 B; `6 s+ R; {6 R$ w8 t- s

0 e) ]9 Z- d$ m8 v$ c5 i5.查询消息队列中消息的数量
* p4 [& F8 J1 G$ n" h4 WuxQueueMessagesWaiting(myQueue01Handle),可以返回消息队列(句柄为myQueue01Handle)中消息的数量,返回值为整数。
% y1 Q. o6 K' h1 Y/ f& {' K% p) D  O& y4 @( F. _
实例( G# ^1 I+ v! W
需求分析
3 w3 e2 |  p! s- W# |
此样例我们使用PC充当上位机,上位机发送数据后,在串口中断函数中将接收到的PC数据发送在消息队列myQueue01Handle中,之后在一个接收线程中接收这个消息的内容,并通过串口将接受到的消息的大小和内容输出出来。9 h% i9 ]: f( o3 y

; N7 y6 q6 p9 L0 P发送消息
3 ^4 j) _  ]' Y8 _/ U6 b9 P当上位机PC下发数据后,串口中断函数将接收到的数据发送在消息队列中。
/ U7 J: P  Q" f% v1 [
3 @1 w: c; {# w
  1. void USART3_IRQHandler(void)
    5 z$ j: s8 a# N; P; d) j4 q
  2. {! T2 t. [! o0 T
  3.         uint8_t Res;
    . A) Q3 f- m0 ?
  4. if(__HAL_UART_GET_FLAG(&huart3,UART_FLAG_RXNE)!=RESET)//检测到有单个字节的中断
    4 \1 ?  L& M) S5 r  X
  5. {
    7 s/ Q. w! s$ t
  6.         HAL_UART_Receive(&huart3,&Res,1,0Xffff);
    : \; i; s6 Z# Z
  7.         xQueueSendFromISR(myQueue01Handle,&Res,0)//发送消息
    2 o5 J; F5 S& p+ u
  8. }3 p1 ~& E% g* O8 i
  9. else if(__HAL_UART_GET_FLAG(&huart3,UART_FLAG_IDLE)!=RESET)//空闲中断(代表这一帧数据传输完了)& Z6 O9 d4 z2 I# F
  10. {
    : v' F/ p4 Q  C6 G
  11.         printf(" Receive a frame data.");$ d2 R$ g8 L* a
  12.         __HAL_UART_CLEAR_IDLEFLAG(&huart3)
      E& N$ o1 g1 r) f# A
  13. }
复制代码

0 s9 \0 U/ {. q* @* L1 q, ~接收消息
. l2 I+ e, S7 Q" K4 V$ _+ w我们创建一个任务,此任务的重要功能就是接收消息队列中的消息。我们将接受到的消息的大小和内容通过串口发送出来。没有消息的时候,一直实现LED的闪烁。. K+ @" _2 N& [" h8 k4 y
/ ?5 y2 K* q& f6 E* Z
  1. void LEDToggleTesk(void const * argument)' p! [6 c/ h1 m( g3 t9 S
  2. {
    / j4 G2 c/ S3 a1 v. J+ d
  3.   /* USER CODE BEGIN LEDToggleTesk */
    " P) }8 ?, N' w! r( j: M* A8 S
  4.   BaseType_t xReturn=pdTRUE;//定义一个创建消息返回值,默认为pdTRUE$ x- v/ ]8 _/ U6 z/ s# S
  5.   UBaseType_t num_queue ;; z8 ^2 A% `# i' R8 W+ A% A" k
  6.   uint8_t Res[20];//存放我们接收到的一包数据4 I( @4 K; ~# Q3 w  `  X$ i& ~& V
  7.   uint8_t queue_buffer;
    $ O. L  X8 D- s- _* B0 o
  8.   int i=0;//接收数组下标
    1 r  U, I- Y' K- x, I
  9.   for(;;)0 h6 f1 [8 m/ q0 F- ~+ |
  10.   {
    9 P( n7 Q7 l1 e0 R* u0 u
  11.     i=0;
    / v( M3 B- M% K5 @' ^; b
  12.     HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_5);
    + Q: a2 v1 j' r2 F
  13.     num_queue=uxQueueMessagesWaiting(myQueue01Handle);//获取消息队列中有多少数据
    . d1 z: c4 \' K4 L' H
  14.     while(num_queue--)
    ; W# ]: J# H& ^" m+ g$ w! ~
  15.     {
    . ^7 e( r  z9 m) S6 S, ]; K
  16.       xReturn=xQueueReceive(myQueue01Handle,&queue_buffer,0);//将消息队列中的数据放在queue_buffer中" B# U+ J& ?' E; Z  p9 i% v+ q5 l
  17.       if(xReturn)0 U! h% G/ d( z/ c2 T
  18.       Res[i++]=queue_buffer;  
    - y  G8 P" Q5 m3 X: T
  19.     }) o8 E) ]- x+ K4 Z6 [) C
  20.     if(i!=0)
    ' w& x; k; @1 r" x% [
  21.     printf(" count %d,LEDTask Receive %s",i,Res);//输出接收消息的大小和内容4 j7 Q1 u' e. f
  22.     osDelay(500);1 t: f) Q6 ^' K; @# R8 u0 A
  23.   }: C4 v5 b' ~$ Z5 u( x! C
  24. }
复制代码

3 b$ r  X! X1 {) z1 }3 K现象
8 e# q. D3 Q) F- Q
PC端发送123456789,MCU回复Receive a frame data! g% g2 s' W. {( N* q5 N
count 8,LEDTask Receive 12345678/ F, J" ]$ @1 j+ w+ ?- ^

4 k( Z: o, b/ B* }( m- k
9 w# @  k. ]2 e& E 640.png 7 B. x2 _7 o3 K' S7 N" B; C
( z  y4 @! C* _: B: I" n6 u* N
转载自: 跋扈洋
7 j8 \/ F, s/ q9 B5 N# ]# a. K+ U
赞 收藏 评论0 发布时间:2022-12-1 18:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版