一、利用单片机如何控制LCD
今天的主题是如何用单片机控制LCD编写数字钟,该数字钟具有校时功能,代码较长,我会仔细为大家讲解的。
当然如果大家对数字钟感兴趣的话可以看我的姐妹篇,如何用74LS192芯片编写数字钟~~~
欢迎“戳一戳”
在写如何用单片机控制LCD的时候,首先需要对LCD的初始化,在初始化中我们需要用到以下几个函数,分别是——LCD初始化函数、检查忙标志函数、写命令函数、写数据函数、显示字符串函数、延时函数、主函数等。接下来我会逐个介绍各个函数。
二、单个函数分解
1. 1、LCD_INITIAL——初始化函数
void lcd_initial(void)
{
RW=0;
E=0;
write_command(0x3C);
write_command(0x0C); //写入0x0C:开整体显示,光标关,无闪烁
write_command(0x06); //写入0x06:光标右移,写入一个字符后地址指针加1
write_command(0x01); //写入0X01:清屏
write_command(0x80); //写入0x80:字符输入地址,字符的第一位
delay(1); //延时
}
2、WRITE_COMMAND——写命令函数
void write_command(uchar com)
{
check_busy();
E=0; //规定RS和E同时为0时,才可以写入命令
RS=0;
RW=0;
out=com; //将命令com写入P0口
E=1; //写命令时,E应为正脉冲,即正跳变,所以前面先置E=0
_nop_(); //空操作一个机器周期,等待硬件反应
E=0; //E由高电平变为低电平,LCD开始执行命令
delay(1);
}
3、CHECK_BUSY——检验忙函数
在执行大多数命令时都需要检测LCD是否为空闲,如果为空闲再进行指令写入,否则等待。
void check_busy(void)
{
uchar dt;
do
{
dt=0xff; //dt为变量单元,初值为0xff
E=0;
RS=0; //按照读写规定,RS=0,E=1时才可以读忙标志
RW=1;
E=1;
dt=out; //out为P0口,P0口的状态送入dt中
}while(dt&0x80);//如果忙标志BF=1,继续循环检测,等待BF=0
E=0;
}
4、WRITE_DATA——写数据函数
void write_data(uchar dat)
{
check_busy(); //检测忙标志BF=1则等待,若BF=0,则可以对LCD1602液
E=0; //晶显示模块写入
RS=1; //按规定写数据时,E应为正脉冲,所以先置E=0
RW=0; //按规定RS=1和RW=0时,才可以写入数据
out=dat; //将数据dat从P0口输出,即写入LCD1602液晶显示模块
E=1; //E产生正跳变
_nop_();
E=0; //E由高电平变为低电平,写数据操作结束
delay(1);
}
三、单片机主程序及其仿真实现
关于如何启动LCD的程序已经介绍完毕,下面是单片机控制的主程序,因为子函数较多,所以我们在开头进行了函数的声明,并且定义了一些全局变量,方便使用。
1、主程序
#include <reg51.h>
#include <intrins.h> //调用_nop_()函数
#define uchar unsigned char
#define uint unsigned int
#define out P2 //定义out为P2
sbit RS=P3^0;
sbit RW=P3^1;
sbit E=P3^2;
uchar code date[]=" H.I.T.CHINA ";//开始显示的画面
uchar code time[]=" TIME 23:59:55 ";
uchar int_time; //用作定时器,定时50ms
uchar second; //50ms*20=1s,即当int_time==20时,second=1s
uchar minute; //同理second==60s时,minute=1min
uchar hour; //小时
uchar box=0;
uchar houchange[2]; //无符号字符型转化为字符型的存储数组
uchar minchange[2]; //存放分
uchar sechange[2]; //存放秒
void lcd_initial(void);
void check_busy(void);
void write_command(uchar com);
void write_data(uchar dat);
void string(uchar ad,uchar *s);
void delay(uint);
void clock_init();
void displaytime();
void write_sfm(uchar ad,uchar *s);
void displaytime() //显示字符函数
{
houchange[0]=hour/10+0x30; //hour存放的是无符号字符型,通过除以10可以得到
houchange[1]=hour%10+0x30; //hour的十位,再加上0x30变成ASCII码
minchange[0]=minute/10+0x30; //然后%10获得个位
minchange[1]=minute%10+0x30;
sechange[0]=second/10+0x30;
sechange[1]=second%10+0x30;
write_sfm(0xC7,houchange); //将hourchange写入相应的地址
write_sfm(0xCa,minchange);
write_sfm(0xCd,sechange);
}
void clock_init() //时钟的初始画面
{
string(0x80,date); //显示" H.I.T.CHINA "
string(0xc0,time); // " TIME 23:59:55 "
}
void string(uchar ad,uchar *s)
{
write_command(ad); //写入地址
while(*s>0) //在该地址用指针写入数组
{
write_data(*s++); //写函数
delay(100);
}
}
void delay(uint j) //延时函数
{
uchar i=250;
for(;j>0;j--)
{
while(--i);
i=249;
while(--i);
i=250;
}
}
void check_busy(void)
{
uchar dt;
do
{
dt=0xff;
E=0;
RS=0;
RW=1;
E=1;
dt=out;
}while(dt&0x80);
E=0;
}
void write_command(uchar com)
{
check_busy();
E=0;
RS=0;
RW=0;
out=com;
E=1;
_nop_();
E=0;
delay(1);
}
void write_data(uchar dat)
{
check_busy();
E=0;
RS=1;
RW=0;
out=dat;
E=1;
_nop_();
E=0;
delay(1);
}
void lcd_initial(void)
{
RW=0;
E=0;
write_command(0x3C);
write_command(0x0C);
write_command(0x06);
write_command(0x01);
write_command(0x80);
delay(1);
}
void write_sfm(uchar ad,uchar *s) //写入数据函数
{
write_command(ad); //先写地址
for(box=0;box<2;box++)//用for循环将数组的数据写入
{
write_data(s[box]);
delay(100);
}
}
void main(void)
{
lcd_initial(); //LCD初始化
clock_init(); //设置时钟开机画面
TMOD=0x01; //时钟模式选择方式1
EA=1; //开启总中断
ET0=1; //打开T0定时器的中断
TH0=0x3C; //定时50ms
TL0=0xB0;
int_time=0; //初始化秒计时器
second=55; //初始化秒
minute=59; //初始化分
hour=23; //初始化时
TR0=1; //打开定时器
while(1) //无限循环
{
displaytime();//写入上面初始化的数据
if((P1&0x80)==0x00) //修改时间按键
{ //按下按键一时
TR0=0; //定时器停止
if((P1&0x40)==0x00) //按下按键二
{
hour++; //小时位+1
displaytime(); //及时显示
if(hour==24) //如果满24归0
{
hour=0;
displaytime(); //显示
while((P1&0x40)==0x00);//如果按键时间过长在这里循环
}
}
if((P1&0x20)==0x00) //按键三控制分
{
minute++;
displaytime();
if(minute==60)
{
minute=0;
displaytime();
}
while((P1&0x20)==0x00);
}
}while((P1&0x10)!=0x00);//按下按键四,时间设置完毕
TH0=0x3C; //重装定时器
TL0=0xB0;
TR0=1; //开始计时
while((P1&0x80)==0x00);//按键一时间过长在此循环
}
}
}
void T0_interserve(void) interrupt 1//中断函数主要用作计时器
{
int_time++;
if(int_time==20) //满1s
{
int_time=0;
second++;
}
if(second==60) //满1min
{
second=0;
minute++;
}
if(minute==60) //满1hour
{
minute=0;
hour++;
}
if(hour==24)
{
hour=0;
}
TH0=0x3c; //重新装载时间
TL0=0xB0;
}
2、运行结果仿真演示
按下按键一——进入校时模式
按下按键二——小时+1
按下按键三——分+1
按下按键四——完成校时,时钟开始显示
四、最后说两句
从上一次写数字钟实验到现在,已经有大概四十二天了吧,想起上次在学校发下毒誓说“不行,我一定要用单片机写出来”,到现在终于写了出来,不得不说其中真的学到了很多,支撑我写下去的其实是——无聊哈哈,当然也挺艰难的,还好我在家无聊的很,有的是时间看。哈哈,再来几把平安京快乐一下,反正快乐就完事了~~~~
欢迎大家一起来讨论呀~。
会水的芝麻
在家
2019.1.31