#include <reg51.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define KEY_DELAY 2
//-------------------定义数组---------------------//
uchar code table[] = {0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};//不带小数点数字编码
uchar code table10[] = {0xbf,0x86,0xdb,0xcf,
0xe6,0xed,0xfd,0x87,
0xff,0xef}; //带小数点数字编码
uchar table1[] = {31,31,29,31,30,31,30,31,31,30,31,30,31}; //闰年
uchar table2[] = {31,31,28,31,30,31,30,31,31,30,31,30,31}; //非闰年
//-----------------定义全局变量-------------------//
uint year,temp,a,b;
uchar mode,n,q,two,i,hh,mm,ss,nhh,nmm,nss;
uchar yearqb,yearsg;
uchar day,mon,week;
uchar set1 = 1,set2 = 0;
uchar DataState = 0 ,Adjust = 0;
//------------------位变量定义--------------------//
sbit ds = P2^2;
sbit fm = P2^3;
sbit k1 = P1^2;
sbit k2 = P1^3;
sbit k3 = P1^4;
sbit k4 = P1^5;
sbit dula = P1^1;
sbit wela = P1^0;
//-----------------子函数申明---------------------//
void jishi(); //计时函数
void alarm(); //闹钟函数
void baoshi(); //整点报时函数
void display();//显示函数
void key_set();//按键设置
void set_mdw();//设置月日星期
void init_com();//初始化函数
void set_time();//设置时间
void set_alarm();//设置闹钟
void key_change();//按键识别
void tem_change();//温度读取
//-------------------主函数-----------------------//
void main()
{
init_com();
while(1)
{
tem_change();
set_mdw(); //设置月日星期
display(); //显示程序
key_change(); //k1按键扫描
key_set(); //k2按键扫描
set_time(); //设置时间
set_alarm(); //设置闹钟
baoshi(); //整点报时
alarm(); //闹钟
}
}
//--------------us延时函数--------------//
void TempDelay (uchar us)
{
while(us--);
}
//--------------ms延时函数--------------//
void delay(uint count)
{
uint i;
while(count)
{
i = 200;
while(i>0)
i--;
count--;
}
}
//-------------------定时器中断-----------------------------//
void timer0() interrupt 1
{
TMOD = 0x01;
TH0 = 0x3c;
TL0 = 0xb1;
n++;
jishi();
}
//--------------------初始化函数---------------------------//
void init_com()
{
TMOD = 0x21;
TH0 = 0x3c;
TL0 = 0xb1;
TR0 = 1;
EA = 1;
ET0 = 1;
TH1 = 0xfd; //装初值设定波特率
TL1 = 0xfd;
TR1 = 1; //启动定时器
SM0 = 0; //串口通信模式设置
SM1 = 1;
PCON = 0; //波特率不倍频
//--------------------初值设定-----------------------------//
P1 = 0xBf;
hh = 01;mm = 00;ss = 00;
nhh = 01;nmm = 10;nss = 10;
year = 2011;mon = 04;day = 16;week = 6; //03-29-04
yearqb = year/100;
yearsg = year%100 ;
}
//------------------传感器复位---------------------------//
void ds_reset(void)
{
uchar flag; //定义局部变量
ds = 1;
_nop_(); //1us
ds = 0;
TempDelay(80); //当总线停留在低电平超过480us,总线上所以器件都将被复位,这里//延时约530us总 线停留在低电平超过480μs,总线上的所有器件都
//将被复位。
_nop_();
ds = 1; //产生复位脉冲后,微处理器释放总线,让总线处于空闲状态,原因查//18b20中文资料
TempDelay(5); //释放总线后,以便从机18b20通过拉低总线来指示其是否在线,
//存在检测高电平时间:15~60us, 所以延时44us,进行 1-wire presence //detect(单线存在检测)
_nop_();
_nop_();
_nop_();
if(ds == 0)
flag = 1; //detect 18b20 success
else
flag = 0; //detect 18b20 fail
TempDelay(20); //存在检测低电平时间:60~240us,所以延时约140us
_nop_();
_nop_();
ds = 1; //再次拉高总线,让总线处于空闲状态
}
/*----------------------------------------
读/写时间隙:DS1820 的数据读写是通过时间隙处理
位和命令字来确认信息交换。
------------------------------------------*/
bit ds_read_bit(void) //读一位
{
bit dat;
ds = 0; //单片机(微处理器)将总线拉低
_nop_(); //读时隙起始于微处理器将总线拉低至少1us
ds = 1; //拉低总线后接着释放总线,让从机18b20能够接管总线,输出有效数据
_nop_();
_nop_(); //小延时一下,读取18b20上的数据 ,因为从ds18b20上输出的数据
//在读"时间隙"下降沿出现15us内有效
dat = ds; //主机读从机18b20输出的数据,这些数据在读时隙的下降沿出现//15us内有效
TempDelay(10); //所有读"时间隙"必须60~120us,这里77us
return(dat); //返回有效数据
}
//-------------------读传感器数据-----------------------//
uchar ds_read_byte(void ) //读一字节
{
uchar value,i,j;
value = 0; //一定别忘了给初值
for(i = 0;i<8;i++)
{
j = ds_read_bit();
value = (j<<7)|(value>>1); //这一步的说明在一个word文档里面
}
return(value); //返回一个字节的数据
}
//--------------------写传感器数据-------------------------//
void ds_write_byte(uchar dat) //写一个字节
{
uchar i;
bit onebit; //onebit是一位
for(i = 1;i <= 8;i++)
{
onebit = dat&0x01;
dat = dat>>1;
if(onebit) //写 1
{
ds = 0;
_nop_();
_nop_(); //看时序图,至少延时1us,才产生写"时间隙"
ds = 1; //写时间隙开始后的15μs内允许数据线拉到高电平
TempDelay(5); //所有写时间隙必须最少持续60us
}
else //写 0
{
ds = 0;
TempDelay(8); //主机要生成一个写0 时间隙,必须把数据线拉到低电平并保持至少60μs,这里64us
ds = 1;
_nop_();
_nop_();
}
}
}
/*****************************************
主机(单片机)控制18B20完成温度转换要经过三个步骤:
每一次读写之前都要18B20进行复位操作,复位成功后发送
一条ROM指令,最后发送RAM指令,这样才能对DS18b20进行
预定的操作。
复位要求主CPU将数据线下拉500us,然后释放,当ds18B20
受到信号后等待16~60us,后发出60~240us的存在低脉冲,
主CPU收到此信号表示复位成功
******************************************/
/*-------------------------------------------------------
进行温度转换:先初始化,然后跳过ROM:跳过64位ROM地址,
直接向ds18B20发温度转换命令,适合单片工作发送温度转换命令
-------------------------------------------------------*/
void tem_change()
{
ds_reset();
delay(1); //约2ms
ds_write_byte(0xcc);
ds_write_byte(0x44);
}
//--------------------获得温度--------------------//
uint get_temperature()
{
float wendu;
uchar a,b;
ds_reset();
delay(1); //约2ms
ds_write_byte(0xcc);
ds_write_byte(0xbe);
a = ds_read_byte();
b = ds_read_byte();
temp = b;
temp <<= 8;
temp = temp|a;
wendu = temp*0.0625; //得到真实十进制温度值,因为DS18B20
//可以精确到0.0625度,所以读回数据的最低位代表的是 //0.0625度
temp = wendu*10+0.5; //放大十倍,这样做的目的将小数点后第一位
//也转换为可显示数字,同时进行一个四舍五入操作。
return temp;
}
//--------------------计时函数--------------------------//
void jishi()
{
if(n==1||n==11)
DataState=~DataState;
if(n == 19)
{
n = 0;ss++;
if(ss == 60)
{
ss = 0;
mm++;
if(mm == 60)
{
mm = 0;
hh++;
if(hh == 24)
{
hh = 0;
day++;
week++;
if(week == 8)
week = 0;
if(year%4 == 0 && year%100 != 0 || year%400 == 0) //闰年
{
if(day == table1[mon]+1)
{
day = 0;
mon++;
if(mon == 13)
{
mon = 0;
year++;
}
}
}
else //非闰年
{
if(day == table2[mon]+1)
{
day = 0;
mon++;
if(mon == 13)
{
mon = 0;
year++;
}
}
}
}
}
}
}
}
//--------------------按键扫描----------------------------//
//--------------------k1按键扫描--------------------------//
void key_change()
{
if(k1 == 0)
{
delay(20);
if(k1 == 0)
{
set1++;