ds1302——斌哥51

2023-05-16

以下内容分别借鉴了“清翔 51”,“斌哥51”,以及CSDN“普通的不普通少年”

在这里插入图片描述

内部结构:
在这里插入图片描述
DS1302 包括时钟/日历寄存器和 31 字节(8 位)的数据暂存寄存器,数据通信仅通过一条串行输入输出口。实时时钟/日历提供包括秒、分、时、日期、月份和年份信息。闰年可自行调整,可选择 12 小时制和 24 小时制,可以设置 AM、PM。

使用同步串行通讯简化了 DS1302 与微处理器的接口。与时钟/RAM通讯只需要三根线: CE, I/O (数据线), and SCLK (串行时钟).*

典型应用电路:
在这里插入图片描述
管脚:
在这里插入图片描述
供电说明说明
Vcc2是主电源,Vcc1是备用电源。
当Vcc2>Vcc1+0.2v的时候,Vcc2供电
当Vcc2<Vcc1,Vcc1供电
在这里插入图片描述
上图是清翔51开发板的DS1302原理图

总结ds1302的引脚:
SCLK:串行时钟输入端,控制数据输入与输出。
I/O:双向输入线
CE:使能端,CE为高时允许DS1302读写数据,CE端为低时DS1302数据不可读写
X1与X2:外接32.768的圆形晶振,给时钟芯片提供晶振频率

控制寄存器(相当于命令控制寄存器)
用于存放ds1302的控制命令,他用于对ds1302的读写进行控制
在这里插入图片描述

要求命令字的bit7在每一次的数据传输过程中必须置为1,如果置为0,则禁止对ds1302写入数据。

位 6 在逻辑 0时规定为时钟/日历数据,
位6在逻辑 1时为 RAM数据.

位 1 至 位 5 为寄存器的5位地址位,用于选择进行读写的日历,时钟寄存器或者片内RAM

LSB (位 0) 在逻辑0时为写操作(输出)
LSB(位0)为逻辑1时为读操作(输入).命令字以 LSB (位 0)开始总是输入.

与日历时钟相关的寄存器(相当于数据寄存器)
在这里插入图片描述
**秒寄存器0x81,0x80:**当CH=0时,DS1302内部时钟运行,反之CH=1停止。
对于数据位,已知秒十位最大为5,个位最大为9,所以高位只需要3位,低位则需要4位。

**分钟寄存器0x83,0x82:**分钟寄存器就只有bit0-bit6作为数据位,bit7为0就好。

**小时寄存器0x85,0x84:**当BIT7为1时为12小时制,当BIT7为0时为24小时制。

**控制寄存器0x8f,0x8e:**当WP为1时,不能对Ds1302做任何操作。

寄存器内容是按照BCD码存放的,如READ:0x83地址读到的0x28代表28分钟。

SPI通信方式:

写操作
在这里插入图片描述
读操作
在这里插入图片描述
写操作描述:
首先要操作ds1302首先得拉高CE口
然后放上要写的数据
最后观察上面的时序图,在控制字指令输入后的下一个SCLK时钟的上升沿时,数据被写入DS1302,数据输入从最低位(0位)开始。

读操作描述:
首先要操作ds1302首先得拉高CE口
在命令字的最后一个上升沿时,我们令SCLK拉低,紧接着就可以读数据了
读出DS1302的数据,读出的数据也是从最低位到最高位。

总结:CE从低到高的的时候,CLK必须为低。
上升沿写入,下降沿读出
写操作:写完命令的紧接着的上升沿写入数据。
读操作:写完命令的紧接着的下降沿读出数据。
注意读写位是低位在前,不管是命令字还是地址。

将BCD码转为十进制码


 uchar BCD2DECIMAL(uchar BCD)
{
	return(BCD>>4)*10+(BCD & 0x0F)}

解释一下上面的代码,BCD码比如是0x28,对应的二进制就是0010 1000 我们先右移4位得到0000 0010,换为十进制就是2,然后乘10得到20。然后用BCD码按位操作与上0x0F 换成二进制就是0000 1000 & 0010 1000 得到了0000 1000换成十进制就是8,然后将20+8得到十进制数28。显然我们的目的就是28。与BCD码对应上了。
BCD码0x28的含义就是将高四位看做十位,低四位看做个位,来直观表示我们的数值,但并非真正意义上的十进制。
我么看做是少了ABCDEF的16进制。

**十进制数转8421码 **
往时钟芯片写入数据时,需将待写的十进制数转换为8421码。

unsigned char hex_to_bcd(unsigned char data)
{
    unsigned char temp;

    temp = (((data/10)<<4) + (data%10));
    return temp;
}

解释上面的代码,将一个十进制数先对10整除,然后左移至高4位。然后对这个十进制数取余,然后加上刚才算好的高位数据,就是BCD码。

复位以及时钟控制:
所有的数据传输在RST置一时进行(反复强调), 输入信号有两种功能:
首先,RST 接通控制逻辑,允许地址/命令序列送入移位寄存器;
其次,RST 提供终止单字节或多字节数据的传送手段。
当 RST 为高电平时,所有的数据传送被初始化,允许对 DS1302 进行操作。
如果在传送过程中 RST 置为低电平,则会终止此次数据传送,I/O 引脚变为高阻态。
上电运行时,在 Vcc≥2.5V 之前,RST 必须保持低电平。只有在 SCLK 为低电平时,才能将 RST 置为高电平。
I/O 为串行数据输入输出端(双向),后面有详细说明。SCLK 始终是输入端。

数据输入:
经过 8 个时钟周期的控制字节的输入,一个字节的输入将在下 8 个时钟周期的上升沿完成,数据传输从字节最低位开始。

数据输出:
经过 8 个时钟周期的控制读指令的输入,控制指令串行输入后,一个字节的数据将在下个 8 个时钟周期的下降沿被输出,注意第一位输出是在最后一位控制指令所在脉冲的下降沿被输出,要求 RST 保持位高电平。

同理 8 个时钟周期的控制读指令如果指定的是突发模式,将会在脉冲的上升沿读入数据,下降沿读出数据,突发模式一次可进行多字节数据的一次性读写,只要控制好脉冲就行了。

主函数:


# include <reg51.h>
# include "display.h"		//1602,忙检测,写数据,写命令,位定义,
# include "ds1302.h"



uchar sec = 0,minu = 0,hour = 0;
uint j ;


//BCD转码方法1
//#define BCD_to_Decimal(bcd) ((((bcd) / 10) << 4) + ((bcd) % 10))
//#define Decimal_to_BCD(dec)  (((0xf0 & (dec)) >> 4)*10 + (0x0f & (dec)))


void main (void)
{
	//1602配置命令
	Lcd1602_Write_CMD(0x01);    //清屏操作
	Lcd1602_Write_CMD(0x06);    //每次写入一个数据光标右移
	Lcd1602_Write_CMD(0x0C);    //打开显示,不显示光标
	Lcd1602_Write_CMD(0x38); 		//8位数据口,2行显示
	
	//我们定时为13:56:12     (如果使用这部分的代码,会导致每次进入main函数,都会重新写入13:56:12,等于说每次都从这个时间点开始执行)
	ds1302_Writedata(0x8E,0x00);		//写保护寄存器,打开写保护,允许写入数据
	ds1302_Writedata(0x80,0x12);		//秒寄存器,这里的数据使用的BCD码格式写入
	ds1302_Writedata(0x82,0x56);		//分钟寄存器
	ds1302_Writedata(0x84,0x13);		//时寄存器
	ds1302_Writedata(0x8E,0x80);		//写保护寄存器,关闭写保护,不允许写入数据
	
	LCD_Position(1,0); 
	LCD_dispaly("welcome!!Testing");
	
	while(1)
	{
		
		sec = ds1302_Readdata(0x81);		//读出秒,形参为要读取的地址
		minu = ds1302_Readdata(0x83);		//读出分钟
		hour = ds1302_Readdata(0x85);		//读出小时
		
		LCD_Position(0,0);
		
		
		//首先要知道BCD码只会显示0-9这十个数
		//那么最大的9是0x09 二进制为0000 1001
		//那么对于9以上的数,比如0x10,0001 0000
		//也就是说高四位用来表示十位0-9,低四位用来显示个位的0-9,正好一个字节
		
		
		Lcd1602_Write_DAT(hour/16 + '0');   //hour,minu,dec读出来的都是BCD码,这里将BCD码转为10进制
		Lcd1602_Write_DAT(hour%16 + '0'); 
		
		Lcd1602_Write_DAT(':'); 
		
		Lcd1602_Write_DAT(minu/16 + '0');   //分钟的高位
		Lcd1602_Write_DAT(minu%16 + '0'); 
		
		Lcd1602_Write_DAT(':'); 
		
		Lcd1602_Write_DAT(sec/16 + '0'); 
		Lcd1602_Write_DAT(sec%16 + '0'); 
		

		 
		
		
		
		j=50000;
		
		while(j--);
	
	}
}

ds1302.c

# include "ds1302.h"

//底层写一个字节
//从低位开始写入
void ds1302_WriteB(uchar dat)
{
	uchar i = 0;
	
	for(i= 0;i<8;i++)   //依次写入8位
	{
		CLK = 0;    //写前保证clk为低
		_nop_();    //_nop_只是短暂延时,并无要求
		IO = dat & 0x01;     //写入dat的最低位到IO口上
		_nop_();    
		CLK = 1;     //上升沿写入
		_nop_();
		dat>>=1;     //准备写入下一位,注意ds1302是先低位再高位
	}

}



//底层读一个字节
//从低位开始读取
uchar ds1302_ReadB()
{
	uchar i = 0;
	uchar rdata = 0;
	for(i=0;i<8;i++)  //依次读1个字节
	{
		rdata>>=1;    //初始radta为0,我们每次将io读到的数据先放在最高位,依次右移直到8位全部读取。注意先读取的是低位。
		CLK = 0;      //下降沿读取
		_nop_();
		
		if(IO==1)    //如果是1则读取,并放到最高位
			rdata = rdata | 0x80; //或上0x80,意味着读取到的最高位只要为1,必然是1。
		else
			rdata = rdata | 0x00;   //如果是0,也读取并放到最高位
		CLK = 1;       //读完一个Bit拉高,准备读取下一个bit
		_nop_();
	}
	return rdata;
}

//向ds1302的某个地址写数据
void ds1302_Writedata(uchar addr,uchar dat)
{
	CE = 0;			//初始为0
	CLK = 0;    //CLK初始必须为0	
	CE = 1;			//使能

	//先写地址
	ds1302_WriteB(addr);
	//写数据
	ds1302_WriteB(dat);
	
	CLK = 0;
	CE = 0;

}

//从ds1302读取数据
uchar ds1302_Readdata(uchar addr)
{
	uchar temp = 0;  //存放读取到的数据
	
	CE = 0;			//初始为0
	CLK = 0;    //CLK初始必须为0	
	CE = 1;			//使能

	//先写地址
	ds1302_WriteB(addr);
	//读数据
	temp = ds1302_ReadB();
	return temp;
}

ds1302.h

# ifndef __ds1302_H__
# define __ds1302_H__


//头文件宏定义
# include<reg51.h>
# include<intrins.h>

//变量类型宏定义
# define uchar unsigned char 
# define uint unsigned int

sbit CLK = P1^0; //时钟
sbit IO = P1^1;   //数据
sbit CE = P1^2;  //使能

//函数声明
void ds1302_WriteB(uchar dat);		//底层写
uchar ds1302_ReadB();			//底层读
void ds1302_Writedata(uchar addr,uchar dat);		//写
uchar ds1302_Readdata(uchar addr);	//读

# endif

lcd1602.c


# include "lcd1602.h"

# define uchar unsigned char
# define uint unsigned int 

/**********************************
*				忙检检测函数								*
*				判断LCD1602当前是否在忙		*
***********************************/

void Lcd1602_busycheck()  
{
	uint sta = 0;  //定义一个变量用来存储Dataport读到的数据
	
	Dataport = 0xff; //人为释放Dataport数据线
	
	RS = 0;      //命令
	RW = 1;      //读
	
	//忙则循环判断,不忙则结束循环
	do
	{

		
		E = 1;        //使能
		
		sta = Dataport;  //读取数据端口的值,如果显示屏不忙那就是0xFF,如果忙就不是0xFF
		
		E = 0;
		
		
	}while((sta & 0x80) == 0x80);   //0x80 就是1000 0000 我们用来判断端口的最高位是不是1,如果是1则代表忙,不是1则不忙

}


/**********************************
*				写数据函数								*
*				判断LCD1602当前是否在忙		*
***********************************/

void Lcd1602_Write_DAT(uchar Dat)  //一次写8Bit
{
	Lcd1602_busycheck();		//检测忙不忙
	
	RS = 1;  //数据
	RW = 0;		//写操作
	
	Dataport = Dat;
	
	E = 1;    //当E由高电平变为低电平的时候,液晶开始执行命令
	_nop_();

	E = 0;
  
}
	
/**********************************
*				写命令函数								*
*				判断LCD1602当前是否在忙		*
***********************************/
void Lcd1602_Write_CMD(uchar Comd)  //一次写8Bit
{
	Lcd1602_busycheck();		//检测忙不忙
	
	RS = 0;  //命令
	RW = 0;		//写操作
	
	Dataport = Comd;
	
	E = 1;    //当E由高电平变为低电平的时候,液晶开始执行命令
	_nop_();
	E = 0;
}

lcd1602.h

# ifndef __lcd1602_H__
# define __lcd1602_H__

# include <reg51.h>
# include <intrins.h>

# define uchar unsigned char
# define uint unsigned int 
# define Dataport P0   //以P0作为数据口


sbit RS = P3^5;  //命令或数据,高数据,低命令

sbit RW = P3^6;	//写或读,高读低写

sbit E = P3^4;	//使能

void Lcd1602_busycheck(); 		//忙检测
void Lcd1602_Write_DAT(uchar Dat);    //写数据
void Lcd1602_Write_CMD(uchar Comd);    //写命令

# endif

dsiplay.h

# ifndef __display_H__
# define __display_H__

# include "lcd1602.h"


# define uchar unsigned char
# define uint unsigned int 
	
void LCD_dispaly(uchar* str);
void LCD_Position(bit x,uchar y) ;
	
#endif

display.c
主要包含了lcd显示字符串的函数,显示位置函数

# include "display.h"


//LCD显示字符串函数
void LCD_dispaly(uchar* str)
{
	//"\0"在c语言中代表“字符串结束符”。“\0”的ASCII码为“0”,
	//也就是空字符;字符串总是以“\0”作为串的结束符;因此当把一个字符
	//串存入一个数组时,也把结束符“\0”存入数组,并以此作为该字符串是
	//否结束的标志。”
	while(*str)  //比如输入good   总共有g o o d \0   5个元素
	{
			Lcd1602_Write_DAT(*str++) ; 
	}

}


//指定写入数据的位置
void LCD_Position(bit x,uchar y)  //定义行x,定义列y
{
	uchar position;
	if(x == 0)
		position = 0x80 + y;		
	else
		position = 0xC0 + y;
	
	Lcd1602_Write_CMD(position);
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ds1302——斌哥51 的相关文章

  • Intel Realsense D435i&L515 驱动安装

    Intel Realsense D435i amp L515 驱动安装 0 引言1 D435i amp L515固件更新1 1 D435i固件更新1 2 L515固件更新 2 Intel Realsense驱动安装3 ROS Wrapper
  • 位置编码Positional Encoding

    位置编码Positional Encoding 1 Transformers中的PE2 什么是Transformer位置编码2 1 表格型2 2 相对位置的关系 函数型 3 为什么可以表示相对距离 xff1f 4 其他参考 内容全来自于网络
  • vscode 调试 Python 代码

    vscode 调试 Python 代码 0 引言1 插件2 环境布置3 parser解析 0 引言 参考0参考1 1 插件 官方的python插件代码助手 xff0c 自动补全 xff1a 解释器选择 xff0c 在窗口右下角选择解释器 x
  • OpenCV 相机转换为 OpenGL 相机

    OpenCV 相机转换为 OpenGL 相机 0 引言1 预备知识和概述2 资源3 OpenCV和OpenGL中的图像坐标系统3 1 OpenCV H Z和OpenGL中的主轴3 2 齐次坐标和OpenGL中的归一化设备坐标 4 OpenC
  • 两轮差速小车循线控制原理分析

    硬件资料设定 xff1a 小车驱动来自于两个相同的电机 xff0c 转向依靠两轮差速实现 xff0c 小车前后左右安装超声波传感器 xff0c 前后各一个 xff0c 左右各两个 xff1b 功能目标 xff1a 假设小车左侧有墙壁 xff
  • ch06-Pytorch的正则化与归一化

    ch06 Pytorch的正则化与归一化 0 引言1 weight decay 和 dropout1 1 Regularization1 2 Dropout 2 Normalization2 1 Batch Normalization2 2

随机推荐

  • ch07-Pytorch的训练技巧

    ch07 Pytorch的训练技巧 0 引言1 模型保存与加载1 1 序列化与反序列化1 2 PyTorch 中的模型保存与加载1 3 模型的断点续训练 2 模型 Finetune2 1 Transfer Learning amp Mode
  • opencv-contrib-Python编译module 'cv2.cv2' has no attribute 'xfeatures2d'

    opencv contrib Python编译module 39 cv2 cv2 39 has no attribute 39 xfeatures2d 39 引言解决步骤一解决步骤二 引言 opencv contrib Python编译出现
  • find_package()函数

    find package函数 引言1 find package用法2 find package原理3 A required library with LAPACK API not found 错误解决4 添加findpackage查询路径
  • py安装文件时报错usage: setup.py [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...]

    py安装文件时报错usage setup py global opts cmd1 cmd1 opts cmd2 cmd2 opts 引言solved 引言 报错 xff1a python setup py fastentrypoints u
  • VScode单步调试

    VScode配置 0 快捷键1 安装clang2 VScodeDebug3 Cmake支持gdb调试的方法 0 快捷键 稍大工程在vscode下的调试参考该博客 Ctrl 43 打开默认终端 Ctrl 43 Shift 43 新建新的终端
  • 串口通信简介

    串口通信 串口通信是一种串行异步通信 xff0c 通信双方以字符帧作为数据传输单位 xff0c 字符帧按位依次传输 xff0c 每个位占固定的时间长度 两个字符帧之间的传输时间间隔可以是任意的 xff0c 即传输完一个字符帧之后 xff0c
  • ubuntu16.0 ROS(介绍EAI的YDLIDAR-X4激光雷达在ROS下使用方法)

    YDLIDAR X4激光雷达介绍 YDLIDAR X4激光雷达是深圳越登智能科技有限公司 xff08 YDLIDAR xff0c 这家公司属于EAI xff09 研发的一款 360 度二维测距产品 xff0c 本产品基于三角测距原理 xff
  • php使用http_build_query,parse_url,parse_str创建与解析url

    1 http build query http build query 可以创建urlencode之后的请求字符串 span class hljs keyword string span http build query mixed spa
  • 无人驾驶小车调试笔记(六)-- 车轮校准

    简介 xff1a 小车的动力完全来自于两个电机带动的车轮 xff0c 在理想状态下 xff0c 给两个电机同样的驱动参数 xff0c 两个车轮会以同样的转速带动小车直线行驶 xff0c 而实际情况是每个电机可能都会有个体差异 xff0c 也
  • Nginx HTTP详解

    正文 1 Nginx启动流程 2 HTTP 初始化 新连接建立时的行为 在上次博客的最后可以看到 xff0c 在ngx event accept方法建立连接的最后一步 xff0c 将会调用ngx listening t监听结构体的handl
  • 时钟周期,机器周期,指令周期的相互关系

    1 时钟周期 61 振荡周期 xff0c 名称不同而已 xff0c 都是等于单片机晶振频率的倒数 xff0c 如常见的外接12M晶振 xff0c 那它的时钟周期 61 1 12M 2 机器周期 xff1a 8051系列单片机的机器周期 61
  • 单片机的分频是什么意思?

    分频就是单片机的时钟频率 xff08 也就是晶振的震荡频率 xff09 F经过12分频 xff0c 变换成F 12的频率 简单的来说就是以整数倍降低频率 2分频就是分频前的频率除以2 xff1b 4分频就是分频前的频率除以4 比如 xff1
  • NMOS和PMOS管

    这里我先说一下我自己分辨MOS管的方法 对于NMOS我们看下图中的箭头 xff0c 都是远离源头 对于PMOS我们看箭头 xff0c 都是指向源头 P xff1a POSITIVE积极的寻找自己的起源 N xff1a NEGTIVE消极的远
  • 基本运算放大电路

    我先说明 下面的内容应该很多人都看到过 xff0c 但是我建议还是细看 xff0c 最好自己推一下 我就是这么做的 运算放大器工作原理综述 xff1a 运算放大器组成的电路五花八门 xff0c 令人眼花瞭乱 xff0c 在分析运算放大器工作
  • PCB板框的绘制——AD19

    pcb板框的绘制当然首先要切换到keep out 层才行 找到设置 xff0c 找到keep out 假如我们要绘制一个矩形的板框 xff0c 我们选择线径就可以 手动绘制一个矩形的板框 我们需要让我们的板子边框按照我们所绘制的走线来定义
  • 零基础自学STM32-野火——GPIO复习篇——使用绝对地址操作GPIO

    今天主要是复习一下 结合野火的 零基础开发指南 名字没记住大概是这个 先放一张结构图 存储器映射 xff08 初学重点 xff09 xff1a 我们的片内外设比如 xff1a Flash Sram Fsmc 以及挂在AHB 总线上的外设 x
  • Lcd1602——斌哥51

    最新修改时间2022 7 22 LCD1602 16代表显示16个字符 xff0c 2代表总共显示两行 芯片的工作电压是4 5 5 5v 工作电流2 0ma xff08 5V xff09 模块最佳工作电压5 0v 字符尺寸 xff1a 2
  • 无人驾驶小车调试笔记(七)-- 相机校准

    简介 xff1a 在第五节的内容中 xff0c 我们学习了使用rqt工具集观看摄像头视频流的方法 xff0c 细心的同学应该会发现camera node发布的视频数据中的图像有变形现象 xff0c 图像变形会导致直线不直 xff0c 部分区
  • Python实现MySql、SqlServer增删改查操作

    span class token keyword import span pymssql span class token keyword def span span class token function connection sql
  • ds1302——斌哥51

    以下内容分别借鉴了 清翔 51 xff0c 斌哥51 xff0c 以及CSDN 普通的不普通少年 内部结构 xff1a DS1302 包括时钟 日历寄存器和 31 字节 xff08 8 位 xff09 的数据暂存寄存器 xff0c 数据通信