1.DS1302
DS1302是低功耗实时时钟芯片,它可以对年、月、日、周、时、分、秒进行计时,且具有闰年补偿等多种功能。主要特点是采用串行数据传输,可为掉电保护电源提供可编程的充电功能,并且可以关闭充电功能。
1.引脚分析
原理图
DS1302是BCD码作为编码方式的,而且是压缩BCD码,8位表示0-99整数(Year = 99),7位表示0-79整数(Sec、Min = 60),6位表示0-49整数(Hour = 24、Date = 31),5位表示0-19整数(Month = 12),4位表示0-9整数(WeekDay = 7)。DS1302是变种SPI,通过SCLK和I/O相互配合,发送和接收信息。SCLK在上升沿前,主机通过I/O口发送数据,DS1302在上升沿是接收;SCLK在下降沿后,DS1302通过I/O口发送数据,主机接收。
使用同步串行通讯简化了DS1302 与微处理器的接口。与时钟/RAM 通讯只需要三根线: CE(也是原理图上的RST,SDA)(读写时必须保持高电平),I/O (数据线), and SCLK (串行时钟)。
2.寄存器结构
如上图,命令字启动每一次数据传输. MSB (位 7)必须是逻辑1. 如果是 0,则禁止对DS1302写入. 位 6 在逻辑0时规定为时钟/日历数据,逻辑1时为RAM数据.位 1 至 位 5 表示了输入输出的指定寄存器.LSB (位 0) 在逻辑0时为写操作(输出),逻辑1时为读操作(输入).命令字以LSB (位 0)开始总是输入.
由于读出来的是BCD码。BCD 的表示法是用4个二进制位来表示 一个十进制位,(就是2进制转化成10进制)也就是一个字节(16位)能够表示2个十进制数位,这是一种压缩的十进制表示方式,应用很广,最常见的就是CMOS里的时间存放格式就是BCD码格式。低四位的值就是实现十进制数的低四,高4位就是高四位的值,这样我们有很高效的转换方法:低四位+高四位×10 (上面是2位十进制数的)。
举例来说就是:如15用BCD码表示为 0001 0101;
明白了BCD是怎么表示后转换也就容易了,低4位和高4位分别转换然后合并起来就是了!低四位+高四位×10 (上面是2位十进制数的)。当然由于我们数码管上也要一位一位取,就不用高四位×10了,取出来就好了~~
2.时序分析
二.利用官方给的驱动程序
我们只需要把figure3上面的图搞清楚就好了
由此可知,写保护 可写是Ds1302_Single_Byte_Write(0XBE,0X00);写保护不可写Ds1302_Single_Byte_Write(0XBE,0X80);
附上全部代码~今天是2月14日耶,祝大家情人节快乐HEIHEI
#include <STC12C5A60S2.H>
#include "ds1302.h"
typedef unsigned char uchar;
typedef unsigned int uint;
uchar code tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0xbf};
uchar dsbuff[]= {10,10,10,10,10,10,10,10};//存数码管各位的显示符号,10就是关掉,11就是-
uchar discom=0;//位选
uchar S_time[7] = {0x50,0x09,0x19,0x14,0x02,0X00,0x20};//设置时间数(把第五位跳过)
uchar G_time[7] = {0};//保存时间组
void dstime_nyr();
void dstime_sfm();
void get_time();
void set_time();
void smg_Timer0Init();
void All_Init();
void All_Init()
{
P2 = (P2&0X1F|0X80);
P0 = 0XFF;
P2 = (P2&0X1F|0XA0);
P0 = 0X00;
P2 =(P2&0X1F|0XC0);
P0 = 0X00;
P2 = (P2&0X1F|0XE0);
P0 = 0XFF;
}
void Delay_ms(uint ms)
{
uint i,j;
for(i = ms;i >0; i--)
for(j = 845;j>0;j--);
}
void display()//2ms刷新一次
{
P2=(P2&0x1f)|0xe0;//顺序不能错
P0=0xff;//循环进来一次要把段清零
P2&=0x1f;
P2=(P2&0x1f)|0xc0;//位选
P0=1<<discom;
P2&=0x1f;//段选
P2=(P2&0x1f)|0xe0;
P0=tab[dsbuff[discom]];
P2&=0x1f;
if(++discom==8)discom=0;
}
void main(void)
{
All_Init();//初始化
smg_Timer0Init();//初始化数码管
set_time();//设置时间
while(1)
{
get_time();
}
}
void smg_Timer0Init(void) //2毫秒@12.000MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x40; //设置定时初值
TH0 = 0xA2; //设置定时初值
EA = 1;
ET0 = 1;
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
}
void smg_time()interrupt 1//每2毫秒进一次中断
{
static uint n1 = 0;
if(n1 <4000)dstime_sfm();//4000*2ms= 8s 显示8s的时分秒
else dstime_nyr();//1000*2ms = 2s 显示2s的年月日
if(++n1 == 5000)n1 = 0;
display();//每2ms刷新一次数码管
}
void set_time()//设置时间
{
char i = 0;
Ds1302_Single_Byte_Write(0x8E,0X00);//写保护可写
for(i = 0;i < 7;i++)
{
Ds1302_Single_Byte_Write(0x80+i*2,S_time[i]);
}//依次设置秒、分、时...
Ds1302_Single_Byte_Write(0X8E,0X80);//写保护不可写
}
void get_time()//获取时间
{
char i = 0;
for(i = 0;i<7;i++)
{
G_time[i] = Ds1302_Single_Byte_Read(0x81+i*2);
Delay_ms(5);//延时
}
}
void dstime_sfm()//显示时间
{
//BCD转码
dsbuff[6] = G_time[0]>>4;//秒十位
dsbuff[7] = G_time[0]&0x0F;//秒个位
dsbuff[5] = 11;//-
dsbuff[3] = G_time[1]>>4;//分十位
dsbuff[4] = G_time[1]&0x0F;//分个位
dsbuff[2] = 11;//-
dsbuff[0] = G_time[2]>>4;//时十位
dsbuff[1] = G_time[2]&0x0F;//时个位
}
void dstime_nyr()//显示年月日
{
dsbuff[6] = G_time[3]>>4;//日十位
dsbuff[7] = G_time[3]&0x0F;//日个位
dsbuff[5] = 11;//-
dsbuff[3] = G_time[4]>>4;//月十位
dsbuff[4] = G_time[4]&0x0F;//月个位
dsbuff[2] = 11;//-
dsbuff[0] = G_time[6]>>4;//年十位 注意这里把DAY跳过了
dsbuff[1] = G_time[6]&0x0F;//年个位
}
特别要注意这个display(),跟我之前的风格有很大的变化,特别是要先对这个段选清零。
超声波
来源:CSDN
作者:avalovef
链接:https://blog.csdn.net/avalovef/article/details/104304172