OpenEdv-开源电子网

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

stm32单片机下使用FreeRTOS编程,如何划分任务及任务间如何通信呢?

[复制链接]

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
发表于 2019-12-5 15:00:56 | 显示全部楼层 |阅读模式
1金钱
我是FreeRTOS的菜鸟,想在STM32下使用FreeRTOS编程,今有如下设备
         (1)、USART1通过串口通信(只有接收中断,无发送中断)采集2个压力数据
         (2)、USART2通过串口通信(只有接收中断,无发送中断)采集2个温度数据
         (3)、AD7708模拟量输入芯片采集3路传感器信号数据
        (4)、USART3通信(既有接收中断,又有发送中断),当收到上位机的请求后,将2个压力数据、2个温度数据、3路传感器信号数据传输给上位机。

     请问:

         (1)、我该如何划分任务?
                     我是依据设备来划分任务呢?还是其它呢?
         (2)、我下面划分任务是否合理
                    USART1划分一个任务,USART1接收中断通过发送信号量通知该任务开始运行。
                    USART2划分一个任务,USART2接收中断通过发送信号量通知该任务开始运行。
                    AD7708划分一个任务,该任务是一个周期性任务,每隔100毫秒执行一次
                    USART3划分一个任务,当收到上位机的请求后,将数据发送给上位机。
         (3)、如果按照(2)划分的任务不合理,该怎么划分任务才合理呢?

         (4)、USART1、USART2、AD7708的数据如何分别传输给USART3的任务呢?
                  

最佳答案

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

我准备这样设计任务: 设计消息队列协议 msg[0] = 1 表示传输2个压力数据 msg[0] = 2 表示传输2个温度数据 msg[0] = 3 表示传输3个通道传感器数据 msg[0] = 4 表示DMA接收上位机通信报文完毕 一、USART1划分一个任务,USART1接收中断中发送信号量通知该任务运行解析完报文后,得到2个压力数据,然后发送msg[0] = 1 消息队列, 传输给USART3任务。 ...
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
 楼主| 发表于 2019-12-5 15:00:57 | 显示全部楼层
本帖最后由 霸王猫 于 2019-12-9 09:02 编辑

我准备这样设计任务:

         设计消息队列协议
            msg[0] = 1   表示传输2个压力数据
            msg[0] = 2   表示传输2个温度数据
            msg[0] = 3   表示传输3个通道传感器数据
            msg[0] = 4   表示DMA接收上位机通信报文完毕

一、USART1划分一个任务,USART1接收中断中发送信号量通知该任务运行解析完报文后,得到2个压力数据,然后发送msg[0] = 1 消息队列,   传输给USART3任务。
二、USART2划分一个任务,USART2接收中断中发送信号量通知该任务运行解析完报文后,得到2个温度数据,然后发送msg[0] = 2 消息队列,  传输给USART3任务。
三、AD7708划分一个任务,该任务是一个周期性任务,每隔100毫秒执行一次,采集到传感器信号后,然后发送msg[0] =3 消息队列,  传输给USART3任务。
四、USART3接收上位机通信使用DMA中断(使用STM32F103的USART3空闲中断+DMA方式采集不定长的上位机报文),当检测到DMA接收完毕,然后发送msg[0] = 4 消息队列, 传输给USART3任务。

五、USART3划分一个任务
               USART3_TASK()
               {

                     while (1)
                    {
                          等待消息队列;
                          读取消息队列头字节
                           switch (消息队列头字节)
                           {
                                  case 1:
                                      读取2个压力数据
                                      break;
                                   case 2:
                                      读取2个温度数据
                                      break;
                                  case 3:
                                      读取3个通道的传感器数据
                                      break;
                                  case 4:
                                      USART3通过DMA方式读取完毕上位机通信报文,解析上位机报文;
                                       if (上位机报文检验通过)
                                     {
                                          给上位机发送压力、温度和传感器数据
                                     }
                                    break;
                                }

                    }
                }   
回复

使用道具 举报

57

主题

1680

帖子

3

精华

资深版主

Rank: 8Rank: 8

积分
4306
金钱
4306
注册时间
2018-6-30
在线时间
808 小时
发表于 2019-12-5 20:10:05 | 显示全部楼层
帮顶!
回复

使用道具 举报

1

主题

882

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3071
金钱
3071
注册时间
2018-2-7
在线时间
285 小时
发表于 2019-12-6 10:04:19 | 显示全部楼层
先写好一个任务,调试没问题了在慢慢添加其他任务,多练习自然就会了。
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
 楼主| 发表于 2019-12-6 16:23:36 | 显示全部楼层
我准备这样设计任务:

    一、USART1划分一个任务,USART1接收中断中发送信号量通知该任务开始运行,解析完报文后,得到2个压力数据,然后通过消息队列   传输给USART3任务。
    二、USART2划分一个任务,USART2接收中断中发送信号量通知该任务开始运行,解析完报文后,得到2个温度数据,然后通过消息队列传输给USART3任务。
    三、AD7708划分一个任务,该任务是一个周期性任务,每隔100毫秒执行一次,采集到传感器信号后,然后通过消息队列传输给USART3任务。
    四、USART3划分一个任务
              当上位机给设备发送请求报文时,开启定时器TIM1(20毫秒),当TIM1定时器溢出时,表示上位机已经给设备发送完请求报文(设备应该解析该报文),此时在TIM1定时器中断服务程序中给USART3任务发送信号量。   

               USART3_TASK()
               {

                     while (1)
                    {
                            等待USART1的消息队列数据;
                            等待USART2的消息队列数据;                            等待AD7708的消息队列数据;
                            等待TIM1溢出中断发出的信号量

                             开始解析报文;
                             if (报文检验通过)
                             {
                                  给上位机发送压力、温度和传感器数据

                             }



                    }
                }   




回复

使用道具 举报

3

主题

1155

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
7462
金钱
7462
注册时间
2015-1-15
在线时间
1367 小时
发表于 2019-12-6 20:04:34 来自手机 | 显示全部楼层
感觉完全没这必要
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
 楼主| 发表于 2019-12-9 08:50:59 | 显示全部楼层
我准备这样设计任务:

     规划消息队列协议
         Msg[0] = 1 :  表示USART1任务发送的压力数据,Msg[1]---Msg[4] = 压力数据

         Msg[0] = 2 :  表示USART2任务发送的温度数据,Msg[1]---Msg[4] = 温度数据
         Msg[0] = 3 :  表示AD7708任务发送的传感器数据,Msg[1]---Msg[6] = 3个通道的传感器数据
         Msg[0] = 4 :  表示DMA中断接收串口通信完毕,准备在USART3任务中解析报文

一、USART1划分一个任务,USART1接收中断中发送信号量通知该任务开始运行,解析完报文后,得到2个压力数据,然后发送消息队列Msg[0] = 1 ,  传输给USART3任务。



二、USART2划分一个任务,USART2接收中断中发送信号量通知该任务开始运行,解析完报文后,得到2个温度数据,然后发送消息队列Msg[0] = 2 ,传输给USART3任务。
三、AD7708划分一个任务,该任务是一个周期性任务,每隔100毫秒执行一次,采集到传感器信号后,然后发送消息队列Msg[0] = 3 ,传输给USART3任务。
四、USART3划分一个任务
      使用DMA接收通信数据,当产生DMA中断,表示接收完毕,在DMA中断中发送消息队列Msg[0] = 4 ,传输给USART3任务发送消息队列。   

               USART3_TASK()
               {

                     while (1)
                    {
                            等待消息队列数据;
                            switch (消息队列头字节)
                           {
                                  case 1:
                                        读取电压数据;
                                        break;
                                  case 2:                                        读取温度数据;
                                        break;

                                  case 3:                                        读取传感器数据;
                                        break;
                                 case 4:                                        USART3接收完毕上位机通信数据,开始解析上位机报文;
                                         if (报文检验通过)
                                       {
                                              给上位机发送压力、温度和传感器数据
                                       }
                                        break;
                            }
                    }
                }
回复

使用道具 举报

3

主题

1155

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
7462
金钱
7462
注册时间
2015-1-15
在线时间
1367 小时
发表于 2019-12-9 16:57:51 来自手机 | 显示全部楼层
感觉楼主还是别上系统了,搞得那么麻烦
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
 楼主| 发表于 2019-12-12 09:07:32 | 显示全部楼层
本帖最后由 霸王猫 于 2019-12-12 09:10 编辑

最近花了一个星期在网上搜索FREERTOS相关知识然后再次仔细拜读了  北京航空航天大学 周慈航 编著的 《基于嵌入式实时操作系统的程序设计技术》,终于有些醒悟啦!

     FreeRTOS 编写程序,实际上站在前后台编写程序的风格来看,就是要编写成【事件驱动型】的架构,所有的任务要么是周期性任务,要么是【事件驱动型】的任务。

        某一个任务A要使用任务B生产的数据DATA_S,一般使用消息邮箱或消息队列进行传输(即:任务B通过消息邮箱或消息队列给任务A传输生产的数据DATA_S)
       解析串口接收的报文需要设计成事件驱动型架构,即:在  串口接收中断中存储数据,当接收完毕,在串口中断中发送信号量或消息队列或消息邮箱来唤醒串口报文解析任务,进行报文的解析工作。

      总结如下:
      1、中断和任务之间通信
           可以使用消息队列和消息邮箱
     2、任务和任务之间通信
           可以使用消息队列和消息邮箱
     3、中断和任务之间行为同步(协调工作)
            可以用信号量、消息邮箱、消息队列或事件标志组
     4、任务和任务之间行为同步(协调工作)  
             可以用信号量、消息邮箱、消息队列或事件标志组
     5、资源共享
             例如:在中断服务器中写某个全局变量A,在某个任务中读全局变量A,需要进行资源保护
             例如:在一个任务 中写某个全局变量B,在某个任务中读全局变量B,也需要进行资源保护
             资源保护方法有:
                   (1)、读变量之前 关中断
                   (2)、关调度(不建议)
                   (3)、使用互斥信号量
                   (4)、使用计数信号量
回复

使用道具 举报

1

主题

27

帖子

0

精华

初级会员

Rank: 2

积分
94
金钱
94
注册时间
2019-6-17
在线时间
29 小时
发表于 2019-12-13 17:02:14 | 显示全部楼层
如果我来做的话,2个任务。一个串口任务,一个ad7708任务。串口任务,可以通过给每一个串口设置接收完成标志位,当标志位标识完成就处理。
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
 楼主| 发表于 2019-12-27 11:39:50 | 显示全部楼层
ben4 发表于 2019-12-13 17:02
如果我来做的话,2个任务。一个串口任务,一个ad7708任务。串口任务,可以通过给每一个串口设置接收完成标 ...

兄弟,你用标识完成处理,会遇到资源共享问题。

    假如:任务A给任务B传输实时时钟数据,任务A的优先级比任务B的优先级高。

    当时钟时间为07:59 分59秒时,任务A给任务B传输了上述时间,
   当任务B收到数据刚刚读取完小时的数据7,还没有读到分钟和秒的时候,中断发生,又切换到任务A,此时任务A发现时间已经到了08:00:00,然后给任务B发送08:00:00,任务B收到08:00:00。
    任务B继续从断点处开始执行,由于任务B刚刚读完小时,现在开始读分和秒,结果分=0,秒=0,但是之前读的小时=7,
任务B显示 07:00:00,显然是由于资源共享没有处理好造成上述现象。
      
回复

使用道具 举报

1

主题

27

帖子

0

精华

初级会员

Rank: 2

积分
94
金钱
94
注册时间
2019-6-17
在线时间
29 小时
发表于 2019-12-30 09:11:00 | 显示全部楼层
霸王猫 发表于 2019-12-27 11:39
兄弟,你用标识完成处理,会遇到资源共享问题。

    假如:任务A给任务B传输实时时钟数据,任务A的优 ...

可以用信号量代替标识
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
 楼主| 发表于 2020-2-14 16:06:55 | 显示全部楼层


   上述功能我已经在STM32F103单片机下实现啦!代码参见附件

V4-006_基础例程 FreeRTOS DMA USART1 消息队列 MODBUS通信OK.zip

3.1 MB, 下载次数: 346

回复

使用道具 举报

4

主题

65

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
461
金钱
461
注册时间
2016-8-4
在线时间
192 小时
发表于 2020-2-15 15:37:31 | 显示全部楼层
霸王猫 发表于 2020-2-14 16:06
上述功能我已经在STM32F103单片机下实现啦!代码参见附件

你好看了下你写的 ,请问下你那几个任务都是周期执行吗?我看每个task都不是阻塞等待信号量,除了MODBUS_Task。
回复

使用道具 举报

19

主题

334

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1108
金钱
1108
注册时间
2018-11-6
在线时间
240 小时
 楼主| 发表于 2020-2-17 08:55:50 | 显示全部楼层
兄弟:
   1、LED1_Task是周期性任务,闪烁2个指示灯
   2、LED2_Task是周期性任务,闪烁3个指示灯
   3、DI2_Task是周期性任务,检测2路DI信号,然后发送消息队列,Msg[0] = 4,表示DI2_Task任务的消息队列数据
   4、DI1_Task是周期性任务,检测2路DI信号,然后发送消息队列,Msg[0] = 3,表示DI1_Task任务的消息队列数据
   5、SD2405ALPI_Task是周期性任务,读取时钟时间(年、月、日、时、分、秒),然后发送消息队列,Msg[0] = 2,表示SD2405ALPI_Task任务的消息队列数据
   6、MODBUS_Task是阻塞任务,使用DMA接收数据,DMA接收完成,然后发送消息队列,Msg[0] = 1,表示接收到上位机的请求报文
   
回复

使用道具 举报

2

主题

474

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
6077
金钱
6077
注册时间
2018-6-27
在线时间
524 小时
发表于 2020-12-17 09:50:06 | 显示全部楼层
学习学习,学习学习。
回复

使用道具 举报

1

主题

11

帖子

0

精华

新手上路

积分
29
金钱
29
注册时间
2020-12-28
在线时间
4 小时
发表于 2020-12-31 16:19:44 | 显示全部楼层
帮顶!
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

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

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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