利用定時器實現51微控制器返回上電執行時間功能

lilanlin發表於2020-12-07

我們知道在windows等作業系統裡可以呼叫API函式獲取系統執行的時間。在Arduino裡也有兩個函式millis()和micros(),可以分別獲得Arduino程式從上電以來累計執行時間的毫秒數和微秒數。我們可以利用51微控制器的定時器中斷實現這個功能。

具體實現的思路是設定1個長整型的全域性時間變數sysRunmillis儲存微控制器上電後的執行時間。讓定時器每1毫秒產生1次中斷,在中斷響應函式裡讓全域性變數sysRunmillis自加1。這個長整型的變數最大值是4294967295毫秒,換算下來就是49天17時2分47秒,然後從0開始繼續計時。

這樣我們可以在程式裡隨時讀取當前時間,實現精確計時、軟體延時等功能。比如要延時n毫秒,我們可以用下面的程式碼實現:

Void delaynmillis(unsigned int n)

{

Unsigned long t;

t=sysRunmillis;//先儲存當前時間

While(sysRunmillis-t<n);迴圈等待直到n毫秒

  }

下面的程式實時顯示51微控制器上電執行的時間,其中大部分程式碼用來實現在動態數碼管上顯示時間。

/*
利用定時器中斷實現51微控制器輸出系統上電累計執行時間
****李蘭林,2020年12月6日,甘肅白銀
*/
#include <reg51.h>
#include <intrins.h>
sbit RCK=P3^5;//定義74HC595儲存暫存器時鐘引腳
sbit SCK=P3^6;//定義74HC595移位暫存器時鐘引腳
sbit SER=P3^4;//定義74HC595序列輸入引腳

typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;

u32 sysRunmillis;	//系統執行時間計數,儲存微控制器從上電覆位以來執行的時間,單位是毫秒。該數值由定時器T0的中斷響應子函式更新
u8 hour,min,sec;	//當前系統執行時間換算成小時數、分數和秒數
u8 strTime[]={0,0,0,0,0,0,0,0};	//儲存時分秒每1位上的數字(0~9),分隔符‘-’的值是10

u8 DigCode[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40};//共陰極數碼管段碼

//把全域性變數sysRunmillis儲存的毫秒數轉換成時分秒格式,把時分秒的每一位數字(0~9)儲存在陣列strTime裡。
void millis2time()
{
	u32 t;
	t=sysRunmillis/1000;	  //毫秒轉換為秒
	hour=t/3600%24;			  //計算小時數	
	min=(t%3600)/60;		  //計算分
	sec=t%60;				  //計算秒
	//以下處理時、分、秒每1位,如時分秒數值小於10,補加0佔位。
	if(hour<10)
	{
		strTime[0]=0;
		strTime[1]=hour;
	}
	else
	{
		strTime[0]=hour/10;
		strTime[1]=hour%10;
	}
	if(min<10)
	{
		strTime[3]=0;
		strTime[4]=min;
	}
	else
	{
		strTime[3]=min/10;
		strTime[4]=min%10;
	}
	if(sec<10)
	{
		strTime[6]=0;
		strTime[7]=sec;
	}
	else
	{
		strTime[6]=sec/10;
		strTime[7]=sec%10;
	}
}

//給74HC95傳送數碼管位選和段碼資料
void _74HC595SendByte(u8 wei,u8 duan)
{
	u8 i;
	RCK=0;
	for(i=0;i<8;i++)
	{
		SCK=0;
		_nop_();
		SER=wei>>7;
		SCK=1;
		_nop_();
		wei<<=1;
	}
	for(i=0;i<8;i++)
	{
		SCK=0;
		_nop_();
		SER=duan>>7;
		SCK=1;
		_nop_();
		duan<<=1;
	}
	RCK=1;
}

//初始化定時器T0
void InitTimer0()
{
    TMOD = 0x01;
    TH0 = 0xFC;	   //計數初值1000,每1毫秒中斷1次
    TL0 = 0x18;
    EA = 1;
    ET0 = 1;
    TR0 = 1;
}

void Timer0Interrupt() interrupt 1
{
    TH0 = 0xFC;
    TL0 = 0x18;
    sysRunmillis++;	//每1毫秒加1
}

void delaynms(u8 millis)   //延時n毫秒
{
    u32 temp;
	temp=sysRunmillis;
    while(millis>sysRunmillis-temp);
}

void main()
{
	u8 i;
	InitTimer0();
	strTime[2]=10;
	strTime[5]=10;
	while(1)
	{
		millis2time();
		for(i=0;i<8;i++)
		{
			_74HC595SendByte(~(0x01<<i),DigCode[strTime[i]]);
			delaynms(1);
		}
	}
}

下圖是程式執行結果。

 

相關文章