红色标记处及问题所在,反正ds3231驱动不了
#include <STC89.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
/********1602定义***********************/
#define LCD_DB P0
sbit LCD_RS=P2^1;//0为指令,1为写数据
sbit LCD_RW=P2^2;//0可写入,1为读
sbit LCD_E=P2^5;//1允许
/*******ds3231相关定义*********/
/**************************** defines *******************************/
sbit SCL = P1^7; /* I2C pin definitions */
sbit SDA = P1^6;
sbit int0 = P3^2;
sbit rest = P3^6;
#define ADDRTW 0xD0 //器件写地址
#define ADDRTD 0xD1 //器件读地址
//#define DS3231_WriteAddress 0xD0 //器件写地址
//#define DS3231_ReadAddress 0xD1 //器件读地址
#define DS3231_SEC 0x00 //秒
#define DS3231_MIN 0x01 //分
#define DS3231_HOUR 0x02 //时
#define DS3231_DAY 0x03 //星期
#define DS3231_DATE 0x04 //日
#define DS3231_MONTH 0x05 //月
#define DS3231_YEAR 0x06 //年
//闹铃1
#define DS3231_Al1SEC 0x07 //秒
#define DS3231_AL1MIN 0x08 //分
#define DS3231_AL1HOUR 0x09 //时
#define DS3231_AL1DAY 0x0A //星期/日
//闹铃2
#define DS3231_AL2MIN 0x0b //分
#define DS3231_AL2HOUR 0x0c //时
#define DS3231_AL2DAY 0x0d //星期/日
#define DS3231_CONTROL 0x0e //控制寄存器
#define DS3231_STATUS 0x0f //状态寄存器
#define BSY 2 //忙
#define OSF 7 //振荡器停止标志
#define DS3231_XTAL 0x10 //晶体老化寄存器
#define DS3231_TEMP_H 0x11 //温度寄存器高字节(8位)
#define DS3231_TEMP_L 0x12 //温度寄存器低字节(高2位)
//extern xdata uchar sec, min, hour, day, date, month, year,Dtemp;
//extern xdata uchar al1_min,al1_hour,al1_day,al2_min,al2_hour,al2_day;
uchar year,month,date,day,hour,min,sec,Dtemp=0;
uchar al1_min,al1_hour,al1_day,al2_min,al2_hour,al2_day;
/*********************** Function Prototypes **************************/
uchar BCD2HEX(uchar val);
uchar B_BCD(uchar val);
void delayus(uchar i);
void Start();
void Stop();
void I2CACK(bit a);
void SendByte(uchar Dat);
uchar ReceiveByte(uchar b);
uchar I2CWrite(uchar addr,uchar bytedata);
uchar I2CRead();
uchar I2CReadAdd(uchar addr);
void read_temp();
void init_alrm();
void Readtime();
void ReadAlarm();
void SetTime(uchar yea,uchar mon,uchar da,uchar hou,uchar min,uchar sec);
void InitDS3231();
bit runnian();
void autoweek();
bit ack;
uchar qushi;
/*******按键定义******/
sbit KEY = P3^2;
void InitTimer0(void);
//要在哪行那位显示啥就修改a和b
uchar idata c[]="ABCDEFGHIJKLMNOP";//显示字符串,一行最多16个字母
uchar idata d[]="0123456789abcdef";
uchar idata num[10]="0123456789";//数字表
uchar a[16]="2000-00-00 Day 0";//显示字符串,一行最多16个字母
uchar b[16]="00-00-00 00C ";
//////////"0123456789123456";
/******定义函数****************/
#define Busy 0x80 //DB7为1时表示忙,为0时表示闲
#define SomeNOP(); { _nop_(); }//空函数,用于微小延时,包含在intrins.h
void LCD_init(void);//初始化函数
void WaitForEnable( void );
void LCD_write_command(uchar dat,uchar AttribC);//写指令函数
void LCD_write_data(uchar dat);//写数据函数
void LCD_disp_addw(uchar x,uchar y,uchar dat);//在某个屏幕位置上显示一个字符,X(0-16),y(1-2)
void LCD_disp_lin(uchar x,uchar y,uchar dat[],uchar s);
void Delay5Ms(void);//延时函数
//********************************
//*******初始化函数***************
void LCD_init(void)
{
LCD_write_command(0x38,0);//设置8位格式,2行,5x7
Delay5Ms();
LCD_write_command(0x38,0);//设置8位格式,2行,5x7
Delay5Ms();
LCD_write_command(0x38,0);//设置8位格式,2行,5x7
Delay5Ms();
LCD_write_command(0x38,1);//设置8位格式,2行,5x7
LCD_write_command(0x08,1);// 显示关闭
LCD_write_command(0x01,1);//清除屏幕显示
LCD_write_command(0x06,1);//设定输入方式,增量不移位
LCD_write_command(0x0c,1);//整体显示,无光标,闪烁,0x0c
Delay5Ms();
}
/*=======================================================
正常读写操作之前必须检测LCD控制器状态: CS=1 RS=0 RW=1
DB7: 0 LCD控制器空闲; 1 LCD控制器忙---忙信号检测函数
========================================================*/
void WaitForEnable( void )//测忙函数
{
LCD_DB=0xff;
LCD_RS=0;
LCD_RW=1;
SomeNOP();
LCD_E=1;
SomeNOP();
SomeNOP();
while(LCD_DB&Busy);
LCD_E=0;
}
//********************************
//********写指令函数************
void LCD_write_command(uchar dat,uchar AttribC)
{
if (AttribC) WaitForEnable(); // 检测忙信号
LCD_DB=dat;
LCD_RS=0;//指令
LCD_RW=0;//写入
LCD_E=1;//允许
SomeNOP();
LCD_E=0;
Delay5Ms();
}
//*******************************
//********写数据函数*************
void LCD_write_data(uchar dat)
{
LCD_DB=dat;
LCD_RS=1;//数据
LCD_RW=0;//写入
LCD_E=1;//允许
SomeNOP();
LCD_E=0;
Delay5Ms();
}
//********************************
//**指定显示位置******************
void LCD_disp_addw(uchar x,uchar y,uchar dat)
{
uchar address;
if(y==1)
address=0x80+x;//第一行
if(y==2)
address=0xc0+x;//第二行
LCD_write_command(address,0);
LCD_write_data(dat);
}
//********************************
//*******显示多个字符函数或向任意行的任意位置写任意个字符,但位置不能超过16个*********
//x表示开始位置,第一位为1;y表示行数;dat[]是要显示的内容;s表示内容的长度,最大16
void LCD_disp_lin(uchar x,uchar y,uchar dat[],uchar s)
{
uchar ss;
if(s>16||x>16)return;//各种情况下保证不超过16位
x=x-1;//为了符合自然习惯,在调用本函数是1代表末一行的第一位
if(s+x>16)return;//各种情况下保证不超过16位
for(ss=0;ss<s;ss++)
{
LCD_disp_addw(x++,y,dat[ss]);//指向每个字符,一个一个的写,x轴自动加1,y表示行
}
}
// 短延时
void Delay5Ms(void)
{uchar w,i,j;
for(w=5;w>0;w--)
for(i=2;i>0;i--)
for(j=255;j>0;j--);
}
/************************************************************/
/**********开始3231***********/
uchar BCD2HEX(uchar val) //BCD转换为Byte
{
uchar i;
i= val&0x0f;
val >>= 4;
val &= 0x0f;
val *= 10;
i += val;
return i;
}
uchar B_BCD(uchar val)//B码转换为BCD码
{
uchar i,j,k;
i=val/10;
j=val%10;
k=j+(i<<4);
return k;
}
void delayus(uchar i)
{
while(--i) ;
}
/************************START***************************/
void Start()
{
SDA=1; //发送起始条件的数据信号
delayus(1);
SCL=1;
delayus(5); //起始条件建立时间大于4.7us,延时
SDA=0; //发送起始信号
delayus(5); // 起始条件锁定时间大于4μs
SCL=0; //钳住I2C总线,准备发送或接收数据
delayus(2);
}
/********************************************************/
/************************STOP****************************/
void Stop()
{
SDA=0; //发送结束条件的数据信号
delayus(1); //发送结束条件的时钟信号
SCL=1; //结束条件建立时间大于4us
delayus(5);
SDA=1; //发送I2C总线结束信号
delayus(4);
}
/********************************************************/
/*******************************************************************
字节数据发送函数
函数原型: void SendByte(uchar Dat);
功能: 将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对
此状态位进行操作.(不应答或非应答都使ack=0)
ack=1 发送数据正常,
ack=0 被控器无应答或损坏。
********************************************************************/
void SendByte(uchar Dat)
{
uchar BitCnt;
for(BitCnt=0;BitCnt<8;BitCnt++) //要传送的数据长度为8位
{
if((Dat<<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);
}
/********************************************************/
/*******************************************************************
字节数据接收函数
函数原型: uchar RcvByte();
功能: 用来接收从器件传来的数据,并判断总线错误(不发应答信号),
发完后请用应答函数应答从机。
********************************************************************/
uchar RcvByte()
{
uchar retc;
uchar BitCnt;
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 I2CACK(bit a);
功能: 主控器进行应答信号(可以是应答或非应答信号,由位参数a决定)
********************************************************************/
void I2CACK(bit a)
{
if(a==0)
SDA=0; //在此发出应答或非应答信号
else
SDA=1;
delayus(3);
SCL=1;
delayus(5); //时钟低电平周期大于4μs
SCL=0; //清时钟线,钳住I2C总线以便继续接收
delayus(2);
}
/****************************************************/
/***********将一个字节写入DS3231指定的地址***********/
uchar I2CWrite(uchar addr,uchar bytedata)
{
Start();
SendByte(ADDRTW);
if (ack == 0)
return 0;
SendByte(addr);
if (ack == 0)
return 0;
SendByte(bytedata);
if (ack == 0)
return 0;
Stop();
delayus(10);
return 1;
}
/****************************************************/
/************从DS3231当前地址读一个字节************/
uchar I2CRead()
{
uchar read_data;
Start();
SendByte(ADDRTD);
if(ack==0)
{
LCD_disp_addw(11,1,'t'); /////
return(0);
}
read_data = RcvByte();
I2CACK(1);
Stop();
return read_data;
}
/****************************************************/
/************从DS3231指定地址读一个字节************/
uchar I2CReadAdd(uchar addr)
{
Start();
SendByte(ADDRTD);
if(ack==0)
{
LCD_disp_addw(12,1,'x');/////读不出来
return(0);
}
SendByte(addr);
if(ack==0)
{
LCD_disp_addw(13,1,'y');
return(0);
}
return(I2CRead());
}
/***************************************************/
/*********************读取时间**********************/
void Readtime()
{
uchar temp;
temp=I2CReadAdd(DS3231_SEC);//秒
sec=BCD2HEX(temp);
temp=I2CReadAdd(DS3231_MIN);//分
min=BCD2HEX(temp);
temp=I2CReadAdd(DS3231_HOUR); //时
//temp&=0x3F;
hour=BCD2HEX(temp);
day=I2CReadAdd(DS3231_DAY);//星期
temp=I2CReadAdd(DS3231_DATE); //日
date=BCD2HEX(temp);
temp=I2CReadAdd(DS3231_MONTH); //月
month=BCD2HEX(temp);
temp=I2CReadAdd(DS3231_YEAR); //年
year=BCD2HEX(temp);
Dtemp=I2CReadAdd(DS3231_TEMP_H);//温度
}
/***************************************************/
/*******************读取闹铃时间********************/
void ReadAlarm()
{
uchar temp;
temp=I2CReadAdd(DS3231_AL1MIN);//分
al1_min=BCD2HEX(temp);
temp=I2CReadAdd(DS3231_AL1HOUR); //时
al1_hour=BCD2HEX(temp);
temp=I2CReadAdd(DS3231_AL1DAY); //星期or日
al1_day=BCD2HEX(temp);
temp=I2CReadAdd(DS3231_AL2MIN);//分
al2_min=BCD2HEX(temp);
temp=I2CReadAdd(DS3231_AL2HOUR); //时
al2_hour=BCD2HEX(temp);
temp=I2CReadAdd(DS3231_AL2DAY); //星期or日
al2_day=BCD2HEX(temp);
}
bit runnian()//闰年判断
{
if((year%4==0&&year%100!=0)||(year%100==0&&year%400==0))
{
return 1;
}
else
{
return 0;
}
}
void autoweek()
{
Readtime();
if( month == 1 || month == 2 )
{
month += 12;
if( year> 0 )
year--;
else
year = 4;
}
day = (1+(( date + 2*month + 3*(month+1)/5 + year + year/4 ) %7));
I2CWrite(DS3231_DAY,day);
}
void InitDS3231()
{
SCL=1;
delayus(5);
SDA=1;
delayus(5);
I2CWrite(DS3231_AL1DAY,0x81); //A1M4置位,时分秒匹配时闹钟响应
I2CWrite(DS3231_AL2DAY,0x81); //A2M4置位,时分匹配时闹钟响应
I2CWrite(DS3231_CONTROL,0x04); //中断允许,闹钟1和2关闭
I2CWrite(DS3231_STATUS,0x00); //32KHZ输出禁止,闹钟标志位清零
//SetTime(11,1,14,8,10,0);
}
/**********3231函数结束******/
void TimeDisplay(uchar Dhour,uchar Dmin,uchar Dsec)
{
b[0]=num[Dhour / 10]; // 时十位
b[1]=num[Dhour % 10]; // 时个位
b[3]=num[Dmin / 10]; // 分十位
b[4]=num[Dmin % 10]; // 分个位
b[6]=num[Dsec / 10]; // 秒十位
b[7]=num[Dsec % 10]; // 秒个位
}
//uchar a[]="2000-00-00 Day 0";//显示字符串,一行最多16个字母
//uchar b[]="00-00-00 00C ";
////////////"0123456789123456";
void DateDisplay(uchar Dyear,uchar Dmonth,uchar Dday)
{
a[2]=num[Dyear / 10]; // 年十位
a[3]=num[Dyear % 10]; // 年个位
a[5]=num[Dmonth / 10]; // 月十位
a[6]=num[Dmonth % 10]; // 月个位
a[8]=num[Dday / 10]; // 天十位
a[9]=num[Dday % 10]; // 天个位
}
/*******定时器0*****/
void InitTimer0(void)//定时器0开,模式1,时长50ms
{
EA = 1;
TMOD = 0x01;
ET0 = 1;
TH0 = 0x3C;
TL0 = 0xB0;
TR0 = 1;
}
void Timer0Interrupt(void) interrupt 1
{
qushi=qushi+1;
if(qushi==8)//ds3231取时间隔400ms
{
qushi=0;
Readtime(); //显示时间
Delay5Ms();
Delay5Ms();
Delay5Ms();
DateDisplay(year,month,date);
TimeDisplay(hour,min,sec);
//字符串显示
//函数原型void LCD_disp_lin(uchar x,uchar y,uchar dat[],uchar s)
//x表示开始位置,第一位为1;y表示行数;dat[]是要显示的内容;s表示内容的长度,最大16
LCD_disp_lin(1,1,a,16);//从指定显示位置显示多个字符,这里指第1行第1位开始
LCD_disp_lin(1,2,b,16);//从指定显示位置显示多个字符,这里指第2行第1位开始
Delay5Ms();
}
//在任意行的任意位置单个字母显示,原始函数,直接调用LCD_disp_addw,可以不用啦
//LCD_disp_addw(0,1,'V');//从指定显示位置显示一个字符,这里指第1行第1位,每行最多16个字符
//LCD_disp_addw(0,2,'Q');//从指定显示位置显示一个字符,这里指第2行第1位
TR0 = 0;//重新装定定时器0
TH0 = 0x3C;
TL0 = 0xB0;
TR0 = 1;
}
//*********主函数*****************
void main(void)
{
LCD_init();//初始化
LCD_disp_lin(1,1,c,16);//从指定显示位置显示多个字符,这里指第1行第1位开始
LCD_disp_lin(1,2,d,16);//从指定显示位置显示多个字符,这里指第2行第1位开始
Delay5Ms();
Delay5Ms();
Delay5Ms();
rest=0;
InitDS3231(); //初始化DS3231
autoweek(); //开机自动星期转换
Delay5Ms();
Delay5Ms();
Delay5Ms();
qushi=0;
InitTimer0();//定时器0开,模式1,时长50ms
while(1);
}
|