51单片机学习--DS1302可调时钟
之前学习过用定时器做的时钟,但是那样不仅误差大还费CPU,接下来利用DS1302时钟模块做一个可调实时时钟
这一次直接编写DS1302模块,首先要在DS1392.c 中根据下面的模块原理图进行位声明:
sbit DS1302_SCLK = P3^6;
sbit DS1302_IO = P3^4;
sbit DS1302_CE = P3^5;
命令字: 命令字确定了是要写还是要读,以及操作的是时还是分还是秒
首先需要一个初始化函数:
void DS1302_Init(void)
{DS1302_CE = 0;DS1302_SCLK = 0;
}
工作时CE必须置1,上升沿的时候可以读, 下降沿的时候可以写
可以理解为0是写入模式,1是读取模式
IO口从左往右是由低位到高位
要注意时序图中Read比Write少一个脉冲因为它上升到1完成了最后一个命令行位的写入之后马上要回到0开始进行读取功能了
单字节写入函数:
按照时序图进行模拟,Command:命令行,Data:写入的数据
void DS1302_WriteByte(unsigned char Command, Data)
{unsigned char i;DS1302_CE = 1;for(i = 0; i < 8; i ++) {DS1302_IO = Command & (0x01 << i); //IO非0即1,从低到高每次取出一位DS1302_SCLK = 1;Delay(10);DS1302_SCLK = 0;}for(i = 0; i < 8; i ++) {DS1302_IO = Data & (0x01 << i); //IO非0即1,从低到高每次取出一位DS1302_SCLK = 1;Delay(10);DS1302_SCLK = 0;}DS1302_CE = 0;
}
单字节读出函数
unsigned char DS1302_ReadByte(unsigned char Command)
{unsigned char i, Data = 0x00;DS1302_CE = 1;for(i = 0; i < 8; i ++) {DS1302_IO = Command & (0x01 << i); //IO非0即1,从低到高每次取出一位DS1302_SCLK = 0; //写入Delay(10);DS1302_SCLK = 1; //这样在不改变写入时序的同时还能保证最后是1}Delay(10);//接下来要读的数据已经在IO口上了已经可以读了for(i = 0; i < 8; i ++) {DS1302_SCLK = 1; //读入Delay(10);DS1302_SCLK = 0;if(DS1302_IO) {Data |= (0x01 << i);} //把IO口的数据由低位到高位复现在Data上}DS1302_IO = 0;DS1302_CE = 0;return Data;
}
要注意在main.c中使用时需要在DS1302初始化后,调用:DS1302_WriteByte(0x8E, 0x00); //关闭写入保护
再进行正常的写入
但其实,在DS1302模块的寄存器存储的数据都是BCD码
所以时钟的秒会从1, 2, ····9然后直接跳到16
9 = 0000 1001
根据BCD的进位原则,四位二进制数达到10就要清零进位了,下一个BCD码是:
0001 0000 这个数以十进制显示在LCD上就是16
此时只要把ShowNum改成ShowHexNum即可正常显示10, 11, 12·····
也可以利用公式来用十进制显示:
LCD_ShowNum(2, 1, Sec / 16 * 10 + Sec % 16, 3 );
接下来就可以编写一个完整的时钟模块了
#include <REGX52.H>
#include "Delay.h"sbit DS1302_SCLK = P3^6;
sbit DS1302_IO = P3^4;
sbit DS1302_CE = P3^5;//其实写的地址 或上 0x01 就是读的地址了
//所以下面只要重定义写的地址就行了
#define DS1302_SECOND 0x80
#define DS1302_MINUTE 0x82
#define DS1302_HOUR 0x84
#define DS1302_DATE 0x86
#define DS1302_MONTH 0x88
#define DS1302_DAY 0x8A
#define DS1302_YEAR 0x8C
#define DS1302_WP 0x8E //写入保护的地址unsigned char DS1302_Time[] = {23, 8, 2, 10, 28, 50, 3};void DS1302_Init(void)
{DS1302_CE = 0;DS1302_SCLK = 0;
}void DS1302_WriteByte(unsigned char Command, Data)
{unsigned char i;DS1302_CE = 1;for(i = 0; i < 8; i ++) {DS1302_IO = Command & (0x01 << i); //IO非0即1,从低到高每次取出一位DS1302_SCLK = 1;Delay(10);DS1302_SCLK = 0;}for(i = 0; i < 8; i ++) {DS1302_IO = Data & (0x01 << i); //IO非0即1,从低到高每次取出一位DS1302_SCLK = 1;Delay(10);DS1302_SCLK = 0;}DS1302_CE = 0;
}unsigned char DS1302_ReadByte(unsigned char Command)
{unsigned char i, Data = 0x00;DS1302_CE = 1;for(i = 0; i < 8; i ++) {DS1302_IO = Command & (0x01 << i); //IO非0即1,从低到高每次取出一位DS1302_SCLK = 0; //写入Delay(10);DS1302_SCLK = 1; //这样在不改变写入时序的同时还能保证最后是1}Delay(10);//接下来要读的数据已经在IO口上了已经可以读了for(i = 0; i < 8; i ++) {DS1302_SCLK = 1; //读入Delay(10);DS1302_SCLK = 0;if(DS1302_IO) {Data |= (0x01 << i);} //把IO口的数据由低位到高位复现在Data上}DS1302_IO = 0;DS1302_CE = 0;return Data;
}void DS1302_SetTime(void) //将数组中的时间写入芯片
{DS1302_WriteByte(DS1302_WP, 0x00); //关闭写保护DS1302_WriteByte(DS1302_YEAR, DS1302_Time[0]/10*16+DS1302_Time[0]%10);DS1302_WriteByte(DS1302_MONTH, DS1302_Time[1]/10*16+DS1302_Time[1]%10);DS1302_WriteByte(DS1302_DATE, DS1302_Time[2]/10*16+DS1302_Time[2]%10);DS1302_WriteByte(DS1302_HOUR, DS1302_Time[3]/10*16+DS1302_Time[3]%10);DS1302_WriteByte(DS1302_MINUTE, DS1302_Time[4]/10*16+DS1302_Time[4]%10);DS1302_WriteByte(DS1302_SECOND, DS1302_Time[5]/10*16+DS1302_Time[5]%10);DS1302_WriteByte(DS1302_DAY, DS1302_Time[6]/10*16+DS1302_Time[6]%10);DS1302_WriteByte(DS1302_WP, 0x80); //打开写保护
}void DS1302_ReadTime(void) //把芯片中的时间读到数组中
{unsigned char temp;temp = DS1302_ReadByte(DS1302_YEAR | 0x01); //写的地址或上0x01就是读的地址DS1302_Time[0] = temp/16*10+temp%16;temp = DS1302_ReadByte(DS1302_MONTH | 0x01);DS1302_Time[1] = temp/16*10+temp%16;temp = DS1302_ReadByte(DS1302_DATE | 0x01);DS1302_Time[2] = temp/16*10+temp%16;temp = DS1302_ReadByte(DS1302_HOUR | 0x01);DS1302_Time[3] = temp/16*10+temp%16;temp = DS1302_ReadByte(DS1302_MINUTE | 0x01);DS1302_Time[4] = temp/16*10+temp%16;temp = DS1302_ReadByte(DS1302_SECOND | 0x01);DS1302_Time[5] = temp/16*10+temp%16;temp = DS1302_ReadByte(DS1302_DAY | 0x01);DS1302_Time[6] = temp/16*10+temp%16;
}
其实如果把BCD码与十进制相互转化的部分写成函数来处理,会大大减少代码量
要注意,这个封装好的DS1302.c要拿到外部调用的话,其中的DS1302_Time数组也需要在头文件中声明,外部可调用的变量要加上关键字extern
#ifndef __DS1302_H__
#define __DS1302_H__extern unsigned char DS1302_Time[]; //外部可调用的变量也需要声明void DS1302_Init(void);
void DS1302_WriteByte(unsigned char Command, Data);
unsigned char DS1302_ReadByte(unsigned char Command);
void DS1302_SetTime(void);
void DS1302_ReadTime(void);#endif
最后给出main.c代码
#include <REGX52.H>
#include "LCD1602.h"
#include "DS1302.h"unsigned char Sec;void main()
{LCD_Init();DS1302_Init();DS1302_WriteByte(0x8E, 0x00); //关闭写入保护LCD_ShowString(1, 1, " - - ");LCD_ShowString(2, 1, " : : ");DS1302_SetTime();while(1){DS1302_ReadTime();LCD_ShowNum(1, 1, DS1302_Time[0], 2);LCD_ShowNum(1, 4, DS1302_Time[1], 2);LCD_ShowNum(1, 7, DS1302_Time[2], 2);LCD_ShowNum(2, 1, DS1302_Time[3], 2);LCD_ShowNum(2, 4, DS1302_Time[4], 2);LCD_ShowNum(2, 7, DS1302_Time[5], 2);LCD_ShowNum(2, 10, DS1302_Time[6], 2);}
}
但是一个好的时钟远不止显示时间这么简单,还需要具有可调的功能。。
于是需要加入按键模块实现修改时间和定时器模块来实现光标闪烁效果
#include <REGX52.H>
#include "LCD1602.h"
#include "DS1302.h"
#include "Key.h"
#include "Timer0.h"unsigned char MODE, KeyNum, TimeSetSelect, TimeFlash;void Time_Show(void) //在LCD显示数组时间
{DS1302_ReadTime();LCD_ShowNum(1, 1, DS1302_Time[0], 2);LCD_ShowNum(1, 4, DS1302_Time[1], 2);LCD_ShowNum(1, 7, DS1302_Time[2], 2);LCD_ShowNum(2, 1, DS1302_Time[3], 2);LCD_ShowNum(2, 4, DS1302_Time[4], 2);LCD_ShowNum(2, 7, DS1302_Time[5], 2);LCD_ShowNum(2, 10, DS1302_Time[6], 2);
}void Time_Set(void) //利用按键修改数组并重新读取数组显示在LCD
{if(KeyNum == 2) //选择修改的位置{TimeSetSelect ++;TimeSetSelect %= 7;}if(KeyNum == 3) //增加时间{DS1302_Time[TimeSetSelect] ++;}if(KeyNum == 4) //减少时间{DS1302_Time[TimeSetSelect] --;}//接下来更新显示 if(TimeFlash == 0 && TimeSetSelect == 0) LCD_ShowString(1, 1, " ");//熄灭的时候用空格覆盖else LCD_ShowNum(1, 1, DS1302_Time[0], 2);if(TimeFlash == 0 && TimeSetSelect == 1) LCD_ShowString(1, 4, " ");else LCD_ShowNum(1, 4, DS1302_Time[1], 2);if(TimeFlash == 0 && TimeSetSelect == 2) LCD_ShowString(1, 7, " ");else LCD_ShowNum(1, 7, DS1302_Time[2], 2);if(TimeFlash == 0 && TimeSetSelect == 3) LCD_ShowString(2, 1, " ");else LCD_ShowNum(2, 1, DS1302_Time[3], 2);if(TimeFlash == 0 && TimeSetSelect == 4) LCD_ShowString(2, 4, " ");else LCD_ShowNum(2, 4, DS1302_Time[4], 2);if(TimeFlash == 0 && TimeSetSelect == 5) LCD_ShowString(2, 7, " ");else LCD_ShowNum(2, 7, DS1302_Time[5], 2);if(TimeFlash == 0 && TimeSetSelect == 6) LCD_ShowString(2, 10, " ");else LCD_ShowNum(2, 10, DS1302_Time[6], 2);
}void Timer0_Routine() interrupt 1
{static unsigned int T0Count;TL0 = 0x66; //设置定时初值TH0 = 0xFC; //设置定时初值T0Count ++;if(T0Count >= 1000) //1s执行一次{T0Count = 0;TimeFlash = !TimeFlash; //1的时候显示数字,0的时候熄灭,达成闪烁}
}void main()
{LCD_Init();DS1302_Init();Timer0_Init();DS1302_WriteByte(0x8E, 0x00); //关闭写入保护LCD_ShowString(1, 1, " - - ");LCD_ShowString(2, 1, " : : ");DS1302_SetTime(); //先从数组中读取时间到芯片里while(1){KeyNum = Key(); //读取按键if(KeyNum == 1) //按下按键1切换时钟模式{if(MODE == 1) {MODE = 0; DS1302_SetTime();} //回到显示模式要重新读取数组到芯片里else MODE = 1;}switch(MODE){case 0: Time_Show(); break;case 1: Time_Set(); break;}}
}
但是这个程序有个bug,就是修改时间的部分没有进行越界判断,可能会出现13月,32日这样的数据,这个修改起来就是逻辑上的事情,在Time++或者–的时候特判一下就行,比较容易,这里偷个懒就不改了
相关文章:

51单片机学习--DS1302可调时钟
之前学习过用定时器做的时钟,但是那样不仅误差大还费CPU,接下来利用DS1302时钟模块做一个可调实时时钟 这一次直接编写DS1302模块,首先要在DS1392.c 中根据下面的模块原理图进行位声明: sbit DS1302_SCLK P3^6; sbit DS1302_IO …...
Matlab统计字符串中共有多少种字符以及每种字符出现次数的功能实现(Matlab R2021a)
在做2023年深圳杯B题的时候,需要使用隐写技术(将特定信息嵌入信息载体且不易被察觉,可被广泛地应用于著作权保护、数据附加等领域)将《中华人民共和国著作权法》全篇10314个字符写入图片,首先我想到的是利用霍夫曼编码…...
HTTPS文件传输
目录 0.https概述1.单钥匙锁2.双钥匙锁 - 防篡改3.双钥匙锁 - 防泄漏4.单双钥匙锁相互配合 0.https概述 HTTPS其实就是HTTP协议加上TLS/SSL,SSL是个加密套件,负责对HTTP的数据进行加密,TLS是SSL的升级版,现在提到HTTPS࿰…...
LOL-v2数据集和VE-LOL数据集的区别
LOL-v2数据集和VE-LOL数据集的区别 LOL-v2 LOL-v2数据集[64]包括两个不同的子集,即LOL-v2-real和LOL-v2-synthetic。LOL-v2-real子集是通过改变ISO和曝光时间在真实场景中捕获的,包括689对用于训练和测试的图像。在LOL-v2-synthetic子集中,…...

RabbitMQ(一) - 基本结构、SpringBoot整合RabbitMQ、工作队列、发布订阅、直接、主题交换机模式
RabbitMQ结构 Publisher : 生产者 Queue: 存储消息的容器队列; Consumer:消费者 Connection:消费者与消息服务的TCP连接 Channel:信道,是TCP里面的虚拟连接。例如:电缆相当于TCP,信道是一条独立光纤束&…...
涉及IMU的专业术语
文章目录 零偏维纳过程/布朗运动随机游走航迹推算 零偏 IMU(惯性测量单元)是一种用于测量物体在空间中的加速度和角速度的装置。它通常由加速度计和陀螺仪组成,这些传感器可以帮助确定物体的运动状态和方向。 在IMU中,“零偏”&…...
二维数组对角线判断
二维数组对角线判断 对于两个点(x1, y1)和(x2, y2)。如何判断二者是否在同一条正对角线,反对角线,或者正或反对角线上? 正对角线判断 x2-x1 y2 -y1 证明:任意一点(x1k, y1k),(k…...

数据可视化(六)多个子图及seaborn使用
1.多个子图绘制 #绘制多个子图 #subplot(*args,**kwargs) 每个subplot函数只能绘制一个子图 #subplots(nrows,ncols) #fig_add_subplot(行,列,区域) #绘制子图第一种方式 plt.subp…...

opencv-34 图像平滑处理-双边滤波cv2.bilateralFilter()
双边滤波(BilateralFiltering)是一种图像处理滤波技术,用于平滑图像并同时保留边缘信息。与其他传统的线性滤波方法不同,双边滤波在考虑像素之间的空间距离之外,还考虑了像素之间的灰度值相似性。这使得双边滤波能够有…...
Leetcode 268. Missing Number
Problem Given an array nums containing n distinct numbers in the range [0, n], return the only number in the range that is missing from the array. Algorithm Sum all the numbers as x x x and use n ( n 1 ) 2 − x \frac{n(n1)}{2} - x 2n(n1)−x. Code …...

MybatisPlus实战笔记
概述 Mybatis支持定制化SQL、存储过程以及高级映射,避免几乎所有的 JDBC 代码和手动设置参数以及获取结果集。可以使用简单的 XML 或注解来配置和映射原生信息,将接口和Java的POJO映射成数据库中的记录。 缺点: SQL工作量很大,尤…...
Android Studio 报错:Failed to create Jar file xxxxx.jar
通过分析,新下载的项目没有project/gradle目录,故通过其他项目复制到当前项目,就解决了该问题。 同时也出现了新的问题 Unable to start the daemon process.The project uses Gradle 4.1 which is incompatible with Java 11 or newer.原因…...

Django实现音乐网站 ⑸
使用Python Django框架制作一个音乐网站, 本篇主要是配置媒体资源设置。 目录 配置介绍 设置媒体资源 创建媒体资源目录 修改settings.py 注册媒体资源路由 总结 配置介绍 静态资源是指项目配置的js/css/image等系统常用文件。对于一些经常变动的资源&#x…...

基于VUE3+Layui从头搭建通用后台管理系统(前端篇)七:工作台界面实现
一、本章内容 本章实现工作台界面相关内容,包括echart框架引入,mock框架引入等,实现工作台界面框架搭建,数据加载。 1. 详细课程地址: 待发布 2. 源码下载地址: 待发布 二、界面预览 三、开发视频 基于VUE3+Layui从头搭建通用后台管理系统合集-工作台界面布局实现 五、…...

前端vue uni-app自定义精美海报生成组件
在当前技术飞速发展的时代,软件开发的复杂度也在不断提高。传统的开发方式往往将一个系统做成整块应用,一个小的改动或者一个小功能的增加都可能引起整体逻辑的修改,从而造成牵一发而动全身的情况。为了解决这个问题,组件化开发逐…...

高通滤波器,低通滤波器
1.高通滤波器是根据像素与邻近像素的亮度差值来提升该像素的亮度。 import cv2 import numpy as np from scipy import ndimagekernel_3_3 np.array([[-1,-1,-1],[-1,8,-1],[-1,-1,-1]]) print(kernel_3_3) kernel_5_5 np.array([[-1,-1,-1,-1,-1],[-1,1,2,1,-1],[-1,2,4,2,-…...

机器学习深度学习——卷积的多输入多输出通道
👨🎓作者简介:一位即将上大四,正专攻机器学习的保研er 🌌上期文章:机器学习&&深度学习——从全连接层到卷积 📚订阅专栏:机器学习&&深度学习 希望文章对你们有所帮…...

HTML5中Canvas学习笔记:Canvas
目录 一、HTML中Canvas画图strokeStyle 和 fillStyle 的区别是什么? 二、如何设置一幅canvas图中某个颜色透明? 三、H5 canvas中strokeRect参数如果是小数,如何处理? 四、H5 Canvas中如何画圆角矩形框? 一、HTML中…...

Windows安装子系统Linux
Windows安装子系统(Linux ubuntu) 安装条件步骤1.安装WSL命令2.设置Linux用户名和密码3.写个简单的.c程序看看4.如何互传文件 安装条件 Windows 10版本2004及更高的版本才能安装。 步骤 1.安装WSL命令 我们可以使用WSL来安装子系统 Linux ubuntu(默认是这个)。 …...

C 语言的 pow() 函数
作用: Calculates x raised to the power of y. 函数原型: double pow( double x, double y ); Required Header: <math.h> Compatibility: ANSI Return Value pow returns the value of x y x^{y} xy. No error message is printed on overflow or underflow. Paramete…...

springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...

学校招生小程序源码介绍
基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码,专为学校招生场景量身打造,功能实用且操作便捷。 从技术架构来看,ThinkPHP提供稳定可靠的后台服务,FastAdmin加速开发流程,UniApp则保障小程序在多端有良好的兼…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...

ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...

USB Over IP专用硬件的5个特点
USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...

毫米波雷达基础理论(3D+4D)
3D、4D毫米波雷达基础知识及厂商选型 PreView : https://mp.weixin.qq.com/s/bQkju4r6med7I3TBGJI_bQ 1. FMCW毫米波雷达基础知识 主要参考博文: 一文入门汽车毫米波雷达基本原理 :https://mp.weixin.qq.com/s/_EN7A5lKcz2Eh8dLnjE19w 毫米波雷达基础…...