基于 51 单片机和 LCD1602 的万年历程序
可实现走时和调时功能 有简单的 1602 菜单制作
欢迎大家交流
LCD1602 和 51 单片机的连接方法
RS = P3^5; //数据/命令选择端(H/L)
RW = P3^4;
EN = P3^3;
P0
//数/写选择端(H/L)
//使能信号
//LCD1602 的数据口 D0-D7
#include
typedef unsigned char uChar8;
typedef unsigned int uInt16;
uChar8 TAB1[]="^_^2016-12-27^_^";
uChar8 TAB2[]="
";
uChar8 year=2016,month=12,day=27,hour=23,minute=59,second=45,count;
23:59:45
//数据/命令选择端(H/L)
//数/写选择端(H/L)
//使能信号
sbit RS = P3^5;
sbit RW = P3^4;
sbit EN = P3^3;
sbit SEG_SELECT = P1^7;
sbit BIT_SELECT = P1^6;
sbit LED1 = P2^0;
sbit Key2 = P3^6;
sbit Key1 = P3^7;
sbit Key3 = P3^0;
void DelayMS(uInt16 ValMS)
{
uInt16 uiVal,ujVal;
for(uiVal = 0; uiVal < ValMS; uiVal++)
for(ujVal = 0; ujVal < 113; ujVal++);
}
void DectectBusyBit(void)
{
P0 = 0xff;
// 读状态值时,先赋高电平
RS = 0;
RW = 1;
EN = 1;
DelayMS(1);
while(P0 & 0x80);
EN = 0;
}
// 若 LCD 忙,停止到这里,否则走起
// 之后将 EN 初始化为低电平
void WrComLCD(uChar8 ComVal)
{
DectectBusyBit();
RS = 0;
RW = 0;
EN = 1;
P0 = ComVal;
DelayMS(1);
EN = 0;
}
void WrDatLCD(uChar8 DatVal)
{
DectectBusyBit();
RS = 1;
RW = 0;
EN = 1;
P0 = DatVal;
DelayMS(1);
EN = 0;
}
void LCD_Init(void)
{
uChar8 ucVal,i;
WrComLCD(0x38);
// 16*2 行显示、5*7 点阵、8 位数据接口
WrComLCD(0x38);
WrComLCD(0x38);
// 重新设置一遍
WrComLCD(0x01);
WrComLCD(0x06);
DelayMS(1);
WrComLCD(0x0c);
for(i=0;i<16;i++)
// 显示清屏
// 光标自增、画面不动
// 稍作延时
// 开显示、关光标并不闪烁
WrComLCD(0x80+i);
WrDatLCD(TAB1[ucVal+i]);
WrComLCD(0xC0+i);
WrDatLCD(TAB2[ucVal+i]);
{
}
}
void Timer_Init()
{
TMOD=0x01;
TH0=0xDC;
TL0=0x00;
EA=1;
ET0=1;
TR0=1;
}
void DisplayYear()
{
WrComLCD(0x80+5);
WrDatLCD(0x30+year/10);
WrComLCD(0x80+6);
WrDatLCD(0x30+year%10);
}
void DisplayMonth()
{
WrComLCD(0x80+8);
WrDatLCD(0x30+month/10);
WrComLCD(0x80+9);
WrDatLCD(0x30+month%10);
DisplayDay()
WrComLCD(0x80+11);
WrDatLCD(0x30+day/10);
WrComLCD(0x80+12);
WrDatLCD(0x30+day%10);
}
void
{
}
void DisplayHour()
{
}
WrComLCD(0xc0+4);
WrDatLCD(0x30+hour/10);
WrComLCD(0xc0+5);
WrDatLCD(0x30+hour%10);
void DisplayMinute()
{
WrComLCD(0xc0+7);
WrDatLCD(0x30+minute/10);
WrComLCD(0xc0+8);
WrDatLCD(0x30+minute%10);
}
void DisplaySecond()
{
WrComLCD(0xc0+10);
WrDatLCD(0x30+second/10);
WrComLCD(0xc0+11);
WrDatLCD(0x30+second%10);
}
void CloseDigTube()
{
BIT_SELECT=1;
P0=0xff;
BIT_SELECT=0;
SEG_SELECT=1;
P0=0x00;
SEG_SELECT=0;
}
void Keyscan()
{
static
uChar8 i=0,j=0;
//static 静态 变量 每按 下一次
Key1(停止计时键)i++; 每按下一次 Key2(调位键)j++;
if(Key1==0)
时键)i++;
{
if(Key1==0)
DelayMS(5);
i++;
//每按下一次 Key1(停止计
//消抖
}
if(i%2==1)
决定 TR 的状态
{
LED1=0;
TR0=0;
}
if(i%2==0)
{
//判断 i 的奇偶性
LED1=1;
TR0=1;
WrComLCD(0xc0+5);
//确定位置 第二行第五位
//确定位置 第二行第八位
//确定位置 第二行第十一位
//光标不闪烁
// 每 按 下 一 次 Key2( 调 位
//消抖
j++;
WrComLCD(0xc0+8);
WrComLCD(0xc0+11);
WrComLCD(0x0c);
}
if(Key2==0)
键)j++;
{
DelayMS(5);
if(Key2==0)
}
if(j%7==1)
{
WrComLCD(0x0f);
//光标闪烁
WrComLCD(0xc0+11);
if(Key3==0)
//哪一位光标闪烁
second++;
if(second==60)
second=0;
DisplaySecond();
{
}
}
if(j%7==2)
{
WrComLCD(0x0f);
//光标闪烁
WrComLCD(0xc0+8);
if(Key3==0)
{
//哪一位光标闪烁
minute++;
if(minute==60)
minute=0;
DisplayMinute();
}
}
if(j%7==3)
{
WrComLCD(0x0f);
//光标闪烁
WrComLCD(0xc0+5);
if(Key3==0)
//哪一位光标闪烁
DelayMS(5);
if(Key3==0)
{
hour++;
if(hour==24)
hour=0;
DisplayHour();
}
}
if(j%7==4)
{
WrComLCD(0x0f);
//光标闪烁
WrComLCD(0x80+12);
if(Key3==0)
//哪一位光标闪烁
DelayMS(5);
if(Key3==0)
{
day++;
if(day==31)
day=1;
DisplayDay();
}
}
if(j%7==5)
{
WrComLCD(0x0f);
//光标闪烁
WrComLCD(0x80+9);
if(Key3==0)
//哪一位光标闪烁
DelayMS(5);
if(Key3==0)
{
month++;
if(month==12)
month=1;
DisplayMonth();
}
}
if(j%7==6)
{
WrComLCD(0x0f);
//光标闪烁
WrComLCD(0x80+6);
if(Key3==0)
//哪一位光标闪烁
DelayMS(5);
if(Key3==0)
{
year++;
if(year==99)
year=0;
DisplayYear();
}
}
if(j%7==0)
{
WrComLCD(0x0c);
//光标不闪烁
}
}
void main(void)
{
LCD_Init();
Timer_Init();
CloseDigTube();
DelayMS(5);
while(1)
{
Keyscan();
//按键扫描 菜单制作
}
}
void Timer0(void) interrupt 1
{
TH0=0xDC;
TL0=0x00;
count++;
if(count==100)
{
}
count=0;
second++;
if(second==60)
{
second=0;
minute++;
if(minute==60)
{
minute=0;
hour++;
if(hour==24)
{
hour=0;
}
DisplayHour();
}
DisplayMinute();
}
DisplaySecond();
}