登录 免费注册 首页 | 行业黑名单 | 帮助
维库电子市场网
技术交流 | 电路欣赏 | 工控天地 | 数字广电 | 通信技术 | 电源技术 | 测控之家 | EMC技术 | ARM技术 | EDA技术 | PCB技术 | 嵌入式系统
驱动编程 | 集成电路 | 器件替换 | 模拟技术 | 新手园地 | 单 片 机 | DSP技术 | MCU技术 | IC 设计 | IC 产业 | CAN-bus/DeviceNe

精品程序:利用T2扩展多个软件定时器,彻底解决定时器不够用的问题

作者:LPC900 栏目:单片机
精品程序:利用T2扩展多个软件定时器,彻底解决定时器不够用的问题
/*
    SoftTimer.h
    利用定时器T2模拟多个软件定时器
作者:21icbbs LPC900,2005-08
特点:
    只占用一个硬件定时器T2,就可以扩展出多达数十个以上的软件定时器
    软件定时器基本定时单位是10ms,定时范围很宽:0.01~163.84s
    软件定时器数量可以按需要设定,每增加一个,只多消耗2个字节的RAM空间
    利用定时器T2的自动重装特性,能够实现所有软件定时器的精确定时
    所有软件定时器都工作在14位倒计时方式,用TR和TF位控制,使用极为方便
    第0号定时器专门用于Delay()函数,其它定时器可供用户程序自由使用
*/



#ifndef _SOFT_TIMER_H_
#define _SOFT_TIMER_H_


#include <REG52.H>


//定义软件定时器数量(至少1个)
#define TIMER_N  8


//定义时钟频率(单位:Hz)
#define MCLK    11059200L


//定义软件定时器结构
//每个定时器只占用2个字节
struct
{
    volatile unsigned TR:1;        //起停标志,0-停止运行,1-开始运行
    volatile unsigned TF:1;        //溢出标志,0-未溢出,1-溢出
    volatile unsigned TV:14;    //14位定时值
}idata Timer[TIMER_N];


//软件定时器初始化
void TimerInit()
{
    unsigned int x;
    unsigned CHAR i;
    EA = 0;
    for ( i=0; i<TIMER_N; i++ )
    {
        Timer[i].TR = 0;
        Timer[i].TF = 0;
        Timer[i].TV = 0;
    }
    T2CON = 0x00;
    x = (unsigned int)(MCLK / 1200L);
#if ( (MCLK % 1200L) >= 600L )
    x++;
#endif
    x = 0 - x;
    RCAP2L = (unsigned CHAR)x;
    RCAP2H = (unsigned CHAR)(x >> 8);
    TL2 = RCAP2L;
    TH2 = RCAP2H;
    ET2 = 1;
    TR2 = 1;
    EA = 1;
}


/*
函数:TimerOn()
功能:启动定时器
参数:
    n:定时器序号
    t:定时器初值,取值0~16383
    t>0时,定时(0.01*t)s
    t=0时,定时163.84s
*/

void TimerOn(unsigned CHAR n,unsigned int t)
{
    Timer[n].TR = 0;
    Timer[n].TF = 0;
    Timer[n].TV = t;
    Timer[n].TR = 1;
}


/*
函数:TimerOff()
功能:关闭定时器
参数:
    n:定时器序号
*/

void TimerOff(unsigned CHAR n)
{
    Timer[n].TR = 0;
    Timer[n].TF = 0;
}


/*
函数:T2_INTR_SVC()
功能:定时器T2中断服务函数,每10ms中断1次
*/

void T2_INTR_SVC() interrupt 5
{
    unsigned CHAR i;
    TF2 = 0;
    for ( i=0; i<TIMER_N; i++ )
    {
        if (Timer[i].TR)
        {
            if ( --Timer[i].TV == 0 )
            {
                Timer[i].TF = 1;
            }
        }
    }
}


/*
函数:Delay()
功能:延时0.01~163.84s
参数:
    t:延时参数,取值0~16383
    t>0时,延时(0.01*t)s
    t=0时,延时163.84s
*/

void Delay(unsigned int t)
{
    TimerOn(0,t);
    for (;;)
    {
        PCON |= 0x01;
        if (Timer[0].TF)
        {
            TimerOff(0);
            break;
        }
    }
}


#undef TIMER_N
#undef MCLK


#endif  //_SOFT_TIMER_H_


* - 本贴最后修改时间:2005-8-20 16:19:11 修改者:LPC900

2楼: >>参与讨论
hotpower
色彩不错就是费时
多个计数器是可以从一个基计数器推出的...

3楼: >>参与讨论
sb_L
对于资源有限的芯片,N年前就这样了!只是用的是ASM
 
4楼: >>参与讨论
athlon64fx
为什么非要用个这么麻烦的数据结构呢?
把简单的问题复杂化了。一切都要尽可能地简单!

5楼: >>参与讨论
hiberhe
用数据结构其实是简单了:)
软件定时器肯定是要用的.

数据结构的方式看起来结构重合理,也更方便.楼主的程序风格不错!

如果RAM足够的话,就可以不用位域,(多耗两个字节),速度会快些,定时也可长些.

另外,
struct
{
    volatile unsigned TR:1;        //起停标志,0-停止运行,1-开始运行
    volatile unsigned TF:1;        //溢出标志,0-未溢出,1-溢出
    volatile unsigned TV:14;    //14位定时值
}idata Timer[TIMER_N];
我喜欢这样用

typedef struct
{
    volatile unsigned TR:1;        //起停标志,0-停止运行,1-开始运行
    volatile unsigned TF:1;        //溢出标志,0-未溢出,1-溢出
    volatile unsigned TV:14;    //14位定时值
}TIMER, *PTIMER;

TIMER idata Timer[TIMER_N];

同时:
    for ( i=0; i<TIMER_N; i++ )
    {
        Timer[i].TR = 0;
        Timer[i].TF = 0;
        Timer[i].TV = 0;
    }
也喜欢写成这样
for (i = 0; i < sizeof(TIMER)*TIMER_N; i++)
{
    ((unsigned CHAR idata*)&Timer)[i] = 0;
}
或者偷懒时就写成
#include <string.h>

// .......

memset((void *)&Timer,0x00,sizeof(TIMER)*TIMER_N);




6楼: >>参与讨论
yadog
re
学习

7楼: >>参与讨论
ketp
大家肯定都在用
只是方法不同,lz的实现方法逻辑清晰,但资源占用就多了点.

8楼: >>参与讨论
faucon
Re
色彩不错啊

9楼: >>参与讨论
LPC900
往上顶
 
10楼: >>参与讨论
wayner
请教斑竹:结构定义里面怎么可以写“unsigned TR:1;”?
 疑问①unsigned后面没有数据类型声明,缺省是int?
     ②TR后面加“:1”是什么意思?我怎么看认为c语法有问题?(从没看到过这样写)
     ③从后面推测TR、TF是位变量,TV是int变量,是吗?
写得不对,请见谅!

11楼: >>参与讨论
computer00
TR后面加“:1”表示位段。去看看C语言的位段吧。
 
12楼: >>参与讨论
pantodd
这段时间正在做多路脉冲检测。
可以学习了。四路脉冲而使用的89C52只有三个定时器。谢谢

13楼: >>参与讨论
LPC900
可以跑定时多任务程序
举例:

#include "SoftTimer.h"
#include "Task.h"    //自行定义的多任务头文件

void main()
{
    TimerInit();
    TimerOn(1,1);
    TimerOn(2,1);
    ...
    while (1)
    {
        PCON |= 0x01;    //节电
        if ( Timer[1].TF )
        {
            Task01();    //注意:不能包含有死循环
            TimerOn(1,10);
        }
        if ( Timer[2].TF )
        {
            Task02();    //注意:不能包含有死循环
            TimerOn(1,85);
        }
        ...
    }
}


14楼: >>参与讨论
LPC900
如果谁不清楚位段(位域)的话,建议回去读读谭浩强的C语言教程
 
15楼: >>参与讨论
toonaive
请教搂住
为什么用
#if ( (MCLK % 1200L) >= 600L )
    x++;
#endif
而不用直接用
if ( (MCLK % 1200L) >= 600L )
    x++;

还有
#undef TIMER_N
#undef MCLK
有什么用意?
谢谢

16楼: >>参与讨论
stintair
路过,关注一下
——

17楼: >>参与讨论
hiberhe
用条件编译的话,不满足条件,不包含代码
如果用if判断的话,总会在程序中有那么不段,不管满足条件不.

#undef的意思就是从这以后,取消对其的定义,这样以后的程序又可以重新对其进行定义和使用了.

18楼: >>参与讨论
hunter01
还没有查询系统时间简单!
 

* - 本贴最后修改时间:2005-8-28 10:58:38 修改者:hunter01

参与讨论
昵称:
讨论内容:
 
 
相关帖子
AT89S51在什么情况下一定要接锁存器(373,573之类)
电机正反转问题!关于TA7257BP
哪种单片机难得解密一些?
12887的问题。
做电磁炉的高手请进!!!
免费注册为维库电子开发网会员,参与电子工程师社区讨论,点此进入


Copyright © 1998-2006 www.dzsc.com 浙ICP证030469号