承接上一節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;
}
}