基于51单片机的lcd1602万年历设计_温度+闹钟心得
下载地址
https://download.youkuaiyun.com/download/weixin_44017446/10908985
当看到这个学习项目的时候,我是一脸的蒙,没办法我还是一个小白,一个刚接触单片机没多久的小菜鸟。
看到这东西我第一想到的就是这该怎么做,有毒吧,好难啊,一点思路都没有,lcd1602好吧这个玩过,ds1302好吧这个也写过,ds18b20咦这个有点难,看那手册就觉得好难,时序图看不懂,到后面看懂了,好吧我延时一直弄不好,所以显示的温度都是负数(-0.06),看着就懵逼,没这么冷吧,换个芯片,噢,插反了,烧了,唉在插一个咯,后来经历过一系列的调试,终于弄好。好了需要的模块已经准备好,开始把他们组合起来,…好吧,它们两跟我作对,在一起就行不通了,什么哦,算了,去网上找找经验,哦原来使能冲突了,emmmm,好啦,它可以了,两个像兄弟一样和平共处,一起显示出来了。
主界面准备好了,切换界面直接用独立按键就好了,这个容易。
我是用4个按键来做的
#ifndef __KEY_H
#define __KEY_H
#include "sys.h"
#include "delay.h"
#define KEYPORT P1 // 四个按键接在了P1口的四个引脚#define NO_KEY 0xf0#define K1 0X01#define K2 0X02#define K3 0X03#define K4 0X04#define KEYSUB 0X02#define KEYADD 0X01#define KEYSET 0X04#define KEYNEXT 0X03 //K1,2,3,4,和这些是一样的,只是写.c文件时#define LONGCNT 150#define SHORTCNT 12
#define K1 1
#define K2 2
#define K3 3
#define K4 4
uchar key_scan();
#endif
#include"key.h"
sbit KeyPort0=P1^4;
sbit KeyPort1=P1^5;
sbit KeyPort2=P1^6;
sbit KeyPort3=P1^7;
/************************************************************************
函数名称:key_scan()
函数功能:4个独立按键检测
输入参数:无
返回值:KeyV 通过返回值的不同来确定哪个按键被按下
*************************************************************************/
uchar key_scan()
{
uchar KeyV;
KEYPORT=0xff;
if(KeyPort0==0||KeyPort1==0||KeyPort2==0||KeyPort3==0) //判断是否有按键按下
//而是从锁存器读的,一直是0xff
{
delay_ms(10); //防止抖动
if(KeyPort0==0) //判断哪个按键被按下
{
KeyV=K1;
}
else if(KeyPort1==0)
{
KeyV= K2;
}
else if(KeyPort2==0)
{
KeyV=K3;
}
else if(KeyPort3==0)
{
KeyV=K4;
}
}
else
{
KeyV= 0;
} //判断哪个按键被按下//
// if(KeyV != 0) //有按键按下时,进行松手检测(不知道为什么,这里一直有毒,反正就是实现不了)
// while(KeyPort0==0||KeyPort1==0||KeyPort2==0||KeyPort3==0);
//delay_ms(10); //延时消抖
return KeyV; //返回KeyV来标识哪一个按键被按下
}
嗯,按键也就这样了,反正行得通就好了。
接下来,lcd1602,ds1302,ds18b20,嗯网上找,一大堆,我就不贴了,
把需要改的地方贴一下
uchar DS1302Read(uchar addr)
{
uchar i,dat,dat1;
DSCE=0;
_nop_();
SCLK=0;
_nop_();
DSCE=1;
_nop_();
for(i=0;i<8;i++)
{
DSIO=addr&0x01;
addr>>=1;
SCLK=1;
_nop_();
SCLK=0;
_nop_();
}
_nop_();
for(i=0;i<8;i++)
{
dat1=DSIO;
dat=(dat>>1)|(dat1<<7);
SCLK=1;
_nop_();
SCLK=0;
_nop_();
}
// DSCE=0; //把这个注释掉就好了 sbit DSCE=P3^5;
_nop_();
SCLK=1;
DSIO=0;
_nop_();
DSIO=1;
_nop_();
return dat;
}
ok!
然后就是一大堆按键处理了
一个一个界面写吧,先把进入和出来的先写好,然后在写里面的功能。
烦哦,一大堆的东西,花了我4天的时间。
/****** 主界面显示 ******/
/2018年01月01日 P 星期五/
/12:01:01 温度:20C 闹钟开关/
/****** 主界面按键功能 ******/
/******key1: 进入设置 ******/
/******key2: 加 ******/
/******key3: 减 ******/
/******key4: 打开闹钟 ******/
/****** 功能选择 ******/
/******1:timeSet ******/
/******2: alarmSet /
/ 按键功能 ******/
/******key1: 进入设置 ******/
/******key2: 加 ******/
/******key3: 减 ******/
/******key4: 退出设置 ******/
/****** 时间设置 ******/
/key1: 选择设置位置/
/******key2: 加 ******/
/******key3: 减 ******/
/******key4: 退出设置 ******/
/****** 闹钟设置 /
/ +:增加,-:删除 ******/
/******key1: 确定选择 ******/
/******key2: 选择设置位置加1 ******/
/******key3: 选择设置位置减1 ******/
/******key4: 退出设置 ******/
/****** 闹钟x ******/
/******key1: 选择设置 (时间,开关,重复/不重复,选择音乐)******/
/******key2: 加1 ******/
/******key3: 减一 ******/
/******key4: 退出设置 ******/
/****** 重复/不重复 ******/
/******key2: 重复 ******/
/******key3: 不重复 ******/
/****** 重复 ******/
/key1:选择设置位置/
/******key2: 开启重复 ******/
/******key3: 关闭重复 ******/
/******key4: 退出设置 ******/
/****** 不重复 ******/
/key1:选择设置位置/
/******key2: 开启 ******/
/******key3: 关闭 ******/
/******key4: 退出设置 ******/
嗯,这是所有的按键处理的思路,
主函数吧,把闹钟需要的参数返回给它处理就好了。
#include "sys.h"
#include "delay.h"
#include "lcd1602.h"
#include "temp.h"
#include "ds1302.h"
#include "keyProcess.h"
#include "otherProcess.h"
#include "musicCode.h"
#define RldTmr(fr) 65536 - (11059200 / 12) / (fr << 1)
#define FuDian(n) (n << 1) / 3 //附点n分音符的换算
sbit beep = P2^0;
uchar Temp_TH0,Temp_TL0;
uchar Temp_TH1,Temp_TL1;
uchar tmrFlg=0,enable = 1;
extern uint mflag; //音符计算
extern bit nflag;
extern bit aflag; //闹钟开关
extern uchar a;
extern uchar b;
void PlayMusic(uchar *Sound,uchar *lengthlen,uint speed); //固定标准为4分音符的速度:例如speed = 108 表示一分钟扫过108个4分音符
void sound_Init();
uint length(uchar *Sound); //判断音符个数
uint mflag; //音符循环个数
bit nflag=0; //1分钟关闭闹钟暂停标志
bit aflag=1; //总开关
uchar stop[7]; //暂停标志位
uchar a; //闹钟x
uchar b; //重复检测
void main()
{
uchar mode;
stop[0]=1; //暂停标志位
stop[1]=1;
stop[2]=1;
stop[3]=1;
stop[4]=1;
stop[5]=1;
stop[6]=1;
Clock=0; //初始闹钟个数
LCD1602_Init(); //1602初始化
DS1302_Init(); //1302初始化
sound_Init(); //定时器初始化
while(1)
{
/**********按键处理***********/
if(key_scan()==K1||key_scan()==K2||key_scan()==K3||key_scan()==K4)
{
switch (key_scan())
{
case K1: mode=MODE0;break; //MODE0进入菜单
case K2: mode=MODE1;break; //MODE0设置日期
case K3: mode=MODE2;break; //MODE0设置闹钟
case K4: mode=MODE3;aflag=!aflag;break; //MODE3退出
}
key_process(mode); //按键处理函数
}
/**********主屏幕显示**********/
LCD1602_DisplayTemp(DS18B20_ReadTemp()); //温度
DS1302_ReadTime(); //读时间
LCD1602_DisplayData(); //显示时间
if(AM_PM==0&&hour12_24==1) //显示上午
{
LCD1602_WriteCom(0x80+13);
LCD1602_WriteData('A');
}
if(AM_PM==1&&hour12_24==1) //显示下午
{
LCD1602_WriteCom(0x80+13);
LCD1602_WriteData('P');
} //24小时制
if(hour12_24==0)
{
LCD1602_WriteCom(0x80+13);
LCD1602_WriteData(' ');
}
LCD1602_WriteCom(0xc0+15); //显示闹钟开关
if(aflag)
LCD1602_WriteData('N');
else
LCD1602_WriteData('F');
/**********闹钟设置**********/
if(aflag==1)
{
for(a=0;a<=Clock;a++) //检测闹钟
{
if(alarm[a][2]==1) //判断闹钟是否开启
{
if(alarm[a][3]==1) //判断是否重复 alarm[a][3]==1为重复
{
for(b=0;b<7;b++) //判断周是否重复
{
if(TIME[5]==b+1&&repeat[a][b]==1) // repeat[a][0] 重复天数星期一到星期日
{
if((alarm[a][0]==TIME[1]&&alarm[a][1]==TIME[2])) //alarm[0][0]=分钟 alarm[0][1]=小时
{
nflag=1;
switch(alarm[a][4])
{
case 0: PlayMusic(musicNote5,noteDuration5,108); break;
case 1: PlayMusic(musicNote1,noteDuration1,108); break;
case 2: PlayMusic(musicNote2,noteDuration2,108); break;
case 3: PlayMusic(musicNote3,noteDuration3,108); break;
case 4: PlayMusic(musicNote4,noteDuration4,108); break;
}
}
else
stop[a]=1;
}
}
}
else
{
for(b=0;b<7;b++)
{
if(TIME[5]==b+1&&repeat[a][b]==1) // repeat[a][0] 重复天数星期一到星期日
{
if((alarm[a][0]==TIME[1]&&alarm[a][1]==TIME[2])) //alarm[0][0]=分钟 alarm[0][1]=小时
{
switch(alarm[a][4])
{
case 0: PlayMusic(musicNote5,noteDuration5,108); break;
case 1: PlayMusic(musicNote1,noteDuration1,108); break;
case 2: PlayMusic(musicNote2,noteDuration2,108); break;
case 3: PlayMusic(musicNote3,noteDuration3,108); break;
case 4: PlayMusic(musicNote4,noteDuration4,108); break;
}
}
else
stop[a]=1;
}
}
}
}
}
}
else
{
beep=1;TR0=0;
}
// LCD1602_WriteCom(0xc0+15);
// if(stop[a]==1)
// {
// LCD1602_WriteData('1');
// }
// else
// LCD1602_WriteData('0');
delay_ms(10);
}
}
延时函数,嗯还算可以吧,不准确
#ifndef __DELAY_H
#define __DELAY_H
#include "sys.h"
#define uchar unsigned char
#define uint unsigned int
void delay_ms(uint i);
void delay_us(uchar x);
#endif
#include "delay.h"
void delay_ms(uint i)
{
uchar n;
while(i--)
for(n=0;n<80;n++)
;
}
void delay_us(uchar x) //x*5 us
{
uchar a,b;
for(b=x;b>0;b--)
for(a=1;a>0;a--);
}
那个按键处理函数太多了,不好贴,
可以去GitHub看看吧,我都放那了
MCU_alarm搜一下
下载地址
https://download.youkuaiyun.com/download/weixin_44017446/10908985