DS12C887
- DS12C887时钟芯片能输出世纪、年、月、日、时、分、秒等时间信息
- 集成电池, 外部掉电时, 时间不会丢失.
- 有12小时和24小时两种模式. 在12小时制模式中, 用AM和PM区分上午和下午
- 时间的存储方式有两种: 一种用二进制数表示, 另一种是用BCD码表示
- 带有128 byte RAM, 其中11 byte用来存储时间信息, 4 byte用来存储DS12C887的控制信息, 称为控制寄存器; 113 byte 通用RAM, 供用户使用. * 可以对DS12C887进行编程, 实现多种方波输出
- 可对其内部的三路中断通过软件进行屏蔽
- 芯片内部有一个精密的温度补偿电路用来监视Vee的状态, 如果检测到主电源故障, 该器件可以自动切换到备用电源供电
- VBAeKUP引脚用于支持可充电电池或超级电容, 内部包括一个始终有效的涓流充电器.
- 可以通过一个多路复用的单字节接口访问, 该接口支持Intel和Motorola模式
引脚功能
GND、 VCC
VCC接+5V输入, 当VCC输入为+5V时, 用户可以访问DS12C887内RAM中的数据, 并可对其进行读写操作. 当VCC的输入小于+4.25V时, 禁止用户对内部RAM进行读写操作, 此时用户不能正确获取芯片内的时间信息. 当VCC的输入小于+3V时, DS12C887会自动将电源发换到内部自带的锂电池上.
MOT
模式选择脚. DA12C887有两种工作模式: Motorola模式和Intel模式, 当MOT接VCC时是Motorola模式, 当MOT接GND时是Intel模式. 一般使用Intel模式.
SQW
方波输出脚. 当供电电压VCC大于4.25V时, SQW脚可进行方波输出, 此时用户可以通过对控制寄存器编程来得到13种方波信号的输出
AD0-AD7
复用地址数据总线, 该总线采用时分复用技术, 在总线周期的前半部分出现在AD0-AD7上的是地址信息, 可用以选通DS12C887内的RAM, 总线周期的后半部分出现在AD0-AD7上的是数据信息.
AS
地址选通输入脚, 在进行读写操作时, AS的上升沿将AD0-AD7上出现的地址信息锁存到DS12C887上, 而下一个下降沿清除AD0-AD7上的地址信息, 不论是否有效, DS12C887都将执行该操作.
DS/RD
数据选择或读输入脚, 该引脚有两种工作模式
- MOT接VCC时, 为Motorola工作模式, 在这种工作模式中, 每个总线周期的后一部分的DS为高电平, 被称为数据选通, 在读操作中, DS的上升沿使DS12C887将内部数据送往总线AD0-AD7上, 以供外部读取, 在写操作中, DS的下降沿将使总线 AD0-AD7上的数据锁存在DS12C887中.
R/W
读/写输入端. 该管脚也有2种工作模式
- 当MOT接VCC时, 工作在Motorola模式, 此时该引脚的作用是区分进行的是读操作还是写操作, 当R/W为高电平时为读操作, R/W 为低电平时为写操作.
- 当MOT接GND时, 工作在Intle模式, 此时该引脚作为写允许输入
STC89C516连接DS12C877
连接
- 操作DS12C887时钟芯片共需要13条信号线, 分别是并行数据地址复用线ADO~AD7, CS, AS, R/W, DS 和 IRQ
- 将RESET引脚固定接高电平
- DS, AS, R/W,CS分别连接单片机的P1.0 - P1.4口, 当然连接其他口也可以, 只要可以正常操作即可
- IRQ是DS12C887的中断申请端, 该引脚不能随便连接, 必须与单片机的外部中断引脚相连, 这样当DS12C887芯片向单片机申请中断时, 单片机才不会遗漏的检测出所有的中断, 这里我们将其与单片机的P3.2相连.
左侧
MOT => GND
AD0 => P0.0
...
AD7 => P0.7
GND => GND
右侧
VCC => VCC
SQW
IRQ => P3.2
RESET => VCC
DS => P1.0
RW => P1.1
AS => P1.2
CS => P1.4
USB2TTL连线
TX => P3.0
RX => P3.1
代码
读取时间信息的测试代码
#include <reg52.h>
#include <stdio.h>
typedef unsigned int u16;
typedef unsigned char u8;
u8 num,time,moshi,moshi1,flag,kaiqi,c;
char shi,fen,miao,shiji,nian,yue,ri,xingqi,ashi,afen,amiao,kaiz;
void delay(u16 z) {
u16 x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
sbit dsds_ds12c887 = P1^0;
sbit dsrw_ds12c887 = P1^1;
sbit dsas_ds12c887 = P1^2;
sbit dscs_ds12c887 = P1^4;
sbit dsirq_ds12c887 = P3^2;
void write_ds_ds12c887(u8 add_ds12c887, u8 data_ds12c887)
{
delay(1);
dscs_ds12c887 = 0; // ds12c887de 使能端 cs=0
delay(1);
dsas_ds12c887=1;
dsds_ds12c887=1;
dsrw_ds12c887=1;
delay(1);
P0 = add_ds12c887;
delay(1);
dsas_ds12c887=0;
dsrw_ds12c887=0;
P0 = data_ds12c887;
dsrw_ds12c887=1;
dsas_ds12c887=1;
delay(1);
dscs_ds12c887 = 1; // ds12c887de 使能端 cs=1
delay(1);
}
u8 read_ds_ds12c887(u8 add_ds12c887)
{
u8 ds_date;
dsas_ds12c887=1;
dsds_ds12c887=1;
dsrw_ds12c887=1;
delay(1);
dscs_ds12c887 = 0; // ds12c887de 使能端 cs=0
delay(1);
P0 = add_ds12c887;
delay(1);
dsas_ds12c887=0;
dsds_ds12c887=0;
P0 = 0XFF;
ds_date=P0;
dsds_ds12c887=1;
dsas_ds12c887=1;
dscs_ds12c887 = 1; // ds12c887de 使能端 cs=1
return ds_date;
}
void init_ds12c887()
{
write_ds_ds12c887(0x0b,0x26); //如果開啓設置 控制器B, 數據爲BCD碼, 時間爲24小時制, 產生鬧鐘中斷
write_ds_ds12c887(0x0a,0x20); //打開時鐘震盪
amiao=read_ds_ds12c887(1);
afen=read_ds_ds12c887(3);
ashi=read_ds_ds12c887(5); //讀DS12C887 鬧鐘 時, 分, 秒 即當進入鬧鐘設置狀態下, 顯示當前設定鬧鐘的時間
}
void set_alarm_ds12c887(u8 ashi, u8 afen, u8 amiao)
{
write_ds_ds12c887(1,amiao);
write_ds_ds12c887(3,afen);
write_ds_ds12c887(5,ashi); //在DS12C887鬧鐘寄存器中寫入 鬧鐘時間 函數
}
void main()
{
P0=0x00; //P0口送清零, 關LED數碼管的必要數據準備.
P1=0xff; //P1口送全1, 關8位發光二極管的必要數據準備.
init_ds12c887();//ds12c887 初始化
EA=1;
IT0=1;
EX0=1;
// 初始化UART
TMOD = 0x20;
SCON = 0x40;
TH1 = 256 - 11.0592 * 1000 * 1000 / 12 / 32 / 9600 + 0.5;
TCON |= 0x40;
SCON |= 0x02;
// 初始化UART结束
c=read_ds_ds12c887(0x0c);
//write_ds_ds12c887(0x0b,0x26);//如果開啓設置 控制器B, 數據爲BCD碼, 時間爲24小時制, 產生鬧鐘中斷
num=0;time=0;moshi=0;moshi1=0;flag=0;kaiqi=0;
/* 該部分是調試程序時候使用, 當出現時間日期亂碼時候, 可以嘗試重新寫入給定數據
判斷是否是內部保存數據長時間未用導致出現亂碼.
write_ds_ds12c887(4,9); //小時寄存器 寫 9點
write_ds_ds12c887(2,27); //分鐘寄存器 寫 27分
write_ds_ds12c887(0,25); //秒鐘寄存器 寫 25秒
write_ds_ds12c887(6,7); //星期寄存器寫 7 星期天
write_ds_ds12c887(9,11); //年寄存器 寫 11年
write_ds_ds12c887(8,8); //月份寄存器 寫 8月
write_ds_ds12c887(7,7); //日期寄存器 寫 7號
*/
while(1) {
miao = read_ds_ds12c887(0x00); //讀 秒
fen = read_ds_ds12c887(0x02); //讀 分
shi = read_ds_ds12c887(0x04); //讀 時
ri = read_ds_ds12c887(0x07); //讀 日
yue = read_ds_ds12c887(0x08); //讀 月
nian = read_ds_ds12c887(0x09); //讀 年
xingqi= read_ds_ds12c887(0x06); //讀 星期
shiji = read_ds_ds12c887(0x10); //讀 實際 保存實際數據, 內部不自加, 只是當做存儲器用
kaiz = read_ds_ds12c887(0x0e); //讀 鬧鐘 標誌位
ashi = read_ds_ds12c887(0x05); //讀 鬧鐘 時
afen = read_ds_ds12c887(0x03); //讀 鬧鐘 分
amiao = read_ds_ds12c887(0x01); //讀 鬧鐘 秒
printf("%bu-%bu-%bu\r\n", nian, yue, ri);
printf(" %bu:%bu:%bu\r\n", shi, fen, miao);
//把讀出的時間, 日期數據, 寫到1602液晶顯示
/*write_twoline_ds12c887_1602(5,shi); //寫 時
write_twoline_ds12c887_1602(8,fen); //寫 分
write_twoline_ds12c887_1602(11,miao); //寫 秒
write_oneline_ds12c887_1602(10,ri); //寫 日
write_oneline_ds12c887_1602(7,yue); //寫 月
write_oneline_ds12c887_1602(4,nian); //寫 年
write_oneline_ds12c887_1602(14,xingqi);//寫 星期
write_oneline_ds12c887_1602(2,shiji); //寫 世紀
write_twoline_ds12c887_1602(2,kaiz); //寫 鬧鐘開啓位
*/
}
}
void exter() interrupt 0
{
flag=1; //開外部中斷 0
}
参考
- https://blog.csdn.net/dai_wen/article/details/81050120
- http://www.51hei.com/bbs/dpj-184639-1.html
- https://blog.csdn.net/huang873036652/article/details/91460594
- http://www.51hei.com/bbs/dpj-29544-1.html
- http://news.eeworld.com.cn/mcu/ic466119.html
- c51的printf格式 https://www.keil.com/support/man/docs/c51/c51_printf.htm