一、 基本要求
1.1 使用 CT107D 单片机竞赛板,完成“电子钟”功能的程序设计与调试;
1.2 设计与调试过程中,可参考组委会提供的“资源数据包” ;
1.3 Keil 工程文件以准考证号命名,完成设计后,提交完整、可编译的 Keil
工程文件到服务器。
二、 硬件框图
三、 功能描述
3.1 初始化
1)关闭蜂鸣器、继电器等无关外设;
2)设备初始化时钟为 23 时 59 分 50 秒,闹钟提醒时间 0 时 0 分 0 秒。
3.2 显示功能
3.3 按键功能
1)按键 S7 定义为“时钟设置”按键,通过该按键可切换选择待调整的
时、分、秒,当前选择的显示单元以 1 秒为间隔亮灭,时、分、秒
的调整需注意数据边界属性。
2) 按键 S6 定义为“闹钟设置”按键,通过该按键可进入闹钟时间设置
功能,数码管显示当前设定的闹钟时间。
3) 按键 S5 定义为“加” 按键, 在“时钟设置” 或“闹钟设置” 状态下,每次按下该按键当前选择的单元(时、分或秒)增加 1 个单位。
4) 按键 S4 定义为“减” 按键, 在“时钟设置” 或“闹钟设置” 状态下,每次按下该按键当前选择的单元(时、分或秒)减少 1 个单位。
5) 按键功能说明:
按键 S4、 S5 的“加” 、 “减”功能只在“时钟设置”或“闹钟设置”状态下有效;
在 “时钟显示”状态下,按下 S4按键,显示温度数据,松开按键,返回“时钟显示”界面。
3.4 闹钟提示功能
1)指示灯 L1 以 0.2 秒为间隔闪烁,持续 5 秒钟;
2)闹钟提示状态下,按下任意按键,关闭闪烁提示功能。
主函数
#include"stc15f2k60s2.h"
#include "ds1302.h"
#include "onewire.h"
typedef unsigned char uchar;
typedef unsigned int uint;
uchar code SMG_duan[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
uchar code SMG_wei[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
uchar time_display[8]; //时间显示
uchar temp_display[8]; //温度显示
uchar set_display[8]; //时间设置显示
uchar clock_display[8]; //闹钟设置显示
uchar clock_shi=0,clock_fen=0,clock_miao=0; //闹钟时间
uchar shi,fen,miao;
uchar clock_mode=0; //闹钟调整模式
uchar mode=0; //时间调整模式
uchar mode_display=0; // 0 时间显示,1 时间设置 2 温度显示 3 闹钟设置
bit clock_flag;
uchar set_blink;
uchar led_blink=0;
uchar temperature;
uchar Key_init();
void Timer0Init(); //1毫秒@11.0592MHz
void main()
{
uchar key_val;
P2=0XA0;P0=0X00;
P2=0X80;P0=0XFF;
Timer0Init();
DS1302();
time_display[2]=0X40; time_display[5]=0X40;
set_display[2]=0X40; set_display[5]=0X40;
clock_display[2]=0x40; clock_display[5]=0x40;
temp_display[0]=0x00; temp_display[1]=0x00;
temp_display[2]=0x00; temp_display[3]=0x00;
temp_display[4]=0x00; temp_display[7]=0x39;
while(1)
{
ET0=0; //不关闭中断,时间显示会有种卡顿感
Read_time();
ET0=1;
if(mode_display==0) //时间
{
time_display[0]=SMG_duan[TIME[2]/16]; time_display[1]=SMG_duan[TIME[2]%16];
time_display[3]=SMG_duan[TIME[1]/16]; time_display[4]=SMG_duan[TIME[1]%16];
time_display[6]=SMG_duan[TIME[0]/16]; time_display[7]=SMG_duan[TIME[0]%16];
}
if(mode_display==3) //闹钟
{
if(set_blink)
{
if(clock_mode==1) //时
{
clock_display[0]=SMG_duan[clock_shi/10];
clock_display[1]=SMG_duan[clock_shi%10];
}
if(clock_mode==2) //分
{
clock_display[3]=SMG_duan[clock_fen/10];
clock_display[4]=SMG_duan[clock_fen%10];
}
if(clock_mode==3) //秒
{
clock_display[6]=SMG_duan[clock_miao/10];
clock_display[7]=SMG_duan[clock_miao%10];
}
}
else
{
if(clock_mode==1)
{
clock_display[0]=0x00;
clock_display[1]=0x00;
}
else
{
clock_display[0]=SMG_duan[clock_shi/10];
clock_display[1]=SMG_duan[clock_shi%10];
}
if(clock_mode==2)
{
clock_display[3]=0x00;
clock_display[4]=0x00;
}
else
{
clock_display[3]=SMG_duan[clock_fen/10];
clock_display[4]=SMG_duan[clock_fen%10];
}
if(clock_mode==3)
{
clock_display[6]=0x00;
clock_display[7]=0x00;
}
else
{
clock_display[6]=SMG_duan[clock_miao/10];
clock_display[7]=SMG_duan[clock_miao%10];
}
}
}
if((TIME[0]==clock_miao)&&(TIME[1]==clock_fen)&&(TIME[2]==clock_shi))
{
if(mode_display==0)
clock_flag=1;
}
temperature=temp_get();
temp_display[5]=SMG_duan[temperature%100/10];
temp_display[6]=SMG_duan[temperature%10];
key_val=Key_init();
if(mode_display==0)
{
if(clock_flag) //闹钟提示状态下,按下任意键关闭提示功能
{
if(key_val)
clock_flag=0;
}
}
switch(key_val)
{
case 4:
if(mode_display==3) //闹钟设置
{
if(clock_mode==1)
{
if(clock_shi>0)
clock_shi--;
}
if(clock_mode==2)
{
if(clock_fen>0)
clock_fen--;
}
if(clock_mode==3)
{
if(clock_miao>0)
clock_miao--;
}
}
if(mode_display==1) //时间设置
{
if(mode==1)
{
if(shi>0)
shi--;
}
if(mode==2)
{
if(fen>0)
fen--;
}
if(mode==3)
{
if(miao>0)
miao--;
}
}
break;
case 5:
if(mode_display==1)
{
if(mode==1)
{
shi++;
if(shi==24)
shi=0;
}
if(mode==2)
{
fen++;
if(fen==60)
fen=0;
}
if(mode==3)
{
miao++;
if(miao==60)
miao=0;
}
}
if(mode_display==3)
{
if(clock_mode==1)
{
clock_shi++;
if(clock_shi==24)
clock_shi=0;
}
if(clock_mode==2)
{
clock_fen++;
if(clock_fen==60)
clock_fen=0;
}
if(clock_mode==3)
{
clock_miao++;
if(clock_miao==60)
clock_miao=0;
}
}
break;
case 6:
if(mode_display==0)
{
mode_display=3; //进入时间设置界面
}
if(mode_display==3)
{
clock_mode++;
if(clock_mode==4)
{
clock_mode=0;
mode_display=0;
}
}
break;
case 7:
if(mode_display==0)
{
mode_display=1; //进入时间设置界面
}
if(mode_display==1)
{
if(mode==0)
{
shi=(TIME[2]/16)*10+TIME[2]%16;
fen=(TIME[1]/16)*10+TIME[1]%16;
miao=(TIME[0]/16)*10+TIME[0]%16;
set_display[0]=SMG_duan[shi/10];
set_display[1]=SMG_duan[shi%10];
set_display[3]=SMG_duan[fen/10];
set_display[4]=SMG_duan[fen%10];
set_display[6]=SMG_duan[miao/10];
set_display[7]=SMG_duan[miao%10];
}
mode++;
if(mode==4)
{
mode=0;
mode_display=0; //返回时间显示界面
TIME[2]=(shi/10)*16+shi%10; //十进制再转成十六进制
TIME[1]=(fen/10)*16+fen%10;
TIME[0]=(miao/10)*16+miao%10;
DS1302(); //重新写入时间
}
}
break;
}
if(mode_display==1)
{
if(set_blink)
{
if(mode==1) //时
{
set_display[0]=SMG_duan[shi/10];
set_display[1]=SMG_duan[shi%10];
}
if(mode==2) //分
{
set_display[3]=SMG_duan[fen/10];
set_display[4]=SMG_duan[fen%10];
}
if(mode==3) //秒
{
set_display[6]=SMG_duan[miao/10];
set_display[7]=SMG_duan[miao%10];
}
}
else
{
if(mode==1)
{
set_display[0]=0x00;
set_display[1]=0x00;
}
else
{
set_display[0]=SMG_duan[shi/10];
set_display[1]=SMG_duan[shi%10];
}
if(mode==2)
{
set_display[3]=0x00;
set_display[4]=0x00;
}
else
{
set_display[3]=SMG_duan[fen/10];
set_display[4]=SMG_duan[fen%10];
}
if(mode==3)
{
set_display[6]=0x00;
set_display[7]=0x00;
}
else
{
set_display[6]=SMG_duan[miao/10];
set_display[7]=SMG_duan[miao%10];
}
}
}
}
}
#define KEY P3
#define key_state0 0
#define key_state1 1
#define key_state2 2
uchar Key_init()
{
static uchar key_state=0; //要定义成静态变量
uchar key_press,key_return=0;
key_press=KEY&0X0F;
switch(key_state)
{
case key_state0:
if(key_press!=0x0f)
key_state=key_state1;
break;
case key_state1:
if(key_press!=0x0f)
{
if(key_press==0x0e) key_return=7;
if(key_press==0x0d) key_return=6;
if(key_press==0x0b) key_return=5;
if(key_press==0x07)
{
if(mode_display==0)
mode_display=2;
key_return=4;
}
key_state=key_state2;
}
else
key_state=key_state0;
break;
case key_state2: //判断按键是否松开
if(key_press==0x0f)
{
key_state=key_state0;
if(mode_display==2)
{
mode_display=0;
}
}
break;
}
return key_return;
}
void Timer0Init() //1毫秒@11.0592MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xCD; //设置定时初值
TH0 = 0xD4; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
EA=1;
ET0=1;
}
void Timer0() interrupt 1
{
uchar i;
static uint SMG_count=0,led_count=0,blink_count=0,set_count=0;
SMG_count++; set_count++;
if(SMG_count==3)
{
SMG_count=0;
P2=0XC0;P0=0X00;
P2=0XC0;P0=SMG_wei[i];
if(mode_display==0) //时间显示
{
P2=0XE0;P0=~time_display[i];
}
if(mode_display==1) //时间设置显示
{
P2=0XE0;P0=~set_display[i];
}
if(mode_display==2) //温度显示
{
P2=0XE0;P0=~temp_display[i];
}
if(mode_display==3) //闹钟设置显示
{
P2=0XE0;P0=~clock_display[i];
}
i++;
if(i==8)
i=0;
}
if(clock_flag)
{
led_count++;
if(led_count>200)
{
led_count=0;
led_blink++;
if(led_blink==2)
led_blink=0;
blink_count++; //200ms加一次
}
if(led_blink)
{
P2=0X80;P0=0xfe;
}
else
{
P2=0X80;P0=0xff;
}
if(blink_count>25) //如果5s时。led恰巧亮着,那么它就不会熄灭,所以要大于
{
blink_count=0;
clock_flag=0;
}
}
if(set_count==1000)
{
set_count=0;
set_blink++;
if(set_blink==2)
set_blink=0;
}
}
DS1302时钟模块
#include "ds1302.h"
unsigned char code Write_addr[]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};
unsigned char code Read_addr[]={0x81,0x83,0x85,0x87,0x89,0x8ab,0x8d};
unsigned char TIME[]={0X50,0X59,0X23};
void Write_Ds1302_Byte(unsigned char dat)
{
unsigned char i;
SCK = 0;
for (i=0;i<8;i++)
{
if (dat & 0x01) // 等价于if((addr & 0x01) ==1)
{
SDA_SET; //#define SDA_SET SDA=1 /*电平置高*/
}
else
{
SDA_CLR; //#define SDA_CLR SDA=0 /*电平置低*/
}
SCK_SET;
SCK_CLR;
dat = dat >> 1;
}
}
/********************************************************************/
/*单字节读出一字节数据*/
unsigned char Read_Ds1302_Byte(void)
{
unsigned char i, dat=0;
for (i=0;i<8;i++)
{
dat = dat >> 1;
if (SDA_R) //等价于if(SDA_R==1) #define SDA_R SDA /*电平读取*/
{
dat |= 0x80;
}
else
{
dat &= 0x7F;
}
SCK_SET;
SCK_CLR;
}
return dat;
}
/********************************************************************/
/*向DS1302 单字节写入一字节数据*/
void Ds1302_Single_Byte_Write(unsigned char addr, unsigned char dat)
{
RST_CLR; /*RST脚置低,实现DS1302的初始化*/
SCK_CLR; /*SCK脚置低,实现DS1302的初始化*/
RST_SET; /*启动DS1302总线,RST=1电平置高 */
addr = addr & 0xFE;
Write_Ds1302_Byte(addr); /*写入目标地址:addr,保证是写操作,写之前将最低位置零*/
Write_Ds1302_Byte(dat); /*写入数据:dat*/
RST_CLR; /*停止DS1302总线*/
}
/********************************************************************/
/*从DS1302单字节读出一字节数据*/
unsigned char Ds1302_Single_Byte_Read(unsigned char addr)
{
unsigned char temp;
RST_CLR; /*RST脚置低,实现DS1302的初始化*/
SCK_CLR; /*SCK脚置低,实现DS1302的初始化*/
RST_SET; /*启动DS1302总线,RST=1电平置高 */
addr = addr | 0x01;
Write_Ds1302_Byte(addr); /*写入目标地址:addr,保证是读操作,写之前将最低位置高*/
temp=Read_Ds1302_Byte(); /*从DS1302中读出一个字节的数据*/
RST_CLR; /*停止DS1302总线*/
_nop_();
SD=0;
_nop_();
SD=1;
_nop_();
return temp;
}
void DS1302()
{
int i;
Ds1302_Single_Byte_Write(0x8e,0x00); //0x8e为写地址,WP=0,允许写操作
for(i=0;i<3;i++)
{
Ds1302_Single_Byte_Write(Write_addr[i],TIME[i]);
}
Ds1302_Single_Byte_Write(0x8e,0x80); //WP=1,禁止写操作
}
void Read_time()
{
int i;
for(i=0;i<3;i++)
{
TIME[i]=Ds1302_Single_Byte_Read(Read_addr[i]);
}
}
DS18B20温度传感器模块
#include "onewire.h"
//单总线延时函数
void Delay_OneWire(unsigned int t)
{
while(t--);
}
void Delay500us(); //@11.0592MHz
void Delay100us(); //@11.0592MHz
void Delay60us(); //@11.0592MHz
void Delay15us(); //@11.0592MHz
void delayms(unsigned char ms)
{
int i,j;
for(i=0;i<ms;i++)
for(j=850;j>0;j--);
}
bit Init_DS18B20(void)
{
bit initflag = 0;
DQ = 1;
Delay_OneWire(12);
DQ = 0;
Delay500us();
DQ = 1;
Delay15us();
initflag = DQ;
Delay_OneWire(5);
return initflag;
}
//通过单总线向DS18B20写一个字节
void Write_DS18B20(unsigned char dat)
{
unsigned char i;
for(i=0;i<8;i++)
{
DQ = 0;
DQ = dat&0x01;
Delay60us();
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;
}
Delay100us();
}
return dat;
}
void DS18B20()
{
Init_DS18B20();
delayms(1);
Write_DS18B20(0xcc);
Write_DS18B20(0x44);
Init_DS18B20();
delayms(1);
Write_DS18B20(0xcc);
Write_DS18B20(0xbe);
}
int temp_get()
{
int low,high;
int temp;
DS18B20();
low=Read_DS18B20();
high=Read_DS18B20();
temp=high<<4;
temp|=low>>4;
return temp;
}
void Delay500us() //@11.0592MHz
{
unsigned char i, j;
_nop_();
_nop_();
i = 6;
j = 93;
do
{
while (--j);
} while (--i);
}
void Delay100us() //@11.0592MHz
{
unsigned char i, j;
_nop_();
_nop_();
i = 2;
j = 15;
do
{
while (--j);
} while (--i);
}
void Delay60us() //@11.0592MHz
{
unsigned char i, j;
i = 1;
j = 162;
do
{
while (--j);
} while (--i);
}
void Delay15us() //@11.0592MHz
{
unsigned char i;
i = 39;
while (--i);
}
以上就是代码全部内容,欢迎交流,共同学习~