OpenEdv-开源电子网

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

软件定期器谈论--欢迎大家拍砖

[复制链接]

10

主题

271

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1236
金钱
1236
注册时间
2015-5-14
在线时间
352 小时
发表于 2015-10-19 14:16:26 | 显示全部楼层 |阅读模式
下面是一个自己写的简易的软件定时器,欢迎大家拍砖,一起来谈论。

#ifndef __SOFTWARE_TIMER__
#define __SOFTWARE_TIMER__

//头文件
#include <p18cxxx.h>
#include <string.h>


#include "../heard/include.h"



//最大定时器个数
#define SOFTWARE_TIMER_MAX_TASKS 3


//软件定时器数组
typedef struct _SoftwareTimer_struct{

//用户层
void (*callback)(void); //回调函数指针

_UWORD delay_time; //延时时间,多少个心跳周期

//内部实现层
BOOL RunFlag; //任务运行标志

}SoftwareTimer_struct;




//软件定时器初始化函数
void SoftwareTimerInit(void);

//放到心跳定时中断函数中
void SoftwareTimerUpdate(void);

//放到main主循环中
void SoftwareTimerUserScheduling(void);



//用户函数
BOOL SoftwareTimerUserAddTask(void (*callback)(),const _UWORD DELAY);
BOOL SoftwareTimerUserDelTask(void (*callback)());
BOOL SoftwareTimerUserHangTask(void (*callback)());
BOOL SoftwareTimerUserContiueTask(void (*callback)());


#endif



#include "../heard/software_timer.h"




static SoftwareTimer_struct SoftwareTimerData[SOFTWARE_TIMER_MAX_TASKS];
#define SoftwareTimerDataLong sizeof(SoftwareTimerData)


//软件定时器初始化函数
void SoftwareTimerUserInit(void)
{
memset(SoftwareTimerData,0,SoftwareTimerDataLong);
}

//软件定时器更新函数
void SoftwareTimerUpdate(void)
{
_UBYTE Index;

for(Index=0;Index<SOFTWARE_TIMER_MAX_TASKS;Index++)
{
if((SoftwareTimerData[Index].RunFlag) && (SoftwareTimerData[Index].delay_time))
{
SoftwareTimerData[Index].delay_time--;
}
}
}

//软件定时器执行函数
void SoftwareTimerUserScheduling(void)
{
_UBYTE Index;

for(Index=0;Index<SOFTWARE_TIMER_MAX_TASKS;Index++)
{
if((SoftwareTimerData[Index].RunFlag) && (!SoftwareTimerData[Index].delay_time))
{
if(SoftwareTimerData[Index].callback)
SoftwareTimerData[Index].callback();

SoftwareTimerData[Index].RunFlag=0;
SoftwareTimerData[Index].callback=0;
}
}
}

//软件定时器添加函数
BOOL SoftwareTimerUserAddTask(void (*callback)(),const _UWORD DELAY)
{
_UBYTE Index;

for(Index=0;Index<SOFTWARE_TIMER_MAX_TASKS;Index++)
{
if(!SoftwareTimerData[Index].callback)
{
SoftwareTimerData[Index].callback =callback;
SoftwareTimerData[Index].delay_time =DELAY;
SoftwareTimerData[Index].RunFlag =1;
return TRUE;
}
}
return FALSE;
}


//软件定时器删除函数
BOOL SoftwareTimerUserDelTask(void (*callback)())
{
_UBYTE Index;

for(Index=0;Index<SOFTWARE_TIMER_MAX_TASKS;Index++)
{
if(SoftwareTimerData[Index].callback==callback)
{
SoftwareTimerData[Index].RunFlag =0;
SoftwareTimerData[Index].callback =0;
SoftwareTimerData[Index].delay_time =0;
return TRUE;
}
}
return FALSE;
}

//软件定期挂起函数
BOOL SoftwareTimerUserHangTask(void (*callback)())
{
_UBYTE Index;

for(Index=0;Index<SOFTWARE_TIMER_MAX_TASKS;Index++)
{
if(SoftwareTimerData[Index].callback==callback)
{
SoftwareTimerData[Index].RunFlag =0;
return TRUE;
}
}
return FALSE;
}

//软件定期继续运行函数
BOOL SoftwareTimerUserContiueTask(void (*callback)())
{
_UBYTE Index;

for(Index=0;Index<SOFTWARE_TIMER_MAX_TASKS;Index++)
{
if(SoftwareTimerData[Index].callback==callback)
{
SoftwareTimerData[Index].RunFlag =1;
return TRUE;
}
}
return FALSE;
}



30年众生牛马,60年诸佛龙象!
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

9

主题

538

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3371
金钱
3371
注册时间
2015-1-7
在线时间
794 小时
发表于 2015-10-19 16:06:17 | 显示全部楼层
赞一个!
可以考虑用个链表是代替软件定时器数组,这样定时器数量可以动态调整;
请问这个void SoftwareTimerUpdate(void)函数是不是放到硬件定时器中断的处理中做回调,比如1ms定时器中断;
是否可以增加一个循环计时,很多定时任务是周期重触发的,时间到了以后执行一次callback后,重新计时,这样就不用重新添加任务了;
callback可否增加个参数?

我以前写过一个软件定时器模块,里面还有点小bug,也欢迎一起讨论
http://blog.chinaunix.net/uid-29151369-id-4855972.html
机器生汇编,汇编生B,B生C,C生万物.... 经过长期对C语言的研究,目前只有两个方面不懂:这也不懂,那也不懂
https://github.com/ianhom
回复 支持 反对

使用道具 举报

10

主题

271

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1236
金钱
1236
注册时间
2015-5-14
在线时间
352 小时
 楼主| 发表于 2015-10-19 16:16:41 | 显示全部楼层
回复【2楼】ianhom:
---------------------------------
 我刚开始想过链表,但是没有想好怎么维护这个链表?不知道您有没有好的历程??我刚开始想到了循环延时,但是想了想,这个功能我已经放到了协作式调度器中了,为了减小RAM开销,就把这个功能舍去了!
30年众生牛马,60年诸佛龙象!
回复 支持 反对

使用道具 举报

10

主题

271

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1236
金钱
1236
注册时间
2015-5-14
在线时间
352 小时
 楼主| 发表于 2015-10-19 16:20:57 | 显示全部楼层
回复【2楼】ianhom:
---------------------------------
SoftwareTimerUpdate(void)这个函数要放到一个硬件定时器中断中的,一般都会有一个用硬件定时器实现的心跳功能,放到这个里面就行。
30年众生牛马,60年诸佛龙象!
回复 支持 反对

使用道具 举报

9

主题

538

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3371
金钱
3371
注册时间
2015-1-7
在线时间
794 小时
发表于 2015-10-19 16:38:07 | 显示全部楼层
回复【3楼】无痕幽雨:
---------------------------------
用链表是有ram开销,你的方法更好一点,RAM消耗少。
不过在一种情况下也可能数组更耗RAM,就是在同时有很多软件定时器的情况下,而且运行完以后就不会再用,这样的话这个数组所占的RAM就得不到释放,这种情况下用链表可能会好一点,或用动态数组来实现。

一般来讲,单片机开发项目里你的方法更实用一点
机器生汇编,汇编生B,B生C,C生万物.... 经过长期对C语言的研究,目前只有两个方面不懂:这也不懂,那也不懂
https://github.com/ianhom
回复 支持 反对

使用道具 举报

10

主题

271

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1236
金钱
1236
注册时间
2015-5-14
在线时间
352 小时
 楼主| 发表于 2015-10-19 16:45:44 | 显示全部楼层
回复【5楼】ianhom:
---------------------------------
对,如果就用一次,以后就不用了,动态申请最理想,不过这种情况很少。我正在看您的代码,回头再写一版用链表实现的。嘿嘿,多多交流啊!
30年众生牛马,60年诸佛龙象!
回复 支持 反对

使用道具 举报

10

主题

271

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1236
金钱
1236
注册时间
2015-5-14
在线时间
352 小时
 楼主| 发表于 2015-10-19 16:48:03 | 显示全部楼层
回复【5楼】ianhom:
---------------------------------
可能是我做的项目比较简单,一般情况下,有2个软件定时器,足够用了,为了减少RAM开销,一直用的上面的数组方法。而且这些定时器是根据条件,频繁起的。
30年众生牛马,60年诸佛龙象!
回复 支持 反对

使用道具 举报

9

主题

538

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3371
金钱
3371
注册时间
2015-1-7
在线时间
794 小时
发表于 2015-10-19 16:53:12 | 显示全部楼层
回复【6楼】无痕幽雨:
---------------------------------
恩,相互学习,我那个代码里还有几个bug,希望不要误导你。
机器生汇编,汇编生B,B生C,C生万物.... 经过长期对C语言的研究,目前只有两个方面不懂:这也不懂,那也不懂
https://github.com/ianhom
回复 支持 反对

使用道具 举报

9

主题

538

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3371
金钱
3371
注册时间
2015-1-7
在线时间
794 小时
发表于 2015-10-19 17:03:58 | 显示全部楼层
回复【7楼】无痕幽雨:
---------------------------------
之前和同事探讨过这种结构的软件定时器,有种观点是定时器统一管理有个小小的缺点,就是上层还需要care底层任务的计时,而且所有的任务的计时都在一起处理,一旦上层操作错误或其他任务误操作会破坏其他任务的工作,这个问题在项目中遇到过,任务a误操作了任务b的定时器,功能相互影响排查的时候很麻烦,后来我们就把定时工作交给每个任务自己处理,这样每个任务维护自己的定时器,其他任务无法修改这个变量,出错也就错一个。上述问题在多人配合开发多个软件模块的时候经常会遇到,尤其是定时器分配问题,编写上层的人必须知道用了多少定时器,而往往每个软件模块使用数量又不确定
机器生汇编,汇编生B,B生C,C生万物.... 经过长期对C语言的研究,目前只有两个方面不懂:这也不懂,那也不懂
https://github.com/ianhom
回复 支持 反对

使用道具 举报

10

主题

271

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1236
金钱
1236
注册时间
2015-5-14
在线时间
352 小时
 楼主| 发表于 2015-10-19 17:18:01 | 显示全部楼层
回复【9楼】ianhom:
---------------------------------
我明白你要表达的什么意思了,你说的是类似时间片轮训吧,每个任务都有自己的时间片。
30年众生牛马,60年诸佛龙象!
回复 支持 反对

使用道具 举报

9

主题

538

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3371
金钱
3371
注册时间
2015-1-7
在线时间
794 小时
发表于 2015-10-19 17:27:33 | 显示全部楼层
回复【10楼】无痕幽雨:
---------------------------------
不算时间片轮询,
就是和你的方式差不多,比如有三个任务,你就会有长度为3个结构体长度的数组,而我会把每个结构体都static定义在各自的任务中而已,这样每个任务都看不到其他人的flag和delay time,也就不会被其他任务误修改。
其实就是比较原始的时间处理方法,while(1)里轮每个任务,每个任务被轮的时候,自己处理时间任务,只需要维护自己flag和delay time就好,更省RAM,任务自己发现时间到了,就做相应的操作。这样做模块化开发更安全、更省事点。缺点是每个任务都要给轮询的机会,不然任务没法维护自己的时间。我这种方式不适合上os。
机器生汇编,汇编生B,B生C,C生万物.... 经过长期对C语言的研究,目前只有两个方面不懂:这也不懂,那也不懂
https://github.com/ianhom
回复 支持 反对

使用道具 举报

13

主题

225

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
289
金钱
289
注册时间
2013-11-12
在线时间
29 小时
发表于 2016-1-12 13:52:30 | 显示全部楼层
ianhom 发表于 2015-10-19 16:06
赞一个!
可以考虑用个链表是代替软件定时器数组,这样定时器数量可以动态调整;
请问这个void&nbsp;Softwa ...

很佩服你写代码的习惯
回复 支持 反对

使用道具 举报

9

主题

538

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3371
金钱
3371
注册时间
2015-1-7
在线时间
794 小时
发表于 2016-1-13 10:17:19 | 显示全部楼层
jiushibuzhidao 发表于 2016-1-12 13:52
很佩服你写代码的习惯

我的编程习惯还有待提高
机器生汇编,汇编生B,B生C,C生万物.... 经过长期对C语言的研究,目前只有两个方面不懂:这也不懂,那也不懂
https://github.com/ianhom
回复 支持 反对

使用道具 举报

10

主题

271

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1236
金钱
1236
注册时间
2015-5-14
在线时间
352 小时
 楼主| 发表于 2018-2-28 19:38:57 来自手机 | 显示全部楼层
ianhom 发表于 2015-10-19 17:27
回复【10楼】无痕幽雨:
---------------------------------
不算时间片轮询,
就是和你的方式差不多,比如 ...

多年以后再回头看帖子,感觉自己写的代码真是一个demo。我感觉把它改为register形式就可以了,两个有点都有了
回复 支持 反对

使用道具 举报

10

主题

271

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1236
金钱
1236
注册时间
2015-5-14
在线时间
352 小时
 楼主| 发表于 2018-2-28 21:16:59 来自手机 | 显示全部楼层
demo意思是中看不中用,大家不要误会啊!
回复 支持 反对

使用道具 举报

33

主题

982

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
7864
金钱
7864
注册时间
2014-8-13
在线时间
1584 小时
发表于 2018-2-28 22:49:47 | 显示全部楼层
我写过一个关于STM32F407ZET6的基于硬件的定时器,分享一个强大的定时器吧。使用灵活
算是比较好用的了,但是跟LZ这个实现不太一样。


只是受限于硬件资源,定时器使用太多的时候会申请不到硬件定时器资源(所有的定时器已经用完。但是其实还是可以添加定时任务的,比如同一高频定时器管理几个频率比较低的任务,有些类似通讯领域里的时分复用和频分复用)。
回复 支持 反对

使用道具 举报

10

主题

271

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1236
金钱
1236
注册时间
2015-5-14
在线时间
352 小时
 楼主| 发表于 2018-3-1 07:47:42 来自手机 | 显示全部楼层
mack13013 发表于 2018-2-28 22:49
我写过一个关于STM32F407ZET6的基于硬件的定时器,分享一个强大的定时器吧。使用灵活
算是比较好用的了, ...

不管是硬件定时器还是软件定时器,其效果是一致的,可以类比进程和线程。但是其设计出发点是不同的,因此应用目的也是不同的。我个人感觉硬件定时器更应该像进程,软件定时器更应该像线程。这里我给的demo是数组,仅供初学者学习入门。项目中应该用list,然后资源隔离的话,用各自的static struct,然后register进去。如果不需要隔离,完全可以用heep,交给”模板”处理,用户接口都感觉不到malloc。
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2024-11-25 23:19

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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