昨晚下班后研究1602液晶,整了一晚上也没有搞明白,后来想了想,就当它是led好了,直接一个字符一个字符的送进去显示,居然给误打误撞弄出来了,原来驱动液晶真的很简单,哈哈。上午没什么别的事情,抓紧时间写了一个1602的电子钟,带utc同步显示。
//头文件:
#include "reg51.h"
/********io引脚定义***********************************************************/
sbit lcd_rs=p1^0;//定义引脚
sbit lcd_rw=p1^1;
sbit lcd_e=p1^2;
/********宏定义***********************************************************/
#define lcd_data p0
#define busy 0x80 //用于检测lcd状态字中的busy标识
/********数据定义*************************************************************/
unsigned char wdlcd,x,y,ddata,a1;
/********函数声明*************************************************************/
void writedatalcd(unsigned char wdlcd); //写数据
void writecommandlcd(unsigned char wclcd,buysc); //写命令
unsigned char readdatalcd(void); //读数据
unsigned char readstatuslcd(void); //读状态
void lcdinit(void); //初始化
void displayonechar(unsigned char x, unsigned char y, unsigned char ddata); //相应坐标显示字节内容
void delay5ms(void); //延时
void delay400ms(void); //延时
//变量定义:
unsigned char tt;
unsigned char ss;
unsigned char mm;
unsigned char hh;//作为计数时间量
char hh_utc; //协调时
//引脚定义:
sbit key_h=p3^3;//设定小时
sbit key_m=p3^2;//设定分钟
//函数声明:
void display(void);//定义显示函数,参数为显示内容,只显示两位数
void delay(void);
void init(); //初如化函数
void delay_ms (unsigned int a);
//主函数,c语言的入口函数:
void main()
{
init(); //初始化中断控制寄存器
delay400ms(); //启动等待,等lcd讲入工作状态
lcdinit(); //初始化
delay5ms(); //延时片刻(可不要)
while(1){
if(key_m==0){ delay_ms(10);if(key_m==0){mm++;if(mm==60) mm=0;} delay_ms(300);}
if(key_h==0){ delay_ms(10);if(key_h==0){hh++;if(hh==24) hh=0;} delay_ms(300);} //设置
if(ss==60){ss=0;mm=mm++;}//60秒计数进位
if(mm==60){mm=0;hh=hh++;}//60分钟计数进位
if(hh==24){hh=0;}//24小时计数
hh_utc=hh-8;
if(hh_utc<0) hh_utc=24+hh_utc;//utc协调时换算
display(); //显示变量内容
}
}
//初始化函数
void init()
{
tt=0;
tmod=0x01; //设置定时器1为模式一,即16位计算模式
th0=(65536-10000)/256; //给计数寄存器赋值,10毫秒时间
tl0=(65536-10000)%256;
ea=1; //开启总中断
et0=1; //开启定时器0中断
tr0=1; //启定定时器0
}
//中断函数,关键字"interrupt" , 这是c语言的中断函数表示法,1表时定地器0
void timer() interrupt 1
{
th0=(65536-10000)/256; //重新赋值
tl0=(65536-10000)%256;
tt++; //10毫秒加1,加100次为一秒
if(tt==100) {tt=0;ss++;} //100*10ms定时时间为1秒 计数变量加1
}
//显示函数,参数为显示内容,只显示两位数
void display(void)
{
//第一行
lcd_data=85;
displayonechar(0, 0, lcd_data);
lcd_data=84;
displayonechar(1, 0, lcd_data);
lcd_data=67;
displayonechar(2, 0, lcd_data);//显示utc
lcd_data=hh_utc /10+0x30;
displayonechar(5, 0, lcd_data);
lcd_data=hh_utc%10+0x30;
displayonechar(6, 0, lcd_data);//显示协调时小时
lcd_data=0x3a;
displayonechar(7, 0, lcd_data);//显示":"
lcd_data=mm/10+0x30;
displayonechar(8, 0, lcd_data);
lcd_data=mm%10+0x30;
displayonechar(9, 0, lcd_data);//显示协调时分钟
lcd_data=0x3a;
displayonechar(10, 0, lcd_data);//显示":"
lcd_data=ss/10+0x30;
displayonechar(11, 0, lcd_data);
lcd_data=ss%10+0x30;
displayonechar(12, 0, lcd_data);//显示协调时秒钟
//第二行
lcd_data=66;
displayonechar(0, 1, lcd_data);
lcd_data=84;
displayonechar(2, 1, lcd_data);//显示bt
lcd_data=hh/10+0x30;
displayonechar(5, 1, lcd_data);
lcd_data=hh%10+0x30;
displayonechar(6, 1, lcd_data) ;//显示北京时间小时
lcd_data=0x3a;
displayonechar(7, 1, lcd_data);//显示":"
lcd_data=mm/10+0x30;
displayonechar(8, 1, lcd_data);
lcd_data=mm%10+0x30;
displayonechar(9, 1, lcd_data);//显示北京时间分钟
lcd_data=0x3a;
displayonechar(10, 1, lcd_data);//显示":"
lcd_data=ss/10+0x30;
displayonechar(11, 1, lcd_data);
lcd_data=ss%10+0x30;
displayonechar(12, 1, lcd_data);//显示北京时间秒钟
}
//延时子函数,短暂延时'
void delay(void){
unsigned char i=10;
while(i--);
}
void delay_ms (unsigned int a){
unsigned int i;
while( a-- != 0){
for(i = 0; i < 100; i++);
}
}
/***********写数据********************************************************/
void writedatalcd(unsigned char wdlcd)
{
readstatuslcd(); //检测忙
lcd_data = wdlcd;
lcd_rs = 1;
lcd_rw = 0;
lcd_e = 0; //若晶振速度太高可以在这后加小的延时
lcd_e = 0; //延时
lcd_e = 1;
}
/***********写指令********************************************************/
void writecommandlcd(unsigned char wclcd,buysc) //buysc为0时忽略忙检测
{
if (buysc) readstatuslcd(); //根据需要检测忙
lcd_data = wclcd;
lcd_rs = 0;
lcd_rw = 0;
lcd_e = 0;
lcd_e = 0;
lcd_e = 1;
}
/***********读数据********************************************************/
unsigned char readdatalcd(void)
{
lcd_rs = 1;
lcd_rw = 1;
lcd_e = 0;
lcd_e = 0;
lcd_e = 1;
return(lcd_data);
}
/***********读状态*******************************************************/
unsigned char readstatuslcd(void)
{
lcd_data = 0xff;
lcd_rs = 0;
lcd_rw = 1;
lcd_e = 0;
lcd_e = 0;
lcd_e = 1;
while (lcd_data & busy); //检测忙信号
return(lcd_data);
}
/***********初始化********************************************************/
void lcdinit(void)
{
lcd_data = 0;
writecommandlcd(0x38,0); //三次模式设置,不检测忙信号
delay5ms();
writecommandlcd(0x38,0);
delay5ms();
writecommandlcd(0x38,0);
delay5ms();
writecommandlcd(0x38,1); //显示模式设置,开始要求每次检测忙信号
writecommandlcd(0x08,1); //关闭显示
writecommandlcd(0x01,1); //显示清屏
writecommandlcd(0x06,1); //显示光标移动设置
writecommandlcd(0x0c,1); //显示开及光标设置
}
/***********按指定位置显示一个字符*******************************************/
void displayonechar(unsigned char x, unsigned char y, unsigned char ddata)
{
y &= 0x1;
x &= 0xf; //限制x不能大于15,y不能大于1
if (y) x |= 0x40; //当要显示第二行时地址码+0x40;
x |= 0x80; //算出指令码
writecommandlcd(x, 0); //这里不检测忙信号,发送地址码
writedatalcd(ddata);
}
/***********短延时********************************************************/
void delay5ms(void)
{
unsigned int tempcyc = 5552;
while(tempcyc--);
}
/***********长延时********************************************************/
void delay400ms(void)
{
unsigned char tempcyca = 5;
unsigned int tempcycb;
while(tempcyca--){
tempcycb=7269;
while(tempcycb--);
}
}