一、 学习要点
1、问:DS1302的(双)总线与DHT11的单总线区别?
答:DS1302的总线是一条数据线,一条时钟线,此类总线“上写下读”,上升沿写入数据给器件,下降沿读取器件发送给主机的数据,此类传感器在读写操作前一定有控制命令发送给器件告知器件此次操作是读还是写,从而决定是给数据口赋值还是读取;DHT11的单总线类是靠检测数据线时长判断高点电平信号的。双总线串行就是把时钟信号当做一扇门了,配合数据信号进行操作。
2、问:串行数据通信接收/发送时高低位的次序怎么决定?
答:数据流发送方向与一元数轴类似从左向右传输,所以先传送低位;当主机接受数据,从机发送数据时候看为数轴的负方向所以先发送高位给主机;
3、问:DS1302数据格式怎么构成的?
答:
1)、写数据发送地址(写命令)+内容;
2)、读数据发送地址(读命令)+内容
4、问:出现实际两分钟的时候,DS1302的分钟才进位的原因?
答:在读取和写入函数中的数值左移一位语句的位置不是随便放置的,写入函数要在循环体末尾插入;读取函数时候要在循环体开始插入;若是多移一次正好差二倍;
5、问:八位数据中如何快速分出高四位与低四位?
答:除以十六就是高四位的值,对16做求余数运算结果就是低四位,同理可得32位数据拆分高16位于低16位;
6、问:时序图中菱形表示什么?
答:表示数据。
二、手册分析
1、
2、DS1302 是 DALLAS (达拉斯)公司推出的涓流充电时钟芯片 内含有一个实时时钟/日历和 31 字节静态 RAM 通过简单的串行接口与单片机进行通信,实时时钟/日历电路提供秒、分、时、日、日期、月、年的信息,每月的天数和闰年的天数可自动调整 时钟操作可通过 AM/PM 指示决定采用 24 或 12 小时格式 DS1302 与单片机之间能简单地采用同步串行的方式进行通信 仅需用到三个口线 1 RES 复位 2 I/O 数据线 3 SCLK串行时钟 时钟/RAM 的读/写数据以一个字节或多达 31 个字节的字符组方式通信 DS1302 工作时功耗很低保持数据和时钟信息时功率小于 1mW
3、实时时钟具有能计算 2100 年之前的秒 分 时 日 日期 星期 月 年的能力 还有闰年调整的能力;
4、读/写时钟或 RAM 数据时有两种传送方式单字节传送和多字节传送字符组方式;
5、引脚描述
6、DS1302 内部寄存器
CH: 时钟停止位 CH=0振荡器工作允许 CH=1振荡器停止;
WP: 写保护位 WP=0寄存器数据能够写入 WP=1寄存器数据不能写入;
TCS: 涓流充电选择 TCS=1010 使能涓流充电 TCS=其它禁止涓流充电;
DS: 二极管选择位 DS=01选择一个二极管 DS=10选择两个二极管,DS=00 或 11, 即使 TCS=1010, 充电功能也被禁止;
寄存器 2 的第 7 位 :12/24 小时标志 bit7=1,12 小时模式 bit7=0,24 小时模式;寄存器 2 的第 5 位:AM/PM 定义 AP=1下午模式 AP=0上午模式;
7、时序图
三:编程
1、 程序功能:在串口和LCD1602上显示时间
2、 程序效果
3、代码
DS1302.c
#include "DS1302.h"
void Delay1ms() //@11.0592MHz
{
unsigned char i,j;
_nop_();
i = 2;
j = 199;
do
{
while (--j);
} while (--i);
}
void Wr_Onebyte2DS1302(char cmd,char val )
{
char i,j;
RST = 0;
CLK = 0;
_nop_();
RST = 1;
for(i=0;i<8;i++) //先发送低位
{
j = cmd & 0x01;
if(j == 0)
{
DAT_1 = 0 ;
}
else
{
DAT_1 = 1 ;
}
CLK = 1;
CLK = 0;
cmd >>= 1;
}
for(i=0;i<8;i++) //先发送低位
{
j = val & 0x01;
if(j == 0)
{
DAT_1 = 0;
}
else
{
DAT_1 = 1;
}
CLK = 1;
CLK = 0;
val >>= 1;
}
RST = 0;
}
char Rd_OnebyteFromDS1302(char cmd)
{
int i,j;
RST = 0;
CLK = 0;
_nop_();
RST = 1;
cmd += 1;
for(i=0;i<8;i++) //先发送低位
{
j = cmd & 0x01;
_nop_();
if(j == 0)
{
DAT_1 = 0;
}
else
{
DAT_1 = 1 ;
}
_nop_();
CLK = 1;
_nop_();
CLK = 0;
cmd >>= 1;
}
for(i=0;i<8;i++) //先读低位
{
j >>= 1;
_nop_();
if(DAT_1 == 0)
{
j &= 0x7f;
}
else
{
j |= 0x80;
}
CLK = 1;
_nop_();
CLK = 0;
}
RST = 0;
return j;
}
Main.c
#include //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
#include "LCD1602.h"
#include "delay.h"
#include "stdio.h"
#include "DS1302.h"
#define second_addr 0x80
#define min_addr 0x82
#define hour_addr 0x84
#define day_addr 0x86
#define month_addr 0x88
#define week_addr 0x8A
#define year_addr 0x8C
typedef unsigned char uChar8;
typedef unsigned int uInt16;
void InitUART (void)
{
SCON = 0x50; // SCON: 模式 1, 8-bit UART, 使能接收
TMOD |= 0x25; // TMOD: timer 1, mode 2, 8-bit 重装 // timer 0,16位计数
TR0=0;
TL0 = 0;
TH0 = 0;
TH1 = 0xF4; // TH1: 重装值 9600 波特率 晶振 11.0592MHz
TR1 = 1; // TR1: timer 1 打开
EA = 1; //打开总中断
ES = 1; //打开串口中断
TI=1;
}
void delay_ms(unsigned int x) //延时 ms
{
unsigned int a,b,c;
for(c=x;c>0;c--)
{
for(b=102;b>0;b--)
for(a=3;a>0;a--);
}
}
void Delay1000ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 8;
j = 1;
k = 243;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void main (void)
{
char year,month,day,week,hour,miao,fen,miao_1,miao_2;
InitUART ( );
LCD1602_Init( );
Wr_Onebyte2DS1302(0x8e,0x00);//写保护去除
Wr_Onebyte2DS1302(year_addr,0x19);
Wr_Onebyte2DS1302(month_addr,0x06);
Wr_Onebyte2DS1302(day_addr,0x28);
Wr_Onebyte2DS1302(week_addr,0x05);
Wr_Onebyte2DS1302(hour_addr,0x08);
Wr_Onebyte2DS1302(min_addr,0x16);
Wr_Onebyte2DS1302(second_addr,0x30);
Wr_Onebyte2DS1302(0x8e,0x80);//写保护去除
while(1)
{
year =Rd_OnebyteFromDS1302(year_addr);
printf("年:%c%c ",year / 16 + '0',year % 16 +'0');
Display_CharOnLcd(3,0,year / 16 + '0');
Display_CharOnLcd(4,0,year % 16 +'0');
Display_CharOnLcd(5,0,'-');
month =Rd_OnebyteFromDS1302(month_addr);
printf("月:%c%c ",month / 16 + '0',month % 16 +'0');
Display_CharOnLcd(6,0,month / 16 + '0');
Display_CharOnLcd(7,0,month % 16 +'0');
Display_CharOnLcd(8,0,'-');
day =Rd_OnebyteFromDS1302(day_addr);
printf("日:%c%c ",day / 16 + '0',day % 16 +'0');
Display_CharOnLcd(9,0,day / 16 + '0');
Display_CharOnLcd(10,0,day % 16 +'0');
Display_CharOnLcd(11,0,'-');
week =Rd_OnebyteFromDS1302(week_addr);
printf("星期:%c\n\n\n\r",week + '0');
Display_CharOnLcd(12,0,week + '0');
hour =Rd_OnebyteFromDS1302(hour_addr);
printf("时:%c%c ",hour / 16 + '0',hour % 16 +'0');
Display_CharOnLcd(3,1,hour / 16 + '0');
Display_CharOnLcd(4,1,hour % 16 +'0');
Display_CharOnLcd(5,1,'-');
fen =Rd_OnebyteFromDS1302(min_addr);
printf("分:%c%c ",fen / 16 + '0',fen % 16 + '0');
Display_CharOnLcd(6,1,fen / 16 + '0');
Display_CharOnLcd(7,1,fen % 16 + '0');
Display_CharOnLcd(8,1,'-');
miao = Rd_OnebyteFromDS1302(second_addr);
miao_1 = miao / 16+'0';
miao_2 = miao % 16+'0';
printf("秒:%c%c\n\n\n\r",miao_1,miao_2);
Display_CharOnLcd(9,1,miao_1);
Display_CharOnLcd(10,1,miao_2);
//Delay1000ms();
}
}
代码下载地址:
链接:https://pan.baidu.com/s/1yt3sonu6KABuYn4yC__Htg
提取码:2q17