专家
公告
财富商城
电子网
旗下网站
首页
问题库
专栏
标签库
话题
专家
NEW
门户
发布
提问题
发文章
51单片机
自制了两款LED电子钟
2020-01-13 18:34
发布
×
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮
站内问答
/
51单片机
2856
33
33
自制LED电子钟在很多网页上都可以见到,正好宿舍里缺少一个时钟。一下子却做了两个!
(原文件名:1.jpg)
(原文件名:2.jpg)
(原文件名:3.jpg)
(原文件名:4.jpg)
(原文件名:5.jpg)
(原文件名:6.jpg)
友情提示:
此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
32条回答
zhc7302
1楼-- · 2020-01-13 19:41
mark
加载中...
jbzzz
2楼-- · 2020-01-14 00:31
有程序不?想仿制一个
加载中...
mon51
3楼-- · 2020-01-14 05:24
精彩回答 2 元偷偷看……
加载中...
wengguichao
4楼-- · 2020-01-14 08:56
LZ把程序分享下就完美了……
加载中...
yangyi
5楼-- · 2020-01-14 13:58
一般般
加载中...
chchg
6楼-- · 2020-01-14 15:36
//程序比较乱!
/*===========================================================================
* --P1.5--
* | |
* P1.6 P1.0 各位数码管控制P2.1 P2.2 P2.4 P2.3 P2.5 P2.0 分号P2^7
* | |
* --P1.7--
* | |
* P1.2 P1.1
* | |
* --P1.4-- []P1.3
* DQ P0.3 SCLK P0.0 IO P0.1 RST P0.2
* KEY0 P0.5 KEY1 P0.6 KEY2 P0.4 BELL P3.6
* 只显示时间 按KEY1显示日期 长按KEY1显示温度
===========================================================================*/
//头文件、宏定义
#include<REG51.H>
#include<INTRINS.h>
#define uchar unsigned char
#define uint unsigned int
#define led_dip 0xbf //分号
#define led_dp 0xf7 //小数点
//IO口定义
#define led_data P1 //段码
#define led_con P2 //位码
sbit DQ = P0^3; //DS18B20温度传感器
sbit SCLK = P0^0; //DS1302时钟
sbit IO = P0^1; //DS1302数据
sbit RST = P0^2; //DS1302复位
sbit BELL = P3^6; //蜂鸣器
sbit KEY0 = P0^5; //按键0
sbit KEY1 = P0^6; //按键1
sbit KEY2 = P0^4; //按键2
sbit LAMP = P3^4; //小灯
//常量 段码 位码 关闭0xff省略
uchar led_code[14]={0x88,0xfc,0x4a,0x4c,0x3c,0x0d,0x09,0xdc,0x08,0x0c,0x7f,0x1e,0x0b,0xff};
// 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , - , 度 , E ,black
uchar led_cs[6]={0xfd,0xfb,0xef,0xf7,0xdf,0xfe};
// 从左到右 0位 ,1位,2位,3位,4位,5位
//变量
uchar led_var[6] = {10,10,10,10,10,10}; //输出段码变量
uchar led_flg; //输出位码循环变量
bit dip_flg; //分号使能变量
bit dp_flg0; //小数点变量1
bit dp_flg1; //小数点变量3
uchar time_var[7] = {0x00,0x00,0x00,0x01,0x01,0x06,0x00}; //秒分时日月星期年2000-1-1
uchar hour_flg; //记录时,整点报时
bit bs_flg; //报时标志
uchar share_flg; //分号闪烁
//函数
void init(void); //初始化
void nus(uchar); //6us延时
void nms(uchar); //1ms延时
void time_change(void); //输出时间
void date_change(void); //输出日期
void close_out(void); //关闭输出
void bs_out(void); //整点报时
void data_set(void); //设置时间
//DS18B20
void ds18b20_init(void); //18B20初始化
void ds18b20_write (uchar); //单字节写入
uchar ds18b20_read (void); //读取单字节
void ds18b20_change(void); //温度值转换
//DS1302
void ds1302_write_byte(uchar); //写入一字节
uchar ds1302_read_byte(void); //读入一字节
void ds1302_write(uchar,uchar); //往ds1302的某个地址写入数据
uchar ds1302_read(uchar); //读ds1302某地址的的数据
void ds1302_set(void); //设置初始时间
void ds1302_nowhmm(void); //读取当前时分秒
void ds1302_nowymd(void); //读取当前年月日
void ds1302_init(void); //初始化
uchar getweek(uchar,uchar,uchar); //计算星期
//===========================================================================
//定时中断0显示
void Timer0_Seriver(void) interrupt 1 using 1 //显示定时中断 3.3ms
{
TR0 = 0; ET0 = 0;
TH0=0xf3; TL0=0x1c; //243 28
//显示
led_data = 0xff; //关闭输出数据
if(dip_flg) led_con = led_cs[led_flg]&led_dip; //选择位码并显示分号
else led_con = led_cs[led_flg]; //选择位码
led_data = led_code[led_var[led_flg]]; //输出段码不包括小数点
switch(led_flg)
{
case 1: if(dp_flg0) led_data = led_code[led_var[led_flg]]&led_dp;
break; //输出段码包括小数点
case 3:
if(dp_flg1) led_data = led_code[led_var[led_flg]]&led_dp;
break; //输出段码包括小数点
default: break;
}
//循环
if(led_flg == 0)led_flg = 5; //复位
else led_flg--; //递减
ET0 = 1; TR0 = 1;
}
//定时中断1循环
void Timer1_Seriver(void) interrupt 3 using 3 //循环定时中断 50ms
{
TR1 = 0; ET1 = 0;
TH1 = 0x3c; TL1 = 0xb0; //60 176
if(dip_flg)
{
if(share_flg == 0) dip_flg = 0;
else share_flg--;
}
ET1 = 1; TR1 = 1;
}
//=============================================================
void main()
{
init(); //初始化
while(1) //主循环
{
time_change();
bs_out(); //报时
if(!KEY0)
{
nms(5);
if(!KEY0)
{
uchar js;
js = 0;
do{
while(!KEY0 && js<116){ nms(10); js++; }
}while(!KEY0 && js<116);
if(js>=116) data_set();
else
{
bs_flg = ~bs_flg;
if(bs_flg)
{
BELL = 0; nms(100); BELL = 1; nms(100);
BELL = 0; nms(100); BELL = 1; nms(100);
BELL = 0; nms(100); BELL = 1;
}
else{ BELL = 0; nms(166); nms(166); BELL = 1;}
}
}
}
if(!KEY1)
{
nms(5);
if(!KEY1)
{
uchar js;
js = 0;
do{
while(!KEY1 && js<100){ nms(10); js++; }
}while(!KEY1 && js<100);
close_out(); //关显示
BELL = 0;
if(js>=100){
dip_flg = 0; dp_flg0 = 0; dp_flg1 = 0;
ds18b20_change();
}
else
{
dip_flg = 0; dp_flg0 = 1; dp_flg1 = 1;
date_change();
}
do{ //消除按键
while(!KEY1){}; nms(10);
}while(!KEY1);
BELL = 1;
nms(255); nms(255); nms(255); nms(255);
nms(255); nms(255); nms(255); nms(255);
dip_flg = 0; dp_flg0 = 0; dp_flg1 = 10;
}
}
if(!KEY2) //开关小灯
{
nms(20);
if(!KEY2)
{
LAMP = ~LAMP;
do{ //消除按键
while(!KEY2){}; nms(20);
}while(!KEY2);
}
}
}
}
void data_set(void)
{
uchar tem_s,tem_c;
uchar t_fir,t_sec; //存放临时时间变量
TR1 = 0; ET1 = 0; //关闭循环变量
close_out(); //关显示
BELL = 0; //提示进入菜单
nms(166); nms(166);
do{ //消除按键
while(!KEY0){}; nms(10);
}while(!KEY0);
BELL = 1;
//秒分时
ds1302_nowhmm(); //读秒分时
dip_flg = 1; //分号
nms(5);
led_var[0] = time_var[2]>>4; //时
if(led_var[0] == 0) led_var[0] = 13; //black
led_var[1] = time_var[2]&0x0f;
led_var[2] = time_var[1]>>4; //分
led_var[3] = time_var[1]&0x0f;
led_var[4] = time_var[0]>>4; //秒
led_var[5] = time_var[0]&0x0f;
//调秒分时
tem_c = 0;
while(KEY0)
{
while(KEY0)
{
if(!KEY1)
{
nms(10);
if(!KEY1)
{
BELL = 0;
if(tem_c == 2) tem_c = 0;
else tem_c++;
do{
while(!KEY1){}; nms(10);
}while(!KEY1);
BELL = 1;
}
}
if(!KEY2)
{
nms(10);
if(!KEY2)
{
BELL = 0;
switch(tem_c)
{
case 0: if(led_var[0]==13)tem_s = led_var[1]; //时
else tem_s = led_var[0]*10 +led_var[1];
if(tem_s<23) tem_s++;
else tem_s = 0;
led_var[0] = tem_s/10;
led_var[1] = tem_s%10;
time_var[2] = led_var[0]*16 + led_var[1];
if(led_var[0]==0)led_var[0]=13;
break;
case 1: tem_s = led_var[2]*10 +led_var[3]; //分
if(tem_s<59) tem_s++;
else tem_s = 0;
led_var[2] = tem_s/10;
led_var[3] = tem_s%10;
time_var[1] = led_var[2]*16 + led_var[3];
break;
case 2: tem_s = led_var[4]*10 +led_var[5]; //秒
if(tem_s<59) tem_s++;
else tem_s = 0;
led_var[4] = tem_s/10;
led_var[5] = tem_s%10;
time_var[0] = led_var[4]*16 + led_var[5];
break;
default: break;
}
nms(66); BELL = 1; nms(156);
}
}
else
{
t_fir = led_var[2*tem_c];
t_sec = led_var[2*tem_c+1];
nms(166);
led_var[2*tem_c] = 13;
led_var[2*tem_c+1] = 13;
nms(166);
led_var[2*tem_c] = t_fir;
led_var[2*tem_c+1] = t_sec;
}
}
nms(10);
}
close_out(); //关显示
BELL = 0; //提示进入年月日设置
do{
while(!KEY0){}; nms(10);
}while(!KEY0);
nms(166); nms(166); BELL = 1;
//年月日
ds1302_nowymd();
dip_flg = 0; //分号关
dp_flg0 = 1; dp_flg1 = 1; //小数点开
nms(5);
led_var[0] = time_var[6]>>4;
led_var[1] = time_var[6]&0x0f;
led_var[2] = time_var[4]>>4;
led_var[3] = time_var[4]&0x0f;
led_var[4] = time_var[3]>>4;
led_var[5] = time_var[3]&0x0f;
//调年月日
tem_c = 0;
while(KEY0)
{
while(KEY0)
{
if(!KEY1)
{
nms(10);
if(!KEY1)
{
BELL = 0;
if(tem_c == 2) tem_c = 0;
else tem_c++;
do{
while(!KEY1){}; nms(10);
}while(!KEY1);
BELL = 1;
}
}
if(!KEY2)
{
nms(10);
if(!KEY2)
{
BELL = 0;
switch(tem_c)
{
case 0: tem_s = led_var[0]*10 +led_var[1]; //年
if(tem_s<16) tem_s++;
else tem_s = 9;
led_var[0] = tem_s/10;
led_var[1] = tem_s%10;
time_var[6] = led_var[0]*16 + led_var[1];
break;
case 1: tem_s = led_var[2]*10 +led_var[3]; //月
if(tem_s<12) tem_s++;
else tem_s = 1;
led_var[2] = tem_s/10;
led_var[3] = tem_s%10;
time_var[4] = led_var[2]*16 + led_var[3];
break;
case 2: tem_s = led_var[4]*10 +led_var[5]; //日
if(tem_s<31) tem_s++;
else tem_s = 0;
led_var[4] = tem_s/10;
led_var[5] = tem_s%10;
time_var[3] = led_var[4]*16 + led_var[5];
break;
}
nms(66); BELL = 1; nms(156);
}
}
else
{
t_fir = led_var[2*tem_c];
t_sec = led_var[2*tem_c+1];
nms(166);
led_var[2*tem_c] = 13;
led_var[2*tem_c+1] = 13;
nms(166);
led_var[2*tem_c] = t_fir;
led_var[2*tem_c+1] = t_sec;
}
}
nms(10);
}
close_out(); //关显示
BELL = 0; //提示进入正常状态
do{
while(!KEY0){}; nms(10);
}while(!KEY0);
BELL = 1; nms(166); nms(166);
ds1302_set(); //写入时钟IC
ET1 = 1; TR1 = 1;
}
void init(void)
{
//端口初始化
led_data = 0xff; //关闭数码管
led_con = 0xff;
DQ = 1;
SCLK = 1; IO = 1; RST = 1;
BELL = 1; //蜂鸣器
LAMP = 1; //关小灯
KEY0 = 1; KEY1 = 1; KEY2 = 1;
//变量初始化
led_flg = 5; //输出位码循环变量
dip_flg = 0; //分号关闭
dp_flg0 = 0; dp_flg1 = 0;
hour_flg = 0;
bs_flg = 1;
share_flg = 8; //500ms闪烁
//中断初始化
TMOD = 0x11;
TH0 = 0xf3; TL0 = 0x1c; //243 28
TH1 = 0x3c; TL1 = 0xb0; //60 176
//硬件驱动加载
ds18b20_init(); //18b20初始化
ds1302_init();
nus(166);
ds1302_nowymd();
nus(16);
if(time_var[6]==0x00) //如果为2000年初始化时钟2009-2-23 1
{
time_var[3] = 0x23; time_var[4] = 0x02;
time_var[5] = 0x01; time_var[6] = 0x09;
BELL = 0; nms(100); BELL = 1; nms(100);
BELL = 0; nms(100); BELL = 1;
ds1302_set();
}
//中断激活
ET0 = 1; TR0 = 1; //启动定时器0显示中断
EA = 1; //开CPU中断
nms(200); nms(200); nms(200); nms(200); //初始化等待
ET1 = 1; TR1 = 1; //启动定时器0显示中断
}
void bs_out(void)//整点报时
{
uchar tem_h;
tem_h = (time_var[2]>>4)*10 + (time_var[2]&0x0f);
if(tem_h!=hour_flg)
{
hour_flg = tem_h;
if(bs_flg)
{
if(hour_flg>=8 && hour_flg<=23) //只在8点到23点之间整点报时
{ BELL = 0; nms(166); nms(166); nms(166); BELL = 1; }
}
}
}
//=============== 关闭输出 =====================================================
void close_out(void)
{
led_var[0] = 13; led_var[1] = 13;
led_var[2] = 13; led_var[3] = 13;
led_var[4] = 13; led_var[5] = 13;
dip_flg = 0;
dp_flg0 = 0;
dp_flg1 = 0;
}
//=============== 时间输出 =====================================================
void time_change(void) //时分秒
{
uchar second_tp;
second_tp = time_var[0];
ds1302_nowhmm();
nms(5);
if(time_var[0] != second_tp)
{
dip_flg = 1;
share_flg = 8;
}
led_var[0] = time_var[2]>>4;
if(led_var[0] == 0) led_var[0] = 13; //black
led_var[1] = time_var[2]&0x0f;
led_var[2] = time_var[1]>>4;
led_var[3] = time_var[1]&0x0f;
led_var[4] = time_var[0]>>4;
led_var[5] = time_var[0]&0x0f;
}
void date_change(void) //日月年
{
uchar day_tp;
day_tp = time_var[3];
ds1302_nowymd();
nms(5);
led_var[0] = time_var[6]>>4;
led_var[1] = time_var[6]&0x0f;
led_var[2] = time_var[4]>>4;
led_var[3] = time_var[4]&0x0f;
led_var[4] = time_var[3]>>4;
led_var[5] = time_var[3]&0x0f;
}
//===============温度值转换=====================================================
void ds18b20_change() //-50~60
{
uint result; //18b20的12位数据
uint tmp; //相应的温度值
uchar x;
uchar readdata_low, readdata_high; //18b20的12位数据的低8位及高8位
bit sflag; //符号标志为 1为负 0为正
EA = 0;
ds18b20_init();
ds18b20_write(0xcc); //跳过ROM
ds18b20_write(0x44); //启动转换
nus(166);
EA = 1;
nms(200); nms(200); nms(200);//转换等待
EA = 0;
//读数据
ds18b20_init();
ds18b20_write(0xcc); //skip rom
ds18b20_write(0xbe); //read rom
readdata_low = ds18b20_read();
readdata_high = ds18b20_read();
nus(166);
EA = 1;
//判断符号
sflag = 0; //符号位置位
if((readdata_high & 0xf8)!= 0x00) //如果是负的
{
sflag = 1; //符号位复位
readdata_high =~ readdata_high; //取反
readdata_low =~ readdata_low; //取反
if(readdata_low == 0xff) //判段低8位是否溢出
{
readdata_low = 0x00;
readdata_high ++;
}
else readdata_low++;
}
//数值转换
readdata_high &= 0x07; //去除符号位影响
result = readdata_high * 256 + readdata_low; //得12位数据
tmp = 0; //温度清零
for(x=0;x<4;x++) //逐次乘625,并4舍5入一位
{
tmp += 625*(result%10);
if(x<3)
{
if(tmp%10>=5) tmp = tmp/10 + 1; //4舍5入
else tmp /= 10;
result /= 10;
}
}
//在60度范围内
if(tmp<600) // "20.6' " " -10.6' "
{
dp_flg1 = 1; //显示
led_var[5] = 11; //度
led_var[0] = 13; //black
led_var[2] = tmp/100;
if(led_var[2]==0)
{
led_var[1] = 13;
if(!sflag)led_var[2] = 13; //black
else led_var[2] = 10; //-
}
else
{
if(!sflag)led_var[1] = 13; //black
else led_var[1] = 10; //-
}
tmp %= 100;
led_var[3] = tmp/10;
led_var[4] = tmp%10;
}
//60度以上
else // out -E-
{
dp_flg1 = 0;
led_var[5] = 10; //-
led_var[4] = 12; //E
led_var[3] = 10; //-
led_var[2] = 13; //black
led_var[1] = 13; //black
led_var[0] = 13; //black
}
}
/*---------------- 18B20驱动 -----------------------
void ds18b0_init(void) : 18B20初始化
void ds18b20_write (uchar) : 单字节写入
uchar ds18b20_read (void) : 读取单字节
| 0xcc 跳过ROM| 0x44 启动转换| 0xbe读ROM|
--------------------------------------------------*/
//18B20初始化
void ds18b20_init()
{
DQ = 1; _nop_(); DQ = 0;
nus(93); //86 delay530
_nop_();
DQ = 1; nus(15); //14 delay100
_nop_(); _nop_(); _nop_();
nus(22); //20
_nop_(); _nop_();
DQ = 1;
}
//18B20单字节写入
void ds18b20_write (uchar wr)
{
uchar i;
for (i=0;i<8;i++)
{
DQ = 0;
_nop_();
DQ = wr&0x01;
nus(5); //5 delay45
_nop_(); _nop_();
DQ = 1;
wr >>= 1;
}
}
//18B20读取单字节
uchar ds18b20_read ()
{
uchar i,u = 0;
for(i=0;i<8;i++)
{
DQ = 0;
u >>= 1;
DQ = 1;
if(DQ == 1) u |= 0x80;
nus(4); _nop_();
}
return(u);
}
/*------------------- DS1302驱动 -------------------
void ds1302_write_byte(uchar inbyte); :写入一字节
uchar ds1302_read_byte(); :读入一字节
void ds1302_write(uchar cmd,uchar indata); :往ds1302的某个地址写入数据
uchar ds1302_read(uchar addr); :读ds1302某地址的的数据
void ds1302_set(); :设置初始时间
void ds1302_nowhmm(); :读取当前时分秒
void ds1302_nowymd(); :读取当前年月日
void ds1302_init(); :初始化
unsigned char getweek(unsigned char,unsigned char,unsigned char); :由年月日计算星期
[!] SCLK的上升沿输入数据,SCLK的下跳沿输出数据,读写时都是从第0位开始
[!] 变量time_var[7]秒分时日月星期年 星期初值由函数计算,不读取
--------------------------------------------------*/
//ds1302写入一字节
void ds1302_write_byte(uchar inbyte)
{
uchar i;
for(i=8;i>0;i--)
{
SCLK = 0; //写的时候低电平改变数据
if(inbyte&0x01)IO = 1;
else IO = 0;
SCLK = 1; //写的时候高电平,把数据写入ds1302
_nop_();
inbyte >>= 1;
}
}
//ds1302读入一字节
uchar ds1302_read_byte() //sclk的下跳沿读数据
{
uchar i,temp=0;
IO = 1; //设置为输入口
for(i=7;i>0;i--)
{
SCLK = 0;
if(IO==1) temp |= 0x80;
else temp &= 0x7f;
SCLK = 1; //产生下跳沿
temp >>= 1;
}
return (temp);
}
//往ds1302的某个地址写入数据
void ds1302_write(uchar cmd,uchar indata)
{
RST = 1;
ds1302_write_byte(cmd);
ds1302_write_byte(indata);
RST = 0; SCLK=0;
}
//读ds1302某地址的的数据
uchar ds1302_read(uchar addr)
{
uchar backdata;
RST = 1; //先写地址,然后读数据
ds1302_write_byte(addr);
backdata = ds1302_read_byte();
RST = 0; SCLK = 0;
return (backdata);
}
//设置初始时间 初始时间格式为: 秒 分 时 日 月 星期 年
void ds1302_set()//写入n个数据
{
uchar addr; uchar n;
time_var[5]=getweek(time_var[6],time_var[4],time_var[3]);
ds1302_write(0x8e,0x00); //写控制字,允许写操作
_nop_(); _nop_(); _nop_();
for(addr = 0x80,n=0;n<7;n++){ //依次写入秒分时日月星期年
ds1302_write(addr,time_var[n]);
addr = addr+2;
}
ds1302_write(0x8e,0x80); //写保护,不允许写
}
//读取当前年月日
void ds1302_nowymd()
{
time_var[3] = ds1302_read(0x87);
time_var[4] = ds1302_read(0x89);
time_var[6] = ds1302_read(0x8d);
}
//读取当前时分秒
void ds1302_nowhmm()
{
time_var[0] = ds1302_read(0x81);
time_var[1] = ds1302_read(0x83);
time_var[2] = ds1302_read(0x85);
}
//初始化
void ds1302_init()
{
RST = 0; SCLK = 0;
ds1302_write(0x8e,0x00); //写控制字,允许写
ds1302_write(0x90,0x00); //禁止涡流充电
}
//由年月日计算星期
unsigned char getweek(unsigned char year,unsigned char month,unsigned char day)
{
unsigned char week,tp;
tp=0; week=5; //初始化2000-01-01星期六
while(tp!=year) //处理年(2000开始)
{
week++; //是上一年的星期的下一天 公式:365%7=1
if(tp%4==0)week++; //判断是否是閏年,閏年2月是29天 公式:366%7=2
tp++; //下一年的1月1日
}
tp=1;
while(tp!=month) //处理月(1月开始)
{
switch(tp)
{
case 1: case 3: case 5: case 7: case 8: case 10: case 12:
week=week+3; break; //大月天数31%7
case 2: if(year%4==0)week++; break; //閏月天数,閏年2月是29天 公式:366%7=2 29%7
case 4: case 6: case 9: case 11:
week=week+2; break; //小月天数30%7
default: break;
}
tp++; //处理月
}
week=week+day; //处理日(從1日开始)
week=week%7;
if(week==0) week=7;
return week; //返回星期
}
/*---------------- 延时子函数 -----------------------
void nus(uchar us); :6us延时
void nms(uchar ms); :1ms延时
--------------------------------------------------*/
//6us延时
void nus(uchar us)
{
for(;us>0;us--)
;
}
//1ms延时
void nms(uchar ms)
{
for(;ms>0;ms--)
nus(167);
}
/*------------------- END -------------------------------------------------------*/
加载中...
1
2
3
4
5
6
下一页
一周热门
更多
>
相关问题
【东软载波ESF0654 PDS开发板活动】开箱
1 个回答
东软载波ESF0654 PDS开发板外部中断
1 个回答
东软载波ESF0654 PDS开发板高级控制定时器AD16C4T
1 个回答
用串口调试助手为什么只能在hex模式接收发送而在文本模式不行
9 个回答
触摸芯片SC02B/SC04B在地砖灯的设计方案
1 个回答
东软载波ESF0654 PDS开发板串口USART0代码分享
1 个回答
普通32位单片机使用linux的应用代码
5 个回答
东软载波ESF0654 PDS开发板AT24C04的调试
9 个回答
相关文章
51单片机与蓝牙模块连接
0个评论
51单片机的硬件结构
0个评论
基于51单片机的无线遥控器制作
0个评论
51单片机 AD转换
0个评论
51单片机数码管递增显示
0个评论
如何实现对单片机寄存器的访问
0个评论
基于51单片机的指纹密码锁
0个评论
×
关闭
采纳回答
向帮助了您的网友说句感谢的话吧!
非常感谢!
确 认
×
关闭
编辑标签
最多设置5个标签!
51单片机
保存
关闭
×
关闭
举报内容
检举类型
检举内容
检举用户
检举原因
广告推广
恶意灌水
回答内容与提问无关
抄袭答案
其他
检举说明(必填)
提交
关闭
×
关闭
您已邀请
15
人回答
查看邀请
擅长该话题的人
回答过该话题的人
我关注的人
/*===========================================================================
* --P1.5--
* | |
* P1.6 P1.0 各位数码管控制P2.1 P2.2 P2.4 P2.3 P2.5 P2.0 分号P2^7
* | |
* --P1.7--
* | |
* P1.2 P1.1
* | |
* --P1.4-- []P1.3
* DQ P0.3 SCLK P0.0 IO P0.1 RST P0.2
* KEY0 P0.5 KEY1 P0.6 KEY2 P0.4 BELL P3.6
* 只显示时间 按KEY1显示日期 长按KEY1显示温度
===========================================================================*/
//头文件、宏定义
#include<REG51.H>
#include<INTRINS.h>
#define uchar unsigned char
#define uint unsigned int
#define led_dip 0xbf //分号
#define led_dp 0xf7 //小数点
//IO口定义
#define led_data P1 //段码
#define led_con P2 //位码
sbit DQ = P0^3; //DS18B20温度传感器
sbit SCLK = P0^0; //DS1302时钟
sbit IO = P0^1; //DS1302数据
sbit RST = P0^2; //DS1302复位
sbit BELL = P3^6; //蜂鸣器
sbit KEY0 = P0^5; //按键0
sbit KEY1 = P0^6; //按键1
sbit KEY2 = P0^4; //按键2
sbit LAMP = P3^4; //小灯
//常量 段码 位码 关闭0xff省略
uchar led_code[14]={0x88,0xfc,0x4a,0x4c,0x3c,0x0d,0x09,0xdc,0x08,0x0c,0x7f,0x1e,0x0b,0xff};
// 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , - , 度 , E ,black
uchar led_cs[6]={0xfd,0xfb,0xef,0xf7,0xdf,0xfe};
// 从左到右 0位 ,1位,2位,3位,4位,5位
//变量
uchar led_var[6] = {10,10,10,10,10,10}; //输出段码变量
uchar led_flg; //输出位码循环变量
bit dip_flg; //分号使能变量
bit dp_flg0; //小数点变量1
bit dp_flg1; //小数点变量3
uchar time_var[7] = {0x00,0x00,0x00,0x01,0x01,0x06,0x00}; //秒分时日月星期年2000-1-1
uchar hour_flg; //记录时,整点报时
bit bs_flg; //报时标志
uchar share_flg; //分号闪烁
//函数
void init(void); //初始化
void nus(uchar); //6us延时
void nms(uchar); //1ms延时
void time_change(void); //输出时间
void date_change(void); //输出日期
void close_out(void); //关闭输出
void bs_out(void); //整点报时
void data_set(void); //设置时间
//DS18B20
void ds18b20_init(void); //18B20初始化
void ds18b20_write (uchar); //单字节写入
uchar ds18b20_read (void); //读取单字节
void ds18b20_change(void); //温度值转换
//DS1302
void ds1302_write_byte(uchar); //写入一字节
uchar ds1302_read_byte(void); //读入一字节
void ds1302_write(uchar,uchar); //往ds1302的某个地址写入数据
uchar ds1302_read(uchar); //读ds1302某地址的的数据
void ds1302_set(void); //设置初始时间
void ds1302_nowhmm(void); //读取当前时分秒
void ds1302_nowymd(void); //读取当前年月日
void ds1302_init(void); //初始化
uchar getweek(uchar,uchar,uchar); //计算星期
//===========================================================================
//定时中断0显示
void Timer0_Seriver(void) interrupt 1 using 1 //显示定时中断 3.3ms
{
TR0 = 0; ET0 = 0;
TH0=0xf3; TL0=0x1c; //243 28
//显示
led_data = 0xff; //关闭输出数据
if(dip_flg) led_con = led_cs[led_flg]&led_dip; //选择位码并显示分号
else led_con = led_cs[led_flg]; //选择位码
led_data = led_code[led_var[led_flg]]; //输出段码不包括小数点
switch(led_flg)
{
case 1: if(dp_flg0) led_data = led_code[led_var[led_flg]]&led_dp;
break; //输出段码包括小数点
case 3:
if(dp_flg1) led_data = led_code[led_var[led_flg]]&led_dp;
break; //输出段码包括小数点
default: break;
}
//循环
if(led_flg == 0)led_flg = 5; //复位
else led_flg--; //递减
ET0 = 1; TR0 = 1;
}
//定时中断1循环
void Timer1_Seriver(void) interrupt 3 using 3 //循环定时中断 50ms
{
TR1 = 0; ET1 = 0;
TH1 = 0x3c; TL1 = 0xb0; //60 176
if(dip_flg)
{
if(share_flg == 0) dip_flg = 0;
else share_flg--;
}
ET1 = 1; TR1 = 1;
}
//=============================================================
void main()
{
init(); //初始化
while(1) //主循环
{
time_change();
bs_out(); //报时
if(!KEY0)
{
nms(5);
if(!KEY0)
{
uchar js;
js = 0;
do{
while(!KEY0 && js<116){ nms(10); js++; }
}while(!KEY0 && js<116);
if(js>=116) data_set();
else
{
bs_flg = ~bs_flg;
if(bs_flg)
{
BELL = 0; nms(100); BELL = 1; nms(100);
BELL = 0; nms(100); BELL = 1; nms(100);
BELL = 0; nms(100); BELL = 1;
}
else{ BELL = 0; nms(166); nms(166); BELL = 1;}
}
}
}
if(!KEY1)
{
nms(5);
if(!KEY1)
{
uchar js;
js = 0;
do{
while(!KEY1 && js<100){ nms(10); js++; }
}while(!KEY1 && js<100);
close_out(); //关显示
BELL = 0;
if(js>=100){
dip_flg = 0; dp_flg0 = 0; dp_flg1 = 0;
ds18b20_change();
}
else
{
dip_flg = 0; dp_flg0 = 1; dp_flg1 = 1;
date_change();
}
do{ //消除按键
while(!KEY1){}; nms(10);
}while(!KEY1);
BELL = 1;
nms(255); nms(255); nms(255); nms(255);
nms(255); nms(255); nms(255); nms(255);
dip_flg = 0; dp_flg0 = 0; dp_flg1 = 10;
}
}
if(!KEY2) //开关小灯
{
nms(20);
if(!KEY2)
{
LAMP = ~LAMP;
do{ //消除按键
while(!KEY2){}; nms(20);
}while(!KEY2);
}
}
}
}
void data_set(void)
{
uchar tem_s,tem_c;
uchar t_fir,t_sec; //存放临时时间变量
TR1 = 0; ET1 = 0; //关闭循环变量
close_out(); //关显示
BELL = 0; //提示进入菜单
nms(166); nms(166);
do{ //消除按键
while(!KEY0){}; nms(10);
}while(!KEY0);
BELL = 1;
//秒分时
ds1302_nowhmm(); //读秒分时
dip_flg = 1; //分号
nms(5);
led_var[0] = time_var[2]>>4; //时
if(led_var[0] == 0) led_var[0] = 13; //black
led_var[1] = time_var[2]&0x0f;
led_var[2] = time_var[1]>>4; //分
led_var[3] = time_var[1]&0x0f;
led_var[4] = time_var[0]>>4; //秒
led_var[5] = time_var[0]&0x0f;
//调秒分时
tem_c = 0;
while(KEY0)
{
while(KEY0)
{
if(!KEY1)
{
nms(10);
if(!KEY1)
{
BELL = 0;
if(tem_c == 2) tem_c = 0;
else tem_c++;
do{
while(!KEY1){}; nms(10);
}while(!KEY1);
BELL = 1;
}
}
if(!KEY2)
{
nms(10);
if(!KEY2)
{
BELL = 0;
switch(tem_c)
{
case 0: if(led_var[0]==13)tem_s = led_var[1]; //时
else tem_s = led_var[0]*10 +led_var[1];
if(tem_s<23) tem_s++;
else tem_s = 0;
led_var[0] = tem_s/10;
led_var[1] = tem_s%10;
time_var[2] = led_var[0]*16 + led_var[1];
if(led_var[0]==0)led_var[0]=13;
break;
case 1: tem_s = led_var[2]*10 +led_var[3]; //分
if(tem_s<59) tem_s++;
else tem_s = 0;
led_var[2] = tem_s/10;
led_var[3] = tem_s%10;
time_var[1] = led_var[2]*16 + led_var[3];
break;
case 2: tem_s = led_var[4]*10 +led_var[5]; //秒
if(tem_s<59) tem_s++;
else tem_s = 0;
led_var[4] = tem_s/10;
led_var[5] = tem_s%10;
time_var[0] = led_var[4]*16 + led_var[5];
break;
default: break;
}
nms(66); BELL = 1; nms(156);
}
}
else
{
t_fir = led_var[2*tem_c];
t_sec = led_var[2*tem_c+1];
nms(166);
led_var[2*tem_c] = 13;
led_var[2*tem_c+1] = 13;
nms(166);
led_var[2*tem_c] = t_fir;
led_var[2*tem_c+1] = t_sec;
}
}
nms(10);
}
close_out(); //关显示
BELL = 0; //提示进入年月日设置
do{
while(!KEY0){}; nms(10);
}while(!KEY0);
nms(166); nms(166); BELL = 1;
//年月日
ds1302_nowymd();
dip_flg = 0; //分号关
dp_flg0 = 1; dp_flg1 = 1; //小数点开
nms(5);
led_var[0] = time_var[6]>>4;
led_var[1] = time_var[6]&0x0f;
led_var[2] = time_var[4]>>4;
led_var[3] = time_var[4]&0x0f;
led_var[4] = time_var[3]>>4;
led_var[5] = time_var[3]&0x0f;
//调年月日
tem_c = 0;
while(KEY0)
{
while(KEY0)
{
if(!KEY1)
{
nms(10);
if(!KEY1)
{
BELL = 0;
if(tem_c == 2) tem_c = 0;
else tem_c++;
do{
while(!KEY1){}; nms(10);
}while(!KEY1);
BELL = 1;
}
}
if(!KEY2)
{
nms(10);
if(!KEY2)
{
BELL = 0;
switch(tem_c)
{
case 0: tem_s = led_var[0]*10 +led_var[1]; //年
if(tem_s<16) tem_s++;
else tem_s = 9;
led_var[0] = tem_s/10;
led_var[1] = tem_s%10;
time_var[6] = led_var[0]*16 + led_var[1];
break;
case 1: tem_s = led_var[2]*10 +led_var[3]; //月
if(tem_s<12) tem_s++;
else tem_s = 1;
led_var[2] = tem_s/10;
led_var[3] = tem_s%10;
time_var[4] = led_var[2]*16 + led_var[3];
break;
case 2: tem_s = led_var[4]*10 +led_var[5]; //日
if(tem_s<31) tem_s++;
else tem_s = 0;
led_var[4] = tem_s/10;
led_var[5] = tem_s%10;
time_var[3] = led_var[4]*16 + led_var[5];
break;
}
nms(66); BELL = 1; nms(156);
}
}
else
{
t_fir = led_var[2*tem_c];
t_sec = led_var[2*tem_c+1];
nms(166);
led_var[2*tem_c] = 13;
led_var[2*tem_c+1] = 13;
nms(166);
led_var[2*tem_c] = t_fir;
led_var[2*tem_c+1] = t_sec;
}
}
nms(10);
}
close_out(); //关显示
BELL = 0; //提示进入正常状态
do{
while(!KEY0){}; nms(10);
}while(!KEY0);
BELL = 1; nms(166); nms(166);
ds1302_set(); //写入时钟IC
ET1 = 1; TR1 = 1;
}
void init(void)
{
//端口初始化
led_data = 0xff; //关闭数码管
led_con = 0xff;
DQ = 1;
SCLK = 1; IO = 1; RST = 1;
BELL = 1; //蜂鸣器
LAMP = 1; //关小灯
KEY0 = 1; KEY1 = 1; KEY2 = 1;
//变量初始化
led_flg = 5; //输出位码循环变量
dip_flg = 0; //分号关闭
dp_flg0 = 0; dp_flg1 = 0;
hour_flg = 0;
bs_flg = 1;
share_flg = 8; //500ms闪烁
//中断初始化
TMOD = 0x11;
TH0 = 0xf3; TL0 = 0x1c; //243 28
TH1 = 0x3c; TL1 = 0xb0; //60 176
//硬件驱动加载
ds18b20_init(); //18b20初始化
ds1302_init();
nus(166);
ds1302_nowymd();
nus(16);
if(time_var[6]==0x00) //如果为2000年初始化时钟2009-2-23 1
{
time_var[3] = 0x23; time_var[4] = 0x02;
time_var[5] = 0x01; time_var[6] = 0x09;
BELL = 0; nms(100); BELL = 1; nms(100);
BELL = 0; nms(100); BELL = 1;
ds1302_set();
}
//中断激活
ET0 = 1; TR0 = 1; //启动定时器0显示中断
EA = 1; //开CPU中断
nms(200); nms(200); nms(200); nms(200); //初始化等待
ET1 = 1; TR1 = 1; //启动定时器0显示中断
}
void bs_out(void)//整点报时
{
uchar tem_h;
tem_h = (time_var[2]>>4)*10 + (time_var[2]&0x0f);
if(tem_h!=hour_flg)
{
hour_flg = tem_h;
if(bs_flg)
{
if(hour_flg>=8 && hour_flg<=23) //只在8点到23点之间整点报时
{ BELL = 0; nms(166); nms(166); nms(166); BELL = 1; }
}
}
}
//=============== 关闭输出 =====================================================
void close_out(void)
{
led_var[0] = 13; led_var[1] = 13;
led_var[2] = 13; led_var[3] = 13;
led_var[4] = 13; led_var[5] = 13;
dip_flg = 0;
dp_flg0 = 0;
dp_flg1 = 0;
}
//=============== 时间输出 =====================================================
void time_change(void) //时分秒
{
uchar second_tp;
second_tp = time_var[0];
ds1302_nowhmm();
nms(5);
if(time_var[0] != second_tp)
{
dip_flg = 1;
share_flg = 8;
}
led_var[0] = time_var[2]>>4;
if(led_var[0] == 0) led_var[0] = 13; //black
led_var[1] = time_var[2]&0x0f;
led_var[2] = time_var[1]>>4;
led_var[3] = time_var[1]&0x0f;
led_var[4] = time_var[0]>>4;
led_var[5] = time_var[0]&0x0f;
}
void date_change(void) //日月年
{
uchar day_tp;
day_tp = time_var[3];
ds1302_nowymd();
nms(5);
led_var[0] = time_var[6]>>4;
led_var[1] = time_var[6]&0x0f;
led_var[2] = time_var[4]>>4;
led_var[3] = time_var[4]&0x0f;
led_var[4] = time_var[3]>>4;
led_var[5] = time_var[3]&0x0f;
}
//===============温度值转换=====================================================
void ds18b20_change() //-50~60
{
uint result; //18b20的12位数据
uint tmp; //相应的温度值
uchar x;
uchar readdata_low, readdata_high; //18b20的12位数据的低8位及高8位
bit sflag; //符号标志为 1为负 0为正
EA = 0;
ds18b20_init();
ds18b20_write(0xcc); //跳过ROM
ds18b20_write(0x44); //启动转换
nus(166);
EA = 1;
nms(200); nms(200); nms(200);//转换等待
EA = 0;
//读数据
ds18b20_init();
ds18b20_write(0xcc); //skip rom
ds18b20_write(0xbe); //read rom
readdata_low = ds18b20_read();
readdata_high = ds18b20_read();
nus(166);
EA = 1;
//判断符号
sflag = 0; //符号位置位
if((readdata_high & 0xf8)!= 0x00) //如果是负的
{
sflag = 1; //符号位复位
readdata_high =~ readdata_high; //取反
readdata_low =~ readdata_low; //取反
if(readdata_low == 0xff) //判段低8位是否溢出
{
readdata_low = 0x00;
readdata_high ++;
}
else readdata_low++;
}
//数值转换
readdata_high &= 0x07; //去除符号位影响
result = readdata_high * 256 + readdata_low; //得12位数据
tmp = 0; //温度清零
for(x=0;x<4;x++) //逐次乘625,并4舍5入一位
{
tmp += 625*(result%10);
if(x<3)
{
if(tmp%10>=5) tmp = tmp/10 + 1; //4舍5入
else tmp /= 10;
result /= 10;
}
}
//在60度范围内
if(tmp<600) // "20.6' " " -10.6' "
{
dp_flg1 = 1; //显示
led_var[5] = 11; //度
led_var[0] = 13; //black
led_var[2] = tmp/100;
if(led_var[2]==0)
{
led_var[1] = 13;
if(!sflag)led_var[2] = 13; //black
else led_var[2] = 10; //-
}
else
{
if(!sflag)led_var[1] = 13; //black
else led_var[1] = 10; //-
}
tmp %= 100;
led_var[3] = tmp/10;
led_var[4] = tmp%10;
}
//60度以上
else // out -E-
{
dp_flg1 = 0;
led_var[5] = 10; //-
led_var[4] = 12; //E
led_var[3] = 10; //-
led_var[2] = 13; //black
led_var[1] = 13; //black
led_var[0] = 13; //black
}
}
/*---------------- 18B20驱动 -----------------------
void ds18b0_init(void) : 18B20初始化
void ds18b20_write (uchar) : 单字节写入
uchar ds18b20_read (void) : 读取单字节
| 0xcc 跳过ROM| 0x44 启动转换| 0xbe读ROM|
--------------------------------------------------*/
//18B20初始化
void ds18b20_init()
{
DQ = 1; _nop_(); DQ = 0;
nus(93); //86 delay530
_nop_();
DQ = 1; nus(15); //14 delay100
_nop_(); _nop_(); _nop_();
nus(22); //20
_nop_(); _nop_();
DQ = 1;
}
//18B20单字节写入
void ds18b20_write (uchar wr)
{
uchar i;
for (i=0;i<8;i++)
{
DQ = 0;
_nop_();
DQ = wr&0x01;
nus(5); //5 delay45
_nop_(); _nop_();
DQ = 1;
wr >>= 1;
}
}
//18B20读取单字节
uchar ds18b20_read ()
{
uchar i,u = 0;
for(i=0;i<8;i++)
{
DQ = 0;
u >>= 1;
DQ = 1;
if(DQ == 1) u |= 0x80;
nus(4); _nop_();
}
return(u);
}
/*------------------- DS1302驱动 -------------------
void ds1302_write_byte(uchar inbyte); :写入一字节
uchar ds1302_read_byte(); :读入一字节
void ds1302_write(uchar cmd,uchar indata); :往ds1302的某个地址写入数据
uchar ds1302_read(uchar addr); :读ds1302某地址的的数据
void ds1302_set(); :设置初始时间
void ds1302_nowhmm(); :读取当前时分秒
void ds1302_nowymd(); :读取当前年月日
void ds1302_init(); :初始化
unsigned char getweek(unsigned char,unsigned char,unsigned char); :由年月日计算星期
[!] SCLK的上升沿输入数据,SCLK的下跳沿输出数据,读写时都是从第0位开始
[!] 变量time_var[7]秒分时日月星期年 星期初值由函数计算,不读取
--------------------------------------------------*/
//ds1302写入一字节
void ds1302_write_byte(uchar inbyte)
{
uchar i;
for(i=8;i>0;i--)
{
SCLK = 0; //写的时候低电平改变数据
if(inbyte&0x01)IO = 1;
else IO = 0;
SCLK = 1; //写的时候高电平,把数据写入ds1302
_nop_();
inbyte >>= 1;
}
}
//ds1302读入一字节
uchar ds1302_read_byte() //sclk的下跳沿读数据
{
uchar i,temp=0;
IO = 1; //设置为输入口
for(i=7;i>0;i--)
{
SCLK = 0;
if(IO==1) temp |= 0x80;
else temp &= 0x7f;
SCLK = 1; //产生下跳沿
temp >>= 1;
}
return (temp);
}
//往ds1302的某个地址写入数据
void ds1302_write(uchar cmd,uchar indata)
{
RST = 1;
ds1302_write_byte(cmd);
ds1302_write_byte(indata);
RST = 0; SCLK=0;
}
//读ds1302某地址的的数据
uchar ds1302_read(uchar addr)
{
uchar backdata;
RST = 1; //先写地址,然后读数据
ds1302_write_byte(addr);
backdata = ds1302_read_byte();
RST = 0; SCLK = 0;
return (backdata);
}
//设置初始时间 初始时间格式为: 秒 分 时 日 月 星期 年
void ds1302_set()//写入n个数据
{
uchar addr; uchar n;
time_var[5]=getweek(time_var[6],time_var[4],time_var[3]);
ds1302_write(0x8e,0x00); //写控制字,允许写操作
_nop_(); _nop_(); _nop_();
for(addr = 0x80,n=0;n<7;n++){ //依次写入秒分时日月星期年
ds1302_write(addr,time_var[n]);
addr = addr+2;
}
ds1302_write(0x8e,0x80); //写保护,不允许写
}
//读取当前年月日
void ds1302_nowymd()
{
time_var[3] = ds1302_read(0x87);
time_var[4] = ds1302_read(0x89);
time_var[6] = ds1302_read(0x8d);
}
//读取当前时分秒
void ds1302_nowhmm()
{
time_var[0] = ds1302_read(0x81);
time_var[1] = ds1302_read(0x83);
time_var[2] = ds1302_read(0x85);
}
//初始化
void ds1302_init()
{
RST = 0; SCLK = 0;
ds1302_write(0x8e,0x00); //写控制字,允许写
ds1302_write(0x90,0x00); //禁止涡流充电
}
//由年月日计算星期
unsigned char getweek(unsigned char year,unsigned char month,unsigned char day)
{
unsigned char week,tp;
tp=0; week=5; //初始化2000-01-01星期六
while(tp!=year) //处理年(2000开始)
{
week++; //是上一年的星期的下一天 公式:365%7=1
if(tp%4==0)week++; //判断是否是閏年,閏年2月是29天 公式:366%7=2
tp++; //下一年的1月1日
}
tp=1;
while(tp!=month) //处理月(1月开始)
{
switch(tp)
{
case 1: case 3: case 5: case 7: case 8: case 10: case 12:
week=week+3; break; //大月天数31%7
case 2: if(year%4==0)week++; break; //閏月天数,閏年2月是29天 公式:366%7=2 29%7
case 4: case 6: case 9: case 11:
week=week+2; break; //小月天数30%7
default: break;
}
tp++; //处理月
}
week=week+day; //处理日(從1日开始)
week=week%7;
if(week==0) week=7;
return week; //返回星期
}
/*---------------- 延时子函数 -----------------------
void nus(uchar us); :6us延时
void nms(uchar ms); :1ms延时
--------------------------------------------------*/
//6us延时
void nus(uchar us)
{
for(;us>0;us--)
;
}
//1ms延时
void nms(uchar ms)
{
for(;ms>0;ms--)
nus(167);
}
/*------------------- END -------------------------------------------------------*/
一周热门 更多>