微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > MCU和单片机设计讨论 > 用89C51定时器做了LCD时钟,走慢,请教,校准方法。

用89C51定时器做了LCD时钟,走慢,请教,校准方法。

时间:10-02 整理:3721RD 点击:
/*******************************************************************************
* 实验名                 : 定时器实验
* 使用的IO             :
* 实验效果       :1602显示时钟,按K3进入时钟设置,按K1选择设置的时分秒,按K2选择
*选择设置加1。
*        注意                 :主程序在不停地判断,是否需要调整设置时间,执行效率低。
*******************************************************************************/
#include<reg51.h>        
#include"lcd.h"
sbit K1=P3^0;
sbit K2=P3^1;
sbit K3=P3^2;
void Delay1ms(unsigned int c);
void TimerConfiguration();
void Int0Configuration();
unsigned char Time;                        //用来计时间的值
unsigned char SetPlace;                //设置修改位
/*******************************************************************************
* 函 数 名         : main
* 函数功能                   : 主函数
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void main(void)
{
        unsigned char hour=10,minute=59,second=57;
        unsigned char H2[]="by Chen Shao ze ";                           //可以改成任意16个字符。
        unsigned int i;
        TimerConfiguration();
        Int0Configuration();
        LcdInit();
        LcdWriteCom(0x84);
        LcdWriteData('0'+hour/10);
        LcdWriteData('0'+hour%10);
        LcdWriteData(':');
        LcdWriteData('0'+minute/10);
        LcdWriteData('0'+minute%10);
        LcdWriteData(':');
        LcdWriteData('0'+second/10);
        LcdWriteData('0'+second%10);
        LcdWriteCom(0xc0);
        for(i=0;i<16;i++)                                  //第2行显示的字符
        {   
                LcdWriteData(H2);                 
        }
        while(1)
        {
                if(TR0==0)
                {        if(K1==0)                        //检测按键K1是否按下
                        {
                                Delay1ms(10);        //消除抖动
                                if(K1==0)
                                {  
                                        SetPlace++;
                                        Delay1ms(100);
                                        if(SetPlace>=3)
                                                SetPlace=0;                                       
                                }
                                while((i<50)&&(K1==0))         //检测按键K1是否松开
                                {
                                        Delay1ms(1);
                                        i++;
                                }
                                i=0;                        
                        }
                        switch(SetPlace)
                                {case 0 :
                                        {LcdWriteCom(0x8b);                   //定位置
                                         LcdWriteCom(0x0f);
                                         Delay1ms(100);
                                         if(K2==0)                //检测按键K2是否按下
                                                {
                                                Delay1ms(10);        //消除抖动
                                                if(K2==0)
                                                        {
                                                        second++;
                                                        Delay1ms(100);
                                                        if(second>=60)
                                                        second=0;
                                
                                                        }
                                                }
                                         LcdWriteCom(0x8a);                   //定位置
                                         LcdWriteData('0'+second/10);
                                         LcdWriteData('0'+second%10);
                                         LcdWriteCom(0x8b);
                                         }break;
                                case 1 :
                                        {LcdWriteCom(0x88);                   //定位置
                                         LcdWriteCom(0x0f);
                                         Delay1ms(100);
                                         if(K2==0)                //检测按键K2是否按下
                                                {
                                                Delay1ms(10);        //消除抖动
                                                if(K2==0)
                                                        {
                                                        minute++;
                                                        Delay1ms(100);
                                                        if(minute>=60)
                                                        minute=0;
                                
                                                        }
                                                }
                                         LcdWriteCom(0x87);                   //定位置
                                         LcdWriteData('0'+minute/10);
                                         LcdWriteData('0'+minute%10);
                                         LcdWriteCom(0x88);
                                         }break;
                                case 2 :
                                        {LcdWriteCom(0x85);                   //定位置
                                         LcdWriteCom(0x0f);
                                         Delay1ms(100);
                                         if(K2==0)                //检测按键K2是否按下
                                                {
                                                Delay1ms(10);        //消除抖动
                                                if(K2==0)
                                                        {
                                                        hour++;
                                                        Delay1ms(100);
                                                        if(hour>=24)
                                                        hour=0;
                                
                                                        }
                                                }
                                         LcdWriteCom(0x84);                   //定位置
                                         LcdWriteData('0'+hour/10);
                                         LcdWriteData('0'+hour%10);
                                         LcdWriteCom(0x85);
                                         }break;
                                }   
                }        
               
                else
                {
                LcdWriteCom(0x0c);         
                if(Time>=20)         //一秒钟来到改变数值
                {
                        Time=0;
                        second++;
                        if(second==60)
                        {
                                second=0;
                                minute++;
                                if(minute==60)
                                {
                                        minute=0;
                                        hour++;
                                        if(hour==24)
                                        {
                                                hour=0;        
                                        }
                                }                                
                        }                                       
                }        
            //--显示时钟--//
                LcdWriteCom(0x84);
                LcdWriteData('0'+hour/10);
                LcdWriteData('0'+hour%10);
                LcdWriteData(':');
                LcdWriteData('0'+minute/10);
                LcdWriteData('0'+minute%10);
                LcdWriteData(':');
                LcdWriteData('0'+second/10);
                LcdWriteData('0'+second%10);
                }
        }                                
}
/*******************************************************************************
* 函 数 名       : Delay1ms()
* 函数功能                 : 延时1ms
* 输    入       : c
* 输    出       : 无
*******************************************************************************/                  
void Delay1ms(unsigned int c)   //误差 0us
{
    unsigned char a,b;
        for (; c>0; c--)
        {
                for(b=199;b>0;b--)
                {
                        for(a=1;a>0;a--);
                }
        }
}
/*******************************************************************************
* 函 数 名         : TimerConfiguration()
* 函数功能                   : 配置定时器值
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/                  
void TimerConfiguration()
{
    TMOD = 0x01;         //选择工作方式1
    TH0 = 0x3D;                 //设置初始值         50ms
    TL0 = 0x5E;
    EA = 1;                         //打开总中断
    ET0 = 1;                 //打开定时器0中断
    TR0 = 1;                 //启动定时器0
}
/*******************************************************************************
* 函 数 名         : Timer0()
* 函数功能                   : 定时器0中断函数
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/                  
void Timer0() interrupt 1
{
    TH0 = 0x3D;                 //设置初始值         50ms
    TL0 = 0x5E;
        Time++;
}
/*******************************************************************************
* 函 数 名         : Int0Configuration()
* 函数功能                   : 配置外部中断0
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/                  
void Int0Configuration()
{
        //设置INT0
        IT0=1;//跳变沿出发方式(下降沿)
        EX0=1;//打开INT0的中断允许。
        EA=1;//打开总中断        
}
/*******************************************************************************
* 函 数 名         : Int0() interrupt 0
* 函数功能                   : 外部中断0的中断函数
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/                  
void Int0() interrupt 0                 
{
        Delay1ms(10);
        if(K3==0)
        {
                TR0=~TR0;
                SetPlace=1;
        }
}


26分钟,走慢了87秒,平均慢 3.34秒/分钟。
如果缩短定时器,计数,是否可以,走快点。应该缩短多少 ,有没有快捷地校准方法,只能一次一次测试吗?

根据经验,如果不采用专用时钟芯片做电子钟:
1.要采用优质晶振外部时钟,不要用内部时钟。
2.定时器要设置为自动重载方式,否则重装初值要消耗时间。
3.定时中断周期要短(<1ms),便于调整精度。

给你一个程序参考,端口定义根据实际电路调整
/*******************************
描述:LCD万年历,TX-1C实验板
STC89C52RC,晶振11.0592MHz
(如果晶振12MHz时间更准些)
********************************/
#include<reg52.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit LCD_EN=P3^4;                                 //定义1602液晶LCDEN端,使能信号
sbit LCD_RS=P3^5;                                 //定义1602液晶RS端,数据/命令选择端(H/L)
//sbit LCD_RW=P3^6;                         //定义1602液晶RW端,读/写选择端(H/L)已接地禁止读
sbit BUZZ=P2^3;                                 //定义蜂鸣器端,按键释放和整点响
sbit dula=P2^6;                                //段端口
sbit wela=P2^7;                                //位端口
sbit key_1=P3^0;                                //进入调试方式
sbit key_2=P3^1;                                //调试+
sbit key_3=P3^2;                                //调试-
sbit key_4=P3^3;                                //退出调试方式
sbit MND_1=P3^7;                                //矩阵键盘模拟地
uchar code keycode[] = {0x11,0x12,0x14,0x18,0x21,0x22,0x24,0x28,//按键键值
                        0x41,0x42,0x44,0x48,0x81,0x82,0x84,0x88};
uchar yue,ri,shi,fen,miao,week,nian;         //月、日、时、分、秒、周、年变量
uchar flag=0;        //功能键计数变量
uint count=0;        //中断计数变量
bit Cnt1s=0;        //秒标志
uchar code table[7][3]={"MON","TUE","WED","THU","FRI","SAT","SUN"};//显示周
/***********毫秒级延时函数**********/
void delay(uint x)
{
        uint y,z;
        for(y=x;y>0;y--)
                for(z=110;z>0;z--);
}
/***********蜂鸣器发声函数**********/
void di(uint dd)
{
        BUZZ=0;
        delay(dd);
        BUZZ=1;
}
/***********LCD1602忙等待**********/
/*
uchar busycheck()
{
        uchar s;                        //临时变量
        LCD_RS=0;                //允许写指令
//        LCD_RW=1;                //允许读数据(读写端已接地,禁止读)
        LCD_EN=1;                //高电平使能读数据
        delay(1);                //延时
        s=P0;                                //读P0数据赋值s
        LCD_EN=0;                //低跳变执行
        return s;                //返回s值 s=0x80有效
}
*/
/***********液晶写指令函数**********/
void write_com(uchar com)
{
//        while((busycheck()&0x80)==0x80);//忙等待
        LCD_RS=0;        //允许写指令
//        LCD_RW=0;        //读写端已接地,禁止读
        LCD_EN=0;        //初始设置LCD_EN低电平
        P0=com;                //传递指令
        delay(5);        //延时
        LCD_EN=1;        //使能写入
        delay(5);        //延时
        LCD_EN=0;        //低跳变执行
}
/***********液晶写数据函数**********/
void write_date(uchar date)
{
//        while((busycheck()&0x80)==0x80);//忙等待
        LCD_RS=1;        //允许写数据
//        LCD_RW=0;        //读写端已接地,禁止读
        LCD_EN=0;        //初始设置LCD_EN低电平
        P0 =date;        //传递数据
        delay(5);        //延时
        LCD_EN=1;        //使能写入
        delay(5);        //延时
        LCD_EN=0;        //低跳变执行
}
/***********写年函数**********/
void write_nian(uchar add,uchar date)reentrant  //reentrant定义为可重入函数,允许被递归调用
{
        uint bai,shi,ge;                //定义百、十、个变量
        bai=date/100;                        //分解百
        shi=date%100/10;                //分解十
        ge=date%100%10;                //分解个
        write_com(0x80+add); //写指令、设置显示位置
        write_date(0x30+bai);//写数据百位0~9对应的字符码是0x30~0x39
        write_date(0x30+shi);//写数据十位
        write_date(0x30+ge); //写数据个位
        /*write_date(dat[bai]);
        write_date(dat[shi]);
        write_date(dat[ge]);*/
}
/***********大小月份设置**********/
uchar dxy(uchar r)
{
        uchar k;
        switch(r)
        {
                case 1:
                        k=31;
                break;
                case 2: //闰年29天, 平年28天
                if((2000+nian)%100==0)
                        if((2000+nian)%400==0)
                                k=29;
                        else
                                k=28;
                        else if((2000+nian)%4==0)
                                k=29;
                        else
                                k=28;
                break;
                case  3:k=31;break;
                case  4:k=30;break;
                case  5:k=31;break;
                case  6:k=30;break;
                case  7:k=31;break;
                case  8:k=31;break;
                case  9:k=30;break;
                case 10:k=31;break;
                case 11:k=30;break;
                case 12:k=31;break;
        }
        return k;
}
/***********写月、日、时、分、秒函数**********/
void write_yrsfm(uchar add,uchar date)
{
        uchar shi,ge;
        shi=date/10;
        ge=date%10;
        write_com(0x80+add); //设置显示位置
        write_date(0x30+shi);
        write_date(0x30+ge);
        /*write_date(dat[shi]);
        write_date(dat[ge]);*/
}
/***********写星期函数**********/
void write_week(uchar add,uchar date)
{
        uchar i;
        write_com(0x80+add); //设置显示位置
        for(i=0;i<3;i++)
        {
                write_date(table[date]);
                delay(5);
        }
}
/***********初始化函数**********/
void init()
{
        count=0;                         //
        dula=0;                                //关闭数码管段端口
        wela=0;                                //关闭数码管位端口
//        P0=0xff;                         //关闭发光二极管
        write_com(0x38); //设置16*2显示,5*7点阵,8位数据接口
        write_com(0x0c); //设置开显示,不显示光标
        write_com(0x06); //写一个字符后地址指针加1
        write_com(0x01); //显示清零,数据指针清零
        write_com(0x80); //设置显示初始位置
        write_com(0x80+1); //写出年份的最高位“2”
        write_date('2');         //写数据'2'
        write_com(0x80+5); //写指令,显示位置 日期显示部分的的两'-'
        write_date('-');         //写数据'-'
        write_com(0x80+8); //写指令,显示位置 日期显示部分的的两'-'
        write_date('-');          //写数据'-'
        write_com(0x80+0x40+6); //写指令,时间显示部分的的两个“:”
        write_date(':');                //写数据':'
        write_com(0x80+0x40+9); //写指令,时间显示部分的的两个“:”
        write_date(':');                                //写数据':'
        miao=0;                                                        //秒
        fen=0;                                                        //分
        shi=0;                                                        //时
        week=4;                                                //星期
        ri=19;                                      //日
        yue=5;                                      //月
        nian=17;                                              //年
        write_yrsfm(0x40+10,miao);        //写入秒
        write_yrsfm(0x40+7,fen);        //写入分
        write_yrsfm(0x40+4,shi);        //写入时
        write_week(12,week);                   //写入星期
        write_yrsfm(9,ri);                        //写入日
        write_yrsfm(6,yue);                        //写入月
        write_nian(2,nian);                        //写入年
}
/***********按键扫描函数**********/
void keyscan()
{
        if(key_1==0) //功能键按下
        {
                delay(10); //消抖
                if(key_1==0)//功能键确认按下
                {
                        flag++; //记录功能键按下次数
                        while(!key_1); //确认释放功能键
                        di(100); //每当有按键释放蜂鸣器发出滴声提醒
                        if((flag==1)||(flag==8)) //第一次按下功能键光标闪烁到秒位置
                        {
                                TR0=0; //关闭定时器
                                write_com(0x80+0x40+11); //光标定位到秒位置
                                write_com(0x0f); //光标开始闪烁
                        }
                        if(flag==2) //第二次按下功能键光标闪烁到分钟位置
                        {
                                write_com(0x80+0x40+8);
                        }
                        if(flag==3) //第三次按下功能键光标闪烁到时位置
                        {
                                write_com(0x80+0x40+5);
                        }
                        if(flag==4) //第四次按下功能键光标闪烁到星期位置
                        {
                                write_com(0x80+12);
                        }
                        if(flag==5) //第五次按下功能键光标闪烁到日位置
                        {
                                write_com(0x80+10);
                        }
                        if(flag==6) //第六次按下功能键光标闪烁到月位置
                        {
                                write_com(0x80+7);
                        }
                        if(flag==7) //第七次按下功能键光标闪烁到年位置
                        {
                                write_com(0x80+4);
                        }
                        if(flag==8) //第八次按下功能键退出功能键
                                flag=1; //记录变成1;光标重新回到秒位置
                }
        }
        if(key_4==0) //退出调节
        {
                delay(10);
                if(key_4==0)
                {
                        while(!key_4); //释放按键
                        if(TR0==0)
                        di(100); //只在调节时有按键释放蜂鸣器发出滴声
                        flag=0; //功能键按键次数清零
                        write_com(0x0c); //取消光标闪烁
                        count=0;
                        Cnt1s=0;
                        TR0=1; //启动定时器
                }
        }
        if(flag!=0) //功能键按下后flag=1
        {  //增大键
                if(key_2==0) //只有功能键按下后,增大和减少键才有效
                {
                        delay(10);
                        if(key_2==0)//确认增加按下
                        {
                                while(!key_2); //释放按键
                                di(100); //每当有按键释放蜂鸣器发出滴声提醒
                                if(flag==1) //功能键第一次按下调节秒
                                {
                                        miao++; //秒加1
                                        if(miao>59)
                                                miao=0;
                                        write_yrsfm(0x40+10,miao); //每调节一次送液晶显示一下
                                        write_com(0x80+0x40+11); //显示位置重新回到调节处
                                }
                                if(flag==2) //功能键第二次按下调节分
                                {
                                        fen++;
                                        if(fen>59)
                                                fen=0;
                                        write_yrsfm(0x40+7,fen);
                                        write_com(0x80+0x40+8);
                                }
                                if(flag==3) //功能键第三次按下调节时
                                {
                                        shi++;
                                        if(shi>23)
                                                shi=0;
                                        write_yrsfm(0x40+4,shi);
                                        write_com(0x80+0x40+5);
                                }
                                if(flag==4)    //功能键第四次按下调节星期
                                {
                                        week++;
                                        if(week>6)
                                                week=0;
                                        write_week(12,week);
                                        write_com(0x80+12);
                                }
                                if(flag==5) //功能键第五次按下调节日
                                {
                                        ri++;
                                        if(ri>(dxy(yue)))
                                                ri=1;
                                        write_yrsfm(9,ri);
                                        write_com(0x80+10);
             

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top