單片機要想實現多個不同時基的控制,除了上系統外,本人采用分時段的方法,結合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, 下載次數: 107)
2020-11-13 15:07 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|