单片机要想实现多个不同时基的控制,除了上系统外,本人采用分时段的方法,结合PLC的控制原理,实现出类似PLC定时器的控制方法,分别有0.01S定时器 12个,0.1MS定时器 10个,1S定时器10个,可以单独设定,同时使用。如果MCU的程序容量比较大,可以实现更多的定时器,不过一般建议根据实际项目要求来调整。实现过程思路代码如下(STC89单片机):
//以下程序及算法由本人zyhlove813原创,特别是soft_timer实现算法值得借鉴,适用所有MCU,源码示例请下载附件 #include "reg51.h" typedef unsigned char uint8_t; typedef unsigned int uint32_t; /* define constants */ #define true 1 #define false 0 #define FOSC 11059200L //时钟频率 #define T1MS (65536-FOSC/12/1000) //1MS定时器设定值 #define T10ms 12 //0.01S定时器数组索引上限=12-1=11,因此0.01S定时器的个数=12个 #define T100ms (T10ms+10) //0.1S定时器数组索引上限=22-1=21,因此0.1S定时器的个数=21-11=10个 #define Timers 32 //1S定时器数组索引上限=32-1=31,因此1S定时器的个数=31-21=10个 #define Timers_bit (Timers/8) //八个定时器为一组,共32/8=4组 #define SET_BIT(s,b,c)(s=(s&(~(1<<b)))+(c<<b)) //宏,设置某个位的值,0或1的状态 #define GET_BIT(s,b)((s>>b)&0x01) //宏,获取某个位的值,返回0或1的状态 #define SET_EN(b,c) (SET_BIT(timer_en[b/8],b%8,c)) //设置对应定时器使能状态 #define SET_ON(b,c) (SET_BIT(timer_on[b/8],b%8,c)) //设置对应定时器对应使能状态 #define GET_EN(b) (GET_BIT(timer_en[b/8],b%8)) //获取对应定时器对应使能状态 #define GET_ON(b) (GET_BIT(timer_on[b/8],b%8)) //获取对应定时器线圈状态 uint8_t timer_en[Timers_bit]; //定时器使能状态缓存 uint8_t timer_on[Timers_bit]; //定时器线圈状态缓存 uint32_t timer_pv[Timers]; //定时器目标值缓存 uint32_t timer_cv[Timers]; //定时器当前值缓存 uint32_tcount_1ms; //硬件定时器1MS计数器 sbit LED1=P1^1; //测试用的IO1 sbit LED2=P1^2; //测试用的IO2 void soft_timer(void); //声明函数 void timer0_isr() interrupt 1 //定时器0中断,每1MS中断一次 { TL0 = T1MS; //reloadtimer0 low byte TH0 = T1MS>> 8; //reload timer0 high byte soft_timer(); //调用软件定时器判断 } void main() { TMOD = 0x01; //set timer0 as mode1 (16-bit) TL0 = T1MS; //initialtimer0 low byte TH0 = T1MS>> 8; //initial timer0 high byte TR0 = 1; //timer0 start running ET0 = 1; //enable timer0 interrupt EA = 1; //open global interrupt switch count_1ms = 0; //initial counter timer_pv[1]=1; //0.01S定时器(1)的目标值设为1,即10MS timer_pv[2]=1; //0.01S定时器(2)的目标值设为1,即10MS timer_pv[12]=5; //0.1S定时器(12)的目标值设为5,即500MS timer_pv[13]=5; //0.1S定时器(13)的目标值设为5,即500MS SET_EN(1,1); //0.01S定时器(1)使能有效,开始计时 SET_EN(12,1); //0.1S定时器(12)使能有效,开始计时 while (1) { if(GET_ON(1)) //如果0.01S定时器(1)的定时线圈为1,即定时时间到 { LED1=1; //LED1亮 SET_EN(2,1); //0.01S定时器(2)使能有效,开始计时 SET_EN(1,0); //0.01S定时器(1)使能无效,停止计时 } if(GET_ON(2)) //如果0.01S定时器(2)的定时线圈为1,即定时时间到 { LED1=0; //LED1灭 SET_EN(1,1); //0.01S定时器(1)使能有效,开始计时 SET_EN(2,0); //0.01S定时器(2)使能无效,停止计时 } if(GET_ON(12)) //如果0.1S定时器(12)的定时线圈为1,即定时时间到 { LED2=1; //LED2亮 SET_EN(13,1); //0.1S定时器(13)使能有效,开始计时 SET_EN(12,0); //0.1S定时器(12)使能无效,停止计时 } if(GET_ON(13)) { LED2=0; //LED2灭 SET_EN(12,1); //0.1S定时器(12)使能有效,开始计时 SET_EN(13,0); //0.1S定时器(13)使能无效,停止计时 } } } //软件定时器的实现 void soft_timer() { uint8_ti; uint8_ttemp; count_1ms++; //1MS计数值+1 if(count_1ms%10==0) //判断是否0.01S时间到 { for(i=0;i<T10ms;i++) //更新0.01S定时器的当前值 { timer_cv+=GET_EN(i); //如果EN=1,则当前值+1,否则+0 timer_cv*=GET_EN(i); //如果EN=1,则当前值不变,否则当前值=0 保障当前值根据使能状态自动加或清零 temp=GET_EN(i)*(timer_cv>=timer_pv); //计算是否到达目标时间,如果使能无效的话,结果是0,如果使能有效的话,而且当前值大于目标值,结果是1 SET_ON(i,temp); //更新线圈是否到时状态 } } //以下算法相同 if(count_1ms%100==0) //判断是否0.1S时间到 { for(i=T10ms;i<T100ms;i++) { timer_cv+=GET_EN(i); timer_cv*=GET_EN(i); temp=GET_EN(i)*(timer_cv>=timer_pv); SET_ON(i,temp); } } if(count_1ms%1000==0) //判断是否1S时间到 { count_1ms=0; //1MS计数器重启 for(i=T100ms;i<Timers;i++) { timer_cv+=GET_EN(i); timer_cv*=GET_EN(i); temp=GET_EN(i)*(timer_cv>=timer_pv); SET_ON(i,temp); } } }
全部资料51hei下载地址:
SoftTimer.rar
(31.31 KB, 下载次数: 104)
|