怎样89c51单片机定时器的精度?
时间:10-02
整理:3721RD
点击:
这是我自己按照郭天祥视频第九节的课后作业编的程序,放掉电的计时器。
#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
uchar code table[]={0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71}; //共阴数码管表
uchar date,sec,save,time0;
sbit sda=P2^0;
sbit scl=P2^1;
sbit dula=P2^6;
sbit wela=P2^7;
void somenop()//小延时
{ ; ; }
void delay(uint z)//ms延时
{
uint x,y;
for(x=0;x<110;x++)
for(y=0;y<z;y++);
}
void display(uchar x)//数码管显示
{
dula=1;
P0=table[x/10];
dula=0;
P0=0xff;
wela=1;
P0=0xfe;
wela=0;
P0=0x00;
delay(1);
dula=1;
P0=table[x%10];
dula=0;
P0=0xff;
wela=1;
P0=0xfd;
wela=0;
P0=0x00;
delay(1);
}
void I2Cstart() //起始信号
{
sda=1;
somenop();
scl=1;
somenop();
sda=0;
somenop();
}
void I2Cstop() //终止信号
{
sda=0;
somenop();
scl=1;
somenop();
sda=1;
somenop();
}
void I2Cresponse() //应答信号
{
uchar i;
scl=1;
somenop();
while((sda==1)&&(i<250))i++;
scl=0;
somenop();
}
void write_byte(uchar date) //写数据
{
uchar i,j;
j=date;
scl=0;
somenop();
for(i=0;i<8;i++)
{
j=j<<1;
sda=CY;
somenop();
scl=1;
somenop();
scl=0;
somenop();
}
sda=1;
somenop();
}
uchar read_byte() //读数据
{
uchar i,j,k;
scl=0;
somenop();
sda=1;
somenop();
for(i=0;i<8;i++)
{
scl=1;
somenop();
j=sda;
k=(k<<1)|j;
scl=0;
somenop();
}
return k;
}
void write_add(uchar x,uchar y) //地址,写入
{
I2Cstart(); //开始
write_byte(0xa0); //器件地址 写入
I2Cresponse();
write_byte(x); //写入地址
I2Cresponse();
write_byte(y);
I2Cresponse(); //写入数据
I2Cstop(); //结束
}
void read_add(uchar x)//地址 读出
{
I2Cstart(); //开始
write_byte(0xa0); //器件地址 写入
I2Cresponse();
write_byte(x); //写入地址
I2Cresponse();
I2Cstart(); //开始
write_byte(0xa1); //器件地址 读出
I2Cresponse();
date=read_byte();
I2Cstop();
}
void init() //初始化
{
time0=0;
sec=0;
read_add(0x06);
sec=date;
sda=1;
scl=1;
EA=1;
ET0=1;
TMOD=0x01;
TH0=0x4c;
TL0=0x00;
TR0=1;
}
void main()
{
init();
while(1)
{
display(sec);
if(save==1)
{
save=0;
write_add(0x06,sec);
}
}
}
void timer0() interrupt 1 //定时器
{
TH0=0x4c;
TL0=0x00;
time0++;
if(time0==20)
{
time0=0;
sec++;
save=1;
if(sec==100)
{
sec=0;
}
}
}
用proteus模拟后用秒表同步测量了下,发现每5分左右会有1秒的误差。求解答
#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
uchar code table[]={0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71}; //共阴数码管表
uchar date,sec,save,time0;
sbit sda=P2^0;
sbit scl=P2^1;
sbit dula=P2^6;
sbit wela=P2^7;
void somenop()//小延时
{ ; ; }
void delay(uint z)//ms延时
{
uint x,y;
for(x=0;x<110;x++)
for(y=0;y<z;y++);
}
void display(uchar x)//数码管显示
{
dula=1;
P0=table[x/10];
dula=0;
P0=0xff;
wela=1;
P0=0xfe;
wela=0;
P0=0x00;
delay(1);
dula=1;
P0=table[x%10];
dula=0;
P0=0xff;
wela=1;
P0=0xfd;
wela=0;
P0=0x00;
delay(1);
}
void I2Cstart() //起始信号
{
sda=1;
somenop();
scl=1;
somenop();
sda=0;
somenop();
}
void I2Cstop() //终止信号
{
sda=0;
somenop();
scl=1;
somenop();
sda=1;
somenop();
}
void I2Cresponse() //应答信号
{
uchar i;
scl=1;
somenop();
while((sda==1)&&(i<250))i++;
scl=0;
somenop();
}
void write_byte(uchar date) //写数据
{
uchar i,j;
j=date;
scl=0;
somenop();
for(i=0;i<8;i++)
{
j=j<<1;
sda=CY;
somenop();
scl=1;
somenop();
scl=0;
somenop();
}
sda=1;
somenop();
}
uchar read_byte() //读数据
{
uchar i,j,k;
scl=0;
somenop();
sda=1;
somenop();
for(i=0;i<8;i++)
{
scl=1;
somenop();
j=sda;
k=(k<<1)|j;
scl=0;
somenop();
}
return k;
}
void write_add(uchar x,uchar y) //地址,写入
{
I2Cstart(); //开始
write_byte(0xa0); //器件地址 写入
I2Cresponse();
write_byte(x); //写入地址
I2Cresponse();
write_byte(y);
I2Cresponse(); //写入数据
I2Cstop(); //结束
}
void read_add(uchar x)//地址 读出
{
I2Cstart(); //开始
write_byte(0xa0); //器件地址 写入
I2Cresponse();
write_byte(x); //写入地址
I2Cresponse();
I2Cstart(); //开始
write_byte(0xa1); //器件地址 读出
I2Cresponse();
date=read_byte();
I2Cstop();
}
void init() //初始化
{
time0=0;
sec=0;
read_add(0x06);
sec=date;
sda=1;
scl=1;
EA=1;
ET0=1;
TMOD=0x01;
TH0=0x4c;
TL0=0x00;
TR0=1;
}
void main()
{
init();
while(1)
{
display(sec);
if(save==1)
{
save=0;
write_add(0x06,sec);
}
}
}
void timer0() interrupt 1 //定时器
{
TH0=0x4c;
TL0=0x00;
time0++;
if(time0==20)
{
time0=0;
sec++;
save=1;
if(sec==100)
{
sec=0;
}
}
}
用proteus模拟后用秒表同步测量了下,发现每5分左右会有1秒的误差。求解答
自己看书!
不至于这么准确吧
问题在你定时初值重装这里。
TH0=0x4c;
TL0=0x00;
定时器中断发生时定时器的初值是0x0000,以后定时器会从0x0000继续计数,并且在ISR中时定时器也不停止;所以当程序执行到ISR里面的初值重装语句的时,TL0已经不是0了,而你又直接把TL0赋值成0。这个时候就会少几个计数。
定时中断频率越高,误差越大。
解决方法:ISR中的初值重装使用TL0 += 初值。当这个初值很大时,要稍微做下处理,以防止TL0溢出,丢失计数。
明白了 十分感谢~
学习 学习