1.底层驱动:
(1)onewire:
//onewire.h
#ifndef _ONEWIRE_H
#define _ONEWIRE_H
#include "reg52.h"
#define OW_SKIP_ROM 0xcc
#define DS18B20_CONVERT 0x44
#define DS18B20_READ 0xbe
//IC引脚定义
sbit DQ = P1^4;
//函数声明
void Delay_OneWire(unsigned int t);
void Write_DS18B20(unsigned char dat);
bit Init_DS18B20(void);
unsigned char Read_DS18B20(void);
#endif
//onewire.c
#include "onewire.h"
//单总线延时函数
void Delay_OneWire(unsigned int t)
{
while(t--);
}
//DS18B20芯片初始化
bit Init_DS18B20(void)
{
bit initflag = 0;
//DQ = 1;
//Delay_OneWire(5);
DQ = 0;
Delay_OneWire(200); //拉低总线480us以上
DQ = 1; //然后释放总线
Delay_OneWire(20); //等待15~60us
initflag = DQ; //读取DS18B20的复位应答信号
Delay_OneWire(100); //等待60~240us后释放总线
return initflag; //应答信号为低电平,表示复位成功
}
//通过单总线向DS18B20写一个字节
void Write_DS18B20(unsigned char dat)
{
unsigned char i;
for(i=0;i<8;i++)
{
DQ = 0; //先将总线拉低10~15us
DQ = dat&0x01; //向总线写入数据
Delay_OneWire(20); //维持20~45us
DQ = 1; //释放总线
dat >>= 1; //发送下一个数据位
}
//Delay_OneWire(5);
}
//从DS18B20读取一个字节
unsigned char Read_DS18B20(void)
{
unsigned char i;
unsigned char dat;
for(i=0;i<8;i++)
{
DQ = 0; //先将总线拉低10~15us
dat >>= 1; //数据位右移
DQ = 1; //释放总线
if(DQ) //读取总线上的数据
{
dat |= 0x80;
}
Delay_OneWire(20); //延迟45us左右,再读下一个数据位
}
return dat;
}
(2)SPI:
//SPI.h
#include
#include
sbit SCLK = P1^7;
sbit RST = P1^3;
sbit DSIO = P2^3;
void DS1302_WriteByte(unsigned char addr, unsigned char dat); //单字节写的时序
unsigned char DS1302_ReadByte(unsigned char addr); //单字节读的时序在这里插入代码片
//SPI.c
#include
//单字节写的时序
void DS1302_WriteByte(unsigned char addr, unsigned char dat)
{
unsigned char n;
RST = 0;
_nop_();
SCLK = 0;
_nop_();
RST = 1;
_nop_();
for (n=0; n<8; n++) //发送要写入数据的内存地址
{
DSIO = addr & 0x01;
addr >>= 1;
SCLK = 1;
_nop_();
SCLK = 0;
_nop_();
}
for (n=0; n<8; n++) //将指定内容写入该地址的内存
{
DSIO = dat & 0x01;
dat >>= 1;
SCLK = 1;
_nop_();
SCLK = 0;
_nop_();
}
RST = 0;
_nop_();
}
//单字节读的时序
unsigned char DS1302_ReadByte(unsigned char addr)
{
unsigned char n,dat,tmp;
RST = 0;
_nop_();
SCLK = 0;
_nop_();
RST = 1;
_nop_();
for(n=0; n<8; n++) //发送要读出数据的内存地址
{
DSIO = addr & 0x01;
addr >>= 1;
SCLK = 1;
_nop_();
SCLK = 0;
_nop_();
}
for(n=0; n<8; n++) //读出该地址内存的数据
{
tmp = DSIO;
dat = (dat>>1) | (tmp<<7);
SCLK = 1;
_nop_();
SCLK = 0;
_nop_();
}
RST = 0;
_nop_();
SCLK = 1;
_nop_();
DSIO = 0;
_nop_();
DSIO = 1;
_nop_();
return dat;
}
2.主程序:
#include
#include"onewire.h"
#include"spi.h"
bit led = 1; //LED亮灭
sbit L1 = P0^0; //定义L1
sbit S7 = P3^0; //定义独立按键S7
sbit S6 = P3^1; //定义独立按键S6
sbit S5 = P3^2; //定义独立按键S5
sbit S4 = P3^3; //定义独立按键S4
unsigned int T_dat; //存放温度
unsigned char hour = 0; //闹钟时
unsigned char minute = 0; //闹钟分
unsigned char second = 0; //闹钟秒
unsigned char count = 0; //定时器0:20ms定时计数(闹钟)
unsigned char num = 0; //定时器1:50ms定时计数(闪烁)
unsigned char clock = 0; //时钟设置时分秒标志位
bit state = 1; //时钟设置闪烁标志位
unsigned char alarm = 0; //闹钟设置时分秒标志位
unsigned char stat = 0; //闹钟闪烁标志位
unsigned char status = 0; //数码管模式显示标志位
unsigned char code WRITE_RTC_ADDR[7] =
{0x80,0x82,0x84,0x86,0x88,0x8a,0x8c}; //定义写操作的日历寄存器地址
unsigned char code READ_RTC_ADDR[7] =
{0x81,0x83,0x85,0x87,0x89,0x8b,0x8d}; //定义读操作的日历寄存器地址
unsigned char TIME[7] =
{0x50,0x59,0x23,0x00,0x00,0x00,0x00}; //定义日历时钟寄存器配置参数(秒、分、时、日、月、周、年)
unsigned char code SEG_code[19] =
{0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,
0xbf,0x7f,0xff}; //定义共阳数码管段码内容:0~F,—,.,熄灭
/*====================================初始化====================================*/
//端口选择
void Select_HC138(unsigned char n)
{
switch(n)
{
case 0:
P2 = (P2 & 0x1f) | 0x00;
break;
case 4:
P2 = (P2 & 0x1f) | 0x80;
break;
case 5:
P2 = (P2 & 0x1f) | 0xa0;
break;
case 6:
P2 = (P2 & 0x1f) | 0xc0;
break;
case 7:
P2 = (P2 & 0x1f) | 0xe0;
break;
}
}
//关闭蜂鸣器、继电器和LED
void Init_system()
{
Select_HC138(5);
P0 = 0x00;
Select_HC138(4);
P0 = 0xff;
Select_HC138(0);
}
/*==============================================================================*/
/*==================================数码管显示==================================*/
//数码管延时函数
void Delay_tube(unsigned char t)
{
while(t--);
}
//数码管显示
void Show_tube(unsigned char position,unsigned char value)
{
Select_HC138(7);
P0 = 0xff; //选通前先熄灭
Select_HC138(6);
P0 = 0x01 << position;
Select_HC138(7);
P0 = value;
}
//熄灭数码管
void Show_all()
{
Select_HC138(7);
P0 = 0xff; //选通前先熄灭
Select_HC138(6);
P0 = 0xff; //全部选通
}
//数码管动态显示(时间)
void Display_time()
{
if((clock == 1)&&(state == 1))
{
Show_tube(0,SEG_code[18]); //熄灭
Show_tube(1,SEG_code[18]); //熄灭
}
else
{
Show_tube(0,SEG_code[TIME[2]/16]); //显示时的十位
Delay_tube(100);
Show_tube(1,SEG_code[TIME[2]%16]); //显示时的个位
Delay_tube(100);
}
Show_tube(2,SEG_code[16]); //显示分隔符
Delay_tube(100);
if((clock == 2)&&(state == 1))
{
Show_tube(3,SEG_code[18]); //熄灭
Show_tube(4,SEG_code[18]); //熄灭
}
else
{
Show_tube(3,SEG_code[TIME[1]/16]); //显示分的十位
Delay_tube(100);
Show_tube(4,SEG_code[TIME[1]%16]); //显示分的个位
Delay_tube(100);
}
Show_tube(5,SEG_code[16]); //显示分隔符
Delay_tube(100);
if((clock == 3)&&(state == 1))
{
Show_tube(6,SEG_code[18]); //熄灭
Show_tube(7,SEG_code[18]); //熄灭
}
else
{
Show_tube(6,SEG_code[TIME[0]/16]); //显示秒的十位
Delay_tube(100);
Show_tube(7,SEG_code[TIME[0]%16]); //显示秒的个位
Delay_tube(100);
}
Show_all();
}
//数码管动态显示(闹钟)
void Display_alarm()
{
if((alarm == 1)&&(state == 1))
{
Show_tube(0,SEG_code[18]); //熄灭
Show_tube(1,SEG_code[18]); //熄灭
}
else
{
Show_tube(0,SEG_code[hour/10]); //显示时的十位
Delay_tube(100);
Show_tube(1,SEG_code[hour%10]); //显示时的个位
Delay_tube(100);
}
Show_tube(2,SEG_code[16]); //显示分隔符
Delay_tube(100);
if((alarm == 2)&&(state == 1))
{
Show_tube(3,SEG_code[18]); //熄灭
Show_tube(4,SEG_code[18]); //熄灭
}
else
{
Show_tube(3,SEG_code[minute/10]); //显示分的十位
Delay_tube(100);
Show_tube(4,SEG_code[minute%10]); //显示分的个位
Delay_tube(100);
}
Show_tube(5,SEG_code[16]); //显示分隔符
Delay_tube(100);
if((alarm == 3)&&(state == 1))
{
Show_tube(6,SEG_code[18]); //熄灭
Show_tube(7,SEG_code[18]); //熄灭
}
else
{
Show_tube(6,SEG_code[second/10]); //显示秒的十位
Delay_tube(100);
Show_tube(7,SEG_code[second%10]); //显示秒的个位
Delay_tube(100);
}
Show_all();
}
//数码管动态显示(温度)
void Display_temp(unsigned char temp)
{
Show_tube(5,SEG_code[temp/10]); //显示温度的十位
Delay_tube(100);
Show_tube(6,SEG_code[temp%10]); //显示温度的个位
Delay_tube(100);
Show_tube(7,SEG_code[12]); //显示温度单位
Delay_tube(100);
Show_all();
}
/*==============================================================================*/
/*=====================================时钟=====================================*/
//时钟参数配置
void DS1302_config()
{
unsigned char i;
DS1302_WriteByte(0x8e,0x00); //允许向内存写入数据
for(i=0;i<7;i++)
{
//TIME[i] = ((TIME[i]/10<<4) | (TIME[i]&0x0f)); //(10->16)
DS1302_WriteByte(WRITE_RTC_ADDR[i],TIME[i]); //低位先写
}
DS1302_WriteByte(0x8e,0x80); //禁止向内存写入数据
}
//读取实时时间
void DS1302_Readtime()
{
unsigned char i;
for(i=0;i<7;i++)
{
TIME[i] = DS1302_ReadByte(READ_RTC_ADDR[i]);
//TIME[i] = (((TIME[i]>>4)*10) | (TIME[i]%16)); //进制转换(16->10)
//TIME[i] = (((TIME[i]>>4)*10) | (TIME[i]&0x0f));
//不能写在这里,会出错!!!!
}
}
/*==============================================================================*/
/*===================================温度读取===================================*/
//温度延时函数
void Delay_temp(unsigned int time)
{
while(time--)
{
Display_temp(T_dat);
}
}
//读取温度
void Read_temperature()
{
unsigned char LSB,MSB;
Init_DS18B20(); //复位
Write_DS18B20(0xcc); //跳过ROM操作
Write_DS18B20(0x44); //温度转换
Delay_temp(1000); //延时700ms,等待温度转换
Init_DS18B20(); //复位
Write_DS18B20(0xcc); //跳过ROM操作
Write_DS18B20(0xbe); //读取RAM
LSB = Read_DS18B20(); //读取温度数据的低8位(低位先读)
MSB = Read_DS18B20(); //读取温度数据的高8位
Init_DS18B20(); //复位,停止读取数据
T_dat = 0x0000; //长度为16位
T_dat = MSB;
T_dat <<= 8;
T_dat |= LSB; //整合温度
if((T_dat & 0xf800) == 0x0000) //根据温度数据的高5位判断温度正负,如果温度为正
{
T_dat >>= 4; //保留温度的整数部分
}
}
/*==============================================================================*/
/*==================================闹钟(定时器0)===============================*/
//定时器0中断初始化
void Init_timer0()
{
TMOD = 0x11; //同时选择定时器0和定时器1
TH0 = (65535 - 20000) / 256;
TL0 = (65535 - 20000) % 256; //20ms定时
EA = 1; //打开总中断
ET0 = 1; //打开定时器0的中断
TR0 = 0; //关闭定时器0
}
//定时器0中断服务函数
void Service_timer0() interrupt 1
{
TH0 = (65535 - 20000) / 256;
TL0 = (65535 - 20000) % 256;
count++;
if(count % 10 == 0) //定时每满0.2s
{
led = ~led;
}
if(count == 250) //定时满5s
{
count = 0;
led = 1;
Select_HC138(4);
P0 = 0xff; //关闭LED
Select_HC138(0);
TR0 = 0; //关闭定时器0
}
}
/*==============================================================================*/
/*====================================LED闪烁===================================*/
void LED_flash()
{
if((TIME[2] == hour)&&(TIME[1] == minute)&&(second == TIME[0]))
{
TR0 = 1;
}
Select_HC138(4);
P0 = 0xff;
L1 = led;
Select_HC138(0);
}
/*==============================================================================*/
/*===============================数码管闪烁(定时器1)============================*/
//定时器1中断初始化
void Init_timer1()
{
TMOD = 0x11; //同时选择定时器0和定时器1
TH1 = (65535 - 50000) / 256;
TL1 = (65535 - 50000) % 256; //50ms定时
EA = 1; //打开总中断
ET1 = 1; //打开定时器1的中断
TR1 = 0; //关闭定时器1
}
//定时器1中断服务函数
void Service_timer1() interrupt 3
{
TH1 = (65535 - 50000) / 256;
TL1 = (65535 - 50000) % 256;
num++;
if(num == 10) //间隔1s
{
state = ~state;
num = 0;
}
}
/*==============================================================================*/
/*===================================独立按键===================================*/
//按键延时函数
void Delay_keys()
{
unsigned char i,j;
i = 108;
j = 145;
do
{
while(--j);
}while(--i);
}
//按键处理
void Press_keys()
{
if(S7 == 0)
{
Delay_keys(); //去抖动
if(S7 == 0) //时钟设置
{
TR0 = 0;
led = 1;
if(alarm == 0)
{
switch(clock)
{
case 0:
clock = 1; //设置时
TR1 = 1; //启动定时器1
break;
case 1:
clock =2; //设置分
break;
case 2:
clock = 3 ; //设置秒
break;
case 3:
clock = 0; //返回时钟显示
TR1 = 0; //关闭定时器1
break;
}
while(S7 == 0)
{
Display_time();
}
}
}
}
else if(S6 == 0)
{
Delay_keys();
if(S6 == 0) //闹钟设置
{
TR0 = 0;
led = 1;
if(clock == 0)
{
switch(alarm)
{
case 0:
status = 1; //数码管显示闹钟
alarm = 1; //设置时
TR1 = 1; //启动定时器1
break;
case 1:
alarm = 2; //设置分
break;
case 2:
alarm = 3; //设置秒
break;
case 3:
status = 0; //返回时钟显示
alarm = 0;
TR1 = 0; //关闭定时器1
break;
}
while(S6 == 0)
{
Display_alarm();
}
}
}
}
else if(S5 == 0)
{
Delay_keys();
if(S5 == 0) //时分秒加1操作
{
TR0 = 0;
led = 1;
if((status == 0)&&(clock != 0)) //时钟调节状态
{
if(clock == 1)
{
TIME[2]++; //时加1
if(TIME[2] == 24)
{
TIME[2] = 0;
}
}
else if(clock == 2)
{
TIME[1]++; //分加1
if(TIME[1] == 60)
{
TIME[1] = 0;
}
}
else if(clock == 3)
{
TIME[0]++; //秒加1
if(TIME[0] == 60)
{
TIME[0] = 0;
}
}
while(S5 == 0)
{
Display_time(); //保证数码管动态显示
}
DS1302_config(); //重新配置日历时钟寄存器
}
else if((status == 1)&&(alarm != 0)) //闹钟调节
{
if(alarm == 1) //时加1
{
hour++;
if(hour == 24)
{
hour = 0;
}
}
else if(alarm == 2) //分加1
{
minute++;
if(minute == 60)
{
minute = 0;
}
}
else if(alarm == 3) //秒加1
{
second++;
if(second == 60)
{
second = 0;
}
}
while(S5 == 0)
{
Display_alarm();
}
}
}
while(S5 == 0);
}
else if(S4 == 0)
{
Delay_keys();
if(S4 == 0) //时分秒减1操作、显示温度
{
TR0 = 0;
led = 1;
if((status == 0)&&(clock == 0)) //时钟显示状态下,按下显示温度
{
while(S4 == 0)
{
Display_temp(T_dat);
}
}
else if((status == 0)&&(clock != 0)) //时钟调节状态
{
if(clock == 1)
{
if(TIME[2] > 0)
{
TIME[2]--; //时减1
}
}
else if(clock == 2)
{
if(TIME[1] > 0)
{
TIME[1]--; //分减1
}
}
else if(clock == 3)
{
if(TIME[0] > 0)
{
TIME[0]--; //秒减1
}
}
while(S4 == 0)
{
Display_time(); //保证数码管动态显示
}
DS1302_config(); //重新配置日历时钟寄存器
}
else if((status == 1)&&(alarm != 0)) //闹钟调节状态
{
if(alarm == 1) //时减1
{
if(hour > 0)
{
hour--;
}
}
else if(alarm == 2) //分减1
{
if(minute > 0)
{
minute--;
}
}
else if(alarm == 3) //秒减1
{
if(second > 0)
{
second--;
}
}
while(S4 == 0)
{
Display_alarm();
}
}
}
}
}
/*==============================================================================*/
/*====================================主函数====================================*/
void main()
{
Init_system();
Init_timer0();
Init_timer1();
Read_temperature();
DS1302_config();
while(1)
{
if((status == 0)&&(clock == 0)) //只在时钟显示时,读取当前时间
{
DS1302_Readtime();
}
switch(status)
{
case 0:
Display_time(); //显示时钟
break;
case 1:
Display_alarm(); //显示闹钟
break;
}
Press_keys();
LED_flash();
}
}
/*==============================================================================*/