基于51单片机+DS1302万年历+LCD1602显示+按键播报时间+温控风扇+按键控灯

发布者:悦耳旋律最新更新时间:2022-09-20 来源: csdn关键字:51单片机  DS1302  万年历  LCD1602显示 手机看文章 扫描二维码
随时随地手机看文章

前段时间做了一个 基于51单片机的万年历加温度控制风扇以及按键播报时间。在这里做一下笔记。

准备硬件

1:51单片机(我这里用的是STC89C52

2:语音播报模块(我这里用的是SYN6288)

3:DS1302时钟模块

4:DS18B20温度模块

5:LCD1602显示屏

6:L298N电机驱动

7:蜂鸣器

8:电机

9:按键 5个

10:灯


功能介绍

功能:

1:修改时间

2:修改日期(软件自动校正日期)

3:闹钟模式

4:温度控制风扇速度

5:调节灯亮度

6:播报时间


主界面设置

下面是大概的流程图 位置不够没画全。。。

在这里插入图片描述

由于代码较多,这里就不全部贴出来了。


修改时间

当我们进入到修改时间的界面,我们屏幕得显示出刚按下的时间,然后我们得让

1: LCD1602显示时间

2:按键的操作

按键 1:让时 / 分 /秒+1 或者按下按键2 让时 / 分 /秒 -1,然后通过按键3 来切换我到底是 调整时 / 分 /秒

3:按键4按下 退出

4:提示是否保存时间(1:保存,4:不保存)

如果保存我们再写入到DS1302这样就完成了修改时间的功能


/*时间数值 加 函数*/

unsigned char time_add(unsigned char cursor)

{

unsigned char hour_high,hour_low;

unsigned char min_high, min_low;

unsigned char sec_high, sec_low;

switch(cursor)

{

case 0: //修改 时++

hour_high = temp[2] >> 4;

hour_low  = temp[2] & 0x0f;

hour_low = hour_low++;

if(hour_low == 4 && hour_high == 2) //如果等于24时 变00

{

hour_low = 0;

hour_high = 0;

}

else if(hour_low == 10)

{

hour_low = 0;

if(hour_high == 2)

hour_high = 0;

else

hour_high = hour_high + 1;

}

hour_high = hour_high << 4;

hour_high = hour_high | hour_low;

temp[2] = hour_high;

lcd_display_byte(5,0,(temp[2]>>4) + 0x30);

lcd_display_byte(6,0,(temp[2]&0x0f) + 0x30);

write_com(0x86);

break;

case 1://修改 分++

min_high  = temp[1] >> 4;

min_low   = temp[1] & 0x0f;

min_low++;

if(min_low == 10)

{

min_high++;

min_low = 0;

if(min_high == 6 && min_low == 0)

{

min_high = 0;

min_low = 0;

}

}

min_high = min_high << 4;

min_high = min_high | min_low;

temp[1] =  min_high;

lcd_display_byte(8,0,(temp[1]>>4) + 0x30);

lcd_display_byte(9,0,(temp[1]&0x0f) + 0x30);

write_com(0x89);

break;

case 2://修改 秒++

sec_high  = temp[0] >> 4;

sec_low   = temp[0] & 0x0f;

sec_low++;

if(sec_low == 10)

{

sec_low = 0;

sec_high++;

if(sec_high == 6 && sec_low == 0)

{

sec_low = 0;

sec_high = 0;

}

}

sec_high = sec_high << 4;

sec_high = sec_high | sec_low;

temp[0] =  sec_high;

lcd_display_byte(11,0,(temp[0]>>4) + 0x30);

lcd_display_byte(12,0,(temp[0]&0x0f) + 0x30);

write_com(0x8c);

break;

default :

break;

}

return cursor;

}


修改日期(并且校正星期)

当我们进入到修改日期的界面,我们屏幕得显示出刚按下的日期,然后我们得让

1: LCD1602显示日期

2:按键的操作

按键 1:让年/月/日+1 或者按下按键2 让年/月/日 -1,然后通过按键3 来切换我到底是 调整年/月/日

3:按键4按下 退出

4:提示是否保存日期(1:保存,4:不保存)

5:星期的自动调整

星期 = (月份对应的数字+日期数字) / 7 余数:则是星期几 0位周日

如果保存我们再写入到DS1302这样就完成了修改日期的功能

在这里插入图片描述

/*自动修正星期 函数*/

void revision_week()

{

unsigned char num;

unsigned char month;

unsigned char day;

unsigned char week;


//星期 = (月份对应数字+日期数字) / 7 余数:则是星期几  0位周日


month = ((temp[4]>>4)*10 + (temp[4]&0x0f));//将月份BCD码转为十进制

day = ((temp[3]>>4)*10 + (temp[3]&0x0f));  //将日BCD码转为十进制

switch(month)

{

//月份对应数字

case 5: num = 5; break;

case 6: num = 1; break;

case 8: num = 6; break;

case 1: case 10: num = 4; break;

case 4: case 7:  num = 3; break;

case 9: case 12: num = 2; break;

case 2:  case 3:  case 11: num = 0; break;  

}

week = (num+day)%7;

    if(week == 0) 

temp[5] = 0x07;

else

temp[5] = week;



闹钟模式

进入到闹钟模式,设置闹钟的时间 选择周几,选择响铃时长。

时间的设置 跟修改时间的设置一模一样,等设置完时间,我们调到设置星期,按键1是 切换周一到 周日,按键2是确认选择当前这个星期,按键3是取消选择当前这个星期。

按键4:是否保存? 不保存就退出了,如果保存继续跳转到选择闹钟时间的界面。这里就没啥了。然后保存退出。主界面OFF 变成 ON 表示开启了


/* 选择/取消星期几 响闹钟*/

/* 周几++   打开   关闭  退出  */  

void lcd_dispaly_chooseClockWeek()

{

unsigned char s = 0;

unsigned char week;

LCD1602_CLS; //清屏

lcd_display_str(0,0,"week:  2:ON3:OFF");

lcd_display_str(0,1,"clock:");

week = temp[5];

while(1)

{

lcd_display_byte(5,0,(week & 0x0f) + 0x30); //显示当前星期

for(s=0;s<7;s++)

{

if((alarmClockWeek>>s)&0x01 == 1)

lcd_display_byte(s+6,1,(s+1)+0x30);

}

write_com(0x85);

menu = gather_key(); //采集哪个按键被按下函数

switch(menu) 

{

case 1:

week++;

if(week >= 8)

week = 1;

break;

case 2:

switch(week)

{  

case 1: alarmClockWeek |= 0x01; lcd_display_byte(6,1,'1'); break;//0000 0001

case 2: alarmClockWeek |= 0x02; lcd_display_byte(7,1,'2'); break;//0000 0010

case 3: alarmClockWeek |= 0x04; lcd_display_byte(8,1,'3'); break;//0000 0100

case 4: alarmClockWeek |= 0x08; lcd_display_byte(9,1,'4'); break;//0000 1000

case 5: alarmClockWeek |= 0x10; lcd_display_byte(10,1,'5'); break;//0001 0000

case 6: alarmClockWeek |= 0x20; lcd_display_byte(11,1,'6'); break;//0010 0000

case 7: alarmClockWeek |= 0x40; lcd_display_byte(12,1,'7'); break;//0100 0000

}

break;

case 3:

switch(week)

{

case 1: alarmClockWeek &= ~0x01; lcd_display_byte(6,1,' '); break;

case 2: alarmClockWeek &= ~0x02; lcd_display_byte(7,1,' '); break;

case 3: alarmClockWeek &= ~0x04; lcd_display_byte(8,1,' '); break;

case 4: alarmClockWeek &= ~0x08; lcd_display_byte(9,1,' '); break;

case 5: alarmClockWeek &= ~0x10; lcd_display_byte(10,1,' '); break;

case 6: alarmClockWeek &= ~0x20; lcd_display_byte(11,1,' '); break;

case 7: alarmClockWeek &= ~0x40; lcd_display_byte(12,1,' '); break;

}

break;

case 4:

s = lcd_display_saveTimeOrDate_YesOrNo(3);//保存? 不:清空为0  保则不清空

if(s)

{

ALARM_CLOCK_OFF; //关闭闹钟

//闹钟日期清空

alarmClockWeek = 0;

LCD1602_CLS; //清屏

return;

}

ALARM_CLOCK_ON;  //开启闹钟

LCD1602_CLS; //清屏

return;

}

}


}


调节灯模式

/*修改灯亮度 函数*/

void modifLightMode()

{

unsigned char s = 0;

s = lcd_display_light_menu(); //显示修改灯亮度菜单

if(s)

{

write_com(CLEAR_SCREEN);//清屏

exitFlag = 1;

return;

}

lcd_display_str(0,0,"Light gear:");

TR0 = 1;

while(menu != 4)

{

lcd_display_byte(11,0,light_gear+0x30);//显示灯档位

menu = gather_key(); //检测是否有按键按下

switch(menu)

{

case 1:

light_gear++;

if(light_gear>=3)

{

light_gear = 3;

TR0 = 0;

LED = 0;

}

else if(light_gear == 0)

{

TR0 = 0;

LED = 1;

}

else

{

TR0 = 1;

LED = 0;

}

break;

case 2:

if(light_gear>=1)

{

light_gear--;

}

else

{

light_gear = 0;

}


if(light_gear == 3)

{

TR0 = 0;

LED = 0;

}

else if(light_gear == 0)

{

TR0 = 0;

LED = 1;

}

else

{

TR0 = 1;

LED = 0;

}

break;


case 4:

exitFlag = 1;

return;

}

}

}


调节风扇模式

/*修改风扇速度 函数*/

void modifFanMode()

{

unsigned char s = 0;

s = lcd_display_fan_menu(); //显示修改风扇速度菜单

if(s)

{

write_com(CLEAR_SCREEN);//清屏

exitFlag = 1;

return;

}

lcd_display_str(0,0,"Fan gear:");

TR1 = 1;

while(menu != 4)

{

lcd_display_byte(9,0,fan_gear+0x30);//显示风扇档位

menu = gather_key(); //检测是否有按键按下

switch(menu)

{

case 1:

fan_gear++;

if(fan_gear>=3)

{

FAN = 1;

TR1 = 0;

fan_gear = 3;

}

else if(fan_gear == 0)

{

FAN = 0;

TR1 = 0;

}

else

{

FAN = 1;

TR1 = 1;

}

break;

case 2:

if(fan_gear>=1)

{

fan_gear--;

}

if(fan_gear == 0)

{

FAN = 0;

TR1 = 0;

fan_gear = 0;

}

else if(fan_gear == 3)

{

FAN = 1;

TR1 = 0;

}

else

{

TR1 = 1;

FAN = 1;

}

break;

case 4:

exitFlag = 1;

return;

}

}

}


按键播报时间

这里我是用外部中断做。


/*SYN6288播报时间*/

void playTime(void)

{

unsigned char syn6288_time[5] = {''};

syn6288_time[0] = (time[2]>>4)+48; //时

syn6288_time[1] = (time[2]&0x0f)+48;

syn6288_time[2] = ':';

syn6288_time[3] = (time[1]>>4)+48; //分

syn6288_time[4] = (time[1]&0x0f)+48;

SYN_FrameInfo(0, "[v16][t5]当前时间");

delay(2000);

SYN_FrameInfo(0,syn6288_time);

delay(2000);

}


void key_handler(void) interrupt 0

{

delay(15);  //消抖作用

if(kk == 0)

{

EX0 = 0;

playTime(); //播报时间

EX0 = 1;

}

}


温度控制风扇

/*风扇速度控制 函数*/

void fan_speed_control()

{

/*在此修改 温度的阈值 从而控制速度 */

if(temperature[0] >= 20 && temperature[0] <= 25)

{

fan_gear = 1;

FAN = 1;

TR1 = 1;

}

else if(temperature[0] >= 26 && temperature[0] <= 30)

{

fan_gear = 2;

FAN = 1;

TR1 = 1;

}

else if(temperature[0] > 30)

{

fan_gear = 3;

FAN = 1;

TR1 = 0;

}

else

{

fan_gear = 0;

FAN = 0;

TR1 = 0;

}

}


主程序代码

#include

#include "lcd1602.h"

#include "ds1302.h"

#include "key.h"

#include "alarmClock.h"

#include "light.h"

#include "ds18b20.h"

#include "fan.h"

#include "uart.h"

#include "syn6288.h"

#include "delay.h"


void main()

{

lcd_init();   //初始化LCD1602 

ds1302_init();//初始化DS1302

key_init();   //初始化按键

light_init(); //初始化灯

ds18b20_init();//初始化DS18B20

fan_init();   //初始化风扇

uart_init();  //初始化串口

while(1)

{

menu = gather_key(); //检测是否有按键按下

switch(menu)

{

/* 默认模式 显示时间*/

case 0:

if(exitFlag == 0)

{

lcd_display_time();//LCD1602显示时间

lcd_display_date();//显示日期

exitFlag = 2;

}

ds1302_burst_read(DS1302_READ_TIME); //读取日期和时间 以及显示温度

lcd_display_dateAndTimeAndTemp(); //1602显示日期以及闹钟状态

if(alarmClock_flag)

{

detectionAlarmClock();//检测闹钟

}

break;


/*显示修改界面 时间/日期/闹钟修改  /  灯亮度修改  /  温度控制风扇阈值修改  /  返回主页*/

case 1:

case 2:

case 3:

lcd_display_menu(); //显示菜单界面

break;

}

}

}


项目演示

在这里插入图片描述

关键字:51单片机  DS1302  万年历  LCD1602显示 引用地址:基于51单片机+DS1302万年历+LCD1602显示+按键播报时间+温控风扇+按键控灯

上一篇:单片机攻略2——I/O通信基础
下一篇:基于51单片机+DHT11温湿度模块+ESP8266模块+上传oneNET APP显示+LCD1602显示

推荐阅读最新更新时间:2024-11-06 20:44

单片机的动手实践篇--51单片机玩转12864
12864液晶的驱动和1602的类似,只不过是多了几个扩展的功能,不如画图功能: 这里讲一下:不要简单的认为12864是y轴64,x为128,那是点阵的分布,不是读写的分布,如正图表示,y轴的32行,从0到31,x轴的16 从0到15,0到7为上半个屏幕,8到15在下半个屏幕,所以绘图的时候,有两个部分要进行书写 在12864上载入任意一幅图: 示例代码: #include reg52.h #define uint unsigned int #define uchar unsigned char sbit lcdrs = P2^4;//数据还是指令的选择端口 sbit lcdwr = P2^5;//读写操作端口 sb
[单片机]
单片机的动手实践篇--<font color='red'>51单片机</font>玩转12864
51单片机心形流水灯源程序
用stc89c51单片机做的心形流水灯效果非常棒,下面是实物图: 背面: 原理图我就不画了4个p口全部接上led灯即可,下面是控制程序: #include at89x52.h #include intrins.h #define uint unsigned int #define uchar unsigned char uchar code table0 ={0xfe,0xfc,0xf8,0xf0,0xe0,0xc0,0x80,0x00};//P0-P7依次点亮 uchar code table1 ={0x01,0x03,0x07,0x0f,0x1f,0x3f,0x7f,0xff};//P0-P7依次熄灭 uch
[单片机]
<font color='red'>51单片机</font>心形流水灯源程序
51单片机专业名词解释
PC = progammer counter //程序计数器 ACC = accumulate //累加器 PSW = progammer status word //程序状态字 SP = stack point //堆栈指针 DPTR = data point register //数据指针 寄存器 IP = interrupt priority //中断优先级 IE = interrupt enable // 中断使能 TMOD = timer mode //定时器 方式 (定时器/计数器 控制寄存器) ALE = alter (变更,可能是) PSEN = progammer saving enable //程序存储器使能(选
[单片机]
51单片机的I/O端口结构及应用特性
1.锁存器加引脚的典型结构 51单片机的I/O端口都有内部总线实现操作控制。P0-P3四个I/O口都可以做普通I/O口,因此,要求具有输出锁存功能。内部总线有事分时操作,因此每个I/O端口都有相应的锁存器。然而I/O端口又是外部的输入/输出通道,必须有相应的引脚,故形成了I/O端口的锁存器加引脚的典型结构。 2.I/O口的复用功能 (1)I/O口的总线复用 80C51在使用并行总线扩展时,P0口可作为数据总 线口和低8位地址总线口,这是,P0为三态双向口。P0口输出总线的地址数据信号,P2口输出高8位地址信号。 (2)I/O口的功能复用 I/O口的P3为功能复用的I/O端口。端口有复用输出的控制端;引脚也有复用输入的控制端。
[单片机]
基于AT89C51单片机的智能台灯设计
一.系统概述 系统使用的模块有AT89C51单片机+按键+两个不同颜色的小灯。 系统内使用AT89C51单片机作为主控,系统内分为普通模式和调节模式,上电之后就是普通模式,小灯会亮但是不能进行亮度调节,按下设置按键后亮度可调节的小灯亮,通过加减按键就能直接控制小灯的亮度。 二.仿真概述 1.系统上电台灯打开,此时的绿灯亮代表的是亮度无法修改的普通灯亮起。 2.按下设置按键后切换到可调节亮度的灯。 3.蓝色小灯的亮度调节是PWM调节,按键加和减可以调节信号的占空比,并实现小灯亮度的控制。 三.程序设计 使用Keil 51进行程序设计,打开Proteus时程序是默认烧录的状态,如果没有烧录点击AT89C51单片机并将
[单片机]
基于AT89C<font color='red'>51单片机</font>的智能台灯设计
51单片机RAM 数据存储区学习笔记
1.RAM keil C语言编程 RAM是程序运行中存放随机变量的数据空间。在keil中编写程序,如果当前模式为small模式,如果总的变量大小未超过128B,则未初始化的变量的初值默认为0.如果所有的变量超过单片机small模式下的128B大小,则必须对变量进行初始化,否则超过RAM大小变量的值是不确定的,在small模式下超过128B大小的变量也必须在编译器中重新设定存储器的存储模式。 在keil中,可选择small,compact,large三种方式存储数据变量: 在keil中可以用“TargetOptions”来配置这一项: 图1 选择数据存储模式 2.片内数据存储区 (1) 工作寄存器区 工作寄存
[单片机]
<font color='red'>51单片机</font>RAM 数据存储区学习笔记
基于AT89C51单片机设计的简易智能机器人
引言 随着微电子技术的不断发展,微处理器芯片的集成程度越来越高,单片机已可以在一块芯片上同时集成CPU、存储器、定时器/计数器、并行和串行接口、看门狗、前置放大器、A/D转换器、D/A转换器等多种电路,这就很容易将计算机技术与测量控制技术结合,组成智能化测量控制系统。这种技术促使机器人技术也有了突飞猛进的发展,目前人们已经完全可以设计并制造出具有某些特殊功能的简易智能机器人。 1 设计思想与总体方案 1.1 简易智能机器人的设计思想 本机器人能在任意区域内沿引导线行走,自动绕障,在有光源引导的条件下能沿光源行走。同时,能检测埋在地下的金属片,发出声光指示信息,并能实时存储、显示检测到的断点数目以及各断点至起跑线间的距离,
[单片机]
基于FPGA和51单片机信号发生器设计与实现
信号发生器又称为波形发生器是一种常用的信号源并且广泛应用于电子电路、通信、控制和教学实验等领域的重要仪器之一。为了降低传统函数信号发生器成本,改善信号发生器低频稳定性。笔者结合FPGA和51单片机产生0.596 Hz频率精度函数信号。笔者设计通过51单片机控制函数信号类型以及相关参数,用户可通过按键设置需要的波形、波形幅度、波形频率以及方波的占空比、相位。本文设计方案不仅具有良好的经济前景,也可以为当代高等教育深化改革做一个参考方向。 1 系统设计方案 1.1 系统硬件设计 本文中设计中硬件包括EP2C8Q20818N芯片和C8051F0201单片机、DAC0800芯片,T6963的LCD。本文中主要利用FPGA(EP2C8
[单片机]
基于FPGA和<font color='red'>51单片机</font>信号发生器设计与实现
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved