江科协51单片机 7-2 LCD1602显示时钟实验

DS1302 时钟实验:数码管显示改 LCD1602 显示

实验平台 :普中(PRECHIN)51 开发板 · STC89C52RC

开发环境 :Keil5 C51(c51v954a)+ STC-ISP

原始工程21-DS1302(数码管显示)时钟实验

完成日期:2026-08-31


目录

  • [1. 实验目标](#1. 实验目标)
  • [2. 硬件基础](#2. 硬件基础)
    • [2.1 DS1302 实时时钟](#2.1 DS1302 实时时钟)
    • [2.2 LCD1602 液晶](#2.2 LCD1602 液晶)
    • [2.3 接线与引脚分配](#2.3 接线与引脚分配)
  • [3. 改造思路](#3. 改造思路)
  • [4. 软件实现](#4. 软件实现)
    • [4.1 新增 LCD1602 驱动](#4.1 新增 LCD1602 驱动)
    • [4.2 重写主程序](#4.2 重写主程序)
    • [4.3 修改 Keil 工程](#4.3 修改 Keil 工程)
  • [5. 关键知识点](#5. 关键知识点)
    • [5.1 LCD1602 写操作时序](#5.1 LCD1602 写操作时序)
    • [5.2 BCD 码转 ASCII](#5.2 BCD 码转 ASCII)
    • [5.3 DDRAM 地址与光标定位](#5.3 DDRAM 地址与光标定位)
  • [6. 编译与烧录](#6. 编译与烧录)
  • [7. 常见问题排查](#7. 常见问题排查)
  • [8. 可扩展方向](#8. 可扩展方向)

1. 实验目标

原实验通过动态数码管 显示 DS1302 的时分秒(格式 XX-XX-XX)。本实验在保留 DS1302 驱动逻辑不变的前提下,将显示部分替换为 LCD1602 字符液晶

  • 第一行显示标题 DS1302 Clock
  • 第二行显示时间 Time: HH:MM:SS

2. 硬件基础

2.1 DS1302 实时时钟

DS1302 是三线制(RST/CLK/IO)串行实时时钟芯片,本工程沿用原有驱动:

信号 单片机引脚
RST(复位) P3.5
CLK(时钟) P3.6
IO(数据) P3.4

时间数据以 BCD 码 存储,gDS1302_TIME[7] 数组顺序为:秒、分、时、日、月、星期、年。

2.2 LCD1602 液晶

  • 16 字符 × 2 行字符型液晶,5×7 点阵
  • 8 位并行数据接口 + 3 根控制线(RS、RW、E)
  • 内置字符发生器(CGROM),写入 ASCII 码即可显示对应字符

2.3 接线与引脚分配

普中开发板 LCD1602 插座引脚分配:

LCD1602 信号 单片机引脚 说明
D0--D7 P0.0--P0.7 8 位数据总线(与数码管共用 P0)
RS P2.6 0=命令,1=数据
RW P2.5 0=写,1=读
E P2.7 使能,上升沿锁存

注意:LCD1602 与数码管段选共用 P0 口,插上 LCD 后数码管不显示属正常现象。对比度由板上电位器调节。


3. 改造思路

整体采用模块替换策略,DS1302 部分零改动:

复制代码
原工程:main.c → smg.c(数码管动态扫描) ┐
                                          ├→ ds1302.c(不变)→ public.c(不变)
新工程:main.c → lcd1602.c(字符液晶)    ┘

改动三处:

  1. 新增 App/lcd1602/lcd1602.clcd1602.h ------ LCD1602 驱动
  2. 重写 User/main.c ------ 显示逻辑从"查段码表"改为"BCD 转 ASCII"
  3. 修改 template.uvproj ------ smg.c 移出编译、加入 lcd1602.c、包含路径增加 .\App\lcd1602

4. 软件实现

4.1 新增 LCD1602 驱动

头文件 lcd1602.h ------ 引脚与接口定义:

c 复制代码
#define LCD1602_DATAPORT  P0      // 数据总线

sbit LCD1602_RS = P2^6;           // 0=命令 1=数据
sbit LCD1602_RW = P2^5;           // 0=写   1=读
sbit LCD1602_EN = P2^7;           // 使能

void lcd1602_write_cmd(u8 cmd);           // 写命令
void lcd1602_write_data(u8 dat);          // 写数据
void lcd1602_init(void);                  // 初始化
void lcd1602_show_string(u8 x,u8 y,u8 *str); // 定位显示字符串
void lcd1602_show_num(u8 x,u8 y,u8 num,u8 len); // 显示数值(高位补0)
void lcd1602_refresh_time(void);          // 刷新时间显示

写命令函数(写数据函数仅 RS 电平不同):

c 复制代码
void lcd1602_write_cmd(u8 cmd)
{
    LCD1602_RS = 0;              // 选择写命令
    LCD1602_RW = 0;              // 选择写
    LCD1602_EN = 0;              // 使能拉低,准备产生上升沿
    LCD1602_DATAPORT = cmd;      // 命令字送上数据总线
    delay_ms(1);
    LCD1602_EN = 1;              // 上升沿,LCD 锁存命令
    delay_ms(1);
    LCD1602_EN = 0;
}

初始化函数

c 复制代码
void lcd1602_init(void)
{
    lcd1602_write_cmd(0x38);  // 8位总线、两行显示、5×7点阵
    lcd1602_write_cmd(0x0c);  // 开显示、关光标
    lcd1602_write_cmd(0x06);  // 写入后地址指针自动+1
    lcd1602_write_cmd(0x01);  // 清屏
    delay_ms(2);
}

字符串定位显示 (第一行基准地址 0x80,第二行 0xC0):

c 复制代码
void lcd1602_show_string(u8 x, u8 y, u8 *str)
{
    u8 i = 0;
    if (y == 0)
        lcd1602_write_cmd(0x80 | x);   // 第一行
    else
        lcd1602_write_cmd(0xC0 | x);   // 第二行
    while (str[i] != '\0')
        lcd1602_write_data(str[i++]);
}

时间刷新函数 ------ 核心:BCD → ASCII:

c 复制代码
void lcd1602_refresh_time(void)
{
    u8 buf[9];
    buf[0] = '0' + (gDS1302_TIME[2] >> 4);   // 时十位(BCD高4位)
    buf[1] = '0' + (gDS1302_TIME[2] & 0x0f); // 时个位(BCD低4位)
    buf[2] = ':';
    buf[3] = '0' + (gDS1302_TIME[1] >> 4);   // 分十位
    buf[4] = '0' + (gDS1302_TIME[1] & 0x0f); // 分个位
    buf[5] = ':';
    buf[6] = '0' + (gDS1302_TIME[0] >> 4);   // 秒十位
    buf[7] = '0' + (gDS1302_TIME[0] & 0x0f); // 秒个位
    buf[8] = '\0';
    lcd1602_show_string(5, 1, buf);           // 第二行第5列起显示
}

4.2 重写主程序

c 复制代码
#include "public.h"
#include "lcd1602.h"
#include "ds1302.h"

void main()
{
    lcd1602_init();                        // 初始化LCD1602
    ds1302_init();                         // 初始化DS1302

    lcd1602_show_string(0, 0, "  DS1302 Clock  ");  // 第一行标题
    lcd1602_show_string(0, 1, "Time:           ");  // 第二行前缀

    while (1)
    {
        ds1302_read_time();      // 读取DS1302时间
        lcd1602_refresh_time();  // 刷新"HH:MM:SS"
    }
}

与原数码管版本对比:动态扫描需要每约 1ms 刷新一次才能维持视觉暂留,而 LCD1602 内部自带显存(DDRAM),只需在数据变化时重写,主循环反而更简单。

4.3 修改 Keil 工程

template.uvproj 的三处修改:

项目 修改内容
编译文件 删除 .\App\smg\smg.c,新增 .\App\lcd1602\lcd1602.c
包含路径 IncludePath 加入 .\App\lcd1602
磁盘文件 App\smg\ 文件夹保留不删,仅移出编译

命令行编译验证:

bash 复制代码
D:\Keil_v5\UV4\UV4.exe -b template.uvproj -j0 -o build.log

结果:0 Error / 2 Warning ,生成 Obj\template.hex(code=769 字节)。两条 L16: UNCALLED SEGMENT 警告来自未被调用的 lcd1602_show_numdelay_10us,属无害警告。


5. 关键知识点

5.1 LCD1602 写操作时序

复制代码
RS ──┐设置(0=命令/1=数据)
RW ──┤拉低(写)
数据──┤送上 P0 总线
E  ──┘先低 → 拉高(上升沿锁存) → 拉低

E 引脚的上升沿 是 LCD 采样数据的时刻,两次 delay_ms(1) 保证建立/保持时间,对 11.0592/12MHz 晶振均足够。

5.2 BCD 码转 ASCII

DS1302 输出 BCD 码(如 0x59 表示 59),LCD1602 需要 ASCII 显示。利用 ASCII 字符 '0'~'9' 连续的特性:

复制代码
十位 = '0' + (bcd >> 4)      // 高4位右移到低4位
个位 = '0' + (bcd & 0x0f)    // 屏蔽高4位

对比原数码管方案:数码管用 BCD 查段码表 gsmg_code[],LCD 直接用字符加法,无需查表。

5.3 DDRAM 地址与光标定位

显示位置 DDRAM 地址 写命令
第一行第 x 列(x=0~15) 0x00 + x `0x80
第二行第 x 列 0x40 + x `0xC0

两行地址不连续(相差 0x40),所以 show_string 需按行选择基准地址。每写一个字符,指针因 0x06 命令自动 +1,实现连续输出。


6. 编译与烧录

  1. 打开 Keil 工程 template.uvprojProject → Rebuild all target files
  2. 确认 Obj\template.hex 生成
  3. STC-ISP:芯片选 STC89C52RC,选串口/USB,加载 HEX,冷启动下载
  4. 下载完成后 LCD 第一行显示标题,第二行从 Time: 13:51:47(初始值)开始走时

7. 常见问题排查

现象 原因 解决
屏幕只亮无字符 对比度不当 调板上 LCD 旁电位器
整屏无反应 E/RS/RW 接线错或 LCD 未插紧 核对 P2.7/P2.6/P2.5
只显示第一行 初始化命令时序过快 确认 delay_ms 足够、0x38 已写入
时间不走 DS1302 接线/电池问题 核对 P3.4~P3.6,检查晶振 32.768kHz
数码管不亮 与 LCD 共用 P0,正常现象 无需处理

8. 可扩展方向

  • 显示日期 :第一行右侧用 lcd1602_show_num 显示 YY-MM-DD 与星期
  • 按键调时 :结合独立按键(K1~K4)实现时/分/加/减,写入 gDS1302_TIME 后调用 ds1302_init 重新写入芯片
  • 自定义字符:利用 CGRAM(0x40 命令)显示℃、爱心等 5×8 自绘符号
  • 秒闪烁冒号 :每秒交替显示 : 与空格,增强时钟观感

相关推荐
思麟呀1 小时前
嵌入式入门(一)宏观生态到首次烧录
c语言·嵌入式硬件
runningshark1 小时前
SC32L14GR8PJR
单片机·嵌入式硬件
智购科技无人售货机厂家1 小时前
2026自动售货机备用电池管理系统设计:从充放电保护到健康监测的工程实践~YH
大数据·linux·单片机·嵌入式硬件·微信
智购无人售货机厂家1 小时前
2026自动售货机软硬件版本管理策略:从版本号规范到兼容性矩阵的工程实践~YH
运维·服务器·人工智能·单片机·嵌入式硬件·线性代数·矩阵
花 满 楼2 小时前
RISC-V APLIC 中断模块总结——第二篇
单片机·嵌入式硬件·mcu·risc-v
无损检测小白白2 小时前
【嵌入式面试题一】
c语言·单片机
Messy create3 小时前
【BMS-Pack检测-短路检测】
单片机·嵌入式硬件·能源
yutian06063 小时前
TI 280049 GPIO 相关笔记
嵌入式硬件·c2000
星一工作室4 小时前
【STM32模块教程】-TT马达(直流电机)
单片机·嵌入式硬件