打印
[技术讨论]

雕虫小技(二) --- 基于软件定时器的简单应用

[复制链接]
980|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
红蛋大叔|  楼主 | 2018-6-18 09:47 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 红蛋大叔 于 2018-6-18 09:48 编辑

上次贴出了软件定时器的源代码,这次基于这个源代码做一些简单的应用。
一:固定周期运行 ,以持续闪烁的LED为例

app_clk_t led_handle;

void  led_example(void )
{
  //LED取反
}

main()
{
    app_construct_clk(&led_handle, led_example,100,200,TRUE);//100ms后运行led_example ,之后以200ms间隔持续运行led_example函数。

  while(1)
  {
      if(clk_1ms)
      {
         clk_1ms = 0;
         app_clk_scheduler();
      }  //1ms时钟调度,下面的例子这一部分将省略。
  }
}

二:先注册,后运行,以开关为例

app_clk_t key_handle;
uint8_t key_status;

//外部中断中调用的一个回调
void key_callback(void )
{
    if(KEY_PIN)
   {
      key_status = 0x01;  //松开
   }
   else
   {
     key_status = 0x00; //按下
   }
   
   app_clk_start(&key_handle);  //有去抖作用
}

void key_detect(void )
{
    read_key = key_status ;
    //处理键值
}

main()
{
    app_construct_clk(&key_handle, key_detect,10,0,FALSE); //将key_detect注册到软件定时器中,但是不立刻运行,等待后面被app_clk_start启动,启动后10ms开始执行key_detect函数
}

三:注册后运行一次,以第一个例子中的led控制为例

main()
{
    app_construct_clk(&led_handle, led_example,10, 0, TRUE) ;
}
关于这个功能还有一个应用,那就是有时候为了初始化一些状态,但是状态初始化后不一定成功,此时,需要再次初始化,例如:

app_clk_t  init_handle;
void fun1(void)
{
    if(初始化某状态成功)
    {
       //切换到别的功能
    }
    else
    {
        app_clk_start(&init_handle);
    }//如果初始化失败,重复执行
}

main()
{
    app_construct_clk(&init_handle, fun1,100, 0, TRUE) ;//注册完成后100ms,运行fun1。
}

四:函数运行指定次数
为了简化软件定时器设计,这个功能由使用者自己封装,一个例子,要让led_example()运行指定次数后从软件定时器中删除。

uint8_t led_ctr_run_count;

//对外调用接口
void app_run_led_example_task(uint8_t count)
{
   led_ctr_run_count = count;
   app_clk_start(&led_handle);
}

void led_example()
{
   //你要做的事情
  //控制这个任务的运行时间
   if(led_ctr_run_count )
   {
       led_ctr_run_count --;
   }
   else
   {
       app_clk_stop(&led_handle);
   }
}

main()
{
   app_construct_clk(&led_handle, led_example,100, 100, TRUE) ;
}

五:同步任务
同步任务在软件设计时是必不可少的,这个软件定时器也能够比较好的处理这种同步任务,一个简单例子是 A->B的同步任务,比如将射频芯片切换为接收状态A,完成A的切换后A不再运行,紧接着启动检测射频数据B任务,如下代码描述了这个过程。
app_clk_t  a_handle;
app_clk_t  b_handle;

void fun_A(void )
{
   //将射频模块切换为RX状态
   if(如果切换成功)
   {
         app_clk_start(&b_handle);    //A顺利完成后,启动B函数
   }
   else
   {
      app_clk_start(&a_handle);//失败后再次将模块转为接收状态
   }


}

void fun_B(void )
{
   //检测模块是否受到数据
}

main()
{
   app_construct_clk(&a_handle, fun_A,10, 0, FALSE) ;//fun_A是单次任务,需要app_clk_start启动
   app_construct_clk(&b_handle, fun_B,10, 10, FALSE) ;//fun_B是重复任务,不过也需要app_clk_start启动后才能运行
}

对于同步任务,要注意一个问题,比如,射频芯片发射数据后(A),将模块切换为接收状态(B),切换成功后,将处于检测接收数据状态(C),这个过程是一个串行过程,如果在执行A->B->C的过程中,有任务又要发送数据,必须要使状态回到发射的初始状态(A),同时删除掉B,C(如果已经在软件定时器中的话),确保启动过程遵循A->B->C的顺序,避免在启动A的时候,B或者C也同时在运行,如下例子:

void send_tx_data(uint8_t *p_dt,uint8_t len)
{
   memcpy(radio_tx_fifo, p_dt, len);


   app_clk_start(&A_handle);
   app_clk_stop(&B_handle);
   app_clk_stop(&C_handle);
}

六:做为一个普通的公共软件定时器,比如注册一个10ms的软件定时器供一些函数使用,
这个在SDK中比较常见。

app_clk_t sf_clock_handle

void software_clock(void )
{
}

main()
{
  app_construct_clk(&sf_clock_handle, software_clock, 10, 10, TRUE) ;
}

以上介绍了基于之前发布的软件定时器的使用方法,希望也能对你有所启发。

再次附上软件定时器的源代码,这次的修正了上次的bug:
app_clk_v1.2.zip (1.83 KB)




相关帖子

沙发
红蛋大叔|  楼主 | 2018-6-18 09:47 | 只看该作者

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

25

主题

69

帖子

3

粉丝