×
单片机 > 单片机程序设计 > 详情

【C51】源码 3 -- 电子时钟(独立按键、8 位数码管、定时器)

发布时间:2020-06-09 发布时间:
|
自购自学单片机有一段日子了,300 多页的 pdf 教程看到一半了,正好看完定时器和独立按键部分,综合前边的数码管,试着编写了“电子时钟”,将源码发上来,用于备份……

注:由于使用了中断以及各种延时程序,此程序并不是真正准确的“电子时钟”,想要真正准确,需要特别的外部模块,如时钟芯片 DS1302。

 

附上源码:(初出茅庐,难免有写的不好的地方,仅作备份之用,欢迎指点,喷子退散……)

/**********************************************************************************
                                         电子时钟

1、初始从 00-00-00 时刻开始显示
2、按 Pause 键暂停,此时可以通过三个按键调节时间
3、再按 Pause 键恢复工作

缺陷:

1、按键过程中,有瞬间闪烁
2、再次按 Pause 开始时,会等待一会儿,电子时钟才会工作
***********************************************************************************/

#include 

#define DATA P1     // 数码管数据传输口

sbit SEG = P0^0;     // 段码输入
sbit BIT = P0^2;       // 位码输入

sbit KEY_PAUSE = P2^0;      // 暂停 / 开始 按键
sbit KEY_H_UP = P2^2;        // 小时调节 按键
sbit KEY_M_UP = P2^4;       // 分钟调节 按键
sbit KEY_S_UP = P2^6;        // 秒调节 按键

unsigned char code SEG_CODE[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x40};
unsigned char code BIT_CODE[] = {0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f};

// 上面是段码表,0-9,还有一个 “-” 符号
// 下面是位码表,指示哪一位显示字符

unsigned char timer0_count;                      // 定时器 50ms 一个中断,计 20 次为 1s
unsigned char H1, H0, M1, M0, S1, S0;       // 电子时钟显示数字 HH-MM-SS

void Delay(unsigned int t);             // 普通延迟函数
void Delay_ms(unsigned int t);      // ms 延迟函数
void Init_Key(void);               // 初始化按键
void Init_Clock(void);            // 初始化电子时钟显示
void Init_Timer0(void);          // 初始化定时器
void Display(unsigned char x, unsigned char num);       // 在 x 位置,显示数字 num
void Display_Clock(void);           // 显示电子时钟

void main (void)
{
    Init_Key();
    Init_Clock();
    Init_Timer0();

    while (1) {

        Display_Clock();        // 在大循环中显示时钟,形成动态扫描

        if (timer0_count == 20) {        // 定时器中断了 20 次,即 1s,开始对显示进行处理
            timer0_count = 0;
            S0 += 1;
            if (S0 == 10) {         // 以下保证了秒:0-59,分钟:0-59,小时:0-23
                S0 = 0;
                S1 += 1;
            }
            if (S1 == 6) {
                S1 = 0;
                M0 +=1;
            }
            if (M0 == 10) {
                M0 = 0;
                M1 += 1;
            }
            if (M1 == 6) {
                M1 = 0;
                H0 += 1;
            }
            if (H0 == 10 && (H1 == 0 || H1 == 1)) {
                H0 = 0;
                H1 += 1;
            }
            else if (H0 == 4 && H1 == 2) {
                H0 = 0;
                H1 = 0;
            }
        }

        if (!KEY_PAUSE) {            // 检测 暂停键 是否按下
            Delay_ms(10);              // 延迟 10ms,消除按键抖动,后边同理
            if (!KEY_PAUSE) {        // 在延迟之后,还能检测到按键,说明真的是按键
                while (!KEY_PAUSE) Display_Clock();       // 如果按住按键不放,就保持时钟显示状态

                while (KEY_PAUSE) {       // 按键终于放开了,处理按键的行为

                    Display_Clock();           // 在此期间,要保持时钟一直动态显示

                    if (!KEY_H_UP) {           // 在暂停期间,检测到了 小时调节 操作,处理显示
                        Delay_ms(10);
                        if (!KEY_H_UP) {
                            while (!KEY_H_UP) Display_Clock();
                            H0 += 1;
                            if (H0 == 10 && (H1 == 0 || H1 == 1)) {
                                H0 = 0;
                                H1 += 1;
                            }
                            else if (H0 == 4 && H1 == 2) {
                                H0 = 0;
                                H1 = 0;
                            }
                        }
                    }

                    if (!KEY_M_UP) {           // 在暂停期间,检测到了 分钟调节 操作,处理显示
                        Delay_ms(10);
                        if (!KEY_M_UP) {
                            while (!KEY_M_UP) Display_Clock();
                            M0 += 1;
                            if (M0 == 10) {
                                M0 = 0;
                                M1 += 1;
                            }
                            if (M1 == 6) M1 = 0;
                        }
                    }

                    if (!KEY_S_UP) {           // 在暂停期间,检测到了 秒调节 操作,处理显示
                        Delay_ms(10);
                        if (!KEY_S_UP) {
                            while (!KEY_S_UP) Display_Clock();
                            S0 += 1;
                            if (S0 == 10) {
                                S0 = 0;
                                S1 += 1;
                            }
                            if (S1 == 6) S1 = 0;
                        }
                    }
                }

                if (!KEY_PAUSE) {           // 再次按下 暂停 按键,恢复工作
                    Delay_ms(10);
                    if (!KEY_PAUSE) {
                        while (!KEY_PAUSE) Display_Clock();
                    }
                }
            }
        }
    }
}

void Delay(unsigned int t)
{
    while (t--);
}

void Delay_ms(unsigned int t)       // 根据测试,可以相当近似的表示 1ms
{
    while (t--) {
        Delay(245);
        Delay(245);
    }
}

void Init_Key(void)
{
    KEY_PAUSE = 1;          // 赋值高电平为 按键断开 状态
    KEY_H_UP = 1;
    KEY_M_UP = 1;
    KEY_S_UP = 1;
}

void Init_Clock(void)      // 初始时钟显示为 00-00-00
{
    H1 = 0;
    H0 = 0;
    M1 = 0;
    M0 = 0;
    S1 = 0;
    S0 = 0;
}

void Init_Timer0(void)
{
    TMOD = 0x01;                       // 使用定时器 0,模式 1
    EA = 1;                                   // 开总中断
    ET0 = 1;                                 // 开定时器 0 中断
    TH0 = (65536-50000)/256;    // 定时器 0 赋值,定时 50ms
    TL0 = (65536-50000)%256;
    TR0 = 1;                                 // 定时器 0 开始工作

    timer0_count = 0;                // 计中断个数,目标 20
}

/*************************************************************************************************
当定时器 0 定时完毕,进入此中断过程,后边的 1 代表定时器 0 的中断
*************************************************************************************************/

void Timer0_ISR(void) interrupt 1
{
    TH0 = (65536-50000)/256;
    TL0 = (65536-50000)%256;

    timer0_count++;
}

void Display(unsigned char x, unsigned char num)
{
    SEG = 1;                                    // 关锁存器
    DATA = SEG_CODE[num];       // 送段码
    SEG = 0;                                    // 开锁存器

    BIT = 1;                                      // 关锁存器
    DATA = BIT_CODE[x-1];           // 送位码
    BIT = 0;                                      // 开锁存器

    Delay(200);                               // 延时,形成动态显示,200 正好,过大闪烁,过小重影
}

void Display_Clock(void)
{
    Display(1, H1);         // 在 1、2 位置显示 小时
    Display(2, H0);
    Display(3, 10);
    Display(4, M1);        // 在 4、5 位置显示 分钟
    Display(5, M0);
    Display(6, 10);
    Display(7, S1);         // 在 7、8 位置显示 秒,其他位置显示 “-”
    Display(8, S0);
}

关键字:C51  电子时钟  独立按键  数码管  定时器 

『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
C51 特殊功能寄存器SFR的名称和地址