zhliao2

风雨兼程,一路向北-------fpga (Keep a quiet heart study)
数字时钟(数码管显示/键盘可调)

有关的硬件原理图:

c程序:

//温馨提示:

/*程序还没有调试完成,实际电路板调节时间时时-分-秒都会有闪烁现象,其实我是不知道的,why,也求解释


#include<reg52.h>         //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
#include<intrins.h>      //与_nop_有关

sbit duan=P2^2;          //定义锁存使能端口 段锁存
sbit wei=P2^3;          //   位锁存
sbit key1 = P1^1;
sbit key2 = P1^2;
sbit key3 = P1^3;
sbit key4 = P1^4;

unsigned char code duanma[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};      // 显示段码值0~9
unsigned char code weima[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};                  //分别对应相应的数码管点亮,即位码
unsigned char temp[8];                                                                //存储显示值的全局变量
char hour; minute; second, num, t, i;


//函数声明
void delay(unsigned int t);
void initial();
void delay20ms();
void keyscan();
void caifen();
void display();


/*------------------------------------------------
                    主函数
------------------------------------------------*/
void main()
{
    initial();                            //调用初始化程序
    
      while(1)
      {
        
        keyscan();                           //调用键盘扫描
        caifen();                           //调用拆分以时-分-秒的形式
        display();                         //调用时间的显示程序
      }        
}

//初始化程序
void initial()
{
    TMOD = 0x01;                               //设置T1工作于定时方式1(有16位计数)
    TH0 = (65536 - 2000)/256;                  //定时器1赋初值,是TH1而不是TH0噢(若要设置是定时器0的话,把1改为0,下同);计数了2000次,即为2ms
    TL0 = (65536 - 2000)%256;
    EA = 1;                                   //开中断                                    
    TR0 = 1;                                  //开定时器0
    ET0 = 1;                                  //开启定时器中断0        
    hour = 23;                                //赋初值
    minute = 59;                             //赋初值
    second = 57;                             //赋初值
}



//中断服务程序
void time0(void) interrupt 1
{
    TH0 = (65536 - 2000)/256;              //重新赋值
    TL0 = (65536 - 2000)%256;

    num ++;                               //中断500次后 即2ms X 500 = 1000MS = 1S,(一般可计数久点如50000ms,中断20次,这样误差就不会太大)
    if (num == 500)
    {
        num = 0;
        second ++;
        if (second == 60)                //秒为60则miao置0,minute加一
        {
            second = 0;
            minute ++;
            if (minute == 60)           //分为60则minute置0,hour加一
            {
                
               
                minute = 0;
                hour ++;
                if (hour == 24)      //小时为24则hour置0
                {
                    hour = 0;
                }
            }
        }
    }
                
}     


//键盘扫描程序,可执行时分的加减
void keyscan()
{
        if(key1 == 0)
        {
            delay20ms();                    //延时20ms,去抖动
            while(key1 == 0);              //等待(上升沿则执行下一行,TRO = 0)                        
                TR0 = 0;                  //关定时器0
                t ++;                    //t++与调节时分秒有关                            
        }
                   
        switch(t)                      //选择调节时分秒有关,与上面的t相关联
        {
            case 1:
            if(key2 == 0)
            {
                delay20ms();
                if(key2 == 0)
                {
                    while(key2 == 0);
                    hour ++;
                    if(hour == 24)
                    {
                        hour = 0;
                    }
                }
            }
            
            if(key3 == 0)
            {
                delay20ms();
                if(key3 == 0)
                {
                    while(key3 == 0);
                    hour --;
                    if(hour == -1)        //因为hour是char型,所以可以有负数,若是unsigned char则不允许,下面的minute同理
                    {
                        hour =23;
                    }
                }
            }

            break;

            case 2:
            
            if(key2 == 0)
            {
                delay20ms();
                if(key2 == 0)
                {
                    while(key2 == 0);
                    minute ++;
                    if(minute == 60)
                    {
                        minute = 0;
                    }
                }
            }
            if(key3 == 0)
            {
                delay20ms();
                if(key3 == 0)
                {
                    while(key3 == 0);
                    minute --;
                    if(minute == -1)
                    {
                        minute = 59;
                    }
                }
            }
            break;
            
            case 3:
            TR0 = 1;                          //当t为3时,则开定时器,重新开始计数,又因为执行了caifen();所以数码管显示时分秒是由我们调节的数
            t = 0; 
            break;
            
            default:                        //default必须加,要养成良好的编程风格
            break;                          //一般也是必须加的,详情请参考c语言书籍,以上所有的break同是
            
        }    
}


//数字拆分程序//数据的转换,因我们采用数码管0~9的显示,将数据分开
void caifen()
{
    
        
         temp[0]=duanma[hour/10]; //
         temp[1]=duanma[hour%10];
         temp[2]=0x40;                          //加入"-"
         temp[3]=duanma[minute/10];//
           temp[4]=duanma[minute%10];
         temp[5]=0x40;
         temp[6]=duanma[second/10];//
         temp[7]=duanma[second%10];        
}


//显示程序
void display()
{
    
        for (i = 0; i < 8; i ++)
        {
           wei=1;                                     //位锁存
               P0=weima[i];                           //取位码 
               wei=0;
    
              duan=1;                                 //段锁存 
              P0=temp[i];                             //取显示数据,段码
              duan=0;
                    delay(310);                       //具体最佳是多少不清楚,大家可自行修改,通过keil调试可具体知道执行时间是多少
        }
}


//延时20ms,使用单片机小精灵生成的
void delay20ms(void)   //误差 20us
{
    unsigned char a,b;
    for(b=215;b>0;b--)
        for(a=45;a>0;a--);
    _nop_;       //if Keil,require use intrins.h
    _nop_;       //if Keil,require use intrins.h
}



//延时
void delay(unsigned int i)
{
    while (i --);
}

 

 

posted on 2012-05-22 21:28  zhliao  阅读(3252)  评论(1)    收藏  举报