嵌入式开发学习(STC51-14-时钟)

news2024/11/14 6:29:16

内容

在数码管上显示时间,时分秒,格式为“XX-XX-XX”;

DS1302时钟芯片介绍

简介

DS1302是DALLAS公司推出的涓流充电时钟芯片,内含有一个实时时钟/日历和31字节静态RAM,通过简单的串行接口与单片机进行通信;

实时时钟/日历电路提供秒、分、时、日、周、月、年的信息,每月的天数和闰年的天数可自动调整;

时钟操作可通过AM/PM指示决定采用24或12小时格式;

DS1302与单片机之间能简单地采用同步串行的方式进行通信,仅需用到三根通信线:RES复位、I/O数据线、SCLK串行时钟;

时钟/RAM的读/写数据以一个字节或多达31个字节的字符组方式通信;

DS1302工作时功耗很低保持数据和时钟信息时功率小于1mW;

结构

物理结构

在这里插入图片描述
1,VCC2:主电源引脚
2,X1、X2:DS1302外部晶振引脚,通常需外接32.768K晶振
3,GND:电源地
4,CE:使能引脚,也是复位引脚(新版本功能变)
5,I/O:串行数据引脚,数据输出或者输入都从这个引脚
6,SCLK:串行时钟引脚
7,VCC1:备用电源

程序结构

DS1302有一个控制寄存器、12 个日历、时钟寄存器和31个RAM

控制寄存器

控制寄存器用于存放DS1302的控制命令字,DS1302的RST引脚回到高电平后写入的第一个字节就为控制命令;

它用于对DS1302读写过程进行控制;

格式如下:
在这里插入图片描述
1、第7位永远都是1;
2、第6位,1表示RAM,寻址内部存储器地址;0表示CK,寻址内部寄存器;
3、第5到第1位,为RAM或者寄存器的地址;
4、最低位,高电平表示RD,即下一步操作将要“读”;低电平表示W,即下一步操作将要“写”;(与AT24C02寄存器类似,这点要理解好)
在这里插入图片描述
在这里插入图片描述
比如读秒寄存器命令为1000 0001,反之写秒寄存器命令为1000 0000

日历/时钟寄存器

DS1302共有12个寄存器,其中有7个与日历、时钟相关,存放的数据为BCD码形式;

格式如下:
在这里插入图片描述
在这里插入图片描述

  • 秒寄存器:低四位为秒的个位,高的次三位为秒的十位;最高位CH为DS1302的运行标志,当CH=0时,DS1302内部时钟运行,反之CH=1时停止;
  • 小时寄存器:最高位为12/24小时的格式选择位,该位为1时表示12小时格式;当设置为12小时显示格式时,第5位的高电平表示下午(PM);而当设置为24小时格式时,第5位为具体的时间数据;
  • 写保护寄存器:当该寄存器最高位WP为1时,DS1302只读不写,所以要在往DS1302写数据之前确保WP为0;
  • 慢充电寄存器(涓细电流充电)寄存器:我们知道,当DS1302掉电时,可以马上调用外部电源保护时间数据,该寄存器就是配置备用电源的充电选项的;其中高四位(4个TCS)只有在1010的情况下才能使用充电选项;低四位的情况与DS1302内部电路有关;

使用

BCD码

在日历/时钟寄存器中一般都是以BCD码存放数据;

BCD码是通过4位二进制码来表示1位十进制中的0~9这10个数码;

如下所示:
在这里插入图片描述
所以从DS1302中读取出来的时钟数据均为BCD码格式,需转换为我们习惯的10进制;

DS1302的读写时序

在控制指令字输入后的下一个SCLK时钟的上升沿时,数据被写入DS1302,数据输入从低位(位0)开始;

同样,在紧跟8位的控制指令字后的下一个SCLK脉冲的下降沿读出DS1302的数据,读出数据时从低位0位到高位7;

其时序图如下所示:
在这里插入图片描述
上图就是DS1302的三个时序:复位时序,单字节写时序,单字节读时序;

  • CE(RST):复位时序,即在RST引脚产生一个正脉冲,在整个读写期间,RST要保持高电平,一次字节读写完毕之后,要注意把RST返回低电平准备下次读写周期;
  • 单字节读时序:注意读之前还是要先对寄存器写命令,从最低位开始写;可以看到,写数据是在SCLK的上升沿实现,而读数据在SCLK的下降沿实现;所以,在单字节读时序中,写命令的第八个上升沿结束后紧接着的第八个下降沿就将要读寄存器的第一位数据读到数据线上了,这个就是DS1302操作中最特别的地方;当然读出来的数据也是最低位开始;
  • 单字节写时序:两个字节的数据配合16个上升沿将数据写入即可;

使用步骤

1 将数据写入DS1302的寄存器,设置它当前的时间的格式;

2 使DS1302开始运作,DS1302时钟会按照设置情况运转,再用单片机将其寄存器内的数据读出;

3 再用液晶显示,就是我们常说的简易电子钟;

原理图

在这里插入图片描述
从上图中可知,DS1302芯片的控制管脚SCLK、I/O、CE接至单片机P3.6、P3.4、P3.5上;

芯片的X1、X2管脚处外接了一个32.768KHZ晶振,为时钟运行提供一个稳定的时钟频率,C2和C3为旁路电容,目的是消除晶振起振时产生的电感干扰;

如果有外部电源还能将电源接入第8脚VCC1;

思路

按照时序图编写DS1302的初始化和读写程序;

读取时间并显示在数码管上;

(读取数据时注意将BCD格式转换为十进制,其实就是,把十进制数取个十百单位时的,除10余10操作,换成除16余16)

编码

User

main.c

/*
 * @Description: 在数码管上显示时间,时分秒,格式为“XX-XX-XX”
 */
#include "public.h"
#include "smg.h"
#include "ds1302.h"

void main()
{
	u8 time_buf[8];

	// 设置初始时间
	// 原本初始化时间2000年01月01日星期六0点0分0秒
	//---存储顺序是秒分时日月周年,存储格式是用BCD码---//
	gDS1302_TIME[0] = 0x06; // 秒
	gDS1302_TIME[1] = 0x06; // 分
	gDS1302_TIME[2] = 0x06; // 时
	// gDS1302_TIME[3] = {}; // 日
	// gDS1302_TIME[4] = {}; // 月
	// gDS1302_TIME[5] = {}; // 周
	// gDS1302_TIME[6] = {}; // 年

	ds1302_init(); // 初始化DS1302

	while (1)
	{
		ds1302_read_time();
		time_buf[0] = gsmg_code[gDS1302_TIME[2] / 16];
		time_buf[1] = gsmg_code[gDS1302_TIME[2] & 0x0f];
		time_buf[2] = 0x40;
		time_buf[3] = gsmg_code[gDS1302_TIME[1] / 16];
		time_buf[4] = gsmg_code[gDS1302_TIME[1] & 0x0f];
		time_buf[5] = 0x40;
		time_buf[6] = gsmg_code[gDS1302_TIME[0] / 16];
		time_buf[7] = gsmg_code[gDS1302_TIME[0] & 0x0f];
		smg_display(time_buf, 1);
	}
}

Public

public.h

#ifndef _public_H
#define _public_H

#include "reg52.h"

typedef unsigned int u16; // 对系统默认数据类型进行重定义
typedef unsigned char u8;

void delay_10us(u16 ten_us);
void delay_ms(u16 ms);

#endif

public.c

#include "public.h"

/**
 * @description: 延时函数,ten_us=1时,大约延时10us
 * @param {u16} ten_us 延时倍数
 * @return {*}
 */
void delay_10us(u16 ten_us)
{
	while (ten_us--)
		;
}

/**ms延时函数,ms=1时,大约延时1ms***
 * @param {u16} ms 延时倍数
 * @return {*}
 */
void delay_ms(u16 ms)
{
	u16 i, j;
	for (i = ms; i > 0; i--)
		for (j = 110; j > 0; j--)
			;
}

App/ds1302

ds1302.h

#ifndef _ds1302_H
#define _ds1302_H

#include "public.h"

// 管脚定义
sbit DS1302_RST = P3 ^ 5; // 复位管脚
sbit DS1302_CLK = P3 ^ 6; // 时钟管脚
sbit DS1302_IO = P3 ^ 4;  // 数据管脚

// 变量声明
extern u8 gDS1302_TIME[7]; // 存储时间

// 函数声明
void ds1302_init(void);
void ds1302_read_time(void);

#endif

ds1302.c

#include "ds1302.h"
#include "intrins.h"

//---DS1302写入和读取时分秒的地址命令---//
//---秒分时日月周年 最低位读写位;-------//
u8 gREAD_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d};
u8 gWRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};

//---DS1302时钟初始化2000年01月01日星期六0点0分0秒---//
//---存储顺序是秒分时日月周年,存储格式是用BCD码---//
u8 gDS1302_TIME[7] = {0x00, 0x00, 0x00, 0x01, 0x06, 0x01, 0x00};

/**
 * @description: DS1302写单字节
 * @param {u8} addr 地址/命令
 * @param {u8} dat 要写入的数据
 * @return {*}
 */
void ds1302_write_byte(u8 addr, u8 dat)
{
	u8 i = 0;

	DS1302_RST = 0;
	_nop_();
	DS1302_CLK = 0; // CLK低电平
	_nop_();
	DS1302_RST = 1; // RST由低到高变化
	_nop_();

	for (i = 0; i < 8; i++) // 循环8次,每次写1位,先写低位再写高位
	{
		DS1302_IO = addr & 0x01;
		addr >>= 1;
		DS1302_CLK = 1;
		_nop_();
		DS1302_CLK = 0; // CLK由低到高产生一个上升沿,从而写入数据
		_nop_();
	}
	for (i = 0; i < 8; i++) // 循环8次,每次写1位,先写低位再写高位
	{
		DS1302_IO = dat & 0x01;
		dat >>= 1;
		DS1302_CLK = 1;
		_nop_();
		DS1302_CLK = 0;
		_nop_();
	}
	DS1302_RST = 0; // RST拉低
	_nop_();
}

/**
 * @description: DS1302读单字节
 * @param {u8} addr 地址/命令
 * @return {u8} 读取的数据
 */
u8 ds1302_read_byte(u8 addr)
{
	u8 i = 0;
	u8 temp = 0;
	u8 value = 0;

	DS1302_RST = 0;
	_nop_();
	DS1302_CLK = 0; // CLK低电平
	_nop_();
	DS1302_RST = 1; // RST由低到高变化
	_nop_();

	for (i = 0; i < 8; i++) // 循环8次,每次写1位,先写低位再写高位
	{
		DS1302_IO = addr & 0x01;
		addr >>= 1;
		DS1302_CLK = 1;
		_nop_();
		DS1302_CLK = 0; // CLK由低到高产生一个上升沿,从而写入数据
		_nop_();
	}
	for (i = 0; i < 8; i++) // 循环8次,每次读1位,先读低位再读高位
	{
		temp = DS1302_IO;
		value = (temp << 7) | (value >> 1); // 先将value右移1位,然后temp左移7位,最后或运算
		DS1302_CLK = 1;
		_nop_();
		DS1302_CLK = 0;
		_nop_();
	}
	DS1302_RST = 0; // RST拉低
	_nop_();
	DS1302_CLK = 1; // 对于实物中,P3.4口没有外接上拉电阻的,此处代码需要添加,使数据口有一个上升沿脉冲。
	_nop_();
	DS1302_IO = 0;
	_nop_();
	DS1302_IO = 1;
	_nop_();
	return value;
}

/**
 * @description: DS1302初始化时间
 * @return {*}
 */
void ds1302_init(void)
{
	u8 i = 0;
	ds1302_write_byte(0x8E, 0X00);
	for (i = 0; i < 7; i++)
	{
		ds1302_write_byte(gWRITE_RTC_ADDR[i], gDS1302_TIME[i]);
	}
	ds1302_write_byte(0x8E, 0X80);
}

/**
 * @description: DS1302读取时间
 * @return {*}
 */
void ds1302_read_time(void)
{
	u8 i = 0;
	for (i = 0; i < 7; i++)
	{
		gDS1302_TIME[i] = ds1302_read_byte(gREAD_RTC_ADDR[i]);
	}
}

App/smg

smg.h

#ifndef _smg_H
#define _smg_H

#include "public.h"

#define SMG_A_DP_PORT P0 // 使用宏定义数码管段码口

// 定义数码管位选信号控制脚
sbit LSA = P2 ^ 2;
sbit LSB = P2 ^ 3;
sbit LSC = P2 ^ 4;

extern u8 gsmg_code[17]; // 使“共阴极数码管显示0~F的段码数据”这个变量定义为外部可用

void smg_display(u8 dat[], u8 pos);

#endif

smg.c

#include "smg.h"

// 共阴极数码管显示0~F的段码数据
u8 gsmg_code[17] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71};

/**
 * @description: 动态数码管显示函数
 * @param {u8} dat 要显示的数据
 * @param {u8} pos 从左开始第几个位置开始显示,范围1-8
 * @return {*}
 */
void smg_display(u8 dat[], u8 pos)
{
	u8 i = 0;
	u8 pos_temp = pos - 1;

	for (i = pos_temp; i < 8; i++)
	{
		switch (i) // 位选
		{
		case 0:
			LSC = 1;
			LSB = 1;
			LSA = 1;
			break;
		case 1:
			LSC = 1;
			LSB = 1;
			LSA = 0;
			break;
		case 2:
			LSC = 1;
			LSB = 0;
			LSA = 1;
			break;
		case 3:
			LSC = 1;
			LSB = 0;
			LSA = 0;
			break;
		case 4:
			LSC = 0;
			LSB = 1;
			LSA = 1;
			break;
		case 5:
			LSC = 0;
			LSB = 1;
			LSA = 0;
			break;
		case 6:
			LSC = 0;
			LSB = 0;
			LSA = 1;
			break;
		case 7:
			LSC = 0;
			LSB = 0;
			LSA = 0;
			break;
		}
		SMG_A_DP_PORT = dat[i - pos_temp]; // 传送段选数据
		delay_10us(100);							  // 延时一段时间,等待显示稳定
		SMG_A_DP_PORT = 0x00;						  // 消影
	}
}

编译和结果

按F7编译,无错误,生成.hex文件,使用pz-isp将hex文件下载到单片机

结果:成功显示时间,并正常计时
在这里插入图片描述

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

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

相关文章

系统架构设计高级技能 · 软件架构概念、架构风格、ABSD、架构复用、DSSA(一)【系统架构设计师】

系列文章目录 C技能系列 Linux通信架构系列 C高性能优化编程系列 深入理解软件架构设计系列 高级C并发线程编程 设计模式系列 期待你的关注哦&#xff01;&#xff01;&#xff01; 现在的一切都是为将来的梦想编织翅膀&#xff0c;让梦想在现实中展翅高飞。 Now everythin…

第4集丨Vue 江湖 —— 计算属性

目录 一、基本使用1.1 在computed中定义1.1.1 案例1.1.2 控制台调用getter1.1.3 控制台中的data和computed 1.2 缓存效果1.3 完整写法1.3.1 案例1.3.2 效果图 1.4 简写形式 二、案例的其他实现2.1 methods实现2.2 插值语法实现 三、体会计算属性的好处3.1 复杂任务时3.2 使用计…

IO模型-信号驱动IO

linux内核中存在一个信号SIGIO&#xff0c;这个信号就是用于实现信号驱动IO的。当应用程序中想要以信号驱动IO的模型读写硬件数据时&#xff0c;首先注册一个SIGIO信号的信号处理函数,当硬件数据就绪&#xff0c;硬件会发起一个中断&#xff0c;在硬件的中断处理函数中向当前进…

求解n阶勒让德多项式的值

描述 用递归方法求n阶勒让德多项式的值&#xff0c;递归公式为&#xff1a; 在主函数中输入一个整数n和一个实数x&#xff0c;调用函数 legendre(n,x)&#xff0c;并输出其返回值。 输入 第一行输入一个整数n&#xff0c;表示阶数&#xff1b;第二行输入一个实数x。 输出 …

增强型Web安全网关在银行的应用

销售&#xff0c;绝不是降低身份去取悦客户&#xff0c;而是像朋友一样给予合理的建议。你刚好需要&#xff0c;我刚好专业&#xff01;仅此而已&#xff01; 乔.吉拉德 健康的安全体系&#xff0c;还可以更完善 浙江某商业银行股份有限公司是一家成立多年的商业银行&#xf…

分布式异步任务处理组件(七)

分布式异步任务处理组件底层网络通信模型的设计--如图&#xff1a; 使用Java原生NIO来实现TCP通信模型普通节点维护一个网络IO线程&#xff0c;负责和主节点的网络数据通信连接--这里的网络数据是指组件通信协议之下的直接面对字节流的数据读写&#xff0c;上层会有另一个线程负…

装饰器模式(C++)

定义 动态(组合)地给一个对象增加一些额外的职责。就增加功能而言&#xff0c;Decorator模式比生成子类(继承)更为灵活(消除重复代码&减少子类个数)。 一《设计模式》 GoF 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xf…

视频安防监控EasyCVR平台海康大华设备国标GB28181告警布防的报文说明

TSINGSEE青犀视频监控综合管理平台EasyCVR基于云边端协同&#xff0c;可支持海量视频的轻量化接入与汇聚管理。平台既具备传统安防视频监控的能力&#xff0c;比如&#xff1a;视频监控直播、云端录像、云存储、录像检索与回看、告警上报、平台级联、云台控制、语音对讲等&…

第一课-前提-Stable Diffusion 教程

学习 SD 的前提是电脑配置! SD 参考配置: 建议选择台式机 i5 CPU, 内存16GB,N卡 RTX3060, 8G显存以上的配置(最低配) 在此基础上的配置越高越好。 比如,cpu i7 更好,显卡能有 RTX4090 更好,32显存要能有最好,嘿嘿嘿。 如何查看自己的显卡配置? Win+R 输入 “dxdiag…

vue2-v-if和v-for的优先级是什么?

1、v-if和v-for的区别 作用&#xff1a; v-if指令用于条件性地渲染一块内容&#xff0c;这块内容只会在指令的表达式返回true值的时候被渲染。 v-for指令基于一个数组来渲染一个列表&#xff0c;v-for指令需要使用item in items 形式的特殊语法&#xff0c;其中&#xff0c;it…

自学(黑客)技术,从入门到精通!

1.网络安全是什么 网络安全可以基于攻击和防御视角来分类&#xff0c;我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术&#xff0c;而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 2.网络安全市场 一、是市场需求量高&#xff1b; 二、则是发展相对成熟入…

Vue3 模板语法简单应用

去官网学习-》 模板语法 | Vue.js 运行示例&#xff1a; 代码&#xff1a;HelloWorld.vue <template><div class"hello"><h1>Vue 模板语法</h1><h2>{{ msg }}</h2><h2>{{ textHtml }}</h2><h2 v-html"text…

【单运放RC振荡器1负反馈方波2正反馈正弦波方波】2021-12-9

缘由multisim运放芯片给一个连上电源另一个引脚打叉不能仿真-测试-CSDN问答 正反馈电阻影响转化阀值,负反馈电阻影响频率 固定负反馈为2时无法起震荡,电位器调节到2%可振荡且波形失真,电位器调节到0%且固定负反馈为2时才能正弦波输出

Spring Boot 集成Seata

Seata的集成方式有&#xff1a; 1. Seata-All 2. Seata-Spring-Boot-Starter 3. Spring-Cloud-Starter-Seata 本案例使用Seata-Spring-Boot-Starter演示&#xff1a; 第一步&#xff1a;下载Seata 第二步&#xff1a;为了更好看到效果&#xff0c;我们将Seata的数据存储改…

MyBatis 查询数据库之二(增、删、改、查操作)

目录 1. 配置打印 MyBatis 执行的SQL 2. 查询操作 2.1 通过用户 ID 查询用户信息、查询所有用户信息 (1) Mapper 接口 (2)UserMapper.xml 查询所有用户的具体实现 SQL (3)进行单元测试 3. 增加操作 3.1 在 mapper&#xff08;interface&#xff09;里面添加增加方法的声…

git仓库与本地暂存区的同步问题

向下同步 对于远程仓库的项目&#xff0c;初始化一个配置文件&#xff0c;配置远程仓库及相关信息&#xff0c;赋值远程仓库的地址&#xff0c;使用git pull命令即可拉取仓库代码。 git pull [remote_addr] 该部分完成向下同步 向上同步 向上同步时会遇到很多的问题&#xf…

viewerjs 如何新增下载图片功能(npm包补丁)

文章目录 先实现正常的效果实现下载图片改变viewerjs的build函数源码改变之后&#xff0c;执行npm i 之后node_modules源码又变回了原样 1、viwerjs所有功能都很完善&#xff0c;但唯独缺少了图片的下载 2、需求&#xff1a;在用viwerjs旋转图片后&#xff0c;可以直接下载旋转…

计算机视觉与图形学-神经渲染专题-Seal-3D(基于NeRF的像素级交互式编辑)

摘要 随着隐式神经表示或神经辐射场 (NeRF) 的流行&#xff0c;迫切需要与隐式 3D 模型交互的编辑方法&#xff0c;以完成后处理重建场景和 3D 内容创建等任务。虽然之前的作品从不同角度探索了 NeRF 编辑&#xff0c;但它们在编辑灵活性、质量和速度方面受到限制&#xff0c;无…

【CI/CD】图解六种分支管理模型

图解六种分支管理模型 任何一家公司乃至于一个小组织&#xff0c;只要有写代码的地方&#xff0c;就有代码版本管理的主场&#xff0c;初入职场&#xff0c;总会遇到第一个拦路虎 git 管理流程&#xff0c;但是每一个企业似乎都有自己的 git 管理流程&#xff0c;倘若我们能掌握…