标题:
蓝桥杯任务基于单片机的电子钟
[打印本页]
作者:
郭振凯
时间:
2017-12-14 10:30
标题:
蓝桥杯任务基于单片机的电子钟
基于单片机的电子钟仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
0.jpg
(131.25 KB, 下载次数: 32)
下载附件
2017-12-14 12:25 上传
0.jpg
(26.44 KB, 下载次数: 41)
下载附件
2017-12-14 12:25 上传
蓝桥杯任务单片机源程序如下:
#include <regx51.h>
#include <intrins.h>
sfr AUXR = 0x8e;
/*数码管显示字符转换表*/
unsigned char tab[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00,0x40,0x39};
signed char num[] = {10,10,10,10,10,10,10,10}; //数码管显示缓冲区
signed char timeclock[] = {0,0,11,0,0,11,0,0}; //闹钟时间
unsigned char TRH0,TRL0; //T0重载值的高字节和低字节
bit clock = 0; //闹钟时间到标志位
bit flag = 0; //1s闪烁标志位
bit flag200ms = 0; //200ms定时标志位
bit timesetup = 0; //时间设置标志位
bit clocksetup = 0; //闹钟设置标志位
unsigned position = 0; //设置小时,分钟,秒标志位(‘1’小时,‘2’分钟,‘3’秒)
unsigned char Temp; //温度值
unsigned char Time[5]; //时间值
void key(); //按键判断执行函数
void Ds1302_Display(); //时间显示函数
void Ds18b20_Display(); //温度显示函数
extern void Ds1302_Init(); //DS1302初始化函数
void Ds1302_Time(unsigned char *time); //带参数的向DS18B20写时间
extern void Write_Ds1302_Byte(unsigned char temp); //向DS1302写入数据
extern unsigned char Read_Ds1302 (unsigned char address); //从DS1302读取数据
extern unsigned char DS18B20_Temp(); //读取DS18B20温度值
/*T0初始化函数 (ms = 中断时间)*/
void Time0_Init(unsigned char ms)
{
unsigned long num; //临时变量
num = 12000000 / 12; //12分频 定时器计数频率
num = (num * ms)/1000; //计算所需的计数值
num = 65536 - num; //计算定时器重载值
TRH0 = (unsigned char)(num>>8); //定时器重载值拆分为高低字节
TRL0 = (unsigned char)num;
TH0 = TRH0; //加载T0重载值
TL0 = TRL0;
AUXR &= 0x7F;
TMOD &= 0xf0; //清零T0的控制位
TMOD |= 0x01; //配置T0为模式1
EA = 1; //使能总中断
ET0 = 1; //使能T0中断
TR0 = 1; //启动T0
}
void main()
{
unsigned char i,k=0;
Time0_Init(1); //初始化T0,定时时间为1ms
Ds1302_Init(); //初始化DS1302
while(1)
{
key();
for(i=0;i<8;i++)
{
if(num[i]==timeclock[i])
k++ ;
else
k = 0;
}
if(k == 8)
clock = 1;
}
}
/*DS18B20显示函数*/
void Ds18b20_Display()
{
unsigned char i;
if(flag200ms != 0)
{
flag200ms = 0;
Temp = DS18B20_Temp();
for(i=0;i<5;i++)
{
num[i] = 10;
}
num[5] = Temp / 10;
num[6] = Temp % 10;
num[7] = 12;
}
}
/*DS1302显示函数*/
void Ds1302_Display()
{
static unsigned char i;
static unsigned char pers = 0xaa;
if(flag200ms != 0)
{
flag200ms = 0;
for(i=0;i<3;i++)
{
Time[i] = Read_Ds1302(i); //每200ms获取时间
}
if(pers != Time[0]) //判断时间有没有变化
{
num[7] = Time[0] & 0x0f; //秒
num[6] = Time[0] >> 4;
num[5] = 11;
num[4] = Time[1] & 0x0f; //分
num[3] = Time[1] >> 4;
num[2] = 11;
num[1] = Time[2] & 0x0f; //时
num[0] = Time[2] >> 4;
pers = Time[0]; //将变化值重新写入判断值
}
}
}
/*数码管显示函数*/
void Display()
{
static unsigned char we = 0;
P0 = 0x00; //清除鬼影
P2 |= 0xff;
P2 &= ~(1<<we); //位选择
if(clocksetup)
P0 = tab[timeclock[we]];
else
P0 = tab[num[we]]; //显示数选择
if(flag) //进入设置状态
{
switch(position) //判断是那个设置位
{
case 1: P2 |= 0xc0; break; //秒
case 2: P2 |= 0x18; break; //分
case 3: P2 |= 0x03; break; //时
default : position = 0; timesetup = 0; clocksetup = 0; break;
}
}
if(++we >= 8) //八个数码管
we = 0;
}
/*T0中断函数*/
void Time0_inte() interrupt 1
{
static unsigned char ms = 0;
static unsigned char flag1s = 0;
static unsigned char flag5s = 0;
TH0 = TRH0; //加载T0重载值
TL0 = TRL0;
Display(); //数码管显示
if(++ms >= 200)
{
flag200ms = 1;
ms = 0;
if(flag5s < 5 && clock) //闹钟5秒时间判断
{
P1_0 = ~P1_0;
}
else
{
clock = 0;
P1_0 = 0;
}
if(++flag1s >= 5)
{
flag1s = 0;
flag = ~flag;
if(clock)
flag5s++;
else
flag5s = 0;
}
}
}
//向DS1302写入时间
void TimeWeite()
{
unsigned char ti[3];
//将两个分开的时间合成在一起
ti[0] = ((num[6]<<4) | num[7]);
ti[1] = ((num[3]<<4) | num[4]);
ti[2] = ((num[0]<<4) | num[1]);
Ds1302_Time(ti);
}
void key()
{
if((P3_0==0||P3_1==0||P3_2==0||P3_3==0)&&clock==1) //闹钟响应,进行关闭
{
clock = 0;
while(!P3_0);while(!P3_1);
while(!P3_2);while(!P3_3);
}
if(timesetup!=1 && clocksetup!=1 && P3_0==1) //按下显示温度值,松开显示时间
{
Ds1302_Display();
}else if(timesetup!=1 && clocksetup!=1 &&P3_0 == 0)
{
Ds18b20_Display();
}
if(clocksetup !=1 && P3_3 == 0) //进入时间设置
{
timesetup = 1;
position++;
if(position == 4) //向DS1302重新写入时间
{
TimeWeite();
}
while(!P3_3);
}
if(timesetup !=1 && P3_2 == 0) //进入闹钟时间设置
{
clocksetup = 1;
position++;
clock = 0;
while(!P3_2);
}
if((timesetup==1||clocksetup==1) && P3_0 == 0) //进入时间设置, 时间+1
{
if(timesetup) //实时时钟设置
{
if(position == 1) //秒
{
if(++num[7] >= 10)
{
num[7] = 0;
if(++num[6] >=6)
num[6] = 0;
}
}else
if(position == 2) //分
{
if(++num[4] >= 10)
{
num[4] = 0;
if(++num[3] >=6)
num[3] = 0;
}
}else
if(position == 3) //时
{
if(num[0] == 2)
{
if(++num[1] >= 5)
{
num[1] = 0;
num[0] = 0;
}
}else
if(++num[1] >= 10)
{
num[1] = 0;
if(++num[0] >=3)
num[0] = 0;
}
}
}else if(clocksetup) //闹钟时间设置
{
if(position == 1) //秒
{
if(++timeclock[7] >= 10)
{
timeclock[7] = 0;
if(++timeclock[6] >=6)
timeclock[6] = 0;
}
}else
if(position == 2) //分
{
if(++timeclock[4] >= 10)
{
timeclock[4] = 0;
if(++timeclock[3] >=6)
timeclock[3] = 0;
}
}else
if(position == 3) //时
{
if(timeclock[0] == 2)
{
if(++timeclock[1] >= 4)
{
timeclock[1] = 0;
timeclock[0] = 0;
}
}else
if(++timeclock[1] >= 10)
{
timeclock[1] = 0;
if(++timeclock[0] >=3)
timeclock[0] = 0;
}
}
}
while(!P3_0);
}
if((timesetup==1||clocksetup==1) && P3_1 == 0) //进入时间设置, 时间-1
{
if(timesetup) //实时时钟设置
{
if(position == 1) //秒
{
if(--num[7] < 0)
{
num[7] = 9;
if(--num[6] < 0)
num[6] = 5;
}
}else
if(position == 2) //分
{
if(--num[4] < 0)
{
num[4] = 9;
if(--num[3] < 0)
num[3] = 5;
}
}else
if(position == 3) //时
{
if(--num[1] < 0)
{
num[1] = 9;
if(--num[0] < 0)
{
num[0] = 2;
……………………
…………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
所有资料51hei提供下载:
基于单片机的电子钟.zip
(84.07 KB, 下载次数: 115)
2017-12-14 10:29 上传
点击文件名下载附件
下载积分: 黑币 -5
作者:
lw1997
时间:
2017-12-23 22:05
感谢分享。
作者:
qwe11156475
时间:
2018-7-11 14:18
感谢大佬!!!!
作者:
Ryushane
时间:
2019-1-22 17:07
厉害,谢谢楼主
作者:
hgy78h
时间:
2020-11-29 16:47
谢谢大佬的分享,给了我很大帮助。
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1