51微控制器定時器的原理與使用(二)
阿新 • • 發佈:2019-02-05
承接上一節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檔案
smg.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) { } }
#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;
}
}