1. 程式人生 > >51微控制器定時器的原理與使用(二)

51微控制器定時器的原理與使用(二)

承接上一節51微控制器定時器的原理與使用,這節我們繼續講述怎麼用定時器做一個電子鐘,PWM脈衝和測電阻。先從實驗三講起吧!

實驗三、定時器測電阻

測量如下圖Rx的電阻並顯示在數碼管上。


測量思路為:
1、電容C1放電,P2.5與P2.6設定為輸入模式,P2.7設定為推輓輸出且為輸出低電平0。這時候C1通過R1和P2.7放電。
2、切斷C1的放電迴路,將P2.7設為輸入模式。
3、P2.5設為推輓輸出,並且輸出高電平5V,即P2.5的高電平通過Rk對C1充電。同時開啟定時器Tx。
4、MCU不斷讀P2.7的狀態,當P2.7為高,則關閉定時器。同時P2.5恢復輸入模式。這個過程中定時器記錄了P2.5通過Rk對C1充電直到P2.7為高電平的時間t1。
5、將P2.7設為推輓輸出並輸出0,即對C1再次放電。放電完成後,將P2.7恢復為輸入狀態。
6、P2.6設為推輓輸出,並且輸出高電平5V,即P2.6的高電平通過Rx對C1充電。同時開啟定時器Tx。MCU不斷讀P2.7的狀態,當P2.7為高,則關閉定時器。這個過程中定時器記錄了P2.6通過Rx對C1充電直到P2.7為高電平的時間t2。
Rk/Rx = t1/t2 即 Rx = t2*Rk/t1
直接上程式碼:



main.c
#include "reg51.h"

unsigned int count;
extern void load_smg();
extern void res_test();
extern  void delay(unsigned int x);

void Timer1_Init()
{
	TMOD|=0x10;
	TH1=64614/256;
	TL1=64614%256;
	TR1=1;
}

void Isr_Init()
{
	EA=1;
	ET1=1;
	ET0=1;
}

void Timer0_Init()
{
	TMOD|=0x01;
	TH0=0;
	TL0=0;
	TR0=0;
}

void TF1_isr() interrupt 3		//1ms
{
	TH1=64614/256;
	TL1=64614%256;
	load_smg();

}
void main()
{
	Timer0_Init();
	Timer1_Init();
	Isr_Init();
    
	while(1)
	{
	   res_test();
	   delay(65000);
	   delay(65000);
	}
}

smg.c
 #include "reg51.h" 
  //char seg[10]={0xC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90};
 code char seg[10]={0xC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90};
 char smgbuf[4]={1,2,3,4}; //從RAM的smgbuf這個地址開始連續存放4個數,並且每個數佔一個單元。
 extern unsigned int count;	//外部申明,表示並不在這裡申明

void fill_smgbuf() //向LED緩衝區填充資料
{
	smgbuf[0]=count/1000;  //千位
	smgbuf[1]=(count%1000)/100;  //百位
	smgbuf[2]=((count%1000)%100)/10;   //十位
	smgbuf[3]=((count%1000)%100)%10;   //個位
}

void load_smg()   //將數碼管顯示緩衝區的資料,顯示到數碼管上
 {
 	static char i;
	fill_smgbuf();
	i++;
	if(i>=4)
	{
		i=0;
	}
	P0=0xFF;   //消除上一個迴圈的影子
	P2 = ~(1<<i);
	P0 = seg[smgbuf[i]];	

 }
resistor.c
#include "reg51.h"
sfr P2M1=0x95; //因為reg51.h裡面沒有,所以自己定義
sfr P2M0=0x94;
float t1, t2;
float Rk=100; //K
float Rx;
extern unsigned int count;
sbit P2_5=P2^5;
sbit P2_6=P2^6;
sbit P2_7=P2^7;

 void delay(unsigned int x)
 {
 	while(x)   
	{
		x--;
	}	
 }

void p25_ppout() //將P2.5配置成推輓輸出
{
	P2M1&=~(1<<5);
	P2M0|=(1<<5);
}

void p25_odin() //將P2.5配置成僅輸入高阻
{
	P2M1|=(1<<5);
	P2M0&=~(1<<5);
}

void p26_ppout() //將P2.6配置成推輓輸出
{
	P2M1&=~(1<<6);
	P2M0|=(1<<6);
}

void p26_odin() //將P2.6配置成僅輸入高阻
{
	P2M1|=(1<<6);
	P2M0&=~(1<<6);
}

void p27_ppout() //將P2.7配置成推輓輸出
{
	P2M1&=~(1<<7);
	P2M0|=(1<<7);
}

void p27_odin() //將P2.7配置成僅輸入高阻
{
	P2M1|=(1<<7);
	P2M0&=~(1<<7);
}

void res_test()
{
	p25_odin(); p26_odin(); p27_ppout(); P2_7=0;  //C1放電
	delay(65000);
	delay(65000);
	p27_odin(); //放電完成

	p25_ppout(); P2_5=1;//P2.5通過Rk對電容C1充電
	TR0=1;	    //開啟定時器0
	while(P2_7==0);//等待充電到P2.7口為高電平
	TR0=0;	     //關閉定時器0
	p25_odin();

	t1=TH0*256+TL0;
	TH0=0;
	TL0=0;

	p25_odin(); p26_odin(); p27_ppout();P2_7=0;	 //C1放電
	delay(65000);
	delay(65000);
	p27_odin(); //放電完成

	p26_ppout();P2_6=1;
	TR0=1;	    //開啟定時器0
	while(P2_7==0);//等待充電到P2.7口為高電平
	TR0=0;	     //關閉定時器0
	p26_odin();

	t2=TH0*256+TL0;

	Rx=t2*Rk/t1;
	count = (unsigned int) Rx;
}

實驗一、電子鐘

main.c檔案

#include "reg51.h"
/*實時時鐘 RTC*/
char RTC[3] = {12,34,56};
extern void load_smg();
unsigned int ms1;

void Timer1_Init()
{
	TMOD|=0x10;
	TH1=64614/256;
	TL1=64614%256;
	TR1=1;
}

void Isr_Init()
{
	EA=1;
	ET1=1;
}
void Run_clock()
{
 	RTC[2]++;
	if(RTC[2]>=60)
	{
		RTC[2]=0;
		RTC[1]++;
		if(RTC[1]>=60)
		{
			RTC[1]=0;
		    RTC[0]++;
			if(RTC[0]>=24)
			{
				RTC[0]=0;
			    	
			}	
		}
	}
}
void TF1_isr() interrupt 3		//1ms
{
 	static int ms;
	TH1=64614/256;
	TL1=64614%256;
	ms++;
	ms1++;
	if(ms1>=1000)
	{
		ms1=0;
	}
	if(ms>=1000)   //1 sec
	{
		ms=0;
		Run_clock();	
		
	}
	load_smg();

}
void main()
{
	Timer1_Init();
	Isr_Init();
	while(1)
	{

	}
}
smg.c檔案
 #include "reg51.h" 
  //char seg[10]={0xC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90};
 code char seg[10]={0xC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90};
 char smgbuf[4]={1,2,3,4}; //從RAM的smgbuf這個地址開始連續存放4個數,並且每個數佔一個單元。
// extern unsigned int count;	//外部申明,表示並不在這裡申明
 extern char RTC[3];
 extern void delay(unsigned int x);
 extern unsigned int ms1;

void fill_smgbuf() //向LED緩衝區填充資料
{
	smgbuf[0]=RTC[1]/10;  //分鐘十位
	smgbuf[1]=RTC[1]%10;  //分鐘個位
	smgbuf[2]=RTC[2]/10;   //秒鐘十位
	smgbuf[3]=RTC[2]%10;   //秒鐘個位
}

void load_smg()   //將數碼管顯示緩衝區的資料,顯示到數碼管上
 {
 	static char i;
	fill_smgbuf();

 	for(i=0;i<4;i++)	
	{
		P0=0xFF;   //消除上一個迴圈的影子
		if(ms1<500)
		{
		   P0 = seg[smgbuf[i]]&0x7F;
		}
		else
		{
		   //P0=0xff;	//整體閃爍
		   P0 = seg[smgbuf[i]];	 //實現分鐘與秒鐘之間的 :閃爍
		}
		
		P2 = ~(1<<i);
		delay(200);
	} 
 }
void delay(unsigned int x)
 {
	   while(x--);
 }

實驗二、產生一個週期周20ms,脈寬1-19ms可變的PWM波,脈寬可以用按鍵選擇,輸出的PWM波去點亮一個led燈,並用示波器觀察效果。

main.c

#include "reg51.h"
/*用定時器1產生週期為20ms,脈寬為1-19ms*/
sbit out=P1^0; //PWM output pin
unsigned int ms;
unsigned int pwm=10;
extern void key3();

void Timer1_Init()
{
	TMOD|=0x10;
	TH1=64614/256;
	TL1=64614%256;
	TR1=1;
}

void Isr_Init()
{
	EA=1;
	ET1=1;
}

void TF1_isr() interrupt 3		//1ms
{
 	TH1=64614/256;
	TL1=64614%256;
	ms++;
	if(ms>=20)
	{
		ms=0;
	}
	//...ms=0-19
	if(ms<pwm)
	{
		out=1;
	}
	else
	{
		out=0;
	}
}
void main()
{
	Timer1_Init();
	Isr_Init();
	while(1)
	{

	    key3();
	}
}
key.c
 #include "reg51.h"
 extern unsigned int pwm;
 sbit K3=P2^6;

  void delay(unsigned int x)
 {
	   while(x--);
 }

 void key3()
 {
 	static char st;
	if(K3==0)
	{
		 if(st==0)
		 {
		 	delay(5000);
			if(K3==0)
			{
				st=1;
				pwm++;
				if(pwm>=20)
				{
					pwm=1;
				}
			}

		 }
	}
	else
	{
		st=0;
	}
 }