51单片机使用ds3231模块

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

//DS3231某宝买的模块,5块不到的样子。

麻烦大家下载一下,不要直接复制。

89c52不能用1t的单片机。

//此修正版的文件可以解决之前的word下载后不能打开的蛋疼问题。

1602数据端口是P2如果需要修改,只有2个地方需要改。

#include <reg51.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define yh 0x80 //第一行的初始位置
#define er 0x80+0x40 //第二行初始位置
sbitrs=P0^7;//1602的3个端口
sbitwr=P0^6;
sbit en=P0^5;
sbit SDA=P1^6; //模拟I2C数据传送位SDA 模块只使用了2个端口
sbit SCL=P1^7; //模拟I2C时钟控制位SCL
//sbit INT=P3^2;
sbit key1=P3^5; //功能键,修改键这是3个按键,低电平有效,串联个4到10千欧的电阻到按键开关上,然后接地就行
sbit key2=P3^4; //上调键
sbit key3=P3^3; //下调键
//sbit RESET=P3^3;
bit ack; //应答标志位
#define DS3231_WriteAddress 0xD0 //器件写地址
#define DS3231_ReadAddress 0xD1 //器件读地址
#define DS3231_SECOND 0x00 //秒
#define DS3231_MINUTE 0x01 //分
#define DS3231_HOUR 0x02 //时
#define DS3231_WEEK 0x03 //星期
#define DS3231_DAY 0x04 //日
#define DS3231_MONTH 0x05 //月
#define DS3231_YEAR 0x06 //年
//闹铃1
#define DS3231_SALARM1ECOND 0x07 //秒
#define DS3231_ALARM1MINUTE 0x08 //分
#define DS3231_ALARM1HOUR 0x09 //时
#define DS3231_ALARM1WEEK 0x0A //星期/日
//闹铃2
#define DS3231_ALARM2MINUTE 0x0b //分
#define DS3231_ALARM2HOUR 0x0c //时
#define DS3231_ALARM2WEEK 0x0d //星期/日
#define DS3231_CONTROL 0x0e //控制寄存器
#define DS3231_STATUS 0x0f //状态寄存器
#define BSY 2 //忙
#define OSF 7 //振荡器停止标志
#define DS3231_XTAL 0x10 //晶体老化寄存器
#define DS3231_TEMPERATUREH 0x11 //温度寄存器高字节(8位) #define DS3231_TEMPERATUREL 0x12 //温度寄存器低字节(高2位)
uchar a,miao,shi,fen,ri,yue,nian,week,temp1,temp2,key1n,temp;
uchar code tab1[]={"2017- - FRI"};
uchar code tab2[]={" : : ."};
/*
uchar HEX2BCD(ucharval) //B码转换为BCD码
{
uchar k;
k=(val)/10*16+(val)%10;
return k;
}
*/
ucharBCD_Decimal(ucharbcd)
{
uchar Decimal;
Decimal=bcd>>4;
return(Decimal=Decimal*10+(bcd&=0x0F));
}
void delayus(uint us)
{
while (us--);
}
void Start_I2C()
{
SDA=1; //发送起始条件的数据信号
delayus(1);
SCL=1;
delayus(5); //起始条件建立时间大于4.7us,延时
SDA=0; //发送起始信号
delayus(5); // 起始条件锁定时间大于4μs
SCL=0; //钳住I2C总线,准备发送或接收数据delayus(2);
}
void Stop_I2C()
{
SDA=0; //发送结束条件的数据信号
delayus(1); //发送结束条件的时钟信号
SCL=1; //结束条件建立时间大于4us
delayus(5);
SDA=1; //发送I2C总线结束信号
delayus(4);
}
void SendByte(uchar c)
{
ucharBitCnt;
for(BitCnt=0;BitCnt<8;BitCnt++) //要传送的数据长度为8位
{
if((c<<BitCnt)&0x80)
SDA=1; //判断发送位
else
SDA=0;
delayus(1);
SCL=1; //置时钟线为高,通知被控器开始接收数据位
delayus(5); //保证时钟高电平周期大于4μs
SCL=0;
}
delayus(2);
SDA=1; //8位发送完后释放数据线,准备接收应答位
delayus(2);
SCL=1;
delayus(3);
if(SDA==1)
ack=0;
else
ack=1; //判断是否接收到应答信号
SCL=0;
delayus(2);
}
ucharRcvByte()
ucharretc;
ucharBitCnt;
retc=0;
SDA=1; //置数据线为输入方式
for(BitCnt=0;BitCnt<8;BitCnt++)
{
delayus(1);
SCL=0; //置时钟线为低,准备接收数据位delayus(5); //时钟低电平周期大于4.7μs
SCL=1; //置时钟线为高使数据线上数据有效delayus(3);
retc=retc<<1;
if(SDA==1)
retc=retc+1; //读数据位,接收的数据位放入retc中
delayus(2);
}
SCL=0;
delayus(2);
return(retc);
}
void Ack_I2C(bit a)
{
if(a==0)
SDA=0; //在此发出应答或非应答信号
else
SDA=1;
delayus(3);
SCL=1;
delayus(5); //时钟低电平周期大于4μs
SCL=0; //清时钟线,钳住I2C总线以便继续接收delayus(2);
}
ucharwrite_byte(ucharaddr, ucharwrite_data)
{
Start_I2C();
SendByte(DS3231_WriteAddress);
if (ack == 0)
return 0;
SendByte(addr);
if (ack == 0)
return 0;
SendByte(write_data);
if (ack == 0)
return 0;
Stop_I2C();
delayus(10);
return 1;
}
ucharread_current()
{
ucharread_data;
Start_I2C();
SendByte(DS3231_ReadAddress);
if(ack==0)
return(0);
read_data = RcvByte();
Ack_I2C(1);
Stop_I2C();
return read_data;
}
ucharread_random(ucharrandom_addr) {
Start_I2C();
SendByte(DS3231_WriteAddress);
if(ack==0)
return(0);
SendByte(random_addr);
if(ack==0)
return(0);
return(read_current());
}
/*
void ModifyTime(ucharyea,ucharmon,ucharda,ucharhou,ucharmin,ucharsec,uchar week) {
uchar temp=0;
temp=HEX2BCD(yea);
write_byte(DS3231_YEAR,temp); //修改年
temp=HEX2BCD(mon);
write_byte(DS3231_MONTH,temp); //修改月
temp=HEX2BCD(da);
write_byte(DS3231_DAY,temp); //修改日
temp=HEX2BCD(hou);
write_byte(DS3231_HOUR,temp); //修改时
temp=HEX2BCD(min);
write_byte(DS3231_MINUTE,temp); //修改分
temp=HEX2BCD(sec);
write_byte(DS3231_SECOND,temp); //修改秒
temp=HEX2BCD(week);
write_byte(DS3231_WEEK,temp); //修改星期
}
*/
/******************液晶写入************************/
void write_1602com(uchar com)//液晶写入指令函数
{
rs=0;//置为写入命令
P2=com;//送入数据
delayus(1000);
en=1;//拉高使能端
delayus(1000);
en=0;//完成高脉冲
}
void write_1602dat(uchardat)
{
rs=1;//置为写入数据
P2=dat;//送入数据
delayus(1000);
en=1;
delayus(1000);
en=0;
}
/*********************over***********************/ void lcd_init()//液晶初始化函数
{ wr=0;
write_1602com(0x38);//设置液晶工作模式
write_1602com(0x0c);//开显示不显示光标
write_1602com(0x06);//整屏不移动,指针加一
write_1602com(0x01);
write_1602com(yh+1);//字符写入的位置
for(a=0;a<14;a++)
{
write_1602dat(tab1[a]);
//delay(3);
}
write_1602com(er);
for(a=0;a<12;a++)
{
write_1602dat(tab2[a]);
//delay(3);
}
write_1602com(er+14); //写温度符号
write_1602dat(0xdf);
write_1602dat(0x43);
}
void write_sfm(ucharadd,uchardat)//写时分秒及温度
{
uchargw,sw;
gw=dat%10;
sw=dat/10;
write_1602com(er+add);
write_1602dat(0x30+sw);
write_1602dat(0x30+gw);
}
void write_nyr(ucharadd,uchardat) //写日期
{
uchargw,sw;
gw=dat%10;
sw=dat/10;
write_1602com(yh+add);
write_1602dat(0x30+sw);
write_1602dat(0x30+gw);
}
void write_week(uchar week)//写星期函数{
write_1602com(yh+0x0c);
switch(week)
{
case 1:write_1602dat('M');//delay(5);
write_1602dat('O');//delay(5);
write_1602dat('N');
break;
case 2:write_1602dat('T');//delay(5);
write_1602dat('U');//delay(5);
write_1602dat('E');
break;
case 3:write_1602dat('W');//delay(5);
write_1602dat('E');//delay(5);
write_1602dat('D');
break;
case 4:write_1602dat('T');//delay(5);
write_1602dat('H');//delay(5);
write_1602dat('U');
break;
case 5:write_1602dat('F');//delay(5);
write_1602dat('R');//delay(5);
write_1602dat('I');
break;
case 6:write_1602dat('S');//delay(5);
write_1602dat('T');//delay(5);
write_1602dat('A');
break;
case 7:write_1602dat('S');//delay(5);
write_1602dat('U');//delay(5);
write_1602dat('N');
break;
}
}
void keyscan()
{
if(key1==0)//key1为功能键
{
delayus(5000);
if(key1==0)
{
while(!key1);
key1n++;
if(key1n==9)
key1n=1;
switch(key1n)
{
case 1: TR0=0;//关闭定时器
//TR1=0;
write_1602com(er+0x06);//写入光标位置
write_1602com(0x0f);//设置光标为闪烁
break;
case 2: write_1602com(er+3);//fen
//write_1602com(0x0f);
break;
case 3: write_1602com(er+0);//shi
//write_1602com(0x0f);
break;
case 4: write_1602com(yh+0x0d);//week
//write_1602com(0x0f);
break;
case 5: write_1602com(yh+0x09);//ri
//write_1602com(0x0f);
break;
case 6: write_1602com(yh+0x06);//yue
//write_1602com(0x0f);
break;
case 7: write_1602com(yh+0x03);//nian
//write_1602com(0x0f);
break;
case 8: write_1602com(0x0c);//设置光标不闪烁
write_sfm(6,miao);//写入新的秒数
temp=(miao)/10*16+(miao)%10;
write_byte(DS3231_SECOND,temp); //退出时修改秒
write_1602com(er+6);
write_sfm(0x03,fen);
temp=(fen)/10*16+(fen)%10;
write_byte(DS3231_MINUTE,temp); //修改分
write_1602com(er+3);
TR0=1;//打开定时器
break;
}
}
}
if(key1n!=0)//当key1按下以下。

再按以下键才有效
{
if(key2==0) //上调键
{
delayus(5000);
if(key2==0)
{
while(!key2);
switch(key1n)
{
case 1:miao++;
if(miao==60)
miao=0;
write_sfm(6,miao);//写入新的秒数
temp=(miao)/10*16+(miao)%10;
write_byte(DS3231_SECOND,temp); //修改秒
write_1602com(er+6);//设置液晶的模式是写入数据后,指针自动加一,在这里是写回原来的位置
break;
case 2:fen++;
if(fen==60)
fen=0;
write_sfm(0x03,fen);
temp=(fen)/10*16+(fen)%10;
write_byte(DS3231_MINUTE,temp);
write_1602com(er+3);
break;
case 3:shi++;
if(shi==24)
shi=0;
write_sfm(0,shi);
temp=(shi)/10*16+(shi)%10;
write_byte(DS3231_HOUR,temp);
write_1602com(er+0);
break;
case 4:week++;
if(week==8)
week=0;
write_week(week);
write_byte(DS3231_WEEK,week); //修改星期
write_1602com(yh+0x0d);
break;
case 5:ri++;
if(ri==31)
ri=0;
write_nyr(9,ri);
temp=(ri)/10*16+(ri)%10;
write_byte(DS3231_DAY,temp); //修改日
write_1602com(yh+9);
break;
case 6:yue++;
if(yue==13)
yue=0;
write_nyr(6,yue);
temp=(yue)/10*16+(yue)%10;
write_byte(DS3231_MONTH,temp); //修改月
write_1602com(yh+6);
break;
case 7:nian++;
if(nian==100)
nian=0;
write_nyr(3,nian);
temp=(nian)/10*16+(nian)%10;
write_byte(DS3231_YEAR,temp); //修改年
write_1602com(yh+3);
break;
}
}
}
if(key3==0)
{
delayus(5000);
if(key3==0)
{
while(!key3);
switch(key1n)
{
case 1:miao--;
if(miao==-1)
miao=59;
write_sfm(6,miao);//写入新的秒数
temp=(miao)/10*16+(miao)%10;
write_byte(DS3231_SECOND,temp); //修改秒
write_1602com(er+6);//因为设置液晶的模式是写入数据后,指针自动加一,在这里是写回原来的位置
break;
case 2:fen--;
if(fen==-1)
fen=59;
write_sfm(3,fen);
temp=(fen)/10*16+(fen)%10;
write_byte(DS3231_MINUTE,temp); //修改分
write_1602com(er+3);
break;
case 3:shi--;
if(shi==-1)
shi=23;
write_sfm(0,shi);
temp=(shi)/10*16+(shi)%10;
write_byte(DS3231_HOUR,temp); //修改时
write_1602com(er+0);
break;
case 4:week--;
if(week==-1)
week=7;
write_week(week);
write_byte(DS3231_WEEK,week); //修改星期
write_1602com(yh+0x0d);
break;
case 5:ri--;
if(ri==-1)
ri=30;
write_nyr(9,ri);
temp=(ri)/10*16+(ri)%10;
write_byte(DS3231_DAY,temp); //修改日
write_1602com(yh+9);
break;
case 6:yue--;
if(yue==-1)
yue=12;
write_nyr(6,yue);
temp=(yue)/10*16+(yue)%10;
write_byte(DS3231_MONTH,temp); //修改月
write_1602com(yh+6);
break;
case 7:nian--;
if(nian==-1)
nian=99;
write_nyr(3,nian);
temp=(nian)/10*16+(nian)%10;
write_byte(DS3231_YEAR,temp); //修改年
write_1602com(yh+3);
break;
}
}
}
}
}
void main()
{
uint ii = 0;
lcd_init();
// RESET=0x1; //DS3231复位操作,正常操作下不需要每次都复位
TMOD=0x11; // 定时器0, 1工作模式1, 16位定时方式
TH0=0;
TL0=0;
EA=1;
ET0=1;
TCON=0x01;
IE=0x82; // 使能timer0,1 中断
TR0=1;
// ModifyTime(17,10,6,21,50,20,5); //初始化,年月日时分秒星期(24小时制)
//这个函数不能用,因为如果使用这个函数,会导致断电后重新打开就重置了时间。

while(1)
{
keyscan();
}
}
void timer0() interrupt 1
{
//TH0=(65536-60000)/256;
//TL0=(65536-60000)%256;
miao = BCD_Decimal(read_random(DS3231_SECOND));
fen = BCD_Decimal(read_random(DS3231_MINUTE));
shi = BCD_Decimal(read_random(DS3231_HOUR));
ri = BCD_Decimal(read_random(DS3231_DAY));
yue = BCD_Decimal(read_random(DS3231_MONTH));
nian=BCD_Decimal(read_random(DS3231_YEAR));
week=BCD_Decimal(read_random(DS3231_WEEK));
temp1=BCD_Decimal(read_random(DS3231_TEMPERATUREH)); //温度高4位temp2=BCD_Decimal(read_random(DS3231_TEMPERATUREL)); //温度低4位keyscan();
temp2=(temp2>>6)*25;
write_sfm(6,miao);
//write_1602com(er+0x0a);
//write_1602dat(':');
write_sfm(3,fen);
//write_1602com(er+0x07);
//write_1602dat(':');
write_sfm(0,shi);
write_nyr(3,nian);
write_nyr(9,ri);
write_nyr(6,yue);
write_week(week);
write_sfm(9,temp1);
write_sfm(12,temp2);
}。

相关文档
最新文档