钻石会员
主题
帖子
积分13827
阅读权限50
注册时间2010-8-2
最后登录1970-1-1
在线时间 小时
|
楼主 |
发表于 2012-7-1 09:59
|
显示全部楼层
本帖最后由 todayinfo 于 2012-7-1 10:03 编辑
下面是程序代码:
#include <REG52.H>
#include <intrins.h>
#include <math.H>
#define uint unsigned int
#define uchar unsigned char
sbit DS1302_CLK = P1^4;
sbit DS1302_IO = P1^3;
sbit DS1302_RST = P1^2;
sbit ACC0 = ACC^0;
sbit ACC7 = ACC^7;
char hide_sec,hide_min,hide_hour,hide_day,hide_week,hide_month,hide_year;
sbit Set = P3^3; //模式切换键
sbit Up = P3^4; //加法按钮
sbit Down = P3^5; //减法按钮
sbit out = P3^2; //跳出调整模式按钮
sbit ds = P3^6; //温度传送数据IO口
char done,count,temp,flag,up_flag,down_flag; //
uint value; //温度值
uchar TempBuffer[10],week_value[2]; //
void DelayMs(unsigned int count)
{ // mSec Delay 11.0592 Mhz
unsigned int i;
while(count) {
i = 115;
while(i>0) i--;
count--;
}
}
void Delay1ms(unsigned int count)
{
unsigned int i,j;
for(i=0;i<count;i++)
for(j=0;j<120;j++);
}
/*延时子程序*/
void mdelay(uint delay)
{ uint i;
for(;delay>0;delay--)
{for(i=0;i<62;i++) //1ms延时.
{;}
}
}
/***********DS1302时钟部分子程序******************/
typedef struct SYSTEMTIME
{
unsigned char Second;
unsigned char Minute;
unsigned char Hour;
unsigned char Week;
unsigned char Day;
unsigned char Month;
unsigned char Year;
unsigned char DateString[11];
unsigned char TimeString[9];
}SYSTEMTIME; //定义的时间类型
SYSTEMTIME CurrentTime; //
#define AM(X) X
#define PM(X) (X+12) // 转成24小时制
#define DS1302_SECOND 0x80 //时钟芯片的寄存器位置,存放时间
#define DS1302_MINUTE 0x82
#define DS1302_HOUR 0x84
#define DS1302_WEEK 0x8A
#define DS1302_DAY 0x86
#define DS1302_MONTH 0x88
#define DS1302_YEAR 0x8C
void DS1302InputByte(unsigned char d) //实时时钟写入一字节(内部函数)
{
unsigned char i;
ACC = d;
for(i=8; i>0; i--)
{
DS1302_IO = ACC0; //相当于汇编中的 RRC
DS1302_CLK = 1;
DS1302_CLK = 0;
ACC = ACC >> 1;
}
}
unsigned char DS1302OutputByte(void) //实时时钟读取一字节(内部函数)
{
unsigned char i;
for(i=8; i>0; i--)
{
ACC = ACC >>1; //相当于汇编中的 RRC
ACC7 = DS1302_IO;
DS1302_CLK = 1;
DS1302_CLK = 0;
}
return(ACC);
}
void Write1302(unsigned char ucAddr, unsigned char ucDa) //ucAddr: DS1302地址, ucData: 要写的数据
{
DS1302_RST = 0;
DS1302_CLK = 0;
DS1302_RST = 1;
DS1302InputByte(ucAddr); // 地址,命令
DS1302InputByte(ucDa); // 写1Byte数据
DS1302_CLK = 1;
DS1302_RST = 0;
}
unsigned char Read1302(unsigned char ucAddr) //读取DS1302某地址的数据
{
unsigned char ucData;
DS1302_RST = 0;
DS1302_CLK = 0;
DS1302_RST = 1;
DS1302InputByte(ucAddr|0x01); // 地址,命令
ucData = DS1302OutputByte(); // 读1Byte数据
DS1302_CLK = 1;
DS1302_RST = 0;
return(ucData);
}
void DS1302_GetTime(SYSTEMTIME *Time) //获取时钟芯片的时钟数据到自定义的结构型数组
{
unsigned char ReadValue;
ReadValue = Read1302(DS1302_SECOND);
Time->Second = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_MINUTE);
Time->Minute = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_HOUR);
Time->Hour = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_DAY);
Time->Day = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_WEEK);
Time->Week = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_MONTH);
Time->Month = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_YEAR);
Time->Year = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
}
void DateToStr(SYSTEMTIME *Time) //将时间年,月,日,星期数据转换成液晶显示字符串,放到数组里DateString[]
{ if(hide_year<2) //这里的if,else语句都是判断位闪烁,<2显示数据,>2就不显示,输出字符串为 2007/07/22
{
Time->DateString[0] = '2';
Time->DateString[1] = '0';
Time->DateString[2] = Time->Year/10 + '0';
Time->DateString[3] = Time->Year%10 + '0';
}
else
{
Time->DateString[0] = ' ';
Time->DateString[1] = ' ';
Time->DateString[2] = ' ';
Time->DateString[3] = ' ';
}
Time->DateString[4] = '/';
if(hide_month<2)
{
Time->DateString[5] = Time->Month/10 + '0';
Time->DateString[6] = Time->Month%10 + '0';
}
else
{
Time->DateString[5] = ' ';
Time->DateString[6] = ' ';
}
Time->DateString[7] = '/';
if(hide_day<2)
{
Time->DateString[8] = Time->Day/10 + '0';
Time->DateString[9] = Time->Day%10 + '0';
}
else
{
Time->DateString[8] = ' ';
Time->DateString[9] = ' ';
}
if(hide_week<2)
{
week_value[0] = Time->Week%10 + '0'; //星期的数据另外放到 week_value[]数组里,跟年,月,日的分开存放,因为等一下要在最后显示
}
else
{
week_value[0] = ' ';
}
week_value[1] = '\0';
Time->DateString[10] = '\0'; //字符串末尾加 '\0' ,判断结束字符
}
void TimeToStr(SYSTEMTIME *Time) //将时,分,秒数据转换成液晶显示字符放到数组 TimeString[];
{ if(hide_hour<2)
{
Time->TimeString[0] = Time->Hour/10 + '0';
Time->TimeString[1] = Time->Hour%10 + '0';
}
else
{
Time->TimeString[0] = ' ';
Time->TimeString[1] = ' ';
}
Time->TimeString[2] = ':';
if(hide_min<2)
{
Time->TimeString[3] = Time->Minute/10 + '0';
Time->TimeString[4] = Time->Minute%10 + '0';
}
else
{
Time->TimeString[3] = ' ';
Time->TimeString[4] = ' ';
}
Time->TimeString[5] = ':';
if(hide_sec<2)
{
Time->TimeString[6] = Time->Second/10 + '0';
Time->TimeString[7] = Time->Second%10 + '0';
}
else
{
Time->TimeString[6] = ' ';
Time->TimeString[7] = ' ';
}
Time->DateString[8] = '\0';
}
void Initial_DS1302(void) //时钟芯片初始化
{
unsigned char Second=Read1302(DS1302_SECOND);
if(Second&0x80) //判断时钟芯片是否关闭
{
Write1302(0x8e,0x00); //写入允许
Write1302(0x8c,0x12); //以下写入初始化时间 日期:12/06/08.星期: 5. 时间: 18:30:00
Write1302(0x88,0x06);
Write1302(0x86,0x08);
Write1302(0x8a,0x05); //xingqi
Write1302(0x84,0x18);
Write1302(0x82,0x30);
Write1302(0x80,0x00);
Write1302(0x8e,0x80); //禁止写入
}
}
/***********ds18b20子程序*************************/
//****************************************************************
void delay(uchar i)
{
uint j;
while(i--)
{
for(j = 0; j < 125; j++);
}
}
//****************************************************************
//延时函数, 对于11.0592MHz时钟, 例i=10,则大概延时10ms.
void dsInit()
{
//对于11.0592MHz时钟, unsigned int型的i, 作一个i++操作的时间大于8us
unsigned int i;
ds = 0;
i = 100; //拉低约800us, 符合协议要求的480us以上
while(i>0) i--;
ds = 1; //产生一个上升沿, 进入等待应答状态
i = 4;
while(i>0) i--;
}
void dsWait()
{
unsigned int i;
while(ds); //等待应答信号
while(~ds); //检测到应答脉冲
i = 4;
while(i > 0) i--;
}
//向DS18B20读取一位数据
//读一位, 让DS18B20一小周期低电平, 然后两小周期高电平,
//之后DS18B20则会输出持续一段时间的一位数据
bit readBit()
{
unsigned int i;
bit b;
ds = 0;
i++; //延时约8us, 符合协议要求至少保持1us
ds = 1;
i++;
i++; //延时约16us, 符合协议要求的至少延时15us以上
b = ds;
i = 8;
while(i>0) i--; //延时约64us, 符合读时隙不低于60us要求
return b;
}
//读取一字节数据, 通过调用readBit()来实现
unsigned char readByte()
{
unsigned int i;
unsigned char j, dat;
dat = 0;
for(i=0; i<8; i++)
{
j = readBit();
//最先读出的是最低位数据
dat = (j << 7) | (dat >> 1);
}
return dat;
}
//向DS18B20写入一字节数据
void writeByte(unsigned char dat)
{
unsigned int i;
unsigned char j;
bit b;
for(j = 0; j < 8; j++)
{
b = dat & 0x01;
dat >>= 1;
//写"1", 将DQ拉低15us后, 在15us~60us内将DQ拉高, 即完成写1
if(b)
{
ds = 0;
i++;
i++; //拉低约16us, 符号要求15~60us内
ds = 1;
i = 8; while(i>0) i--; //延时约64us, 符合写时隙不低于60us要求
}
else //写"0", 将DQ拉低60us~120us
{
ds = 0;
i = 8; while(i>0) i--; //拉低约64us, 符号要求
ds = 1;
i++;
i++; //整个写0时隙过程已经超过60us, 这里就不用像写1那样, 再延时64us了
}
}
}
//向DS18B20发送温度转换命令
void sendChangeCmd()
{
dsInit(); //初始化DS18B20, 无论什么命令, 首先都要发起初始化
dsWait(); //等待DS18B20应答
delay(1); //延时1ms, 因为DS18B20会拉低DQ 60~240us作为应答信号
writeByte(0xcc); //写入跳过序列号命令字 Skip Rom
writeByte(0x44); //写入温度转换命令字 Convert T
}
//向DS18B20发送读取数据命令
void sendReadCmd()
{
// EA=0;//关闭中断是因为进入显示中断会影响到DS18B20的读写时序
dsInit();
dsWait();
delay(1);
writeByte(0xcc); //写入跳过序列号命令字 Skip Rom
writeByte(0xbe); //写入读取数据令字 Read Scratchpad
// EA=1;
}
//获取当前温度值
int getTmpValue()
{
unsigned int tmpvalue;
int value; //存放温度数值
float t;
unsigned char low, high;
// EA=0;
sendReadCmd();
//连续读取两个字节数据
low = readByte();
high = readByte();
//将高低两个字节合成一个整形变量
//计算机中对于负数是利用补码来表示的
//若是负值, 读取出来的数值是用补码表示的, 可直接赋值给int型的value
tmpvalue = high;
tmpvalue <<= 8;
tmpvalue |= low;
value = tmpvalue;
//使用DS18B20的默认分辨率12位, 精确度为0.0625度, 即读回数据的最低位代表0.0625度
t = value * 0.0625;
//将它放大100倍, 使显示时可显示小数点后两位, 并对小数点后第三位进行4舍5入
//如t=11.0625, 进行计数后, 得到value = 1106, 即11.06 度
//如t=-11.0625, 进行计数后, 得到value = -1106, 即-11.06 度
value = t * 100 + (value > 0 ? 0.5 : -0.5); //大于0加0.5, 小于0减0.5
return value;
}
void temp_to_str() //温度数据转换成字符显示
{
uchar SH,SZ,SL,GH,GL;
uint dda;
dda=abs(value);
SH = dda/10000;
SZ = (dda % 10000) / 1000;
SL = (dda % 1000) / 100;
GH = (dda % 100) / 10;
GL = dda % 10;
if (value<0)
TempBuffer[0]='-'; //是负温度,显示“-”
else
TempBuffer[0]=' '; //温度高位是0,不显示
TempBuffer[1]=SH+48;
TempBuffer[2]=SZ+48;
TempBuffer[3]=SL+48;
TempBuffer[4]=GH+48;
TempBuffer[5]=GL+48;
TempBuffer[6]=248; //温度符号
TempBuffer[7]='C';
TempBuffer[8]='\0';
}
void send_str(unsigned char *str)
// 传送字串
{
unsigned char i = 0;
while(str != '\0')
{
SBUF = str;
while(!TI); // 等特数据传送
TI = 0; // 清除数据传送标志
i++; // 下一个字符
}
}
void show() //VFD显示程序
{
DS1302_GetTime(&CurrentTime); //获取时钟芯片的时间数据
TimeToStr(&CurrentTime); //时间数据转换字符
DateToStr(&CurrentTime); //日期数据转换字符
sendChangeCmd();
getTmpValue(); //开启温度采集程序
temp_to_str(); //温度数据转换成字符
SBUF=0x1B;
while(!TI){};
TI=0;
SBUF=0x13;
while(!TI){};
TI=0;
SBUF=0x03; //
while(!TI){};
TI=0;
send_str(CurrentTime.TimeString); //显示时间
SBUF=0x1B;
while(!TI){};
TI=0;
SBUF=0x13;
while(!TI){};
TI=0;
SBUF=0x0e;
while(!TI){};
TI=0;
send_str(TempBuffer); //显示温度
SBUF=0x1B;
while(!TI){};
TI=0;
SBUF=0x13;
while(!TI){};
TI=0;
SBUF=0x12;
while(!TI){};
TI=0;
send_str(CurrentTime.DateString); //显示日期
SBUF=0x1B;
while(!TI){};
TI=0;
SBUF=0x13;
while(!TI){};
TI=0;
SBUF=0x23; //液晶字符显示位置
while(!TI){};
TI=0;
send_str("Week"); //在液晶上显示 字母 week
send_str(week_value); //显示星期
Delay1ms(50); //扫描延时
}
void outkey() //跳出调整模式,返回默认显示
{ uchar Second;
if(out==0)//if(out==0||wireless_1==1) //
{ mdelay(8);
count=0;
hide_sec=0,hide_min=0,hide_hour=0,hide_day=0,hide_week=0,hide_month=0,hide_year=0;
Second=Read1302(DS1302_SECOND);
Write1302(0x8e,0x00); //写入允许
Write1302(0x80,Second&0x7f);
Write1302(0x8E,0x80); //禁止写入
done=0;
while(out==0);
//while(wireless_1==1);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Upkey()//升序按键
{
Up=1;
if(Up==0)//if(Up==0||wireless_2==1)
{
mdelay(8);
switch(count)
{case 1:
temp=Read1302(DS1302_SECOND); //读取秒数
temp=temp+1; //秒数加1
up_flag=1; //数据调整后更新标志
if((temp&0x7f)>0x59) //超过59秒,清零
temp=0;
break;
case 2:
temp=Read1302(DS1302_MINUTE); //读取分数
temp=temp+1; //分数加1
up_flag=1;
if(temp>0x59) //超过59分,清零
temp=0;
break;
case 3:
temp=Read1302(DS1302_HOUR); //读取小时数
temp=temp+1; //小时数加1
up_flag=1;
if(temp>0x23) //超过23小时,清零
temp=0;
break;
case 4:
temp=Read1302(DS1302_WEEK); //读取星期数
temp=temp+1; //星期数加1
up_flag=1;
if(temp>0x7)
temp=1;
break;
case 5:
temp=Read1302(DS1302_DAY); //读取日数
temp=temp+1; //日数加1
up_flag=1;
if(temp>0x31)
temp=1;
break;
case 6:
temp=Read1302(DS1302_MONTH); //读取月数
temp=temp+1; //月数加1
up_flag=1;
if(temp>0x12)
temp=1;
break;
case 7:
temp=Read1302(DS1302_YEAR); //读取年数
temp=temp+1; //年数加1
up_flag=1;
if(temp>0x85)
temp=0;
break;
default:break;
}
while(Up==0);
//while(wireless_2==1);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Downkey()//降序按键
{
Down=1;
if(Down==0)//if(Down==0||wireless_3==1)
{
mdelay(8);
switch(count)
{case 1:
temp=Read1302(DS1302_SECOND); //读取秒数
temp=temp-1; //秒数减1
down_flag=1; //数据调整后更新标志
if(temp==0x7f) //小于0秒,返回59秒
temp=0x59;
break;
case 2:
temp=Read1302(DS1302_MINUTE); //读取分数
temp=temp-1; //分数减1
down_flag=1;
if(temp==-1)
temp=0x59; //小于0秒,返回59秒
break;
case 3:
temp=Read1302(DS1302_HOUR); //读取小时数
temp=temp-1; //小时数减1
down_flag=1;
if(temp==-1)
temp=0x23;
break;
case 4:
temp=Read1302(DS1302_WEEK); //读取星期数
temp=temp-1; //星期数减1
down_flag=1;
if(temp==0)
temp=0x7;;
break;
case 5:
temp=Read1302(DS1302_DAY); //读取日数
temp=temp-1; //日数减1
down_flag=1;
if(temp==0)
temp=31;
break;
case 6:
temp=Read1302(DS1302_MONTH); //读取月数
temp=temp-1; //月数减1
down_flag=1;
if(temp==0)
temp=12;
break;
case 7:
temp=Read1302(DS1302_YEAR); //读取年数
temp=temp-1; //年数减1
down_flag=1;
if(temp==-1)
temp=0x85;
break;
default:break;
}
while(Down==0);
//while(wireless_3==1);
}
}
void Setkey()//模式选择按键
{
Set=1;
if(Set==0)//if(Set==0||wireless_4==1)
{
mdelay(8);
count=count+1; //Setkey按一次,count就加1
done=1; //进入调整模式
while(Set==0);
//while(wireless_4==1);
}
}
void keydone()//按键功能执行
{ uchar Second;
if(flag==0) //关闭时钟,停止计时
{ Write1302(0x8e,0x00); //写入允许
temp=Read1302(0x80);
Write1302(0x80,temp|0x80);
Write1302(0x8e,0x80); //禁止写入
flag=1;
}
Setkey(); //扫描模式切换按键
switch(count)
{case 1:do //count=1,调整秒
{
outkey(); //扫描跳出按钮
Upkey(); //扫描加按钮
Downkey(); //扫描减按钮
if(up_flag==1||down_flag==1) //数据更新,重新写入新的数据
{
Write1302(0x8e,0x00); //写入允许
Write1302(0x80,temp|0x80); //写入新的秒数
Write1302(0x8e,0x80); //禁止写入
up_flag=0;
down_flag=0;
}
hide_sec++; //位闪计数
if(hide_sec>3)
hide_sec=0;
show(); //液晶显示数据
}while(count==2);break;
case 2:do //count=2,调整分
{
hide_sec=0;
outkey();
Upkey();
Downkey();
if(temp>0x60)
temp=0;
if(up_flag==1||down_flag==1)
{
Write1302(0x8e,0x00); //写入允许
Write1302(0x82,temp); //写入新的分数
Write1302(0x8e,0x80); //禁止写入
up_flag=0;
down_flag=0;
}
hide_min++;
if(hide_min>3)
hide_min=0;
show();
}while(count==3);break;
case 3:do //count=3,调整小时
{
hide_min=0;
outkey();
Upkey();
Downkey();
if(up_flag==1||down_flag==1)
{
Write1302(0x8e,0x00); //写入允许
Write1302(0x84,temp); //写入新的小时数
Write1302(0x8e,0x80); //禁止写入
up_flag=0;
down_flag=0;
}
hide_hour++;
if(hide_hour>3)
hide_hour=0;
show();
}while(count==4);break;
case 4:do //count=4,调整星期
{
hide_hour=0;
outkey();
Upkey();
Downkey();
if(up_flag==1||down_flag==1)
{
Write1302(0x8e,0x00); //写入允许
Write1302(0x8a,temp); //写入新的星期数
Write1302(0x8e,0x80); //禁止写入
up_flag=0;
down_flag=0;
}
hide_week++;
if(hide_week>3)
hide_week=0;
show();
}while(count==5);break;
case 5:do //count=5,调整日
{
hide_week=0;
outkey();
Upkey();
Downkey();
if(up_flag==1||down_flag==1)
{
Write1302(0x8e,0x00); //写入允许
Write1302(0x86,temp); //写入新的日数
Write1302(0x8e,0x80); //禁止写入
up_flag=0;
down_flag=0;
}
hide_day++;
if(hide_day>3)
hide_day=0;
show();
}while(count==6);break;
case 6:do //count=6,调整月
{
hide_day=0;
outkey();
Upkey();
Downkey();
if(up_flag==1||down_flag==1)
{
Write1302(0x8e,0x00); //写入允许
Write1302(0x88,temp); //写入新的月数
Write1302(0x8e,0x80); //禁止写入
up_flag=0;
down_flag=0;
}
hide_month++;
if(hide_month>3)
hide_month=0;
show();
}while(count==7);break;
case 7:do //count=7,调整年
{
hide_month=0;
outkey();
Upkey();
Downkey();
if(up_flag==1||down_flag==1)
{
Write1302(0x8e,0x00); //写入允许
Write1302(0x8c,temp); //写入新的年数
Write1302(0x8e,0x80); //禁止写入
up_flag=0;
down_flag=0;
}
hide_year++;
if(hide_year>3)
hide_year=0;
show();
}while(count==8);break;
case 8: count=0;hide_year=0; //count8, 跳出调整模式,返回默认显示状态
Second=Read1302(DS1302_SECOND);
Write1302(0x8e,0x00); //写入允许
Write1302(0x80,Second&0x7f);
Write1302(0x8E,0x80); //禁止写入
done=0;
break; //count=7,开启中断,标志位置0并退出
default:break;
}
}
main()
{
flag=1; //时钟停止标志
//串口初始化
SCON = 0x52; // setup serial port control
TMOD = 0x20; // hardware (9600 BAUD @11.05592MHZ)
TH1 = 0xFD; // TH1
TR1 = 1; // Timer 1 on
dsInit( ) ; //DS18B20初始化
Initial_DS1302(); //时钟芯片初始化
up_flag=0;
down_flag=0;
done=0; //进入默认液晶显示
while(1)
{
while(done==1)
keydone(); //进入调整模式
while(done==0)
{
flag=0;
Setkey(); //扫描各功能键
SBUF=0x1B;
while(!TI){};
TI=0;
SBUF=0x05;
while(!TI){};
TI=0;
DelayMs(50);
show(); }
}
} |
评分
-
查看全部评分
|