51单片机+DS1302设计一个电子钟(LCD1602显示时间)

一、前言

电子钟是一种能够准确显示时间的设备,广泛应用于家庭、办公场所和公共场所,为人们提供了方便和准确的时间信息。本项目设计一个基于51单片机的电子钟,使用DS1302作为RTC时钟芯片,LCD1602作为显示屏,并通过串口方式连接上位机进行时间设置和闹钟设置。

STC89C52作为主控芯片,具有较高的性能和稳定性,可完成对外设的控制和数据处理。DS1302是一款低功耗的实时时钟芯片,能够提供准确的时间计数和日期功能。LCD1602是一款常用的字符型液晶显示屏,具有两行16列的显示区域,能够清晰显示时间和其他相关信息。

通过串口连接上位机,用户可以方便地设置电子钟的时间和闹钟时间,实现个性化需求。电子钟带有一个蜂鸣器,可以根据设置的闹钟时间进行响铃,提醒用户。

image-20230913112300737

image-20230913112208076

电子钟具有以下功能:

(1)显示当前时间和日期:LCD1602显示屏将实时更新并显示当前的时间和日期信息。

(2)时间设置:通过串口连接上位机,用户可以进行时间的设置,包括小时、分钟和秒。

(3)日期设置:用户可以通过上位机设置当前的年、月和日。

(4)闹钟设置:用户可以设置闹钟的时间,包括小时和分钟。到达设定时间时,蜂鸣器将响铃提醒用户。

(5)整点报时:每到整点,蜂鸣器将发出短促的提示音,提醒用户当前时间。

(6)闹钟响铃:当闹钟时间到达时,蜂鸣器将持续响铃,直到用户停止。

(7)该项目将借助STC89C52单片机的控制能力和串口通信功能,结合DS1302时钟芯片和LCD1602显示屏,实现一个简单而实用的电子钟。用户可以根据自己的

(8)需求进行时间设置和闹钟设置,方便实用,并且具有较高的准确性和稳定性。

二、项目的设计思路

项目的设计思路分为硬件设计和软件设计两部分。

2.1 硬件设计思路

(1)主控芯片选择:选择STC89C52作为主控芯片,由于其较高的性能和稳定性,适合用于控制和数据处理。

(2)RTC时钟芯片选择:选择DS1302作为RTC时钟芯片,具有低功耗、精确计时和日期功能。

(3)显示屏选择:选择LCD1602作为显示屏,它具有两行16列的字符显示区域,能够清晰显示时间和其他相关信息。

(4)串口连接:设计串口连接电路,实现与上位机的通信,用于时间设置和闹钟设置。

(5)蜂鸣器:添加蜂鸣器模块,用于整点报时和闹钟响铃功能。

(6)按键输入:添加按键输入模块,用于用户操作,如切换设置模式、调整时间和设置闹钟。

2.2 软件设计思路

(1)初始化设置:在程序启动时,进行硬件初始化,包括配置主控芯片的引脚、初始化DS1302时钟芯片和LCD1602显示屏。

(2)时间获取与显示:通过DS1302时钟芯片获取当前的时间和日期,并将其显示在LCD1602显示屏上。

(3)串口通信:通过串口与上位机进行通信,接收上位机发送的时间设置和闹钟设置指令,并进行相应的处理

(4)时间设置:根据上位机发送的时间设置指令,更新DS1302时钟芯片的时间计数器。

(5)日期设置:根据上位机发送的日期设置指令,更新DS1302时钟芯片的日期计数器。

(6)闹钟设置:根据上位机发送的闹钟设置指令,设置闹钟时间,并将其保存在主控芯片的内部存储器中。

(7)整点报时:通过检测DS1302时钟芯片的小时计数器,当小时值变化时,触发蜂鸣器发出短促的提示音。

(8)闹钟响铃:通过比较当前时间和保存的闹钟时间,当达到闹钟时间时,触发蜂鸣器持续响铃,直到用户停止或设定的时间段结束。

三、项目硬件接线

(1)STC89C52与DS1302:

STC89C52的P2.0口连接到DS1302的SCLK(时钟)引脚,用于提供时钟信号。

STC89C52的P2.1口连接到DS1302的IO(数据)引脚,用于数据传输。

STC89C52的P2.2口连接到DS1302的RST(复位)引脚,用于对DS1302进行复位操作。

(2)STC89C52与LCD1602:

STC89C52的P0口连接到LCD1602的D0-D7引脚,用于传输字符数据和控制信号。

STC89C52的P2.3口连接到LCD1602的RS(寄存器选择)引脚,用于选择数据或命令寄存器。

STC89C52的P2.4口连接到LCD1602的RW(读写选择)引脚,用于选择读或写操作。

STC89C52的P2.5口连接到LCD1602的E(使能)引脚,用于启动传输。

(3)STC89C52与蜂鸣器模块:

STC89C52的P3.7口连接到蜂鸣器模块的信号引脚,用于触发蜂鸣器响铃。

(4)串口通信接口。在STC89C52单片机上,串口引脚如下:

UART接收线(RXD):连接至外部设备的发送线。

STC89C52的P3.0口(RXD)用于接收串口数据。

UART发送线(TXD):连接至外部设备的接收线。

STC89C52的P3.1口(TXD)用于发送串口数据。

四、项目代码

4.1 DS1302时钟读取、设置

下面代码实现了,STC89C52读取DS1302时钟信息打印到串口,以及设置闹钟、时间读取、打印到串口的功能。其中,采用了UART通信进行与上位机交互,可以接收上位机发送过来的时间字符串,并据此设置闹钟和时间。

#include <reg52.h>
#include <stdio.h>#define uchar unsigned char
#define uint unsigned int// 定义DS1302时钟寄存器地址
#define DS1302_SEC_REG 0x80
#define DS1302_MIN_REG 0x82
#define DS1302_HR_REG 0x84
#define DS1302_DAY_REG 0x86
#define DS1302_MONTH_REG 0x88
#define DS1302_YEAR_REG 0x8C// 定义DS1302控制寄存器命令
#define DS1302_CMD_WRITE 0x80
#define DS1302_CMD_READ 0x81// 定义串口波特率为9600
#define BAUDRATE 9600
#define FOSC 11059200L
#define TIMER_INTERVAL (65536 - FOSC / 12 / BAUDRATE)// 声明全局变量
uchar time_buffer[20]; // 存放时间字符串
uchar alarm_buffer[20]; // 存放闹钟时间字符串
uint i;
bit flag; // 标记是否接收到上位机的时间字符串// 初始化UART模块
void InitUart() {TMOD &= 0x0F;TMOD |= 0x20;TH1 = TIMER_INTERVAL / 256;TL1 = TIMER_INTERVAL % 256;PCON |= 0x80;SCON = 0x50;ES = 1;TR1 = 1;EA = 1;
}// 将单个字节发送到串口
void SendData(uchar dat) {SBUF = dat;while (!TI);TI = 0;
}// 将字符串发送到串口
void SendString(uchar *s) {while (*s != '\0') {SendData(*s++);}
}// 初始化DS1302时钟芯片
void InitDS1302() {uchar i;// 使能DS1302写保护功能DS1302_CE = 0;DS1302_SCL = 0;DS1302_CE = 1;Write_DS1302(DS1302_CMD_WRITE | 0x8e, 0x80);// 关闭时钟允许,准备写入数据Write_DS1302(DS1302_CMD_WRITE | 0x90, 0x00);// 写入年月日时分秒周Write_DS1302(DS1302_SEC_REG, 0x00);Write_DS1302(DS1302_MIN_REG, 0x30);Write_DS1302(DS1302_HR_REG, 0x11);Write_DS1302(DS1302_DAY_REG, 0x08);Write_DS1302(DS1302_MONTH_REG, 0x09);Write_DS1302(DS1302_YEAR_REG, 0x21);Write_DS1302(0x8e, 0x00);// 初始化闹钟时间for (i = 0; i < 20; i++) {alarm_buffer[i] = 0;}
}// 向DS1302写入数据
void Write_DS1302(uchar addr, uchar dat) {uchar i;DS1302_CE = 0;DS1302_SCL = 0;// 发送起始信号DS1302_CE = 1;DS1302_SCL = 1;DS1302_CE = 0;// 发送命令字节地址DS1302_WriteByte(addr);// 发送数据字节DS1302_WriteByte(dat);// 停止信号DS1302_SCL = 0;DS1302_CE = 1;// 延时至少1usfor (i = 0; i < 10; i++);
}// 向DS1302读取数据
uchar Read_DS1302(uchar addr) {uchar dat;uchar i;DS1302_CE = 0;DS1302_SCL = 0;// 发送起始信号DS1302_CE = 1;DS1302_SCL = 1;DS1302_CE = 0;// 发送命令字节地址DS1302_WriteByte(addr | 0x01);// 读取数据字节dat = DS1302_ReadByte();// 停止信号DS1302_SCL = 0;DS1302_CE = 1;// 延时至少1usfor (i = 0; i < 10; i++);return dat;
}// 读取DS1302时间并打印到串口
void ReadTime() {uchar sec, min, hour, day, month, year;sprintf(time_buffer, "Time: ");sec = Read_DS1302(DS1302_SEC_REG);min = Read_DS1302(DS1302_MIN_REG);hour = Read_DS1302(DS1302_HR_REG);day = Read_DS1302(DS1302_DAY_REG);month = Read_DS1302(DS1302_MONTH_REG);year = Read_DS1302(DS1302_YEAR_REG);sprintf(time_buffer + 6, "%02d:%02d:%02d %02d/%02d/%02d\r\n", hour, min, sec, day, month, year);SendString(time_buffer);
}// 向DS1302写入闹钟时间
void SetAlarm(uchar *str) {uint i = 0;// 将字符串转换为数字while (str[i] != '\0') {alarm_buffer[i] = str[i] - '0';i++;if (i > 19) // 防止溢出break;}// 写入闹钟时间Write_DS1302(DS1302_CMD_WRITE | 0x81, alarm_buffer[10] << 4 | alarm_buffer[11]);Write_DS1302(DS1302_CMD_WRITE | 0x83, alarm_buffer[8] << 4 | alarm_buffer[9]);Write_DS1302(DS1302_CMD_WRITE | 0x85, alarm_buffer[6] << 4 | alarm_buffer[7]);
}// 从串口接收数据中解析出时间信息
void ParseTime() {uchar i, j;uchar temp;for (i = 0; i < 20; i++) {time_buffer[i] = 0;}// 接收字符串格式为:hh:mm:ss dd/mm/yyfor (i = 0; i < 8; i++) {temp = 0;for (j = 0; j < 2; j++) {temp *= 10;temp += (SBUF - '0');while (!RI); // 等待接收完成RI = 0;}time_buffer[i] = temp;if (i == 2 || i == 4) {while (SBUF != ' '); // 跳过空格字符while (!RI); // 等待接收完成RI = 0;}}flag = 1; // 标记已经接收到字符串
}// 主函数
void main() {InitUart();InitDS1302();flag = 0;while (1) {if (flag) { // 接收到时间字符串,设置闹钟和时间SetAlarm(time_buffer);Write_DS1302(DS1302_CMD_WRITE | 0x80, time_buffer[6] << 4 | time_buffer[7]);Write_DS1302(DS1302_CMD_WRITE | 0x82, time_buffer[3] << 4 | time_buffer[4]);Write_DS1302(DS1302_CMD_WRITE | 0x84, time_buffer[0] << 4 | time_buffer[1]);flag = 0;}ReadTime(); // 读取当前时间并发送到串口}
}// UART接收中断函数
void UartIsr() interrupt 4 {if (RI) { // 接收到数据ParseTime(); // 解析时间字符串}RI = 0;
}

4.2 LCD1602显示时钟

基于STC89C52控制LCD1602显示时间字符串的实现代码。

#include <reg52.h>
#include <stdio.h>// 定义Data和Command寄存器选择端口
sbit LCD_RS = P2^0;  // RS引脚(寄存器选择)
sbit LCD_RW = P2^1;  // RW引脚(读写选择)
sbit LCD_EN = P2^2;  // EN引脚(使能)// 定义数据总线端口
#define LCD_DATA P0    void DelayMs(unsigned int ms) {unsigned int i, j;for (i = 0; i < ms; i++)for (j = 0; j < 120; j++);
}void WriteCommand(unsigned char cmd) {LCD_RS = 0;  // 选择指令寄存器LCD_RW = 0;  // 写模式LCD_EN = 0;  // 低电平使能LCD_DATA = cmd;  // 发送指令DelayMs(1);  // 延时等待指令写入LCD_EN = 1;  // 高电平使能DelayMs(1);  // 持续一段时间LCD_EN = 0;  // 结束使能
}void WriteData(unsigned char dat) {LCD_RS = 1;  // 选择数据寄存器LCD_RW = 0;  // 写模式LCD_EN = 0;  // 低电平使能LCD_DATA = dat;  // 发送数据DelayMs(1);  // 延时等待数据写入LCD_EN = 1;  // 高电平使能DelayMs(1);  // 持续一段时间LCD_EN = 0;  // 结束使能
}void LCDInit() {WriteCommand(0x38);  // 设置显示模式为2行、5x8点阵字符WriteCommand(0x0C);  // 显示器开,光标关闭WriteCommand(0x06);  // 光标右移,整屏不移动WriteCommand(0x01);  // 清除显示并设置光标回到初始位置
}void LCDDisplayTime(char* time) {int i;WriteCommand(0x80);  // 设置光标位置为第一行的起始位置for (i = 0; i < 16; i++) {WriteData(time[i]);  // 在第一行显示时间字符串}WriteCommand(0xC0);  // 设置光标位置为第二行的起始位置for (i = 0; i < 16; i++) {WriteData(time[16 + i]);  // 在第二行显示时间字符串}
}void main() {char time_buffer[32] = "Current Time: 00:00:00";  // 时间字符串unsigned char sec = 0, min = 0, hour = 0;  // 当前时间变量LCDInit();  // 初始化LCD显示器while (1) {// 更新时间变量sec++;if (sec >= 60) {sec = 0;min++;if (min >= 60) {min = 0;hour++;if (hour >= 24) {hour = 0;}}}// 格式化时间字符串sprintf(time_buffer + 14, "%02d:%02d:%02d", hour, min, sec);// 显示时间字符串LCDDisplayTime(time_buffer);DelayMs(1000);  // 延时1秒}
}

代码使用LCD_RSLCD_RWLCD_EN分别表示LCD1602的RS、RW和EN引脚。数据总线通过LCD_DATA定义,连接到P0端口。先初始化LCD显示器,在一个无限循环中更新时间变量并格式化时间字符串,最后在LCD上显示时间字符串。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/144129.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

torch_cluster、torch_scatter、torch_sparse三个包的安装

涉及到下面几个包安装的时候经常会出现问题&#xff0c;这里我使用先下载然后再安装的办法&#xff1a; pip install torch_cluster pip install torch_scatter pip install torch_sparse 1、选择你对应的torch版本&#xff1a;https://data.pyg.org/whl/ 2、点进去然后&…

网络安全-学习手册

前言 前几天发布了一篇 网络安全&#xff08;黑客&#xff09;自学 没想到收到了许多人的私信想要学习网安黑客技术&#xff01;却不知道从哪里开始学起&#xff01;怎么学 今天给大家分享一下&#xff0c;很多人上来就说想学习黑客&#xff0c;但是连方向都没搞清楚就开始学习…

C#检查服务状态,以及进行服务启停

1. linux环境 linux环境通过执行bash命令直接执行&#xff1a; public string RunCmdLinux(string cmd){var proc new Process();System.Console.Write($"Run Linux cmd > [{cmd}] START!");proc.StartInfo.CreateNoWindow true;proc.StartInfo.FileName &…

git clone:SSL: no alternative certificate subject name matches target host name

git clone 时的常见错误&#xff1a; fatal: unable to access ‘https://ip_or_domain/xx/xx.git/’: SSL: no alternative certificate subject name matches target host name ‘ip_or_domain’ 解决办法&#xff1a; disable ssl verify git config --global http.sslVe…

Redis分布式锁(中)

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 我们在不久前介绍了Spr…

JavaEE初阶(18)(JVM简介:发展史,运行流程、类加载:类加载的基本流程,双亲委派模型、垃圾回收相关:死亡对象的判断算法,垃圾回收算法,垃圾收集器)

接上次博客&#xff1a;初阶JavaEE&#xff08;17&#xff09;Linux 基本使用和 web 程序部署-CSDN博客 目录 JVM 简介 JVM 发展史 JVM 运行流程 JVM的内存区域划分 JVM 执行流程 堆 堆的作用 JVM参数设置 堆的组成 垃圾回收 堆内存管理 类加载 类加载的基本流…

Flink(五)【DataStream 转换算子(上)】

前言 这节注定是一个大的章节&#xff0c;我预估一下得两三天&#xff0c;涉及到的一些东西不懂就重新学&#xff0c;比如 Lambda 表达式&#xff0c;我只知道 Scala 中很方便&#xff0c;但在 Java 中有点发怵了&#xff1b;一个接口能不能 new 来构造对象? 答案是可以的&…

Vue模板语法

模板语法有两大类&#xff1a; 1.插值语法 2.指令语法 让我为大家介绍一下吧&#xff01; 一、插值语法 功能:用于解析标签体内容。 写法: {{xxx}}&#xff0c;xxx是js表达式&#xff0c;且可以直接读取到data中的所有属性。 举个例子&#xff1a; <!DOCTYPE html> &l…

idea maven 构建本地jar包及pom文件

1、设置模块build 本地输出路径 <build><defaultGoal>compile</defaultGoal><resources><resource><directory>${basedir}/src/main/resources</directory><includes><include>**/**</include></includes>…

腾讯云服务器可用区是什么意思?

腾讯云服务器可用区是什么意思&#xff1f;云服务器可用区如何选择&#xff1f;可用区是指在同一个地域内电力和网络相互独立的区域&#xff0c;可用区可以做到故障隔离&#xff0c;所以可用区存在的意义在于构建高可用、高容灾应用&#xff0c;将应用部署在不同可用区内&#…

ChatkBQA:一个基于大语言模型的知识库问题生成-检索框架11.13

ChatkBQA&#xff1a;一个基于大语言模型的知识库问题生成-检索框架 摘要1 引言3 准备工作4 方法4.1 ChatKBQA概述4.2 在LLMS上进行高效微调4.3 用微调LLMS生成逻辑形式4.4 实体和关系的非监督检索4.5 可解释查询执行 摘要 基于知识的问答&#xff08;KBQA&#xff09;旨在从大…

Windows Server 2012 R2系统服务器远程桌面服务多用户登录配置分享

Windows Server 2012系统在没有安装远程多界面的情况下&#xff0c;最多只能同时运行2个远程桌面&#xff0c;如果是有多个技术员、合伙人同时操作或是像游戏开发需要用到多界面&#xff0c;但是没有安装就很不方便&#xff0c;今天飞飞来和你们分享Windows server 2012R2系统远…

C++ opencv基本用法【学习笔记(九)】

这篇博客为修改过后的转载&#xff0c;因为没有转载链接&#xff0c;所以选了原创 文章目录 一、vs code 结合Cmake debug1.1 配置tasks.json1.2 配置launch.json 二、图片、视频、摄像头读取显示2.1 读取图片并显示2.2 读取视频文件并显示2.3 读取摄像头并写入文件 三、图片基…

通过注释来埋点

目录 开始 插件编写 功能一 功能二 功能三 合并功能 运行代码 总结 这篇文章主要讲如何根据注释&#xff0c;通过babel插件自动地&#xff0c;给相应函数插入埋点代码&#xff0c;在实现埋点逻辑和业务逻辑分离的基础上&#xff0c;配置更加灵活 这篇文章想要达到的效…

2023最受推荐的五款项目管理工具

1、进度猫 进度猫是国内一款轻量级项目管理工具&#xff0c;适用于实时协作的团队。 以甘特图为向导&#xff0c;基于任务清单todolist&#xff0c;支持多用户协作&#xff1b; 甘特图显示具体任务清单、时间和任务的进度&#xff1b; 对未完成任务、已完成任务进行分类管…

Vue3源码reactive和readonly对象嵌套转换,及实现shallowReadonly

前言 官方文档中对reactive的描述&#xff1a; 响应式转换是“深层”的&#xff1a;它会影响到所有嵌套的属性。一个响应式对象也将深层地解包任何 ref 属性&#xff0c;同时保持响应性。 官方文档中对readonly的描述: 只读代理是深层的&#xff1a;对任何嵌套属性的访问都将是…

深入了解域名与SSL证书的关系

在如今数字化的世界里&#xff0c;网络安全成为我们关注的重要议题之一。为了确保数据在网络上传输的安全性&#xff0c;我们通常会采取各种安全措施&#xff0c;其中最常用的就是SSL证书。然而&#xff0c;很多人并不了解SSL证书是如何与域名相互关联的。 首先&#xff0c;我…

[C/C++] 数据结构 链表OJ题:相交链表(寻找两个链表的相交起始结点)

题目描述: 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交&#xff1a; 题目数据 保证 整个链式结构中不存在环。 注意&#xff0c;函数返…

HTML简单介绍

且视他人之疑目如盏盏鬼火&#xff0c;大胆地去你的夜路。 目录 1.网页 2.Web标准 3.HTML 3.1HTML结构 3.2HTML标签​编辑 4.标签介绍 4.1排版标签 4.2文本格式化标签 4.3媒体标签 4.3.1图片标签 4.3.2 音频标签 4.3.3视频标签 5.相对路径 6.链接标签 6.1target属…

图论15-有向图-环检测+度数+欧拉回路

文章目录 1. 有向图设计1.1 私有变量标记是否有向1.2 添加边的处理&#xff0c;双向变单向1.3 删除边的处理&#xff0c;双向变单向1.4 有向图的出度和入度 2 有向图的环检测2.1 普通的算法实现换检测2.2 拓扑排序中的环检测 3 欧拉回路 1. 有向图设计 1.1 私有变量标记是否有…