单片机定时器之改良版:时间轮定时器

发布者:CuriousTraveler最新更新时间:2016-12-29 来源: eefocus关键字:单片机  定时器  时间轮定时器 手机看文章 扫描二维码
随时随地手机看文章

前段时间把自己以前用的单片机定时器整理出来,我称之为简单定时器,这种简单定时器比较适合定时器使用量少的程序中,如果定时器数量要求多,精度要求高,效率就会有问题,为此,俺就实现了一个时间轮定时器,简单测试下来效果非常不错。

 1 #ifndef __SOFT_TIMER_H__

 2 #define __SOFT_TIMER_H__

 3 

 4 #define EVENT_TYPE_ONESHOT 0

 5 #define EVENT_TYPE_PERIODIC 1

 6 

 7 #define TMR_POOL_SIZE 20  // 定时器池,即可用定时器个数

 8 #define TMR_WHEEL_SIZE 8  // 时间轮的粒度

 9 

10 #define HANDLE int

11 

12 typedef void (*pTimerProc)(void*);

13 

14 void TimerInit(void);

15 HANDLE SetTimer(unsigned long uElapse,pTimerProc pFunc,void *para,unsigned int Tmr_type);

16 void KillTimer(HANDLE hTmr);

17 void TimerServer(void);     // call in main loop

18 void TimerSignal(void);     // call it in timer isr

19 unsigned long TmrGetTime(void);

20 

21 #endif 

简单介绍一下:

SetTimer():   
参数uElapse:定时器超时时间. 参数pFunc:定时器超时回调函数. 参数para:定时器超时回调函数参数.参数Tmr_type:定时器类型,EVENT_TYPE_ONESHOT为单次定时器,定时器超时后,会被自动删除.EVENT_TYPE_PERIODIC 表示周期性定时器,使用完后需主动删除。
返回值:返回定时器id,用于删除定时器。

KillTimer(): 删除由SetTimer()创建的定时器。
TimerServer(): 定时器管理函数,需在主循环中调用。
TimerSignal(): 定时器信号函数,提供定时器运行所需节拍数,需在硬件定时器中断中调用,例如,硬件定时器10ms中断一次,在中断中调用TimerSignal(),则时间轮定时器的节拍时间为10ms.
TmrGetTime():记录定时器的节拍数

  1 #include "timer.h"

  2 

  3 typedef struct _tagTimer{

  4     unsigned int elapse;

  5     unsigned int interval;

  6     void *prev;

  7     void *next;

  8     TimerProc pFunc;

  9     void *para;

 10     unsigned char state;

 11     unsigned char event_type;

 12     unsigned char timeout;

 13 }Timer_Typedef;

 14 

 15 typedef struct _tagTimerWheel{

 16     Timer_Typedef *pFirst;

 17     unsigned int entries;

 18 }TimerWheel_Typedef;

 19 

 20 #define TMR_STATE_FREE 0

 21 #define TMR_STATE_STOP 1

 22 #define TMR_STATE_RUNNING 3

 23 

 24 static Timer_Typedef _timerArray[TMR_POOL_SIZE]={0};

 25 static TimerWheel_Typedef TmrWheel[TMR_WHEEL_SIZE]={0};

 26 static Timer_Typedef* tmr_free_list;

 27 static unsigned tmr_free_slot = 0;

 28 static unsigned _tmr_tick = 0;

 29 

 30 

 31 static Timer_Typedef* Tmr_alloc(void);

 32 static void Tmr_free(Timer_Typedef* pTmr);

 33 static void Tmr_link(Timer_Typedef* pTmr);

 34 static void Tmr_unlink(Timer_Typedef* pTmr);

 35 

 36  

 37 void TimerInit(void)

 38 {

 39     int i = 0;

 40     for(i=0;i

 41     {

 42        _timerArray[i].next = (void*)(&_timerArray[i+1]);

 43     }

 44     _timerArray[TMR_POOL_SIZE-1].next = (void*)0;

 45     tmr_free_list = _timerArray;

 46     tmr_free_slot = TMR_POOL_SIZE;

 47     

 48     for(i=0;i

 49     {

 50        TmrWheel[i].pFirst = (void*)0;

 51        TmrWheel[i].entries = 0;

 52     }

 53 }

 54 

 55 HANDLE SetTimer(unsigned long uElapse,TimerProc pFunc,void *para,unsigned int Tmr_type)

 56 {

 57     int unused_slot = -1;

 58     Timer_Typedef *pTmr = (Timer_Typedef *)0;

 59     

 60     pTmr = Tmr_alloc();

 61     if(pTmr) unused_slot = pTmr - _timerArray;

 62 

 63     if(unused_slot !=  -1)

 64     {

 65         _timerArray[unused_slot].pFunc = pFunc;

 66         _timerArray[unused_slot].para = para;

 67         _timerArray[unused_slot].interval = uElapse;

 68         _timerArray[unused_slot].event_type = Tmr_type;

 69         _timerArray[unused_slot].state = 1;

 70         Tmr_link(pTmr);

 71     }

 72     return unused_slot;

 73 }

 74 

 75 void KillTimer(HANDLE hTmr)

 76 {

 77     if((hTmr >= 0)&&(hTmr < TMR_POOL_SIZE))

 78     {

 79         switch(_timerArray[hTmr].state)

 80         {

 81             case TMR_STATE_STOP:

 82                     Tmr_free(&_timerArray[hTmr]);

 83                 break;

 84             case TMR_STATE_RUNNING:

 85                     Tmr_unlink(&_timerArray[hTmr]);

 86                     Tmr_free(&_timerArray[hTmr]);

 87                 break;

 88             default:

 89                 break;

 90         }

 91         _timerArray[hTmr].timeout = 0;

 92     }

 93 }

 94 

 95 void TimerServer(void)

 96 {

 97     int i = 0;

 98     Timer_Typedef* pTmr = _timerArray;

 99     for(i = 0;i

100     {

101         if((pTmr->timeout)&&(pTmr->pFunc))

102         {

103             (*(pTmr->pFunc))(pTmr->para);

104             pTmr->timeout = 0;

105         }

106         pTmr++;

107     }

108 }

109 

110 

111 void TimerSignal(void)

112 {

113     int spoke = 0;

114     Timer_Typedef* pTmr,*pNext;

115     

116     ++_tmr_tick;

117     spoke = _tmr_tick%TMR_WHEEL_SIZE;

118     pTmr = TmrWheel[spoke].pFirst;

119     while(pTmr)

120     {

121        pNext = pTmr->next;

122        if(pTmr->elapse == _tmr_tick)

123        {

124            Tmr_unlink(pTmr);

125            if(pTmr->event_type == EVENT_TYPE_PERIODIC)

126            { 

127                 Tmr_link(pTmr);

128            }

129            else

130            {

131                 Tmr_free(pTmr);

132            }

133            pTmr->timeout = 1;

134         }

135         pTmr = pNext;

136     }

137 }

138 

139 static void Tmr_link(Timer_Typedef* pTmr)

140 {

141    int spoke;

142    TimerWheel_Typedef *pWhl;

143    pTmr->state =  TMR_STATE_RUNNING;

144    pTmr->elapse = pTmr->interval + _tmr_tick;

145    spoke = pTmr->elapse%TMR_WHEEL_SIZE;

146    pWhl = &TmrWheel[spoke];

147    

148    if(pWhl->pFirst)  pWhl->pFirst->prev = pTmr;

149    

150    pTmr->next = pWhl->pFirst;

151    pWhl->pFirst = pTmr;

152    pWhl->entries++;

153 }

154 

155 static void Tmr_unlink(Timer_Typedef* pTmr)

156 {

157    int spoke;

158    TimerWheel_Typedef *pWhl;

159    pTmr->state =  TMR_STATE_STOP;

160    spoke = pTmr->elapse%TMR_WHEEL_SIZE;

161    pWhl = &TmrWheel[spoke];

162    

163    if(pWhl->pFirst == pTmr) 

164    {

165         pWhl->pFirst = pTmr->next;

166         if(pTmr->next) ((Timer_Typedef*)pTmr->next)->prev = (void*)0;

167    }

168    else

169    {

170         ((Timer_Typedef*)pTmr->prev)->next = pTmr->next;

171         if(pTmr->next) ((Timer_Typedef*)pTmr->next)->prev = pTmr->prev;

172    }

173    pWhl->entries--;

174 }

175 

176 

177 static Timer_Typedef* Tmr_alloc(void)

178 {

179     Timer_Typedef *pTmr = (Timer_Typedef*)0;

180     if(tmr_free_list)

181     {

182        pTmr = tmr_free_list;

183        tmr_free_list =  tmr_free_list->next;

184        tmr_free_slot--;

185     }

186     return pTmr;

187 }

188 

189 

190 

191 static void Tmr_free(Timer_Typedef* pTmr)

192 {

193    pTmr->state = TMR_STATE_FREE;

194    pTmr->prev = (Timer_Typedef*)0;

195    pTmr->next = tmr_free_list;

196    tmr_free_list = pTmr;

197    tmr_free_slot++;

198 }

199 

200 unsigned long TmrGetTime(void)

201 {

202     return _tmr_tick;

203 }








关键字:单片机  定时器  时间轮定时器 引用地址:单片机定时器之改良版:时间轮定时器

上一篇:单片机中的ms级软定时器
下一篇:CRC16-循环冗余校验

推荐阅读最新更新时间:2024-03-16 15:27

单片机c语言中菜单系统源码分析
最近在学习单片机的菜单系统时,发现有这么一些代码,定义了4个按键,确认键,返回键,上键,下键,先贴出来在vc里边建的,先定义一个结构体KbdTabStruct,在用结构体定义一个const型的数组KBD ,那么数组的每一个成员对应的原本结构体的数则是它的初始化值,并且这个值初始化后就成立,以后不再改变。比如说KBD .KeyCurrentIndex所对应的则是数组table中成员0 的值,这些值就是它的初始化值,相当于KBD .KeyCurrentIndex=0,但如果这样写N层的菜单,如此定义肯定麻烦,所以用这样的数组实现。 int main() { typedef struct { u8 KeyCurrentIndex;//
[单片机]
<font color='red'>单片机</font>c语言中菜单系统源码分析
51单片机,汇编语言,定时与计数
要求:将定时器 T1 设置为外部事件计数器,要求每计 500 个脉冲,再将 T1 转为定时方式,在 P1.2 输出一个脉宽 10ms 的正脉冲。 周而复始。 设系统时钟频率为 12MHz。 程序如下: ORG 0000H ;----------------------------------- START: CLR P1.2 CLR TR1 MOV TMOD, #50H ;T1计数方式1 MOV TH1, #(65536 - 500) / 256 ;计数值为500 MOV TL1, #(65536 - 500) MOD 256 SETB TR1 JNB TF1,
[单片机]
影响PIC单片机功耗主要有以下几个因素
一直在做 pic 单片机功耗问题。由于项目使用电池供电,所以功耗问题显得非常重要。根据数据手册以及网络上的资料,影响单片机功耗主要由以下几个因素: 1:所有 I/O 引脚保持为高阻输入高点平或低电平 2:关闭比较器和 CVref(可编程偏上参考电压)、WTD、T1OSC、BOR(欠压复位)等 3:PORTB 片内弱上拉 4:所有不用的模块全部关闭,在用到时再打开 5:MCLR 引脚必须处于逻辑高电平 PIC 单片机在执行 SLEEP 指令后进入睡眠省电模式。进入 SLEEP 模式后,主振荡停止,如果看门狗在烧写时打开了,看门狗定时器将被清并保持运行。I/O 口,周边模块和内部 RAM 将保持原来状态,所以如果要求睡眠后有很
[单片机]
PIC16C64单片机所具有的外部功能特点
一、捕抓/比较/脉宽 调制 模块   P IC I6C64 单片机 的RC2/C CPI脚具有捕抓/比较/ PWM 输出的功能,对应于内部的捕抓/比较/PWM模块,简称 CC PI模块。该模块内有一16位寄存器。(CCPR1)可由软件设置而作为捕抓寄存器,比较寄存器或PWM输出寄存器。由图工中的CCP1控制寄存器(CCP1CON)来选择模式。   (一)捕抓功能   RC2/CCP 1脚作为捕抓功能时,应置为输入态。当有脉冲事件在CCP1脚上发生时,CCPR1即捕抓记录下此时TMR1(计数器1)的值,井产生捕抓发生中断请求.   例程1. BSF TRISC,2 ;CCP1脚置为输入   MOVLW,XXXX0101;选
[单片机]
PIC16C64<font color='red'>单片机</font>所具有的外部功能特点
MCU多元再进化 强化运算及各种介面延伸字号
微控制器(MCU)近年在智慧系统、物联网需求提高,成为电子产业中,再次翻红的产品,怎么说翻红。过去的MCU功能较简单,已大量应用在传统电子产品如冰箱、电视等家电到自动化产品等,如今在网路影响及数位资讯云端化,传统应用方向不再单一,还多了分享,因此MCU随之进化,强化运算及各种介面的延伸,打造出符合市场需求的产品,让MCU需求不断提高。 意法半导体大中华暨南亚区产品行销经理杨正廉说,MCU市场受M2M(MachinetoMachine)加持,近年出货表现确实不俗,但对整体MCU市场,则是一场厂商生存战的开始,主因推出低阶MCU的业者,将面临技术提升及价格竞争,反观谁拥有技术及整体多元的产品支援才符合市场期待。以意法半导体为
[单片机]
基于MSP430F149型FLASH单片机实现微波辐射成像系统的设计
引言 ----在无源微波遥感中,微波辐射计是一种获取场景微波特征的重要手段。微波辐射计通常是一部超外差接收机,通过接收被测场景在一定频带内的电磁辐射,转换为输出的低频信号,来表征被测场景的地物信息。利用微波辐射计来探测、接收被测目标、背景在微波波段的电磁辐射,并把接收到的辐射信号按比例用伪彩色图像直观地显现出来的系统称为微波辐射成像系统。 ----微波辐射成像系统要求在恶劣的环境和天气下长期稳定地进行天线扫描成像,所以要求系统设备用于天线扫描控制及数据采集的电路尽量简单、稳定。基于以上的要求,采用了TI公司所生产的MSP430F149型超低功耗FLASH单片机作为这套系统的从机部分,该单片机有60KB的FLASH存储器和2KB
[单片机]
基于MSP430F149型FLASH<font color='red'>单片机</font>实现微波辐射成像系统的设计
单片机玩PID控制—从理想PID控制至先进PID控制_4
2.2 基于VB6的通信程序 通信程序分成两部分,一部分是与单片机串口通信,另一部分是与WINCC OPC数据交换。用VB6进行通信编程,需要添加串口通信MSComm控件,如图1所示,为了在VB6中开发OPC应用程序,需要一个OPC包装DLL:OPC Automation2.0,并添加在引用中,如图2所示。在串口通信中,接收数据采用事件驱动的方式,而发送数据采用周期性发送方式,在OPC数据交换中,读写数据均是周期性的,那为了实现周期性数据收发,就需要一个定时器控件Timer,VB6的开发界面图3所示。在串口通信程序调试过程中,发现数据交换量多了,通信容易出错,貌似两侧(单片机和VB端)都有问题,如像前面图中的控制信号突变这种现
[单片机]
用<font color='red'>单片机</font>玩PID控制—从理想PID控制至先进PID控制_4
MC9S12NE64型单片机的嵌入式以太网连接
1 引言   随着互联网的出现和以太网的迅速发展,基于以太网的设备控制越来越多,发展也越来越快。目前,以太网(EtImmet)已经广泛地应用于各种计算机网络,通过以太网及TCP/IP协议栈可以使不同的网络设备实现互连、交换数据。   用以太网实现嵌入式系统的网络连接有多种方案。传统的多器件以太网连接方案是通过MCU扩展以太网控制器来实现的,必要时还需要扩展外部RAM和 ROM。虽然这种方案应用起来不是很困难,但所用外部元件数量较多,系统开销较大。稳定性不高。为了解决传统方案的不足,本文讨论以集成以太网MAC层和物理层的16位单片机MC9S12NE64来实现单器件以太网连接。与多器件方案相比.单器件连接方案具有所用外部元件少
[单片机]
MC9S12NE64型<font color='red'>单片机</font>的嵌入式以太网连接
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved