//http://www.eehome.cn/read-htm-tid-11141.html 、http://www.sunman.cn/
//第三届“太阳人”杯遥控电子时钟设计大赛
//该设计采用STC89C52RC单片机为主要芯片,配合DS1302等芯片,完成了LCD602显示时间和温度,红外遥控(型号JINXING TC9012-011)调整时间、设置闹钟等
//作者:罗旌机(电话15880262713)张楠(电话 13255062816)联系地址:福建省厦门大学学生公寓5栋311室 邮编:361005
#include <reg52.h>
#include <intrins.h>
sbit S=P3^4; //闹钟引脚
sbit SCL2=P1^3; //SCL2定义为P1口的第3位脚,连接DS1302SCL脚
sbit SDA2=P1^4; //SDA2定义为P1口的第4位脚,连接DS1302SCL脚
sbit DQ=P3^7; //温度接口
sbit RST = P1^5; // DS1302片选脚
sbit hwx=P3^3; //定义红外接收脚,
sbit LCD_RS=P1^0;
sbit LCD_RW=P1^1;
sbit LCD_E=P1^2;
#define LCD_Data P2
#define Busy 0x80 // LCD 忙标志位
unsigned char l_tmpdate[8]={0x00,0x00,0x00,0x01,0x05,0x05,0x09,0x20}; //读时间的续冲,初始值是写入的时间,
//秒,分,时,日,月,星期,年,
unsigned char l_tmpclock[2]={0x00,0x12}; //闹钟 初始为12点
unsigned char l_tmpdisplay[16]={"FRI "}; //设好显示的开头
unsigned char l_tmpdisplay2[16]={"T:27 "};
unsigned char numkey,flagclock; //红外键码,闹钟标志
code unsigned char write_rtc_address[7]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c}; //写时间的地址
code unsigned char read_rtc_address[7]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d}; //读时间的地址
// DS1302控制函数
void delay(); //延时子函数
void Write_Ds1302_byte(unsigned char temp);
void Write_Ds1302( unsigned char address,unsigned char dat );
unsigned char Read_Ds1302 ( unsigned char address );
void Read_RTC(void); //read RTC
void Set_RTC(void); //set RTC
void tiaoshi(void);
void clock(void);
void tiaoshiclock(void);
//LCD控制函数
void WriteDataLCD(unsigned char WDLCD);
void WriteCommandLCD(unsigned char WCLCD,BuysC);
unsigned char ReadDataLCD(void);
unsigned char ReadStatusLCD(void);
void LCDInit(void);
void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData);
void DisplayListChar(unsigned char X, unsigned char Y, unsigned char *DData);
void Delay5Ms(void);
void Delay400Ms(void);
void displaylcd(void); //LCD显示函数
//温度函数的声明
void delay(unsigned int i);
void Init_DS18B20(void);
unsigned char ReadOneChar(void);
void WriteOneChar(unsigned char dat);
unsigned char ReadTemperature(void);
unsigned char k,l;
void main(void) //入口函数
{
numkey=0xff;
EA=1; //首先开启总中断
EX1=1; //开启外部中断 1
IT1=1; //下降沿触发方式
TMOD=0x10; //定时器中断
TH1=0xff;
TL1=0x50;
ET1=1;
PX1=1;
S=0;
Set_RTC(); //写时间
Delay400Ms(); //启动等待,等LCD讲入工作状态
LCDInit(); //LCD初始化
Delay5Ms();
while(1){
if(flagclock) //闹钟设定,发出滴滴的鸣声
{
if(numkey!=0x8b) //止闹键TV/AV
{
flagclock=0;
k=25;
S=0;
while (k)
k-- ;
S=1;
k=25;
while(k)
k--;
}
}
S=0;
if (numkey==14) //若按下MIN键则进入调时状态
{ numkey=0xff;
TR1=0; //禁止定时器中断
tiaoshiclock();
}
TR1=1; //开启定时器中断
}
}
void delay(void)
{
unsigned char i=10;
while(i)
i--;
}
void Write_Ds1302_Byte(unsigned char temp)
{
unsigned char i;
for (i=0;i<8;i++) //循环8次 写入数据
{
SCL2=0;
SDA2=temp&0X01; //每次传输低字节
temp>>=1; //右移一位
SCL2=1;
}
}
/****************************************************************************/
void Write_Ds1302( unsigned char address,unsigned char dat )
{
RST=0;
_nop_();
SCL2=0;
_nop_();
RST=1;
_nop_(); //启动
Write_Ds1302_Byte(address); //发送地址
Write_Ds1302_Byte(dat); //发送数据
RST=0; //恢复
}
/****************************************************************************/
unsigned char Read_Ds1302 ( unsigned char address )
{
unsigned char i,temp=0x00;
RST=0;
_nop_();
SCL2=0;
_nop_();
RST=1;
_nop_();
Write_Ds1302_Byte(address);
for (i=0;i<8;i++) //循环8次 读取数据
{
if(SDA2)
temp|=0x80; //每次传输低字节
SCL2=0;
temp>>=1; //右移一位
SCL2=1;
}
RST=0;
_nop_(); //以下为DS1302复位的稳定时间
RST=0;
SCL2=0;
_nop_();
SCL2=1;
_nop_();
SDA2=0;
_nop_();
SDA2=1;
_nop_();
return (temp);
}
/****************************************************************************/
void Read_RTC(void) //读取 日历
{
unsigned char i,*p;
p=read_rtc_address; //地址传递
for(i=0;i<7;i++) //分7次读取 年月日时分秒星期
{
l_tmpdate[i]=Read_Ds1302(*p);
p++;
}
}
/***********************************************************************/
void Set_RTC(void) //设定 日历
{
unsigned char i,*p,tmp;
for(i=0;i<7;i++){
tmp=l_tmpdate[i]/10;
l_tmpdate[i]=l_tmpdate[i]%10;
l_tmpdate[i]=l_tmpdate[i]+tmp*16;
}
Write_Ds1302(0x8E,0X00);
p=write_rtc_address; //传地址
for(i=0;i<7;i++) //7次写入 年月日时分秒星期
{
Write_Ds1302(*p,l_tmpdate[i]);
p++;
}
Write_Ds1302(0x8E,0x80);
}
//写数据
void WriteDataLCD(unsigned char WDLCD)
{
ReadStatusLCD(); //检测忙
LCD_Data = WDLCD;
LCD_RS = 1;
LCD_RW = 0;
LCD_E = 0; //若晶振速度太高可以在这后加小的延时
LCD_E = 0; //延时
LCD_E = 1;
}
//写指令
void WriteCommandLCD(unsigned char WCLCD,BuysC) //BuysC为0时忽略忙检测
{
if (BuysC) ReadStatusLCD(); //根据需要检测忙
LCD_Data = WCLCD;
LCD_RS = 0;
LCD_RW = 0;
LCD_E = 0;
LCD_E = 0;
LCD_E = 1;
}
//读数据
unsigned char ReadDataLCD(void)
{
LCD_RS = 1;
LCD_RW = 1;
LCD_E = 0;
LCD_E = 0;
LCD_E = 1;
return(LCD_Data);
}
//读状态
unsigned char ReadStatusLCD(void)
{
LCD_Data = 0xFF;
LCD_RS = 0;
LCD_RW = 1;
LCD_E = 0;
LCD_E = 0;
LCD_E = 1;
while (LCD_Data & Busy); //检测忙信号
return(LCD_Data);
}
void LCDInit(void) //LCD初始化
{
LCD_Data = 0;
WriteCommandLCD(0x38,0); //三次显示模式设置,不检测忙信号
Delay5Ms();
WriteCommandLCD(0x38,0);
Delay5Ms();
WriteCommandLCD(0x38,0);
Delay5Ms();
WriteCommandLCD(0x38,1); //显示模式设置,开始要求每次检测忙信号
WriteCommandLCD(0x08,1); //关闭显示
WriteCommandLCD(0x01,1); //显示清屏
WriteCommandLCD(0x06,1); // 显示光标移动设置
WriteCommandLCD(0x0C,1); // 显示开机光标设置
}
//按指定位置显示一个字符
void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData)
{
Y &= 0x1;
X &= 0xF; //限制X不能大于15,Y不能大于1
if (Y) X |= 0x40; //当要显示第二行时地址码+0x40;
X |= 0x80; // 算出指令码
WriteCommandLCD(X, 0); //这里不检测忙信号,发送地址码
WriteDataLCD(DData);
}
//按指定位置显示一串字符
void DisplayListChar(unsigned char X, unsigned char Y, unsigned char *DData)
{