搜索
bottom↓
回复: 38

[代码分享]一个简单好用的轮询延时器模块

  [复制链接]

出0入8汤圆

发表于 2017-5-23 10:08:59 | 显示全部楼层 |阅读模式
本帖最后由 Jmhh247 于 2017-5-23 10:08 编辑

关键字:延时器;非阻塞自由延时


在一些按键或其它形式的命令响应中,要求严格的话通常会需要队列缓存命令,以防丢失。

但是我通常还会遇到一些要求非常不严格的场景,这些场景甚至要限制响应的次数或频率(这里指不能响应太快)。
比如(只是个例子),我的产品是一个根据接收到的串口命令来工作的。串口命令发送的速度是不确定的,有时候1秒
会发送10帧命令过来,有的时候1秒确能发送100帧,但是这个产品每秒只打算处理20帧命令。而且由于命令有多个,
对于有些命令码可能每秒响应40帧或30帧等,这种场景用多个延时器就很合适了。


延时器模块的接口函数一共3个,如下:
  1. /* Exported functions ------------------------------------------------------- */
  2. bool zl_poll_delay_set(uint8_t chUserId, uint16_t hwTime);
  3. bool zl_poll_delay_timeout(uint8_t chUserId);
  4. void zl_poll_delay_tick(void);
复制代码


看下接口函数的实现,很简单的
  1. /*   Z L _ P O L L _ D E L A Y _ S E T   */
  2. /*-------------------------------------------------------------------------
  3. 功能描述  : 设定延时时间,同时启动延时。
  4. 输入参数  : uint8_t chUserId  延时器ID
  5.              uint16_t hwTime   延时时间
  6. 输出参数  : 无
  7. 返 回 值  :

  8. 修改历史      
  9.   1.日    期   : 2017年2月6日
  10.     作    者   : zys
  11.     修改内容   : 新生成函数,OK。

  12. -------------------------------------------------------------------------*/
  13. bool zl_poll_delay_set(uint8_t chUserId, uint16_t hwTime)
  14. {
  15.     if (chUserId >= ZL_POLL_DELAY_NUM) {
  16.         return false;
  17.     }

  18.     if (0 == hwTime) {
  19.         return false;
  20.     }

  21.     s_tPollBuf[chUserId].Time = hwTime;

  22.     return true;

  23. }


  24. /*   Z L _ P O L L _ D E L A Y _ T I M E O U T   */
  25. /*-------------------------------------------------------------------------
  26. 功能描述  : 查询给定ID的延时器是否超时。
  27. 输入参数  : uint8_t chUserId  
  28. 输出参数  : 无
  29. 返 回 值  : true 超时;false 未超时。

  30. 修改历史      
  31.   1.日    期   : 2017年5月22日
  32.     作    者   : zys
  33.     修改内容   : 新生成函数。

  34. -------------------------------------------------------------------------*/
  35. bool zl_poll_delay_timeout(uint8_t chUserId)
  36. {
  37.     if (chUserId >= ZL_POLL_DELAY_NUM) {
  38.         return false;
  39.     }

  40.     if ( !s_tPollBuf[chUserId].Time) {
  41.         return true;
  42.     }

  43.     return false;
  44. }


  45. /*   Z L _ P O L L _ D E L A Y _ T I C K   */
  46. /*-------------------------------------------------------------------------
  47. 功能描述  : 延时模块的驱动任务,在心跳中断里运行。
  48. 输入参数  : void  
  49. 输出参数  : 无
  50. 返 回 值  :

  51. 修改历史      
  52.   1.日    期   : 2017年5月22日
  53.     作    者   : zys
  54.     修改内容   : 新生成函数。

  55. -------------------------------------------------------------------------*/
  56. void zl_poll_delay_tick(void)
  57. {
  58.     uint8_t i;


  59.     for ( i = 0 ; i < ZL_POLL_DELAY_NUM; i++ ) {
  60.         if (s_tPollBuf[i].Time) {
  61.             s_tPollBuf[i].Time--;
  62.         }
  63.     }
  64. }
复制代码


模块的使用
使用很简单,首先把模块源文件添加到工程中,然后把
  1. void zl_poll_delay_tick(void)
复制代码

放到心跳中断里,我一般用1ms的心跳中断。


现在就能使用
  1. bool zl_poll_delay_set(uint8_t chUserId, uint16_t hwTime)
复制代码

来设置延时器了,入参分别是延时器的ID和延时时间,延时时间单位和心跳中断有关,看自己需求了。。。


然后用
  1. bool zl_poll_delay_timeout(uint8_t chUserId)
复制代码

来查询延时器是否超时,入参是要查询的延时器ID号。


延时器的可用最大数量通过宏定义配置
  1. /* 定义可用的延时数量 */
  2. #define ZL_POLL_DELAY_NUM   5
复制代码




模拟一个应用场景演示代码


  1. /* 定义延时器信息,便于阅读修改 */
  2. #define DELAY_ID0           0
  3. #define DELAY_TIME0         50

  4. #define DELAY_ID1           1
  5. #define DELAY_TIME1         900



  6. /* 模拟一个应用场景 */
  7. void xxx_cmd_process(uint8_t chCmd)
  8. {
  9.     switch (chCmd) {
  10.     case CMD_LEFT:

  11.         /* 该命令执行间隔不能小于50ms */
  12.         if (zl_poll_delay_timeout(DELAY_ID0)) {
  13.             zl_poll_delay_set(DELAY_ID0, DELAY_TIME0);

  14.             cmd_do_left();
  15.         }
  16.         break;

  17.     case CMD_RIGHT:

  18.         /* 该命令执行间隔不能小于900ms */
  19.         if (zl_poll_delay_timeout(DELAY_ID1)) {
  20.             zl_poll_delay_set(DELAY_ID1, DELAY_TIME1);

  21.             cmd_do_left();
  22.         }
  23.         break;

  24.     case CMD_UP:

  25.         /* 该命令无限制,来就执行 */
  26.         cmd_do_up();
  27.         break;

  28.     case CMD_DOWN:
  29.         break;

  30.     default:
  31.         break;
  32.     }
  33. }


  34. /* 在1ms心跳(时基)中断里运行 */
  35. void st_systick_1ms_irq(void)
  36. {
  37.     zl_poll_delay_tick()
  38. }
复制代码



延时器的用处还有很多,可以灵活。。。



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

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

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出5入0汤圆

发表于 2017-5-23 12:25:45 来自手机 | 显示全部楼层
支持   

出0入0汤圆

发表于 2017-5-23 22:43:02 | 显示全部楼层
定时时间到后自动调用回调函数,是否更方便

出0入8汤圆

 楼主| 发表于 2017-5-23 23:15:17 来自手机 | 显示全部楼层
bitter 发表于 2017-5-23 22:43
定时时间到后自动调用回调函数,是否更方便

是方便,但是那样就变成定时器了。定时器是周期运行,用回调函数最合适。

这里是作延时器用的,延时的处理是随机的,不适合回调函数。

不知道我这样说合适不。。。

我还有篇帖子是写的就是软件定时器,用回调函数的,你可以看看区别。

出0入0汤圆

发表于 2017-5-23 23:49:47 | 显示全部楼层
值得学习学习

出0入0汤圆

发表于 2017-5-23 23:52:06 | 显示全部楼层
先收藏再看看

出0入0汤圆

发表于 2017-5-23 23:54:54 | 显示全部楼层
这种写法没用过,有机会在项目中试试

出0入0汤圆

发表于 2017-5-24 08:29:48 | 显示全部楼层
本帖最后由 943941946 于 2017-5-24 08:31 编辑

感觉不怎么好用,谢谢lz分享

出0入8汤圆

 楼主| 发表于 2017-5-24 09:36:34 | 显示全部楼层
本帖最后由 Jmhh247 于 2017-5-24 09:38 编辑
943941946 发表于 2017-5-24 08:29
感觉不怎么好用,谢谢lz分享


哈哈,好不好用是对比才知道的,我原来的延时器是这么做的

  1. /* 使用标志位方式的延时器例子 */


  2. /* 标志,延时时间到为1,不到为0,同作为启动开关,等于0时启动延时 */
  3. uint32_t g_wDelayFlag1 = 1;
  4. uint32_t g_wDelayFlag2 = 1;



  5. /*
  6. 下面是用到延时器的服务,通过查询标志,需要说明的是,使用延时器的服务
  7. 不是周期运行的,是随机发生的,否则就可以用软件定时器了。
  8. */
  9. void xxx1_service(void)
  10. {
  11.         if (g_wDelayFlag1)
  12.         {
  13.                 do_something1();
  14.                
  15.                 g_wDelayFlag1 = 0;                /* 启动延时器1 */
  16.         }
  17.        
  18. }



  19. void xxx2_service(void)
  20. {
  21.         if (g_wDelayFlag2)
  22.         {
  23.                 do_something2();
  24.                
  25.                 g_wDelayFlag2 = 0;                /* 启动延时器2 */
  26.         }
  27. }



  28. /* 在1ms心跳(时基)中断里运行 */
  29. void st_systick_1ms_irq(void)
  30. {
  31.     static uint16_t s_hwCnt1 = 0;
  32.     static uint16_t s_hwCnt2 = 0;


  33.         /* 第一个延时 */
  34.     if (!g_wDelayFlag1) {
  35.         if (++s_hwCnt1 >= 1000) {
  36.             g_wDelayFlag1 = 1;
  37.             s_hwCnt1 = 0;
  38.         }
  39.     }

  40.         /* 第二个延时 */
  41.     if (!g_wDelayFlag2) {
  42.         if (++s_hwCnt2 >= 600) {
  43.             g_wDelayFlag2 = 2;
  44.             s_hwCnt2 = 0;
  45.         }
  46.     }

  47. }
复制代码


可以看出来在心跳中断里,有两段重复代码,事实上,按这种方式,需要几个延时器
就必须重复几个这段代码。

而采用我帖子说的模块化后,就避免了这种重复劳动,好不好用就很明显了吧。。。

不知道大家是怎么做的。。。


修改原因:

/*
下面是用到延时器的服务,通过查询标志,需要说明的是,延时器使用的服务
不是周期运行的,是随机发生的,否则就可以用软件定时器了。
*/

修改为
/*
下面是用到延时器的服务,通过查询标志,需要说明的是,使用延时器的服务
不是周期运行的,是随机发生的,否则就可以用软件定时器了。
*/

出0入0汤圆

发表于 2017-5-24 09:48:55 | 显示全部楼层
思路很清晰,谢谢楼主分享。

出0入0汤圆

发表于 2017-5-24 10:56:25 | 显示全部楼层
路过,哪天静下心来好好看看。。

出0入0汤圆

发表于 2017-5-24 11:31:40 | 显示全部楼层
为什么要延时?

出0入0汤圆

发表于 2017-5-24 13:48:23 | 显示全部楼层
不错,简洁实用。多谢

出0入0汤圆

发表于 2017-5-25 17:05:19 来自手机 | 显示全部楼层
楼主的办法很好 像是操作系统里面的事件组 用数组省去了离散的标志位 通过ID直接查询超时信息 学习了 感谢

出0入0汤圆

发表于 2017-5-25 22:54:07 | 显示全部楼层
如果没启动,其计数值也为0,不是返回成功的吗

出0入8汤圆

 楼主| 发表于 2017-5-26 08:54:18 | 显示全部楼层
miscell 发表于 2017-5-25 22:54
如果没启动,其计数值也为0,不是返回成功的吗

是的,就是这样设计的。因为上电后是第一次执行,所以有没有延时,结果都是一样的。

所以,在我写的用例中,都是先查询,超时后再设定延时的
  1. /* 该命令执行间隔不能小于900ms */
  2.         if (zl_poll_delay_timeout(DELAY_ID1)) {
  3.             zl_poll_delay_set(DELAY_ID1, DELAY_TIME1);

  4.             cmd_do_left();
  5.         }
复制代码




出0入0汤圆

发表于 2017-7-19 16:30:04 | 显示全部楼层
感谢楼主分享,我目前也使用过这种思路的,但是用的是离散的结构体标志

出0入9汤圆

发表于 2017-7-19 21:35:43 | 显示全部楼层
本帖最后由 istars2005 于 2017-7-19 21:37 编辑

楼主的方式貌似有点繁琐


  1. vu32 *gTimOut[TM_OUT_CNT] = {0};   // 超时计数变量指针数组
  2. static u8  tm_Out_Cnt = 0;                   // 实际超时变量个数
复制代码

  1. /**
  2. * 函数功能: 配置超时指针
  3. * 输入参数: *ptout 需要传入的超时变量指针
  4. * 输出参数: 配置结果 0:成功  -1:索引溢出  1:超时指针重复(不影响正常结果)
  5. * 功能说明: 修改原来实现方式的bug,不再使用idx变量
  6.              当超过最大允许的超时变量个数时返回-1
  7. */
  8. s8 TimeOutSet(vu32 *ptout)
  9. {
  10.     if(tm_Out_Cnt >= TM_OUT_CNT)
  11.         return -1;
  12.     for(int i=0;i<tm_Out_Cnt;i++) {
  13.         if(ptout == gTimOut[i])
  14.             return 1;
  15.     }
  16.     gTimOut[tm_Out_Cnt] = ptout;
  17.     tm_Out_Cnt++;
  18.     return 0;
  19. }
复制代码


在系统滴答定时器中调用如下代码

  1.     int i=0;
  2.     while(i<tm_Out_Cnt) {                                                       // 扫描超时变量,并且把不为0的变量进行自减一
  3.         *gTimOut[i] ? (*gTimOut[i])-- : 0;
  4.         i++;
  5.     }
复制代码



使用方法
  1. vu32 _gTimeOut1 = 0;                          // 全局变量
  2. TimeOutSet(&_gTimeOut1 );                         // 超时变量注册,最好注册一次,重复注册也可以使用,但是稍浪费一点时间

  3. //正式使用
  4. if(_gTimeOut1  == 0) {
  5.        _gTimeOut1 = 50;
  6.       
  7.        // DoSomeThing();
  8. }
复制代码

出0入55汤圆

发表于 2017-7-19 22:28:31 来自手机 | 显示全部楼层
感谢分享

出0入8汤圆

 楼主| 发表于 2017-7-20 09:05:48 | 显示全部楼层
istars2005 发表于 2017-7-19 21:35
楼主的方式貌似有点繁琐

哈哈,你的方式很不错哈,简单说,你的是将数据与算法分离了

对于这种起辅助作用的功能模块,我现在的思维是尽可能的多做封装,
不去管理数据,而是管理 ID,让使用者更关注自己的代码实现。


现在很火的共享单车(辅助模块),对用户来说,有很多车摆在那里,根本
无需申请一辆车(声明数据),直接扫码(管理ID)骑走。


繁琐与否,就看个人理解吧。。。


我另外一个帖子,也是基于这样的考虑
点我 [代码分享]一个软件定时器模块,简单好用

出0入8汤圆

 楼主| 发表于 2017-7-20 09:07:08 | 显示全部楼层
fm007 发表于 2017-7-19 16:30
感谢楼主分享,我目前也使用过这种思路的,但是用的是离散的结构体标志

结构体标志也不错

出0入9汤圆

发表于 2017-7-20 09:20:25 | 显示全部楼层
Jmhh247 发表于 2017-7-20 09:05
哈哈,你的方式很不错哈,简单说,你的是将数据与算法分离了

对于这种起辅助作用的功能模块,我现在的思 ...


我也是考虑到封装问题,
把这部分功能放到了STM32的SysTick处理的模块当中,
只提供一个延时变量注册的接口.

这样使用时候只需注册一下自己模块内部的静态变量
后面的操作都是本地变量的赋值和判断.
自我感觉封装的还不错


编辑原因: 标题错误

出0入8汤圆

 楼主| 发表于 2017-7-20 10:36:21 | 显示全部楼层
istars2005 发表于 2017-7-20 09:20
我也是考虑到封装问题,
把这部分功能放到了STM32的SysTick处理的模块当中,
只提供一个延时变量注册的接口 ...

你这么说我就看懂了,很有参考价值哈

用户处理好超时变量一次注册的问题就行了。

出0入9汤圆

发表于 2017-7-20 10:47:55 | 显示全部楼层
Jmhh247 发表于 2017-7-20 10:36
你这么说我就看懂了,很有参考价值哈

用户处理好超时变量一次注册的问题就行了。

是的
开始时候是只允许注册一次,重复注册会多占用空间,而且重复意义不大
后来就改了一下
重复注册的话不会多占用空间了
只是需要浪费几个时钟周期去检查一下

为了不占太多空间我一般配置不超过16个超时变量
更改一下宏定义即可

出0入0汤圆

发表于 2017-8-22 08:23:43 | 显示全部楼层
楼主的非阻塞延时器很实用,在工程中使用了一下,出了点问题,请教一下楼主是不是哪个步骤使用错误了,贴上代码
  1. void Task_Thread(void)
  2. {   
  3.         switch(step)
  4.                   {       

  5.                            case 0: //两个LED全灭
  6.                           
  7. //                              
  8.                    if (zl_poll_delay_timeout(0))        //DELAY_ID1  0   标志位
  9.                                                                                  {
  10.                                                                                  
  11.                       zl_poll_delay_set(0, 4000);    //    延时4000ms,4s
  12.                                                                                           LED1=1;
  13.                         LED2=1;
  14.                                                                                         step=1;
  15.                                                                                  }
  16.                              
  17.                      break;
  18.                              
  19.                  
  20.                                       
  21.                      case 1:        // led1亮
  22.                   
  23.                                    
  24.                           LED1=0;
  25.                                if (zl_poll_delay_timeout(1))        //DELAY_ID1  1   标志位
  26.                                                                                  {
  27.                                                                                  
  28.                          zl_poll_delay_set(1, 4000);          //    延时4000ms,4s
  29.                                                                                            LED1=0;
  30.                                                                                            step=2;
  31.                                                                                  }
  32.                            break;
  33.                            
  34.                            
  35.                        case 2:        // led2亮
  36.                                                                                                
  37.                                                                                          
  38.                         if (zl_poll_delay_timeout(2))        //DELAY_ID1  0   标志位
  39.                                                                                  {
  40.                                                                                  
  41.                       zl_poll_delay_set(2, 4000);    //    延时4000ms,4s
  42.                                                                                           LED2=0;
  43.                                                                                           step=0;
  44.                                                                                  }

  45.                            break;
  46.                                                                                  
  47.                                                                                  
  48.                                                                                  default:
  49.                        break;

  50.                         }
  51. }
复制代码



//定时器3中断服务程序  1ms
void TIM3_IRQHandler(void)   //TIM3中断
{
         u8 Index;       

       
        zl_poll_delay_tick();
       

出0入8汤圆

 楼主| 发表于 2017-8-22 09:08:08 | 显示全部楼层
jiangyimfs1 发表于 2017-8-22 08:23
楼主的非阻塞延时器很实用,在工程中使用了一下,出了点问题,请教一下楼主是不是哪个步骤使用错误了,贴上 ...

呃,大哥,你得告诉我出了啥问题吧,光贴代码不知道你想表达啥问题。。。另,你的代码缩进好难受



只能让我猜猜你所谓的问题吧

你想要实现的是不是:
>状态0:两个LED全灭,延时4S
>状态1:LED1亮,延时4S
>状态2:LED2亮,延时4S,LED2亮起的同时切换到状态0

如果是这样,你的写法确实存在些问题,用一个延时器就可以实现了。。。

出0入8汤圆

 楼主| 发表于 2017-8-22 09:29:44 | 显示全部楼层
jiangyimfs1 发表于 2017-8-22 08:23
楼主的非阻塞延时器很实用,在工程中使用了一下,出了点问题,请教一下楼主是不是哪个步骤使用错误了,贴上 ...

按我猜测的功能写的,不过代码未测试,只是展示延时器的使用。。。


  1. #define LED_DELAY_TIME                                                4000

  2. /*   L E D _ D E M O _ T A S K   */
  3. /*-------------------------------------------------------------------------
  4.     *功能:延时器测试闪灯,在超级循环中运行。
  5.     *参数:无
  6.     *返回:无
  7.     *备注:未测试。
  8. -------------------------------------------------------------------------*/
  9. void led_demo_task(void)
  10. {
  11.         static uint8_t s_chStep = 0;


  12.         switch (s_chStep)
  13.         {
  14.                 case 0:
  15.                         /* 全灭 */
  16.                         /* 第一次用直接就是超时状态,因为还未设置超时时间 */
  17.                         if (zl_poll_delay_timeout(0)) {
  18.                                 zl_poll_delay_set(0, LED_DELAY_TIME);

  19.                                 LED_1 = 1;
  20.                                 LED_2 = 1;

  21.                                 s_chStep = 1;
  22.                         }

  23.                         break;

  24.                 case 1:
  25.                         /* LED1 亮 */
  26.                         if (zl_poll_delay_timeout(0)) {
  27.                                 zl_poll_delay_set(0, LED_DELAY_TIME);

  28.                                 LED_1 = 0;

  29.                                 s_chStep = 2;
  30.                         }
  31.                        
  32.                         break;

  33.                 case 2:
  34.                         /* LED2 亮 */
  35.                         if (zl_poll_delay_timeout(0)) {
  36.                                 zl_poll_delay_set(0, LED_DELAY_TIME);

  37.                                 LED_2 = 0;

  38.                                 s_chStep = 0;
  39.                         }
  40.                         break;

  41.                 default:
  42.                         break;
  43.         }
  44. }
复制代码


在每个case里设置的延时,是为下个case服务的。


出0入8汤圆

 楼主| 发表于 2017-8-22 09:32:06 | 显示全部楼层
我去,我这个代码的缩进也不对,居然变长了。。。

出0入0汤圆

发表于 2017-8-22 10:05:00 | 显示全部楼层
@楼主: 假如有大量的定时要处理,中断处理会消耗不少时间,会降低系统实时性。
建议设计成一个查询函数,可以被调用,系统时钟可以查询定时器得到,这样可以不用中断函数了。

出0入8汤圆

 楼主| 发表于 2017-8-22 14:01:01 | 显示全部楼层
gtnr 发表于 2017-8-22 10:05
@楼主: 假如有大量的定时要处理,中断处理会消耗不少时间,会降低系统实时性。
建议设计成一个查询函数, ...

你说的对,量大消耗的时间也多

就是设计查询函数,我不太明白,是基于心跳计数查询吗

18楼的方法我觉得也不错。

出0入0汤圆

发表于 2017-8-22 15:12:08 | 显示全部楼层
本帖最后由 jiangyimfs1 于 2017-8-22 16:02 编辑
Jmhh247 发表于 2017-8-22 09:08
呃,大哥,你得告诉我出了啥问题吧,光贴代码不知道你想表达啥问题。。。另,你的代码缩进好难受


对的,代码就是实现这样的效果了,代码我直接复制黏贴了,没注意看显示的效果 了,不好意思,看了一下楼主的代码,是我自己理解错误了,按楼主的代码试了一下,效果很好,非常感谢了。。。


再问一下楼主, 我case0 延时3s,case1 延时2s,case2 延时1s,是下面这么写吗,现象是LED1,LED2同时亮了,我是不是又哪里用错了



#define DELAY_ID0           0
#define DELAY_TIME0         1000

#define DELAY_ID1           1
#define DELAY_TIME1         2000

#define DELAY_ID2           2
#define DELAY_TIME2         3000

/*   L E D _ D E M O _ T A S K   */
/*-------------------------------------------------------------------------
    *功能:延时器测试闪灯,在超级循环中运行。
    *参数:无
    *返回:无
    *备注:未测试。
-------------------------------------------------------------------------*/
void led_demo_task(void)
{
        static uint8_t s_chStep = 0;


        switch (s_chStep)
        {
                case 0:
                        /* 全灭 */
                        /* 第一次用直接就是超时状态,因为还未设置超时时间 */
                        if (zl_poll_delay_timeout(DELAY_ID2)) {
                                zl_poll_delay_set(DELAY_ID2, DELAY_TIME2);  //延时3s

                                LED1 = 1;
                                LED2 = 1;

                                s_chStep = 1;
                        }

                        break;

                case 1:
                        /* LED1 亮 */
                        if (zl_poll_delay_timeout(DELAY_ID1)) {
                                zl_poll_delay_set(DELAY_ID1,DELAY_TIME1);   //延时2s

                                LED1 = 0;

                                s_chStep = 2;
                        }
                        
                        break;

                case 2:
                        /* LED2 亮 */
                        if (zl_poll_delay_timeout(DELAY_ID0)) {
                                zl_poll_delay_set(DELAY_ID0, DELAY_TIME0);  //1s

                                LED2 = 0;

                                s_chStep = 0;
                        }
                        break;

                default:
                        break;
        }
}

出0入8汤圆

 楼主| 发表于 2018-5-4 11:59:04 | 显示全部楼层
本帖最后由 Jmhh247 于 2018-5-4 12:02 编辑
jiangyimfs1 发表于 2017-8-22 15:12
对的,代码就是实现这样的效果了,代码我直接复制黏贴了,没注意看显示的效果 了,不好意思,看了一下楼 ...


为什么更新这个问题我没看到?


过了这么久,还是说说吧

像你这种延时需求,只用一个延时器就行,所以,
你把每个CASE 里的延时器ID都改成统一的,比如DELAY_ID0 ,应该就是你要的效果了!


编辑原因,增加这句——(我在27楼的回复你,就是用的一个延时器,仔细看下)

出0入8汤圆

发表于 2018-5-4 14:21:09 | 显示全部楼层
有一本书,叫《时间触发嵌入式系统设计模式》

出0入0汤圆

发表于 2018-6-15 14:01:40 | 显示全部楼层
谢谢分享,又学习了

出0入85汤圆

发表于 2018-6-15 14:23:08 | 显示全部楼层
挺好,处理AT指令的时候可以用~

出0入0汤圆

发表于 2018-6-21 08:23:35 | 显示全部楼层
早都这么用了,不过没有楼主的代码规范,赞楼主一个

出0入14汤圆

发表于 2018-9-25 15:01:13 | 显示全部楼层
谢谢分享,又学习了

出0入0汤圆

发表于 2018-10-22 17:13:02 | 显示全部楼层
思路很清晰,借鉴一下。

出0入10汤圆

发表于 2018-10-22 18:05:39 | 显示全部楼层
学习一下。。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-7-24 04:19

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

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