OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 7182|回复: 11

FreeRTOS如何解决使用消息队列时,生产者可以随时生产消息,但是无法确定消费者何时消费消息的问题

[复制链接]

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
发表于 2020-8-7 21:47:53 | 显示全部楼层 |阅读模式
1金钱
本帖最后由 霸王猫 于 2020-8-7 21:55 编辑

FreeRTOS要求使用消息队列时必须满足如下条件:生产者生产速度小于消息者消息速度。

    现今有以下要求:
      1、单片机和手机APP进行MODBUS通信,手机APP为MODBUS主站,单片机为MODBUS从站。
      2、单片机采集传感器信息上传给手机APP。
      3、单片机规划2个任务。任务1为传感器任务,任务2为MODBUS任务(MODBUS任务负责将数据上传给手机APP软件)
      4、传感器任务(任务1)每隔1秒采集1次传感器数据,然后发送到消息队列
      5、MODBUS任务(任务2)收到手机APP的请求信号量后,从消息队列中取出传感器数据,通过MODBUS-TCP传输手机APP软件。
      6、单片机一直上电运行
      7、工人随机巡查设备时,打开手机APP软件读取单片机设备的运行数据,可以观察设备的运行状态,巡查完毕,关闭手机APP软件。
                  调试时发现刚刚打开手机APP软件时,观察到的传感器数据是很久之前采集的数据,需要等一会才会显示最近采集的数据。
            分析原因可能是因为由于传感器任务每隔1秒钟往消息队列发送消息,而由于消费者(MODBUS任务)在这期间一直都不取走消息(因为这段时间没有人来巡查设备),导致消息队列早就已经装满了,
因此某个时间段内当巡查员打开手机APP软件巡查时,观察到的数据就是消息队列早期采集到的传感器数据。
           当MODBUS任务将消息队列中存储的很久之前采集的传感器数据消费完毕后,这时候消息队列里才会装最近采集的数据,手机APP主页画面上才会显示最近采集的传感器数据。


      请问:对于生产者周而复始不停的生产,而无法确定消费者何时消费的场景,该如何解决呢?








最佳答案

查看完整内容[请看2#楼]

1、定义全局变量用于存储传感器数据 uint8_t buffer[20] 2、单片机接收传感器数据任务: 用消息队列接收传感器数据(因为生产者生产速度小于消费者消费速度,所以可以使用消息队列传输数据) 互斥信号量保护 传感器数据存储到buffer 互斥信号量释放 3、手机APP任务 由于手机APP任务是MODBUS主站,有可能一周才触发一次,不能使用消息队列传输 ...
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
 楼主| 发表于 2020-8-7 21:47:54 | 显示全部楼层
ufbycd 发表于 2021-12-8 11:36
不要用全局变量,用函数封装一下再给Modus线程,用互斥量确保没有同时进行传感器数据的读跟写。

1、定义全局变量用于存储传感器数据
      uint8_t  buffer[20]

2、单片机接收传感器数据任务:
           用消息队列接收传感器数据(因为生产者生产速度小于消费者消费速度,所以可以使用消息队列传输数据)
             互斥信号量保护
             传感器数据存储到buffer
             互斥信号量释放

3、手机APP任务
           由于手机APP任务是MODBUS主站,有可能一周才触发一次,不能使用消息队列传输传感器数据,因此使用全局变量+拍照功能进行数据交换。
          (1)、定义局部变量  uint8_t Temp_buffer[20]
           (2)、 互斥信号量保护
                         for (i=0;i<20;i++)
                             Temp_buffer = buffer   --->拍照
                        互斥信号量释放
             (3)、Modbus通信使用Temp_buffer
     
回复

使用道具 举报

0

主题

113

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2538
金钱
2538
注册时间
2019-10-18
在线时间
403 小时
发表于 2020-8-8 17:56:47 | 显示全部楼层
为什么一定要将数据堵在消息队列里呢.从消息队列里读出来放到一个环形缓冲区里循环覆盖不行么.
等app需要的时候整个队列一起发走
这样这个缓冲区里的数据一直就是最近几秒的新数据
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
 楼主| 发表于 2021-12-7 17:21:45 | 显示全部楼层
本帖最后由 霸王猫 于 2021-12-7 17:23 编辑

你这样使用就相当于:使用信号量方式访问全局数组式啦!
    我想用消息队列实现,但是FreeRTOS要求使用消息队列时必须满足如下条件:生产者生产速度小于消息者消息速度
        但是我的条件显然不能满足,因为传感器每隔1秒给单片机上传采集数据(生产数据),但是你也不知道工人什么时候来巡检(消费数据),有可能工人每隔1个星期才来巡检一次。
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165309
金钱
165309
注册时间
2010-12-1
在线时间
2108 小时
发表于 2021-12-8 01:41:05 | 显示全部楼层
一般这种是存起来,超过就覆盖。只要你存储够大,就可以存储很长的时间。
回复

使用道具 举报

3

主题

312

帖子

0

精华

高级会员

Rank: 4

积分
907
金钱
907
注册时间
2011-10-19
在线时间
196 小时
发表于 2021-12-8 10:46:48 | 显示全部楼层
既然传感器数据只有一个数值,那么传感器线程只更新这个值就行了,没必要做成队列,ModuBus有请求就读这个值。
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
 楼主| 发表于 2021-12-8 11:25:46 | 显示全部楼层
ufbycd 发表于 2021-12-8 10:46
既然传感器数据只有一个数值,那么传感器线程只更新这个值就行了,没必要做成队列,ModuBus有请求就读这个 ...

传感器有一堆数据(大概20个字节)

   1、传感器定时每隔1秒给单片机上传传感器采集数据(生产者)
   2、巡检工人定时每隔1周用手机APP连接单片机查看系统状态(包括:传感器数据)(消费者)

      像这种:生产者和消费者严重不对等的特殊情况,看来就不能用消息队列传输,只能用全局变量(全局缓冲区)+信号量进行传输。
        因为操作系统消息队列的使用原则是:生产者生产速度必须小于消费者消费速度,否则系统就会严重滞后。
回复

使用道具 举报

3

主题

312

帖子

0

精华

高级会员

Rank: 4

积分
907
金钱
907
注册时间
2011-10-19
在线时间
196 小时
发表于 2021-12-8 11:36:09 | 显示全部楼层
霸王猫 发表于 2021-12-8 11:25
传感器有一堆数据(大概20个字节)

   1、传感器定时每隔1秒给单片机上传传感器采集数据(生产者)

不要用全局变量,用函数封装一下再给Modus线程,用互斥量确保没有同时进行传感器数据的读跟写。
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
 楼主| 发表于 2021-12-10 11:07:38 | 显示全部楼层
ufbycd 发表于 2021-12-8 11:36
不要用全局变量,用函数封装一下再给Modus线程,用互斥量确保没有同时进行传感器数据的读跟写。

搞不明白,能具体点吗?
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
 楼主| 发表于 2021-12-13 11:22:33 | 显示全部楼层
ufbycd 发表于 2021-12-8 11:36
不要用全局变量,用函数封装一下再给Modus线程,用互斥量确保没有同时进行传感器数据的读跟写。

不要用全局变量,用函数封装一下再给Modus线程,用互斥量确保没有同时进行传感器数据的读跟写。


     怎么搞,能否给个简单的示例呢?谢谢!
回复

使用道具 举报

49

主题

340

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
5246
金钱
5246
注册时间
2012-8-25
在线时间
1024 小时
发表于 2021-12-14 08:00:47 | 显示全部楼层
有rtos不要用全局变量,用共享内存.其实就是全局变量加锁.
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
 楼主| 发表于 2021-12-24 10:55:36 | 显示全部楼层
霸王猫 发表于 2021-12-10 11:07
搞不明白,能具体点吗?

不要用全局变量,用函数封装一下再给Modus线程,用互斥量确保没有同时进行传感器数据的读跟写。


     怎么搞,能否给个简单的示例呢?谢谢!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-22 17:27

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表