本帖最后由 红蛋大叔 于 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)
|