搜索
bottom↓
回复: 20

请教freertos“重启”任务的问题

[复制链接]

出0入4汤圆

发表于 2019-8-29 22:35:26 | 显示全部楼层 |阅读模式
如题,举例我有1个闪灯的任务,

while(1)
{
LED_ON;
vTaskDelay(1000);
LED_OFF;
vTaskDelay(1000);
}

还有个485任务,接收到特定的命令的时候想让这个闪灯任务“重启”,即:无论现在LED是ON还是OFF状态,无论现在的vTaskDelay到了500还是800,在这个485任务中要能够使这个闪灯任务从头开始,有没有什么好的办法?

我看了任务挂起,好像不适合这种用法,任务恢复之后还是从挂起点继续运行。
我想到一种解决办法,就是这个删除任务,再新建这个任务,但是这样做会不会产生内存碎片?

大神们有没有其他更好的办法?

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入25汤圆

发表于 2019-8-29 23:25:00 | 显示全部楼层
退一步行吗?  
信号量 + 双while (1)   
检测到信号量就break第二层while(1)  弹到第一层while(1) 从头开始 , 放小task delay 的颗粒度,LED闪烁延时用个变量自己计数呗。  响应“重启” 的滞后时间就是一个task的delay粒度。

出0入224汤圆

发表于 2019-8-29 23:29:07 | 显示全部楼层
freertos不知道,比如rt-thread可以用信号量。

while(1)
{
  LED_ON;
  获取信号量(超时时间1秒)
  if(获取到信号量)  continue;
  LED_OFF;
  获取信号量(超时时间1秒)
}

出100入143汤圆

发表于 2019-8-30 00:13:55 来自手机 | 显示全部楼层
灯闪烁延时做成状态机,想怎么玩都行

出0入4汤圆

 楼主| 发表于 2019-8-30 08:51:32 来自手机 | 显示全部楼层
墨非 发表于 2019-8-29 23:25
退一步行吗?  
信号量 + 双while (1)   
检测到信号量就break第二层while(1)  弹到第一层while(1) 从头开 ...

这是一个办法,把delay1000改成10个delay100,在间隙里判断标志位

出0入0汤圆

发表于 2019-8-30 08:51:58 | 显示全部楼层
按4楼说的,用信号量,在循环结束等信号量

出0入4汤圆

 楼主| 发表于 2019-8-30 08:55:06 来自手机 | 显示全部楼层
zzh90513 发表于 2019-8-30 00:13
灯闪烁延时做成状态机,想怎么玩都行

目前是有45个灯或者继电器,而且不完全是闪烁,是可编程的,用状态机太麻烦了,所以用的freer ‘tis 操作系统,跑了九十多个任务

出0入12汤圆

发表于 2019-8-30 08:58:05 | 显示全部楼层
3 楼做法是是比较简洁合理的,前提是有等待信号量超时机制。

出0入0汤圆

发表于 2019-8-30 10:06:44 | 显示全部楼层
zqf441775525 发表于 2019-8-30 08:55
目前是有45个灯或者继电器,而且不完全是闪烁,是可编程的,用状态机太麻烦了,所以用的freer ‘tis 操作 ...

90多个任务?
还是考虑下基于事件(信号)去设计逻辑吧。

出100入143汤圆

发表于 2019-8-30 10:14:02 | 显示全部楼层
zqf441775525 发表于 2019-8-30 08:55
目前是有45个灯或者继电器,而且不完全是闪烁,是可编程的,用状态机太麻烦了,所以用的freer ‘tis 操作 ...

1. 每个灯用一个结构体定义:
  1. /*
  2. * LED control structure
  3. */
  4. typedef struct
  5. {
  6.     uint8_t mode;    /* Operation mode */
  7.     uint8_t todo;    /* Blink cycles left */
  8.     uint8_t onPct;   /* On cycle percentage */
  9.     uint16_t time;   /* On/Off cycle time(msec) */
  10.     uint32_t next;   /* Time for next change */

  11. }LedCtrl_t;
复制代码


2. 在freertos开一个定时器
  1. /**
  2. * @brief  Update leds to work with blink
  3. * @param  None
  4. * @retval None
  5. */
  6. void LedUpdate(void)
  7. {
  8.     uint8_t led;
  9.     uint8_t pct = 10;
  10.     uint8_t leds;
  11.     LedCtrl_t *pledctrl;
  12.     uint32_t time;
  13.     uint16_t next;
  14.     uint16_t wait;

  15.     /* Check if sleep is active or not */
  16.     if (sxLedObj.sleepAct)
  17.     {
  18.         return;
  19.     }

  20.     next = 0;
  21.     led = 1;
  22.     leds = LED_ALL;
  23.     pledctrl = sxLedObj.ledCtrlTbl;

  24.     while (leds)
  25.     {
  26.         if (!(leds & led))
  27.         {
  28.             led <<= 1;
  29.             pledctrl++;
  30.             continue;
  31.         }

  32.         if (!(pledctrl->mode & LED_MODE_BLINK))
  33.         {
  34.             leds ^= led;
  35.             led <<= 1;
  36.             pledctrl++;
  37.             continue;
  38.         }

  39.         /* Get current system tick count(ms) */
  40.         time = Led_GetSystemClock();

  41.         if (time >= pledctrl->next)
  42.         {
  43.            if (pledctrl->mode & LED_MODE_ON)
  44.            {
  45.                pct = 100U - pledctrl->onPct;   /* Percentage of cycle for off */
  46.                pledctrl->mode &= ~LED_MODE_ON; /* Say it's not on */
  47.                LedOnOff(led, LED_MODE_OFF);    /* Turn it off */

  48.                if (!(pledctrl->mode & LED_MODE_FLASH))
  49.                {
  50.                    pledctrl->todo--;  /* Not continuous, reduce count */
  51.                }
  52.            }
  53.            else if ((!pledctrl->todo) && !(pledctrl->mode & LED_MODE_FLASH))
  54.            {
  55.                pledctrl->mode ^= LED_MODE_BLINK;  /* No more blinks */
  56.            }
  57.            else
  58.            {
  59.                pct = pledctrl->onPct;          /* Percentage of cycle for on */
  60.                pledctrl->mode |= LED_MODE_ON;  /* Say it's on */
  61.                LedOnOff(led, LED_MODE_ON);     /* Turn it on */
  62.            }

  63.            if (pledctrl->mode & LED_MODE_BLINK)
  64.            {
  65.                wait = (((uint32_t)pct * (uint32_t)pledctrl->time) / 100U);
  66.                pledctrl->next = time + wait;
  67.            }
  68.            else
  69.            {
  70.                /* No more blink, No more wait */
  71.                wait = 0;

  72.                /* After blinking, set the LED back to the state before it blinks */
  73.                LedSet(led, ((sucLedPreBlinkState & led) != 0U)? LED_MODE_ON : LED_MODE_OFF);

  74.                /* Clear the saved bit */
  75.                sucLedPreBlinkState &= led ^ 0xFF;
  76.            }
  77.         }
  78.         else
  79.         {
  80.            wait = pledctrl->next - time;  /* Time left */
  81.         }

  82.         if (!next || (wait && (wait < next)))
  83.         {
  84.            next = wait;
  85.         }

  86.         leds ^= led;
  87.         led <<= 1;
  88.         pledctrl++;
  89.     }

  90.     if (next)
  91.     {
  92.        /* Start timer to schedule event */
  93.        if (xTimerChangePeriod(shTmrLed,  pdMS_TO_TICKS(next), 0) != pdPASS)
  94.        {
  95.            xprintf("Led blink timer start failure!\r\n");
  96.        }
  97.     }
  98. }
复制代码


3. 再写一个函数控制结构体变量,随时可以开启,关闭,控制闪烁次数,随时停止

出0入0汤圆

发表于 2019-8-30 10:37:41 | 显示全部楼层
延时改为pend,消息触发,然后加if判断,continue.

出0入4汤圆

 楼主| 发表于 2019-8-30 10:48:05 | 显示全部楼层
dalige 发表于 2019-8-30 10:06
90多个任务?
还是考虑下基于事件(信号)去设计逻辑吧。

其实我是在做密室逃脱的集中控制主板,45个输入,45个输出(继电器),每个输入触发可以设置最多3个输出,每个输出可以设置开的时间,关的时间,是否循环等设置的参数比较多。为了使程序逻辑简单些,就是每个输入和每个输出都是一个任务。再加上485等,总共大约90多个任务。

“基于事件(信号)”设计逻辑,是怎么样的思路呢?

出0入4汤圆

发表于 2019-8-30 10:51:01 | 显示全部楼层
90多个任务,内核调度快累死了

出0入4汤圆

 楼主| 发表于 2019-8-30 10:53:20 | 显示全部楼层
dalige 发表于 2019-8-30 10:06
90多个任务?
还是考虑下基于事件(信号)去设计逻辑吧。

45个继电器任务占用的堆栈大小是一样的,如果我删除一个继电器任务,再新建这个继电器任务,会产生内存碎片吗?有没有了解过FREERTOS的任务堆栈空间是怎么配置的?

出0入4汤圆

 楼主| 发表于 2019-8-30 10:55:25 | 显示全部楼层
liuqian 发表于 2019-8-30 10:51
90多个任务,内核调度快累死了

还好吧,任务实时性要求不是太高,基本上是vtaskdelay(200)或者vtaskdelay(100)这样,每个任务执行时间很短,就是判断几个if语句。应该是留出足够的内核调度时间的。

出0入4汤圆

 楼主| 发表于 2019-8-30 11:15:28 | 显示全部楼层
zzh90513 发表于 2019-8-30 10:14
1. 每个灯用一个结构体定义:

定时器中断,在中断里判断计时是否到了相应的时间。这种方法在裸机的时候比较常用。
按照您的程序,我这边45个继电器对应45个Led_GetSystemClock();,而且这45个时间的开始点都是完全独立的,由45个输入随时触发开始,想想就麻烦。

我先试试“删除任务”之后再“新建任务”的方法。

出0入0汤圆

发表于 2019-8-30 12:57:54 来自手机 | 显示全部楼层
多输入多输出,用cpld更好搞定

出100入143汤圆

发表于 2019-8-30 14:01:42 | 显示全部楼层
zqf441775525 发表于 2019-8-30 11:15
定时器中断,在中断里判断计时是否到了相应的时间。这种方法在裸机的时候比较常用。
按照您的程序,我这 ...

不是在定时器中断,是freertos的定时器任务,在任务内扫描45个对象数组的标志而已,我一直这样用;
可以随时改变某一个LED的开关状态,指定闪烁次数,一直闪烁,以及闪烁的占空比;
PS:频繁创建删除任务,一直在分配释放内存,对系统稳定性肯定有一定影响

出0入4汤圆

 楼主| 发表于 2019-8-30 14:07:54 | 显示全部楼层
zzh90513 发表于 2019-8-30 14:01
不是在定时器中断,是freertos的定时器任务,在任务内扫描45个对象数组的标志而已,我一直这样用;
可以 ...

45个LED任务都是使用相同大小的堆栈空间,删除和重建任务也仅限于这45个LED的任务,应该不会对系统有太大的影响。删除完立马再重建上,因为可能还有别的输入点要触发这个LED任务。

出0入0汤圆

发表于 2019-8-30 14:49:23 | 显示全部楼层
你这做法类似于http server的多线程,实际上单线程处理就可以了。
否则假设你有200个输入输出,你咋控制?
我不认为输入检测和输出控制的实时性有多高,实际上,把数据结构的定义好,压根不用啥freertos就搞好了。

出0入4汤圆

 楼主| 发表于 2019-8-30 16:35:32 | 显示全部楼层
dalige 发表于 2019-8-30 14:49
你这做法类似于http server的多线程,实际上单线程处理就可以了。
否则假设你有200个输入输出,你咋控制?
...

这个实时性要求确实不高,100mS - 200mS都无所谓的。
单线程肯定是能够处理的,TIM定时100mS,然后每100mS把这45个灯的状态处理一遍就OK了。
现在是程序已经写的差不多了,只差这一步了。如果放弃这个方案推倒重来,自己又心有不甘。唉
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-18 08:12

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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