基于DS1302与数码管的可调电子表设计

基于DS1302与数码管的可调电子表设计

一、系统概述

设计以DS1302实时时钟芯片为核心,结合数码管显示和按键调时功能,实现一款低成本、高精度的可调电子表。系统支持时分秒显示、时间调整(时/分/秒)、24小时制,并具备掉电走时功能(通过纽扣电池备份),适用于家庭、办公等场景的时间显示与校准。

二、系统组成与核心功能

1. 核心组件

模块 器件型号 功能
实时时钟 DS1302 提供年/月/日/时/分/秒,支持掉电走时
显示模块 6位共阳数码管 显示时分秒(HH:MM:SS)
主控制器 STC89C52RC(51单片机) 系统控制、数据处理、按键响应
调时模块 3个轻触按键 设置/加/减(调整时、分、秒)
电源模块 5V DC + CR2032纽扣电池 主电源供电+掉电备份(3V)
驱动芯片 74HC595移位寄存器 数码管段选驱动(节省IO口)

2. 核心功能

三、硬件设计

1. 电路原理图

+-----------------------------------+  
|  STC89C52RC                       |  
|                                   |  
|  P1.0-P1.7 → 74HC595 (D0-D7)       |  // 数码管段选  
|  P2.0 → 74HC595 (SHCP)             |  // 移位时钟  
|  P2.1 → 74HC595 (STCP)             |  // 锁存时钟  
|  P2.2-P2.4 → 数码管位选 (6位)       |  // 位选控制  
|  P3.0 → DS1302 (RST)               |  // 复位/片选  
|  P3.1 → DS1302 (SCLK)              |  // 串行时钟  
|  P3.2 → DS1302 (I/O)               |  // 数据线  
|  P3.3 → 按键1 (设置)                |  // 进入调时模式  
|  P3.4 → 按键2 (加)                  |  // 时间加1  
|  P3.5 → 按键3 (减)                  |  // 时间减1  
|  VCC → 5V, GND → GND               |  
+-----------------------------------+  

关键电路说明

2. 元件清单

序号 名称 规格 数量
1 STC89C52RC 51单片机 1
2 DS1302 实时时钟芯片 1
3 6位共阳数码管 0.56英寸 1
4 74HC595 8位移位寄存器 1
5 轻触按键 6×6×5mm 3
6 纽扣电池 CR2032 (3V) 1
7 32.768kHz晶振 圆柱型 1
8 电阻 10kΩ (上拉) 3
9 电阻 220Ω (限流) 8
10 电容 30pF (晶振匹配) 2

四、软件设计

1. 主程序流程

graph TD
    A[系统初始化] --> B[DS1302初始化(启动时钟、设置初始时间)]
    B --> C[数码管显示初始时间]
    C --> D[扫描按键]
    D -- 按键1按下 --> E[进入调时模式(选择时/分/秒)]
    D -- 无按键 --> F[读取DS1302时间]
    E --> G[按键2/3调整时间(时/分/秒)]
    G --> H[更新DS1302时间]
    H --> C
    F --> C

2. 关键代码实现

(1)DS1302驱动(读写时间)

DS1302通过SPI-like接口通信,需实现写字节读字节函数,时间数据以BCD码存储。

#include <reg52.h>
#include "ds1302.h"

// DS1302引脚定义
sbit DS1302_RST = P3^0;
sbit DS1302_SCLK = P3^1;
sbit DS1302_IO = P3^2;

// 写1字节到DS1302
void DS1302_WriteByte(unsigned char dat) {
    unsigned char i;
    for(i=0; i<8; i++) {
        DS1302_IO = dat & 0x01;  // 低位在前
        DS1302_SCLK = 1;
        _nop_(); _nop_();
        DS1302_SCLK = 0;
        dat >>= 1;
    }
}

// 从DS1302读1字节
unsigned char DS1302_ReadByte() {
    unsigned char i, dat=0;
    for(i=0; i<8; i++) {
        dat >>= 1;
        if(DS1302_IO) dat |= 0x80;
        DS1302_SCLK = 1;
        _nop_(); _nop_();
        DS1302_SCLK = 0;
    }
    return dat;
}

// 写时间到DS1302(时、分、秒)
void DS1302_WriteTime(unsigned char hour, unsigned char min, unsigned char sec) {
    DS1302_RST = 0; _nop_();
    DS1302_SCLK = 0; _nop_();
    DS1302_RST = 1; _nop_();
    
    // 写秒(0x80为写保护位,需先关闭)
    DS1302_WriteByte(0x8E);  // 控制寄存器
    DS1302_WriteByte(0x00);  // 关闭写保护
    DS1302_WriteByte(0x80);  // 秒寄存器地址
    DS1302_WriteByte(sec);   // 秒(BCD码,如0x59=59秒)
    
    // 写分
    DS1302_WriteByte(0x82);  // 分寄存器地址
    DS1302_WriteByte(min);   // 分(BCD码)
    
    // 写时
    DS1302_WriteByte(0x84);  // 时寄存器地址
    DS1302_WriteByte(hour);  // 时(BCD码,24小时制)
    
    // 恢复写保护
    DS1302_WriteByte(0x8E);
    DS1302_WriteByte(0x80);
    DS1302_RST = 0;
}

// 从DS1302读时间(时、分、秒)
void DS1302_ReadTime(unsigned char *hour, unsigned char *min, unsigned char *sec) {
    DS1302_RST = 0; _nop_();
    DS1302_SCLK = 0; _nop_();
    DS1302_RST = 1; _nop_();
    
    DS1302_WriteByte(0x81);  // 读秒寄存器
    *sec = DS1302_ReadByte();
    DS1302_WriteByte(0x83);  // 读分寄存器
    *min = DS1302_ReadByte();
    DS1302_WriteByte(0x85);  // 读时寄存器
    *hour = DS1302_ReadByte();
    
    DS1302_RST = 0;
}

(2)数码管动态显示

6位数码管采用动态扫描,通过74HC595输出段选码,P2.2-P2.4控制位选(6位需2个IO口+译码器,或3个IO口直接控制)。

// 数码管段码表(0-9,共阳)
unsigned char code seg_table[] = {
    0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90, 0xBF  // 0-9, 冒号
};

// 显示缓存(6位:时十位、时个位、冒号、分十位、分个位、冒号、秒十位、秒个位?需6位则合并)
unsigned char display_buf[6] = {0};

// 更新显示缓存(时、分、秒转BCD码后拆分)
void UpdateDisplayBuf(unsigned char hour, unsigned char min, unsigned char sec) {
    display_buf[0] = hour / 10;   // 时十位
    display_buf[1] = hour % 10;   // 时个位
    display_buf[2] = 10;          // 冒号(段码表第10位)
    display_buf[3] = min / 10;    // 分十位
    display_buf[4] = min % 10;    // 分个位
    display_buf[5] = 10;          // 冒号(或秒十位,根据6位显示调整)
    // 若为6位显示,可显示 HH:MM:SS 中的 HH:MM,或 HH MM SS(需调整位选)
}

// 数码管动态扫描
void DisplayScan() {
    static unsigned char pos = 0;
    P2 = (P2 & 0xF8) | pos;  // 位选(假设P2.0-P2.2控制6位,需根据实际调整)
    P1 = seg_table[display_buf[pos]];  // 段选(通过74HC595输出,此处简化直接P1口)
    pos = (pos + 1) % 6;
    _delay_ms(2);  // 扫描间隔2ms,避免闪烁
}

(3)按键调时逻辑

通过3个按键实现“设置-加-减”功能,短按“设置”键进入调时模式,依次切换调整时、分、秒;长按“加/减”键快速调整。

sbit KEY_SET = P3^3;
sbit KEY_ADD = P3^4;
sbit KEY_SUB = P3^5;

unsigned char adjust_mode = 0;  // 0-正常显示,1-调时,2-调分,3-调秒
unsigned char hour, min, sec;   // 当前时间

void KeyProcess() {
    if(KEY_SET == 0) {  // 设置键按下
        _delay_ms(10);  // 消抖
        if(KEY_SET == 0) {
            adjust_mode = (adjust_mode + 1) % 4;  // 循环切换模式(0→1→2→3→0)
            if(adjust_mode == 0) {  // 退出调时模式,保存时间到DS1302
                DS1302_WriteTime(hour, min, sec);
            }
        }
        while(KEY_SET == 0);  // 等待释放
    }
    
    if(adjust_mode > 0) {  // 调时模式下
        if(KEY_ADD == 0) {  // 加键
            _delay_ms(10);
            if(KEY_ADD == 0) {
                if(adjust_mode == 1) hour = (hour + 1) % 24;  // 时(0-23)
                if(adjust_mode == 2) min = (min + 1) % 60;  // 分(0-59)
                if(adjust_mode == 3) sec = (sec + 1) % 60;  // 秒(0-59)
            }
            while(KEY_ADD == 0);
        }
        if(KEY_SUB == 0) {  // 减键
            _delay_ms(10);
            if(KEY_SUB == 0) {
                if(adjust_mode == 1) hour = (hour + 23) % 24;  // 时减1
                if(adjust_mode == 2) min = (min + 59) % 60;  // 分减1
                if(adjust_mode == 3) sec = (sec + 59) % 60;  // 秒减1
            }
            while(KEY_SUB == 0);
        }
    }
}

参考代码 用DS1302与1602LCD设计的可调式电子日历与时钟 www.youwenfan.com/contentcst/135510.html

五、Proteus仿真

1. 仿真步骤

  1. 创建工程:Proteus中添加STC89C52、DS1302、6位共阳数码管、74HC595、按键、晶振、纽扣电池等元件;
  2. 连接电路:按原理图连接DS1302(SCLK-P3.1, I/O-P3.2, RST-P3.0)、数码管(段选-P1,位选-P2.2-P2.4)、按键(P3.3-P3.5);
  3. 加载程序:将编译好的HEX文件(Keil C51编译)加载到STC89C52;
  4. 运行仿真:观察数码管显示时间,按下按键测试调时功能,修改DS1302初始时间验证准确性。

2. 仿真截图

六、制作与调试

1. 制作步骤

  1. 焊接电路:按原理图焊接元件,注意DS1302的晶振(32.768kHz)和纽扣电池(CR2032)正确连接;
  2. 烧录程序:用STC-ISP工具将HEX文件烧录到STC89C52;
  3. 校准时间:首次上电时,通过按键设置初始时间,DS1302将自动走时;
  4. 测试功能:检查数码管显示是否稳定,按键调时是否灵敏,掉电后时间是否保持。

2. 常见问题解决

问题 原因 解决方法
数码管不亮 段选/位选接反、限流电阻过大 检查接线,减小限流电阻(220Ω)
时间不走时 DS1302晶振未起振、电池没电 更换32.768kHz晶振,检查纽扣电池电压
调时模式无反应 按键消抖不良、程序逻辑错误 增加按键消抖延时,检查adjust_mode变量
显示乱码 BCD码转换错误、段码表错误 确认时间数据以BCD码写入DS1302,核对段码表

七、总结

本设计基于DS1302和数码管实现了可调电子表,具有以下特点:

  1. 低成本:核心元件(STC89C52、DS1302、数码管)价格低廉,适合DIY;
  2. 高精度:DS1302走时精度±2ppm(日误差<2秒),配合32.768kHz晶振;
  3. 易扩展:可添加日期显示(DS1302支持年/月/日)、闹钟功能(增加蜂鸣器)。

应用场景:家庭桌面时钟、实验室时间基准、教学演示(单片机+实时时钟应用)。

专注于matlab/simulink,电子电路,编程