看之前强烈建议先自己做一遍!!!
- 演示视频
- 题目讲解
- 完整程序
- main.c
- onewire.h
- onewire.c
- ds1302.h
- ds1302.c
- 工程文件
演示视频
题目讲解
首先还是一如既往从题目的程序框图准备起。
将ds18b20,独立按键,数码管显示,实时时钟调试好,值得注意的是(题目里没有明确指出实时时钟是什么,所以既可以用定时器也可以用ds1302)。
调试完成后接着往下看题目。
首先是初始化的时间:23:59:50,闹钟的时间:0:0:0。
然后按照数码管的显示两种界面。
char time[7]={50,59,23,0,0,0,0};//ds1302.c中定义的存储时间的数组23:59:50
uchar tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,\
0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0xff,0xbf,0xc6}; //- c
uchar SMG[8]={20,20,20,20,20,20,20,20};//初始显示10,全息数码管
char clock[3]={0,0,0};//闹钟0:0;0
uchar SMG_mode=0,temp; //数码管模式定义 温度定义
void main(void)
{
init(); //初始开发板
Timer0Init();//初始化定时器
ds1302_init();//初始化时间
while(1)
{
if(SMG_mode==0) //界面1时间显示
{
get_time(); //时间获取
SMG[0]=time[2]/10;SMG[1]=time[2]%10; //显示时
SMG[3]=time[1]/10;SMG[4]=time[1]%10; //显示分
SMG[6]=time[0]/10;SMG[7]=time[0]%10; //显示秒
}
else if(SMG_mode==1)//界面2温度显示
{
temp=rd_temperature();//温度获取
SMG[0]=SMG[1]=SMG[2]=SMG[3]=SMG[4]=20; //数码管全熄
SMG[5]=temp/10;SMG[6]=temp%10;SMG[7]=22; //显示温度
}
SMG_output();
Dkey_scan();
}
}
然后接着往下看按键的设置,首先看S7,S6。
S7是时钟设置,设置时,分,秒都需要对应的数码管进行1s为间隔的闪亮,所以肯定是需要定时器的。
S6为闹钟设置,没有说明要闪亮。
//main.c
else //设置界面显示,闪亮!!
{
SMG[2]=21;SMG[5]=21;//不闪的,不要获取时间
switch(SMG_mode)
{
case 5:SMG[3]=time[1]/10;SMG[4]=time[1]%10;//时闪
SMG[6]=time[0]/10;SMG[7]=time[0]%10;break;
case 4:SMG[0]=time[2]/10;SMG[1]=time[2]%10;//分闪
SMG[6]=time[0]/10;SMG[7]=time[0]%10;break;
case 3:SMG[0]=time[2]/10;SMG[1]=time[2]%10; //秒闪
SMG[3]=time[1]/10;SMG[4]=time[1]%10;break;
}
}
void Dkey_scan(void)
{
static uchar keybyte=0;
static uchar key;
if(((P3&0X0F)!=0X0F)&&(keybyte==0))
{
delay5ms();
if((P3&0X0F)!=0X0F)
{
keybyte=1;key=P3&0x0f;
}
}
if((keybyte==1)&&((P3&0X0F)==0X0F))
{
if((P3&0X0F)==0X0F)
{
switch(key)
{
case 0x0e://S7 //切换时间设置
if(SMG_mode==0)SMG_mode=5;
else if(SMG_mode==5)SMG_mode=4;
else if(SMG_mode==4)SMG_mode=3;
else if(SMG_mode==3)ds1302_init();}//初始化时间
break;
case 0x0d://S6 //切换时钟设置
if(SMG_mode==0){SMG_mode=2;clockset=0;}
else if(clockset==0)clockset=1;
else if(clockset==1)clockset=2;
else if(clockset==2)SMG_mode=0;
break;
case 0x0b://S5
break;
case 0x07://S4
break;
}
keybyte=0;
}
}
}
uint t; //定时器计时
bit state=0; //数码管状态定义
//定时器0中断服务函数
void time0() interrupt 1
{
if(SMG_mode>=3)
{
t++;
if(t>=200) //200*5 ==1s
{
t=0;
if(state==0)
{
state=1;
switch(SMG_mode)
{
case 3:SMG[6]=time[0]/10;SMG[7]=time[0]%10;break;//秒亮
case 4:SMG[3]=time[1]/10;SMG[4]=time[1]%10;break;//分亮
case 5:SMG[0]=time[2]/10;SMG[1]=time[2]%10;break;//时亮
}
}
else
{
state=0;
switch(SMG_mode)
{
case 3:SMG[6]=20;SMG[7]=20;break; //20熄灭
case 4:SMG[3]=20;SMG[4]=20;break;//20熄灭
case 5:SMG[0]=20;SMG[1]=20;break;//20熄灭
}
}
}
}
}
接下来设置S5,S4两个按键。
case 0x0b://S5
if(SMG_mode>=3)
{
switch(SMG_mode)
{
case 3:time[0]++;break; //秒加1时钟
case 4:time[1]++;break; //分加1时钟
case 5:time[2]++;break; //时加1时钟
}
if(time[0]>=60)time[0]=60; //限幅设置时钟
if(time[1]>=60)time[1]=60; //限幅设置时钟
if(time[2]>=24)time[2]=24; //限幅设置时钟
}
else if(SMG_mode==2)
{
switch(clockset)
{
case 0:clock[2]++;break; //秒加1闹钟
case 1:clock[1]++;break; //秒加1闹钟
case 2:clock[0]++;break; //秒加1闹钟
}
if(clock[0]>=60)clock[0]=60; //限幅设置闹钟
if(clock[1]>=60)clock[1]=60; //限幅设置闹钟
if(clock[2]>=24)clock[2]=24; //限幅设置闹钟
}
break;
case 0x07://S4
if(SMG_mode>=3)
{
switch(SMG_mode)
{
case 3:time[0]--;break; //秒加1时钟
case 4:time[1]--;break; //分加1时钟
case 5:time[2]--;break; //时加1时钟
}
if(time[0]<=0)time[0]=0; //限幅设置时钟
if(time[1]<=0)time[1]=0; //限幅设置时钟
if(time[2]<=0)time[2]=0; //限幅设置时钟
}
else if(SMG_mode==2)
{
switch(clockset)
{
case 0:clock[2]--;break; //减加1闹钟
case 1:clock[1]--;break; //减加1闹钟
case 2:clock[0]--;break; //减加1闹钟
}
if(clock[0]<=0)clock[0]=0; //限幅设置闹钟
if(clock[1]<=0)clock[1]=0; //限幅设置闹钟
if(clock[2]<=0)clock[2]=0; //限幅设置闹钟
}
break;
//main.c此处由于后面是长安按键生效,所以修改致按键扫描内了
// else if(SMG_mode==1)//界面2温度显示
// {
// temp=rd_temperature();
// SMG[0]=SMG[1]=SMG[2]=SMG[3]=SMG[4]=20; //数码管全熄
// SMG[5]=temp/10;SMG[6]=temp%10;SMG[7]=22; //显示采集间隔
// }
if(SMG_mode==0) //当时间显示下长安S4按键
{
while(key==0x07)
{
temp=rd_temperature();//温度获取
SMG[0]=SMG[1]=SMG[2]=SMG[3]=SMG[4]=20; //数码管全熄
SMG[5]=temp/10;SMG[6]=temp%10;SMG[7]=22; //显示显示温度
SMG_mode=1;SMG_output();
key=P3&0x0f;keybyte=0;
}
SMG_mode=0;
}
注意各按键的使用前提。(比如在哪个界面生效)
然后看最后的闹钟提示功能。
//main。c
bit ledenable=0;//闹钟使能
if((time[0]==clock[0])&&(time[1]==clock[1])&&(time[2]==clock[2]))//时间相等
{
ledenable=1;//打开闹钟
}
uchar led=0xff; //led定义,好处是不影响别的p0口
if(ledenable==1)
{
P2=0X80;P0=led;//打开led闪烁
}
else
{
P2=0X80;P0=0xff;//关闭led闪烁
}
//定时器中断服务函数
uchar tt; //闹钟led计时
if(ledenable==1)
{
tt++;
if(tt>=40) //40*5=200=0.2s
{
tt=0;
if(state==0)
{
state=1;
led&=0xfe;
}
else
{
state=0;
led|=0x01;
}
}
}
//然后在按键里面关闭闹钟
//enable=0;
完整程序
main.c
#include <stc15f2k60s2.h>
#include "intrins.h"
#include "onewire.h"
#include "ds1302.h"
#define uchar unsigned char
#define uint unsigned int
void SMG_output(void);
void init(void);
void Delay1ms(void);
void delay5ms(void);
void Dkey_scan(void);
void Timer0Init(void);
char time[7]={50,59,23,0,0,0,0};//ds1302.c中定义的存储时间的数组23:59:50
uchar tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,\
0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0xff,0xbf,0xc6}; //- c
uchar SMG[8]={20,20,20,20,20,20,20,20};//初始显示10,全息数码管
char clock[3]={0,0,0};//闹钟0:0;0
uchar SMG_mode=0,temp; //数码管模式定义 温度定义
uchar clockset=0; //0为设置时 1为设置分 2为设置秒
bit ledenable=0;//闹钟使能
uchar led=0xff; //led定义,好处是不影响别的p0口
void main(void)
{
init(); //初始开发板
Timer0Init();//初始化定时器
ds1302_init();//初始化时间
while(1)
{
if(SMG_mode==0) //界面1时间显示
{
get_time(); //时间获取
SMG[2]=21;SMG[5]=21;
SMG[0]=time[2]/10;SMG[1]=time[2]%10; //显示时
SMG[3]=time[1]/10;SMG[4]=time[1]%10; //显示分
SMG[6]=time[0]/10;SMG[7]=time[0]%10; //显示秒
}
//此处由于后面是长安按键生效,所以修改致按键扫描内了
// else if(SMG_mode==1)//界面2温度显示
// {
// temp=rd_temperature();
// SMG[0]=SMG[1]=SMG[2]=SMG[3]=SMG[4]=20; //数码管全熄
// SMG[5]=temp/10;SMG[6]=temp%10;SMG[7]=22; //显示采集间隔
// }
else if(SMG_mode==2)//界面3闹钟显示
{
SMG[0]=clock[2]/10;SMG[1]=clock[2]%10; //显示时
SMG[3]=clock[1]/10;SMG[4]=clock[1]%10; //显示分
SMG[6]=clock[0]/10;SMG[7]=clock[0]%10; //显示秒
}
else //设置界面显示,闪亮!!
{
SMG[2]=21;SMG[5]=21;//不闪的,不要获取时间
switch(SMG_mode)
{
case 5:SMG[3]=time[1]/10;SMG[4]=time[1]%10;//时闪
SMG[6]=time[0]/10;SMG[7]=time[0]%10;break;
case 4:SMG[0]=time[2]/10;SMG[1]=time[2]%10;//分闪
SMG[6]=time[0]/10;SMG[7]=time[0]%10;break;
case 3:SMG[0]=time[2]/10;SMG[1]=time[2]%10; //秒闪
SMG[3]=time[1]/10;SMG[4]=time[1]%10;break;
}
}
if((time[0]==clock[0])&&(time[1]==clock[1])&&(time[2]==clock[2]))//时间相等
{
ledenable=1;//打开闹钟
}
if(ledenable==1)
{
P2=0X80;P0=led;//打开led闪烁
}
else
{
P2=0X80;P0=0xff;//关闭led闪烁
}
SMG_output();
Dkey_scan();
}
}
void Dkey_scan(void)
{
static uchar keybyte=0;
static uchar key;
if(((P3&0X0F)!=0X0F)&&(keybyte==0))
{
delay5ms();
if((P3&0X0F)!=0X0F)
{
keybyte=1;key=P3&0x0f;
}
}
if(SMG_mode==0) //当时间显示下长安S4按键
{
while(key==0x07)
{
temp=rd_temperature(); //温度获取
SMG[0]=SMG[1]=SMG[2]=SMG[3]=SMG[4]=20; //数码管全熄
SMG[5]=temp/10;SMG[6]=temp%10;SMG[7]=22; //显示温度
SMG_mode=1;SMG_output();
key=P3&0x0f;keybyte=0;
ledenable=0;//关闭闹钟
}
SMG_mode=0;
}
if((keybyte==1)&&((P3&0X0F)==0X0F))
{
if((P3&0X0F)==0X0F)
{
switch(key)
{
case 0x0e://S7 //切换时间设置
ledenable=0;//关闭闹钟
if(SMG_mode==0)SMG_mode=5;
else if(SMG_mode==5)SMG_mode=4;
else if(SMG_mode==4)SMG_mode=3;
else if(SMG_mode==3){SMG_mode=0;ds1302_init();}//初始化时间
break;
case 0x0d://S6 //切换时钟设置
ledenable=0;//关闭闹钟
if(SMG_mode==0){SMG_mode=2;clockset=0;}
else if(clockset==0)clockset=1;
else if(clockset==1)clockset=2;
else if(clockset==2)SMG_mode=0;
break;
case 0x0b://S5
ledenable=0;//关闭闹钟
if(SMG_mode>=3)
{
switch(SMG_mode)
{
case 3:time[0]++;break; //秒加1时钟
case 4:time[1]++;break; //分加1时钟
case 5:time[2]++;break; //时加1时钟
}
if(time[0]>=60)time[0]=60; //限幅设置时钟
if(time[1]>=60)time[1]=60; //限幅设置时钟
if(time[2]>=24)time[2]=24; //限幅设置时钟
}
else if(SMG_mode==2)
{
switch(clockset)
{
case 0:clock[2]++;break; //秒加1闹钟
case 1:clock[1]++;break; //秒加1闹钟
case 2:clock[0]++;break; //秒加1闹钟
}
if(clock[0]>=60)clock[0]=60; //限幅设置闹钟
if(clock[1]>=60)clock[1]=60; //限幅设置闹钟
if(clock[2]>=24)clock[2]=24; //限幅设置闹钟
}
break;
case 0x07://S4
ledenable=0;//关闭闹钟
if(SMG_mode>=3)
{
switch(SMG_mode)
{
case 3:time[0]--;break; //秒加1时钟
case 4:time[1]--;break; //分加1时钟
case 5:time[2]--;break; //时加1时钟
}
if(time[0]<=0)time[0]=0; //限幅设置时钟
if(time[1]<=0)time[1]=0; //限幅设置时钟
if(time[2]<=0)time[2]=0; //限幅设置时钟
}
else if(SMG_mode==2)
{
switch(clockset)
{
case 0:clock[2]--;break; //减加1闹钟
case 1:clock[1]--;break; //减加1闹钟
case 2:clock[0]--;break; //减加1闹钟
}
if(clock[0]<=0)clock[0]=0; //限幅设置闹钟
if(clock[1]<=0)clock[1]=0; //限幅设置闹钟
if(clock[2]<=0)clock[2]=0; //限幅设置闹钟
}
break;
}
keybyte=0;
}
}
}
uint t; //定时器计时
bit state=0; //数码管状态定义
uchar tt; //闹钟led计时
//定时器0中断服务函数
void time0() interrupt 1
{
if(SMG_mode>=3)
{
t++;
if(t>=200) //200*5 ==1s
{
t=0;
if(state==0)
{
state=1;
switch(SMG_mode)
{
case 3:SMG[6]=time[0]/10;SMG[7]=time[0]%10;break;//秒亮
case 4:SMG[3]=time[1]/10;SMG[4]=time[1]%10;break;//分亮
case 5:SMG[0]=time[2]/10;SMG[1]=time[2]%10;break;//时亮
}
}
else
{
state=0;
switch(SMG_mode)
{
case 3:SMG[6]=20;SMG[7]=20;break; //20熄灭
case 4:SMG[3]=20;SMG[4]=20;break;//20熄灭
case 5:SMG[0]=20;SMG[1]=20;break;//20熄灭
}
}
}
}
if(ledenable==1)
{
tt++;
if(tt>=40) //40*5=200=0.2s
{
tt=0;
if(state==0)
{
state=1;
led&=0xfe;
}
else
{
state=0;
led|=0x01;
}
}
}
}
void Timer0Init(void) //5毫秒@11.0592MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x00; //设置定时初值
TH0 = 0x28; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
EA=1;ET0=1; //打开定时器中断
}
void SMG_output(void)
{
uchar i;
for(i=0;i<8;i++)
{
P2=(P2&0X1F)|0Xc0;
P0=(1<<i);
P2=(P2&0X1F)|0Xe0;
P0=tab[SMG[i]];
Delay1ms();
}
P2=(P2&0X1F)|0Xc0;
P0=0Xff;
P2=(P2&0X1F)|0Xe0;
P0=0Xff;
}
void init(void)
{
P2=(P2&0X1F)|0XA0;
P0=0X00;
P2=(P2&0X1F)|0X80;
P0=0Xff;
P2=(P2&0X1F)|0Xc0;
P0=0Xff;
P2=(P2&0X1F)|0Xe0;
P0=0Xff;
}
void Delay1ms(void) //@11.0592MHz
{
unsigned char i, j;
_nop_();
_nop_();
_nop_();
i = 11;
j = 190;
do
{
while (--j);
} while (--i);
}
void delay5ms(void) //@11.0592MHz
{
unsigned char i, j;
i = 54;
j = 199;
do
{
while (--j);
} while (--i);
}
onewire.h
#ifndef __ONEWIRE_H
#define __ONEWIRE_H
#include <stc15f2k60s2.h>
sbit DQ = P1^4;
unsigned char rd_temperature(void); //; ;
void Delay_OneWire(unsigned int t);
unsigned char Read_DS18B20(void);
bit init_ds18b20(void);
void Write_DS18B20(unsigned char dat);
#endif
onewire.c
#include "onewire.h"
unsigned char rd_temperature(void)
{
unsigned char de,gao;
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0x44);
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0xbe);
de=Read_DS18B20();
gao=Read_DS18B20();
return((de >>4)|(gao<<4));
}
//
void Delay_OneWire(unsigned int t)
{
t=t*8;
while(t--);
}
//
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);
}
//
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;
}
//
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;
}
ds1302.h
#ifndef __DS1302_H
#define __DS1302_H
#include <stc15f2k60s2.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit SCK = P1^7;
sbit SDA = P2^3;
sbit RST = P1^3;
void ds1302_init(void);
void get_time(void);
void Write_Ds1302(unsigned char temp);
void Write_Ds1302_Byte( unsigned char address,unsigned char dat );
unsigned char Read_Ds1302_Byte( unsigned char address );
#endif
ds1302.c
#include "ds1302.h"
extern char time[7];
void ds1302_init(void)
{
uchar i,j=0x80;
Write_Ds1302_Byte(0x8e,0x00);
for(i=0;i<7;i++)
{
Write_Ds1302_Byte(j,time[i]);
j +=2;
}
Write_Ds1302_Byte(0x8e,0x80);
}
void get_time(void)
{
uchar i,j=0x81;
Write_Ds1302_Byte(0x8e,0x00);
for(i=0;i<7;i++)
{
time[i]=Read_Ds1302_Byte(j);
j +=2;
}
Write_Ds1302_Byte(0x8e,0x80);
}
//
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/10)<<4)|(dat%10));
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/16)*10)+(temp%16));
}
工程文件
代码内有注释详细讲解