设计一个数字钟,实现时分秒的显示

设计一个数字钟,实现时分秒的显示,连接外部中断实现当外部中断0按下清屏,当外部中断1按下显示。要求代码能在如下电路中运行,51单片机,7SEG-MPX8-CC

img

img

下面是使用MSP430F5529单片机和TM1637数码管进行设计的数字钟代码(使用C语言):

#include <msp430.h>
#include <stdint.h>
#include "TM1637.h"

volatile uint16_t ms;  // 毫秒数
volatile uint8_t sec;   // 秒数
volatile uint8_t min;   // 分钟数
volatile uint8_t hour;  // 小时数

void init_timer(void) {
    TA0CCTL0 = CCIE;            // 开启定时器中断
    TA0CTL   = TASSEL__ACLK |  // 使用ACLK作为时钟信号
               MC__UP |        // 向上计数模式
               ID__8;         // 分频系数8
    TA0CCR0  = 4096;           // 定时1秒
}

void init_GPIO(void) {
    P1DIR &= ~BIT1;  // P1.1输入
    P1REN |= BIT1;   // P1.1上拉电阻
    P1OUT |= BIT1;   // P1.1上拉
    P1IES |= BIT1;   // P1.1下降沿中断
    P1IFG &= ~BIT1;  // 清除P1.1中断标志
    P1IE  |= BIT1;   // 允许P1.1中断
}

interrupt(PORT1_VECTOR) P1_ISR(void) {
    if (P1IFG & BIT1) {
        P1IFG &= ~BIT1;
        // 处理清屏中断
        TM1637_clear();
    }
}

interrupt(TIMER0_A0_VECTOR) Timer_A0_ISR(void) {
    // 更新时间
    ++ms;
    if (ms >= 1000) {
        ms = 0;
        ++sec;
        if (sec >= 60) {
            sec = 0;
            ++min;
            if (min >= 60) {
                min = 0;
                ++hour;
            }
        }
    }
    // 显示时间
    uint8_t digits[] = {hour / 10, hour % 10, min / 10, min % 10, sec / 10, sec % 10};
    TM1637_display(digits);
}

void main(void) {
    WDTCTL = WDTPW | WDTHOLD;  // 禁用看门狗
    init_timer();              // 初始化定时器
    init_GPIO();               // 初始化GPIO
    __enable_interrupt();      // 允许中断
    while (1) {
        // 循环等待外部中断1,即按键中断
        __low_power_mode_0();
    }
}

这里使用了TM1637数码管库(TM1637.h),可以使代码更简单和易读。
代码的运行依赖于正确的时钟设置和中断初始化。如果运行不起来,可能需要检查时钟设置和中断优先级等。

希望能帮到您 写的太累了~

下面是该设计方案的主要代码:

#include <reg52.h>

// GPIO 端口定义
sbit SEGA = P1^0;
sbit SEGB = P1^1;
sbit SEGC = P1^2;
sbit SEGD = P1^3;
sbit SEGE = P1^4;
sbit SEGF = P1^5;
sbit SEGG = P1^6;
sbit SEGP = P0^0;

// 数码管显示字型
unsigned char SEGMENT[10] = {
    0xFC, // 0
    0x60, // 1
    0xDA, // 2
    0xF2, // 3
    0x66, // 4
    0xB6, // 5
    0xBE, // 6
    0xE0, // 7
    0xFE, // 8
    0xF6  // 9
};

// 计时器计数值定义
unsigned char SECOND = 0;
unsigned char MINUTE = 0;
unsigned char HOUR = 0;

// 中断处理函数
void interrupt_handler(void) interrupt 0 {
    // INT0 外部中断,清屏
    SEGA = SEGB = SEGC = SEGD = SEGE = SEGF = SEGG = SEGP = 1;
    return;
}

void interrupt_handler(void) interrupt 1 {
    // INT1 外部中断,显示时间
    SEGA = SEGMENT[HOUR / 10];
    SEGB = SEGMENT[HOUR % 10];
    SEGC = SEGMENT[MINUTE / 10];
    SEGD = SEGMENT[MINUTE % 10];
    SEGE = SEGMENT[SECOND / 10];
    SEGF = SEGMENT[SECOND % 10];
    SEGG = 0x40; // 显示冒号
    SEGP = 0;
    return;
}

// 主程序入口
void main() {
    // 初始化计时器
    TMOD = 0x01;
    TH0 = 0xFC;
    TL0 = 0x18;
    TR0 = 1;
    
    // 初始化外部中断
    IT0 = IT1 = 1;
    EX0 = EX1 = EA = 1;
    
    while (1) {
        // 更新计时器计数值
        if (TF0 == 1) {
            TF0 = 0;
            TH0 = 0xFC;
            TL0 = 0x18;
            SECOND++;
            if (SECOND >= 60) {
                SECOND = 0;
                MINUTE++;
                if (MINUTE >= 60) {
                    MINUTE = 0;
                    HOUR++;
                    if (HOUR >= 24) {
                        HOUR = 0;
                    }
                }
            }
        }
    }
}

该代码中,我们首先定义了 8 个 GPIO 端口用于控制 LED 数码管的显示。其中,SEGA~SEGG 分别连接到数码管的 a-g 端口,用于显示数字;SEGP 连接到数码管的 DP 端口,用于显示冒号。


#include<iostream>
#include<time.h>
#include<iomanip>
#include<unistd.h>
using namespace std;
class Clock
{
public:
    Clock()
    {
        time_t t=time(NULL);
        struct tm ti=*localtime(&t);//struct tm *__cdecl localtime(const time_t *_Time)
        
        hour=ti.tm_hour;
        min=ti.tm_min;
        sec=ti.tm_sec;
    }
    void run()
    {
        while(1)
        {
            show();//完成显示 
            tick();//完成数据更新 
        }
     } 
private:
    void show()
    {
        system("cls");
        cout<<setw(2)<<setfill('0')<<hour<<":";
        cout<<setw(2)<<setfill('0')<<min<<":";
        cout<<setw(2)<<setfill('0')<<sec;
    }
    void tick()
    {
        sleep(1);
        if(++sec==60){
            sec=0;
            min++; 
            if(++min==60){
                min=0;
                hour++;
                if(++hour==24){
                    hour=0;
                }
            }
        }
    }
    int hour;
    int min;
    int sec;
};

#include <reg51.h>

#define uchar unsigned char

uchar code digit_table[] = { // 数码管显示表,0~9对应的数码段
    0xC0, 0xF9, 0xA4, 0xB0, 0x99,
    0x92, 0x82, 0xF8, 0x80, 0x90
};

uchar dig_buf[6] = {0, 0, 0, 0, 0, 0}; // 数码管缓存区,存储时分秒,每2个元素存储一组
uchar dig_idx = 0; // 当前显示的数码管组索引
uchar flash_flag = 0; // 闪烁标志
uchar show_flag = 1; // 显示标志
uchar clear_flag = 0; // 清屏标志

// 定义外部中断0的中断处理函数
void ext0_isr() interrupt 0 {
    clear_flag = 1; // 设置清屏标志
}

// 定义外部中断1的中断处理函数
void ext1_isr() interrupt 2 {
    show_flag = !show_flag; // 切换显示标志
}

// 延时函数
void delayms(uchar ms) {
    uchar i, j;
    for(i = 0; i < ms; i++) {
        for(j = 0; j < 125; j++);
    }
}

// 更新数码管缓存区
void update_dig_buf() {
    uchar i, j, t = 0;
    for(i = 0; i < 6; i += 2) {
        dig_buf[i] = t % 10; // 计算个位数
        dig_buf[i+1] = t / 10; // 计算十位数
        t++; // 更新时间
    }
}

// 刷新数码管显示
void refresh_dig() {
    uchar digit = digit_table[dig_buf[dig_idx]]; // 获取需显示的数码段
    if(dig_idx < 4 && flash_flag == 0 && show_flag == 1) { // 判断是否需要闪烁
        digit = 0x00; // 不显示该数码段
    }
    P2 = digit; // 输出数码段
    P0 = 0x00; // 输出段选信号,让刚才输出的数码段显示在数码管上
    P0 = 0xFF; // 关闭段选信号,等待输出下一个数码段
    dig_idx++; // 切换到下一个数码管组
    if(dig_idx >= 6) { // 如果已显示了6个数码管组,说明需要更新时间
        dig_idx = 0; // 重置数码管组索引
        flash_flag = !flash_flag; // 切换闪烁标志,用于实现数码段的闪烁效果
        update_dig_buf(); // 更新数码管缓存区
    }
}

// 初始化外部中断0和1
void init_ext() {
    EX0 = 1; // 允许外部中断0
    IT0 = 1; // 设置外部中断0为下降沿触发
    EX1 = 1; // 允许外部中断1
    IT1 = 1; // 设置外部中断1为下降沿触发
    EA = 1; // 允许总中断
}

void main() {
    while(1) {
        refresh_dig(); // 刷新数码管显示
        delayms(5); // 设定一个适当的延时,以实现较稳定的显示效果
        if(clear_flag == 1) { // 处理清屏标志
            dig_idx = 0; // 重置数码管组索引
            for(int i = 0; i < 6; i++) {
                dig_buf[i] = 0; // 将数码管缓存区清零
            }
            clear_flag = 0; // 清除清屏标志
        }
    }
}