承接上一节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文件
void delay(unsigned int x)#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); } }
{ while(x--); }
实验二、产生一个周期周20ms,脉宽1-19ms可变的PWM波,脉宽可以用按键选择,输出的PWM波去点亮一个led灯,并用示波器观察效果。
main.c
key.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(); } }
#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; } }