好好学习 发表于 2023-5-7 11:40:52

我也来分享一个我使用的软定时器

因为在实际应用中可能需要大量的定时器,需要不同的定时时间,
但硬件定时器数量较少,不能满足需求,
所以我写了一个的定时器的子程序,供参考一下,
也请各位大侠多多指教!废话不多说,上代码{:lol:}
定时器h和C文件,此部分参考了STC官网程序

time.h文件


#ifndef TIME
#define TIME
#include "../comm/STC32G.h"
#define MAIN_Fosc       24000000UL//定义主时钟

#define Timer0_Reload   (MAIN_Fosc / 1000)      //Timer 0 中断频率, 1000次/秒
#define Timer1_Reload   (MAIN_Fosc / 2000)      //Timer 1 中断频率, 2000次/秒
#define Timer2_Reload   (MAIN_Fosc / 3000)      //Timer 2 中断频率, 3000次/秒
#define Timer3_Reload   (MAIN_Fosc / 4000)      //Timer 3 中断频率, 4000次/秒
#define Timer4_Reload   (MAIN_Fosc / 5000)      //Timer 4 中断频率, 5000次/秒
//-------------------------------引脚定义----------------------------------


//-------------------------------变量声明----------------------------------
extern unsigned int Flag_1ms;                                                                                                //1ms时基
extern unsigned int Flag_10ms;                                                                                        //10ms时基
extern unsigned int Flag_100ms;                                                                                        //100ms时基

extern bit flag1ms;                                                                                                                //1ms时基位变量
extern bit flag10ms ;                                                                                                                //10ms时基位变量
extern bit flag100ms;                                                                                                                //100ms时基位变量

//-------------------------------函数声明----------------------------------
void Timer0_init(void);                                                                                                      //定时器0初始化
void Timer1_init(void);                                                                                                      //定时器1初始化
void Timer2_init(void);                                                                                                      //定时器2初始化
void Timer3_init(void);                                                                                                      //定时器3初始化
void Timer4_init(void);                                                                                                      //定时器4初始化
                                                                                                                              
#endiftime.c文件


/*---------------------------------------------------------------------*/
/* --- STC MCU Limited ------------------------------------------------*/
/* --- STC 1T Series MCU Demo Programme -------------------------------*/
/* --- Mobile: (86)13922805190 ----------------------------------------*/
/* --- Fax: 86-0513-55012956,55012947,55012969 ------------------------*/
/* --- Tel: 86-0513-55012928,55012929,55012966 ------------------------*/
/* --- Web: www.STCMCU.com --------------------------------------------*/
/* --- Web: www.STCMCUDATA.com---------------------------------------*/
/* --- QQ:800003751 -------------------------------------------------*/
/* 如果要在程序中使用此代码,请在程序中注明使用了STC的资料及程序            */
/*---------------------------------------------------------------------*/

/*************功能说明    **************

本例程基于STC32G为主控芯片的实验箱进行编写测试。

使用Keil C251编译器,Memory Model推荐设置XSmall模式,默认定义变量在edata,单时钟存取访问速度快。

edata建议保留1K给堆栈使用,空间不够时可将大数组、不常用变量加xdata关键字定义到xdata空间。

本程序演示5个定时器的使用, 本例程均使用16位自动重装.

定时器0做16位自动重装, 中断频率为1000HZ,中断函数从P6.7取反输出500HZ方波信号.

定时器1做16位自动重装, 中断频率为2000HZ,中断函数从P6.6取反输出1000HZ方波信号.

定时器2做16位自动重装, 中断频率为3000HZ,中断函数从P6.5取反输出1500HZ方波信号.

定时器3做16位自动重装, 中断频率为4000HZ,中断函数从P6.4取反输出2000HZ方波信号.

定时器4做16位自动重装, 中断频率为5000HZ,中断函数从P6.3取反输出2500HZ方波信号.

下载时, 选择时钟 24MHZ (用户可自行修改频率).

******************************************/
//下面程序修改自STC官网例程,主要修改了定时器0的中断函数,使用了定时器0的时基作为软定时器的基准

#include "time.h"   


//========================================================================
// 函数: void Timer0_init(void)
// 描述: timer0初始化函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2015-1-12
//========================================================================
void Timer0_init(void)
{
      TR0 = 0;    //停止计数

    #if (Timer0_Reload < 64)    // 如果用户设置值不合适, 则不启动定时器
      #error "Timer0设置的中断过快!"

    #elif ((Timer0_Reload/12) < 65536UL)    // 如果用户设置值不合适, 则不启动定时器
      ET0 = 1;    //允许中断
    //PT0 = 1;    //高优先级中断
      TMOD &= ~0x03;
      TMOD |= 0;//工作模式, 0: 16位自动重装, 1: 16位定时/计数, 2: 8位自动重装, 3: 16位自动重装, 不可屏蔽中断
    //T0_CT = 1;//计数
      T0_CT = 0;//定时
    //T0CLKO = 1; //输出时钟
      T0CLKO = 0; //不输出时钟

      #if (Timer0_Reload < 65536UL)
            T0x12 = 1;//1T mode
            TH0 = (unsigned char)((65536UL - Timer0_Reload) / 256);
            TL0 = (unsigned char)((65536UL - Timer0_Reload) % 256);
      #else
            T0x12 = 0;//12T mode
            TH0 = (unsigned char)((65536UL - Timer0_Reload/12) / 256);
            TL0 = (unsigned char)((65536UL - Timer0_Reload/12) % 256);
      #endif

      TR0 = 1;    //开始运行

    #else
      #error "Timer0设置的中断过慢!"
    #endif
}

//========================================================================
// 函数: void Timer1_init(void)
// 描述: timer1初始化函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2015-1-12
//========================================================================
void Timer1_init(void)
{
      TR1 = 0;    //停止计数

    #if (Timer1_Reload < 64)    // 如果用户设置值不合适, 则不启动定时器
      #error "Timer1设置的中断过快!"

    #elif ((Timer1_Reload/12) < 65536UL)    // 如果用户设置值不合适, 则不启动定时器
      ET1 = 1;    //允许中断
    //PT1 = 1;    //高优先级中断
      TMOD &= ~0x30;
      TMOD |= (0 << 4);   //工作模式, 0: 16位自动重装, 1: 16位定时/计数, 2: 8位自动重装
    //T1_CT = 1;//计数
      T1_CT = 0;//定时
    //T1CLKO = 1; //输出时钟
      T1CLKO = 0; //不输出时钟

      #if (Timer1_Reload < 65536UL)
            T1x12 = 1;//1T mode
            TH1 = (unsigned char)((65536UL - Timer1_Reload) / 256);
            TL1 = (unsigned char)((65536UL - Timer1_Reload) % 256);
      #else
            T1x12 = 0;//12T mode
            TH1 = (unsigned char)((65536UL - Timer1_Reload/12) / 256);
            TL1 = (unsigned char)((65536UL - Timer1_Reload/12) % 256);
      #endif

      TR1 = 1;    //开始运行

    #else
      #error "Timer1设置的中断过慢!"
    #endif
}

//========================================================================
// 函数: void Timer2_init(void)
// 描述: timer2初始化函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2015-1-12
//========================================================================
void Timer2_init(void)
{
      T2R = 0;    //停止计数

    #if (Timer2_Reload < 64)    // 如果用户设置值不合适, 则不启动定时器
      #error "Timer2设置的中断过快!"

    #elif ((Timer2_Reload/12) < 65536UL)    // 如果用户设置值不合适, 则不启动定时器
      ET2 = 1;    //允许中断
    //T2_CT = 1;//计数
      T2_CT = 0;//定时
    //T2CLKO = 1; //输出时钟
      T2CLKO = 0; //不输出时钟

      #if (Timer2_Reload < 65536UL)
            T2x12 = 1;    //1T mode
            T2H = (unsigned char)((65536UL - Timer2_Reload) / 256);
            T2L = (unsigned char)((65536UL - Timer2_Reload) % 256);
      #else
            T2x12 = 0;    //12T mode
            T2H = (unsigned char)((65536UL - Timer2_Reload/12) / 256);
            T2L = (unsigned char)((65536UL - Timer2_Reload/12) % 256);
      #endif

      T2R = 1;    //开始运行

    #else
      #error "Timer2设置的中断过慢!"
    #endif
}

//========================================================================
// 函数: void Timer3_init(void)
// 描述: timer3初始化函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2015-1-12
//========================================================================
void Timer3_init(void)
{
      T3R = 0;    //停止计数

    #if (Timer3_Reload < 64)    // 如果用户设置值不合适, 则不启动定时器
      #error "Timer3设置的中断过快!"

    #elif ((Timer3_Reload/12) < 65536UL)    // 如果用户设置值不合适, 则不启动定时器
      ET3 = 1;    //允许中断
    //T3_CT = 1;//计数
      T3_CT = 0;//定时
    //T3CLKO = 1; //输出时钟
      T3CLKO = 0; //不输出时钟

      #if (Timer3_Reload < 65536UL)
            T3x12 = 1;    //1T mode
            T3H = (unsigned char)((65536UL - Timer3_Reload) / 256);
            T3L = (unsigned char)((65536UL - Timer3_Reload) % 256);
      #else
            T3x12 = 0;    //12T mode
            T3H = (unsigned char)((65536UL - Timer3_Reload/12) / 256);
            T3L = (unsigned char)((65536UL - Timer3_Reload/12) % 256);
      #endif

      T3R = 1;    //开始运行

    #else
      #error "Timer3设置的中断过慢!"
    #endif
}

//========================================================================
// 函数: void Timer4_init(void)
// 描述: timer4初始化函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2015-1-12
//========================================================================
void Timer4_init(void)
{
      T4R = 0;    //停止计数

    #if (Timer4_Reload < 64)    // 如果用户设置值不合适, 则不启动定时器
      #error "Timer4设置的中断过快!"

    #elif ((Timer4_Reload/12) < 65536UL)    // 如果用户设置值不合适, 则不启动定时器
      ET4 = 1;    //允许中断
    //T4_CT = 1;//计数
      T4_CT = 0;//定时
    //T4CLKO = 1; //输出时钟
      T4CLKO = 0; //不输出时钟

      #if (Timer4_Reload < 65536UL)
            T4x12 = 1;    //1T mode
            T4H = (unsigned char)((65536UL - Timer4_Reload) / 256);
            T4L = (unsigned char)((65536UL - Timer4_Reload) % 256);
      #else
            T4x12 = 0;    //12T mode
            T4H = (unsigned char)((65536UL - Timer4_Reload/12) / 256);
            T4L = (unsigned char)((65536UL - Timer4_Reload/12) % 256);
      #endif

      T4R = 1;    //开始运行

    #else
      #error "Timer4设置的中断过慢!"
    #endif
}

//========================================================================
// 函数: void timer0_int (void) interrupt TIMER0_VECTOR
// 描述:timer0中断函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2015-1-12
//========================================================================
bit flag1ms=0;//1ms时基位变量
bit flag10ms=0;//10ms时基位变量
bit flag100ms=1;//100ms时基位变量
unsigned int Flag_1ms=0;//1ms时基
unsigned int Flag_10ms=0;//10ms时基
unsigned int Flag_100ms=0;//100ms时基
void timer0_int (void) interrupt 1
{   
      static unsigned char count10=0;//软定时器10ms计数值
      static unsigned char count100=0;//软定时器100ms计数值                  
    Flag_1ms=0xffff;      
      flag1ms=1;
    count10++;
    count100++;
    if (count10>=10)
    {
            Flag_10ms=0xffff;
            count10=0;
                flag10ms=1;               
    }      
    if (count100>=100)
    {
            Flag_100ms=0xffff;
            count100=0;
                flag100ms=1;                        
    }
}

//========================================================================
// 函数: void timer1_int (void) interrupt TIMER1_VECTOR
// 描述:timer1中断函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2015-1-12
//========================================================================
void timer1_int (void) interrupt 3
{
    P76 = ~P76;
}

//========================================================================
// 函数: void timer2_int (void) interrupt TIMER2_VECTOR
// 描述:timer2中断函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2015-1-12
//========================================================================
void timer2_int (void) interrupt 12
{
    P77 = ~P77;
}

//========================================================================
// 函数: void timer3_int (void) interrupt TIMER3_VECTOR
// 描述:timer3中断函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2015-1-12
//========================================================================
void timer3_int(void) interrupt 19
{
    P45 = ~P45;
}

//========================================================================
// 函数: void timer4_int (void) interrupt TIMER4_VECTOR
// 描述:timer4中断函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2015-1-12
//========================================================================
void timer4_int(void) interrupt 20
{
    P46 = ~P46;
}
下面是软定时器函数
delay.h
#ifndef DELAY
#define DELAY
#include "time.h"
/*******************************************************************
*                                                                   *
* 软定时器的实现                                                                                                                                                    *
*                                                                   *
* 1、定义了48个定时器                                              *
* 2、定时器定义如下                                                               *
//1、定义的定时器0~15为1ms定时器 ,定时范围为0~32768ms
//2、定义的定时器16~31为10ms定时器, 定时范围为0~327680ms
//3、定义的定时器32~47为100ms定时器,定时范围为0~3276800ms
//4、定时器设定时间最大32768,不要用靠近的 定时器,
//比如定时100ms使用1ms定时器而不要使用100ms定时器,不然有定时误差
* 3、使用的是stc32的定时器0,基础时基为1ms                                                                              *
*                                                                   *
*********************************************************************/

//-------------------------------引脚定义----------------------------------


//-------------------------------变量声明----------------------------------


//-------------------------------函数声明----------------------------------
void TMR(unsigned char _id,unsigned int Presets);//设定定时器id和此定时器需要的定时时间
unsigned int TD(unsigned char _id); //返回定时器当前计数值
void Init_T(unsigned char _id);//定时器初始化
bit Tim(unsigned char _id); //定时器状态值

#endifdelay.c

#include "delay.h"

/*******************************************************************
*                                                                   *
* 软定时器的实现                                                                                                                                                    *
*                                                                   *
* 1、定义了48个定时器                                              *
* 2、定时器定义如下                                                               *
//1、定义的定时器0~15为1ms定时器 ,定时范围为0~32768ms
//2、定义的定时器16~31为10ms定时器, 定时范围为0~327680ms
//3、定义的定时器32~47为100ms定时器,定时范围为0~3276800ms
//4、定时器设定时间最大32768,不要用靠近的 定时器,
//比如定时100ms使用1ms定时器而不要使用100ms定时器,不然有定时误差
* 3、使用的是stc32的定时器0,基础时基为1ms                                                                              *
*                                                                   *
*********************************************************************/

//使用位段功能,大大减少内存占用,使用结构体改变定义不影响后面程序
typedefstruct
{
               unsigned int current:15;//低15位作为计数值
               unsigned int state:1;//最高位作为标志位
         
} Timer_TypeDef;

Timer_TypeDefT;

//1、定义的定时器0~15为1ms定时器 ,定时范围为0~32768ms
//2、定义的定时器16~31为10ms定时器, 定时范围为0~327680ms
//3、定义的定时器32~47为100ms定时器,定时范围为0~3276800ms
//4、定时器设定时间最大32768,不要用靠近的 定时器,
//比如定时100ms使用1ms定时器而不要使用100ms定时器,不然有定时误差

/**********************************************************************
//函数名称:TMR(unsigned char _id,uint16_t Presets)
//函数功能:设定定时器id和此定时器需要的定时时间
//入口参数:定时器id,需要定时时间
//返回参数:无
//当前版本:V1.0
//修改日期:
//当前作者:
//其它备注:

**********************************************************************/

void TMR(unsigned char _id,unsigned int Presets)//设定定时器id和此定时器需要的定时时间
{
      if(_id<16)      //时基是1ms
      {
      if((Flag_1ms & (1<<_id)) && T.state==0)//相比下面语句精简一点,下同
      {
            Flag_1ms &=~(1<<_id);//对应标志位清零
                                           T.current++;//软定时器计数值+1
                     if(T.current<Presets) return;
                               T.state=1; //软定时器定时时间到
      }      
      }
      if(_id<32 && _id>=16)      //时基是10ms
      {
      if((Flag_10ms & (1<<(_id-16))) && T.state==0)      
      {
                Flag_10ms &=~(1<<(_id-16));//对应标志位清零
          T.current++;//软定时器计数值+1
                     if(T.current>=Presets)
                  T.state=1;//软定时器定时时间到
      }      
      }      
                if(_id<48 && _id>=32)      //时基是100ms
      {
      if((Flag_100ms & (1<<(_id-32))) && T.state==0)
      {
            Flag_100ms &=~(1<<(_id-32));//对应标志位清零
                                          T.current++;//软定时器计数值+1
                                 if(T.current<Presets) return;
                                       T.state=1;//软定时器定时时间到
      }      
      }               
}

/**********************************************************************
//函数名称: unsigned int TD(unsigned char _id)
//函数功能: 返回定时器当前值
//入口参数: 定时器的ID值
//返回参数: 定时器已过计数值
//当前版本: V1.0
//修改日期:
//当前作者:
//其它备注:

**********************************************************************/

unsigned int TD(unsigned char _id)
{
         return T.current;
}
/**********************************************************************
//函数名称: void Init_T(unsigned char _id)
//函数功能:初始化定时器
//入口参数:定时器id
//返回参数:无
//当前版本:V1.0
//修改日期:
//当前作者:
//其它备注:

**********************************************************************/


void Init_T(unsigned char _id)
{
         T.current=0;
         T.state=0;
}

/**********************************************************************
//函数名称:bit Tim(unsigned char _id)
//函数功能:定时器状态值
//入口参数:定时器id
//返回参数:定时器结果,1为定时器时间到,0为时间未到
//当前版本:V1.0
//修改日期:
//当前作者:
//其它备注:

**********************************************************************/
bit Tim(unsigned char _id)
{
    if(T.state==1)
            return 1;
    else
            return 0;
}至于使用就简单了:

if(A)TMR(0,1234);//如果A条件满足,执行软定时器0
if(Tim(0))//软定时器设定时间到
{
   巴拉巴拉;
Init(0);//初始化软定时器0,下次可以接着用
}



好好学习 发表于 2023-5-11 09:55:56

看来需要用这个的不多啊

jwd 发表于 2023-5-11 10:13:48

这有点类似PLC的定时器

梁工 发表于 2023-5-11 15:37:43

软件定时器,我就用一个timer0,1ms中断,就可以做N多定时器,我一般用倒计时,为0则定时到。
有人对结构体感冒,我就用普通数组吧,大约如下:
#define SoftTimerNum   32;   //软件定时器个数
u8xdata TimerFlag;   //软件定时器标志, 0: 无事件发生,1:定时到
u16xdata SoftTimer; //软件定时器倒计时

使用时,比如用SoftTimer;
SoftTimer = 1000;    //定时1000ms
查询完成:
if(TimerFlag == 1)//定时到
{
   //处理代码
}

Timer0 1ms中断里处理:

for(i=0;i<SoftTimerNum; i++)
{
   if(SoftTimer != 0)    //软件定时器倒计时
   {
       if(--SoftTimer == 0)    TimerFlag = 1;   //定时完成
   }
}

天源电子 发表于 2024-2-4 12:55:25

梁工 发表于 2023-5-11 15:37
软件定时器,我就用一个timer0,1ms中断,就可以做N多定时器,我一般用倒计时,为0则定时到。
有人对结构体 ...

查询完成:
if(TimerFlag == 1)//定时到
{
   //处理代码
}

这段怎么用呢,那不是32个标志位都会执行这个代码,
还有个问题,我要定时不同的时间,if(SoftTimer != 0)    //软件定时器倒计时
   {
       if(--SoftTimer == 0)    TimerFlag = 1;   //定时完成
   }
那这段不同的时间都要写一次吗

梁工 发表于 2024-2-4 13:03:38

天源电子 发表于 2024-2-4 12:55
查询完成:
if(TimerFlag == 1)//定时到
{


每一个定时都是独立的,你要启用哪个定时,就装一个定时值。
比如用SoftTimer,启用时装载定时值:
    SoftTimer = 1000;    //定时1000ms

在定时到时要处理的任务,在任务重查询:
if(TimerFlag == 1)//定时到
{
    TimerFlag = 0;
   //处理代码
}

jwd 发表于 2024-2-4 13:16:44

梁工 发表于 2023-5-11 15:37
软件定时器,我就用一个timer0,1ms中断,就可以做N多定时器,我一般用倒计时,为0则定时到。
有人对结构体 ...

梁工,这种的话木有定时器计数值的清零和定时时间的获取吧

_奶咖君_ 发表于 2024-2-4 13:19:05

jwd 发表于 2024-2-4 13:16
梁工,这种的话木有定时器计数值的清零和定时时间的获取吧

源码都给了 想实现什么自己往上加呗

梁工 发表于 2024-2-4 15:56:45

jwd 发表于 2024-2-4 13:16
梁工,这种的话木有定时器计数值的清零和定时时间的获取吧

要清零就直接写0(就是提前主动结束定时器),定时时间的获取是指什么?

jwd 发表于 2024-2-4 16:02:19

梁工 发表于 2024-2-4 15:56
要清零就直接写0(就是提前主动结束定时器),定时时间的获取是指什么? ...

类似plc里面的定时器,当某个条件满足时才开始启动软定时器,当条件断开后软定时器需要复位,计数值需要清零;定时时间是当启动某个软定时器后,我可能需要在定时到一定时间后开始某些动作,但是此时此软件定时器还没有到达设定的时间,所以此时标志位不会置位
页: [1] 2 3
查看完整版本: 我也来分享一个我使用的软定时器