难一点的地方就是注意修改时间时数码管显示要保持不走时。两种实现方法,一是设一个标志,进入设置时不执行vRead_ds1302(),从设置退出时把设好的time写入ds1302,再允许读取ds1302。二是用另一个数组表示设置值,进入设置时把当前时间赋给该数组Save_time,设置完成后写入ds1302。这样设置时间时就算走时,改变的也是Time数组,但是我们设置状态下显示的是Save_time数组。
写的过程遇到的一些问题:数码管闪烁,设置一个count判断在设置界面按的次数,来切换不同的闪烁位置;按住与松开判断;设置时间时保存时间防止走时;显示时钟时数字有跳动原因是读取ds1302时可能被定时器打断了,可以在读取时间时EA=0关闭中断,读完再EA=1打开中断;数组元素不能用++,要用+1
main.c
#include <STC15F2K60S2.H>
#include "onewire.h"
#include "ds1302.h"
//问题:数码管闪烁
unsigned char code smg_duanma[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
unsigned char smg_show[8];
unsigned char smg_set[8];
unsigned char Time[3];
unsigned char Save_Time[3];
unsigned char Clock[3]={0,0,0};
void vDevice_Process(unsigned char p2dat,unsigned char p0dat)
{
P0 = p0dat;
P2 = (P2&0x1f)|p2dat;
P2 = (P2&0x1f)|0x00;
}
//定时器2
void Timer2Init(void) //1毫秒@12.000MHz
{
AUXR |= 0x04; //定时器时钟1T模式
T2L = 0x20; //设置定时初值
T2H = 0xD1; //设置定时初值
AUXR |= 0x10; //定时器2开始计时
EA=1;
IE2 = IE2|0x04;
}
//读取时间 返回是16进制
void vRead_ds1302()
{
Time[0]=Read_Ds1302_Byte(0x81);
Time[1]=Read_Ds1302_Byte(0x83);
Time[2]=Read_Ds1302_Byte(0x85);
}
//读取温度 返回是十进制
unsigned char temperture;
unsigned int cnt_temp; //400ms读取一次
void vRead_temperture()
{
if(cnt_temp>=400)
{
cnt_temp = 0;
temperture = rd_temperature();
}
}
//数码管操作
unsigned char smg_mode=0; //模式0显示时间,1显示温度,2设置时间,3设置闹钟
unsigned char flash_bit=0; //闪烁的位置
unsigned int cnt_smg; // 数码管闪烁计时
bit flash;
void vSMG_Process()
{
//显示时间
if(smg_mode==0)
{
smg_show[0] = smg_duanma[Time[2]/16];
smg_show[1] = smg_duanma[Time[2]%16];
smg_show[2] = 0xbf;
smg_show[3] = smg_duanma[Time[1]/16];
smg_show[4] = smg_duanma[Time[1]%16];
smg_show[5] = 0xbf;
smg_show[6] = smg_duanma[Time[0]/16];
smg_show[7] = smg_duanma[Time[0]%16];
}
//显示温度
if(smg_mode==1)
{
smg_show[0] = 0xff;
smg_show[1] = 0xff;
smg_show[2] = 0xff;
smg_show[3] = 0xff;
smg_show[4] = 0xff;
smg_show[5] = smg_duanma[temperture/10];
smg_show[6] = smg_duanma[temperture%10];
smg_show[7] = 0xc6;
}
//设置时间
if(smg_mode==2)
{
if(flash) //亮
{
smg_show[0] = smg_duanma[Save_Time[2]/10];
smg_show[1] = smg_duanma[Save_Time[2]%10];
smg_show[3] = smg_duanma[Save_Time[1]/10];
smg_show[4] = smg_duanma[Save_Time[1]%10];
smg_show[6] = smg_duanma[Save_Time[0]/10];
smg_show[7] = smg_duanma[Save_Time[0]%10];
}
else //灭
{
if(flash_bit==1)
{
smg_show[0] = 0xff;
smg_show[1] = 0xff;
}
else //不是让这两个数码管闪烁时保持常亮
{
smg_show[0] = smg_duanma[Save_Time[2]/10];
smg_show[1] = smg_duanma[Save_Time[2]%10];
}
if(flash_bit==2)
{
smg_show[3] = 0xff;
smg_show[4] = 0xff;
}
else
{
smg_show[3] = smg_duanma[Save_Time[1]/10];
smg_show[4] = smg_duanma[Save_Time[1]%10];
}
if(flash_bit==3)
{
smg_show[6] = 0xff;
smg_show[7] = 0xff;
}
else
{
smg_show[6] = smg_duanma[Save_Time[0]/10];
smg_show[7] = smg_duanma[Save_Time[0]%10];
}
}
smg_show[2] = 0xbf;
smg_show[5] = 0xbf;
}
//设置闹钟
if(smg_mode==3)
{
if(flash) //亮
{
smg_show[0] = smg_duanma[Clock[2]/10];
smg_show[1] = smg_duanma[Clock[2]%10];
smg_show[3] = smg_duanma[Clock[1]/10];
smg_show[4] = smg_duanma[Clock[1]%10];
smg_show[6] = smg_duanma[Clock[0]/10];
smg_show[7] = smg_duanma[Clock[0]%10];
}
else //灭
{
if(flash_bit==1)
{
smg_show[0] = 0xff;
smg_show[1] = 0xff;
}
else
{
smg_show[0] = smg_duanma[Clock[2]/10];
smg_show[1] = smg_duanma[Clock[2]%10];
}
if(flash_bit==2)
{
smg_show[3] = 0xff;
smg_show[4] = 0xff;
}
else
{
smg_show[3] = smg_duanma[Clock[1]/10];
smg_show[4] = smg_duanma[Clock[1]%10];
}
if(flash_bit==3)
{
smg_show[6] = 0xff;
smg_show[7] = 0xff;
}
else
{
smg_show[6] = smg_duanma[Clock[0]/10];
smg_show[7] = smg_duanma[Clock[0]%10];
}
}
smg_show[2] = 0xbf;
smg_show[5] = 0xbf;
}
}
//数码管显示
void vSMG_Display()
{
static unsigned char i=0;
vDevice_Process(0xc0, 0x00);
vDevice_Process(0xe0, smg_show[i]);
vDevice_Process(0xc0, 0x01<<i);
i=(i+1)%8;
}
//读取按键
unsigned char Trg,Cont; //Trg是单击,Cont是长按
void Three_Key()
{
unsigned char ReadData = P3^0xff;
Trg = ReadData & (ReadData ^ Cont);
Cont = ReadData;
}
//判断按键
unsigned int cnt_key; //10ms扫描一次消抖
unsigned char key_time; //判断按了几次
unsigned char hour,min,sec;
void Judge_Key()
{
if(cnt_key>=10)
{
cnt_key=0;
Three_Key();
if(Trg & 0x01) //S7
{
if(smg_mode==0)
{
smg_mode=2; //进入设置时间
Save_Time[0]=Time[0];Save_Time[1]=Time[1];Save_Time[2]=Time[2];//保存当前时间
Save_Time[2] = (Save_Time[2]/16*10+Save_Time[2]%16);
Save_Time[1] = (Save_Time[1]/16*10+Save_Time[1]%16);
Save_Time[0] = (Save_Time[0]/16*10+Save_Time[0]%16);
}
if(smg_mode==2)
{
key_time++; //按的次数
flash_bit++; //要闪烁的位置
if(key_time==4)
{
smg_mode=0;
key_time=0;
flash_bit=0;
Write_time(Save_Time[0]/10*16+Save_Time[0]%10,Save_Time[1]/10*16+Save_Time[1]%10,Save_Time[2]/10*16+Save_Time[2]%10);//写入设置好的时间
}
}
}
if(Trg & 0x02) //S6
{
if(smg_mode==0)
{
smg_mode=3; //进入设置闹钟
}
if(smg_mode==3)
{
key_time++;
flash_bit++;
if(key_time==4)
{
smg_mode=0;
key_time=0;
flash_bit=0;
}
}
}
if(Trg & 0x04) //S5
{
if(smg_mode==2)//设置时间
{
switch(flash_bit)
{
case 1:
if(Save_Time[2]<23)
{
Save_Time[2] = Save_Time[2]+1;
}
break;
case 2:
if(Save_Time[1]<59)
{
Save_Time[1] = Save_Time[1]+1;
}
break;
case 3:
if(Save_Time[0]<59)
{
Save_Time[0] = Save_Time[0]+1;
}
break;
}
}
if(smg_mode==3)//设置闹钟
{
switch(flash_bit)
{
case 1:
if(Clock[2]<23)
{
Clock[2] = Clock[2]+1;
}
break;
case 2:
if(Clock[1]<59)
{
Clock[1] = Clock[1]+1;
}
break;
case 3:
if(Clock[0]<59)
{
Clock[0] = Clock[0]+1;
}
break;
}
}
}
if(Trg & 0x08) //S4
{
if(smg_mode==2)//设置时间
{
switch(flash_bit)
{
case 1:
if(Save_Time[2]>0)
{
Save_Time[2] = Save_Time[2]-1;
}
break;
case 2:
if(Save_Time[1]>0)
{
Save_Time[1] = Save_Time[1]-1;
}
break;
case 3:
if(Save_Time[0]>0)
{
Save_Time[0] = Save_Time[0]-1;
}
break;
}
}
if(smg_mode==3)//设置闹钟
{
switch(flash_bit)
{
case 1:
if(Clock[2]>0)
{
Clock[2] = Clock[2]-1;
}
break;
case 2:
if(Clock[1]>0)
{
Clock[1] = Clock[1]-1;
}
break;
case 3:
if(Clock[0]>0)
{
Clock[0] = Clock[0]-1;
}
break;
}
}
}
if(Cont & 0x08)//长按S4
{
if(smg_mode==0)
{
smg_mode=1;
}
}
else //没有长按时,判断在不在模式1,在模式1下才回到模式0.如果没有这个判断会导致切换
if(smg_mode==1) //不到其它模式,因为没有长按时这个else是一直成立的
{
smg_mode=0;
}
}
}
}
//闹钟
bit alarm_flag=0;
unsigned int cnt_clock;
void alarm()
{
if((Clock[0]==Time[0])&&(Clock[1]==Time[1])&&(Clock[2]==Time[2]))
{
alarm_flag=1;
}
}
void System_init()
{
vDevice_Process(0x80,0xff);
vDevice_Process(0xa0,0x00);
Write_time(0x50,0x59,0x23);
}
unsigned char five;
void main()
{
System_init();
Timer2Init();
while(1)
{
vSMG_Process();
Judge_Key();
vRead_temperture();
if(alarm_flag==1)
{
if(cnt_clock<=200)
{
vDevice_Process(0x80,0xff);
}
else if(cnt_clock<=400)
{
vDevice_Process(0x80,0xfe);
}
else
{
cnt_clock=0;
five++;
vDevice_Process(0x80,0xff);
}
if(five==12)
{
five=0;
alarm_flag=0;
}
}
}
}
void Timer2_sercive() interrupt 12
{
cnt_key++;cnt_temp++;cnt_smg++;
if(cnt_smg>=1000)
{
cnt_smg=0;
flash = !flash;
}
vRead_ds1302();
vSMG_Display();
alarm();
if(alarm_flag==1)
{
cnt_clock++;
}
}
ds1302.c
/*
程序说明: DS1302驱动程序
软件环境: Keil uVision 4.10
硬件环境: CT107单片机综合实训平台 8051,12MHz
日 期: 2011-8-9
*/
#include <reg52.h>
#include <intrins.h>
sbit SCK=P1^7;
sbit SDA=P2^3;
sbit RST = P1^3; // DS1302复位
void Write_Ds1302(unsigned char temp)
{
unsigned char i;
for (i=0;i<8;i++)
{
SCK=0;
SDA=temp&0x01;
temp>>=1;
SCK=1;
}
}
void Write_Ds1302_Byte( unsigned char address,unsigned char dat )
{
RST=0; _nop_();
SCK=0; _nop_();
RST=1; _nop_();
Write_Ds1302(address);
Write_Ds1302(dat);
RST=0;
}
unsigned char Read_Ds1302_Byte ( unsigned char address )
{
unsigned char i,temp=0x00;
RST=0; _nop_();
SCK=0; _nop_();
RST=1; _nop_();
Write_Ds1302(address);
for (i=0;i<8;i++)
{
SCK=0;
temp>>=1;
if(SDA)
temp|=0x80;
SCK=1;
}
RST=0; _nop_();
SCK=0; _nop_();
SCK=1; _nop_();
SDA=0; _nop_();
SDA=1; _nop_();
return (temp);
}
//写入时间
void Write_time(unsigned char sec,unsigned char min,unsigned char hour)
{
Write_Ds1302_Byte(0x8e, 0x00); //关闭写保护
Write_Ds1302_Byte(0x80, sec);
Write_Ds1302_Byte(0x82, min);
Write_Ds1302_Byte(0x84, hour);
Write_Ds1302_Byte(0x8e, 0x80); //打开写保护
}
onewire.c
/*
程序说明: 单总线驱动程序
软件环境: Keil uVision 4.10
硬件环境: CT107单片机综合实训平台(外部晶振12MHz) STC89C52RC单片机
日 期: 2011-8-9
*/
#include "reg52.h"
sbit DQ = P1^4; //单总线接口
//单总线延时函数
void Delay_OneWire(unsigned int t) //STC89C52RC
{
t = t*12;
while(t--);
}
//通过单总线向DS18B20写一个字节
void Write_DS18B20(unsigned char dat)
{
unsigned char i;
for(i=0;i<8;i++)
{
DQ = 0;
DQ = dat&0x01;
Delay_OneWire(5);
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;
dat >>= 1;
DQ = 1;
if(DQ)
{
dat |= 0x80;
}
Delay_OneWire(5);
}
return dat;
}
//DS18B20设备初始化
bit init_ds18b20(void)
{
bit initflag = 0;
DQ = 1;
Delay_OneWire(12);
DQ = 0;
Delay_OneWire(80);
DQ = 1;
Delay_OneWire(10);
initflag = DQ;
Delay_OneWire(5);
return initflag;
}
//获取温度
float rd_temperature(void)
{
unsigned char low,high;
float temp;
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0x44);
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0xBE);
low = Read_DS18B20();
high = Read_DS18B20();
temp = ((high<<8)|low)*0.0625;
return temp;
}