原创 LCD1602演示程序(很多函数哦)

2009-5-21 21:05 6329 7 21 分类: MCU/ 嵌入式

zipLCD1602演示程序(很多函数哦)控制芯片为HD44780


里面还有HD44780器件手册


函数都是经过测试的,实物显示都通过了,呵呵,请大家放心使用^_^


呵呵,支持四线数据接口模式,可以任意切换编程,只须改模式选择Port_Type_Select就可以咯!很方便的。


     并且我说一下我的个人体会,希望大家在写程序的时候,最好考虑一下程序的可移植性,而且要方便更改参数和硬件资源的选择,最好使用条件编译,任意切换硬件资源,可以方便以后更改参数,就会省去以后不少的不必要的麻烦和错误以及宝贵的时间!!!


里面有标准测试,如果您觉得好的话,请您帮忙顶一下希望有更多的朋友能知道的更多,更好,学习得更快^_^一起努力加油,写出更好的功能函数。


点击开大图


先简单介绍一下功能函数吧:


/*--------------------------------------------------------------*/
//模式选择(条件编译)
#define Port_Type_Select 1 //=1, 选择八位数据模式
        //=0, 选择四位数据模式, LCD高四位接MCU端口高四位


/*--------------------------------------------------------------*/
//函数声明
void LCD_busy  (void);             //检测LCD是否忙
void LCD_init  (void);             //LCD初始化
void LCD_cmd   (unsigned char cmd);          //写入指令
void LCD_dat   (unsigned char dat);          //写入数据
void LCD_pos   (unsigned char x, unsigned char y);      //显示定位
void LCD_printc(unsigned char x, unsigned char y, unsigned char c);  //定位输出字符
void LCD_prints(unsigned char x, unsigned char y, unsigned char *s); //定位输出字符串
void LCD_printn(unsigned char x, unsigned char y, unsigned int num); //定位输出16位二进制数字


unsigned char LCD_current_addr(void);         //读出AC当前地址(DB6~DB0)或忙标志位DB7
unsigned char LCD_current_addr_dat(void);        //读出AC当前地址的数据
unsigned char LCD_addr_dat(unsigned char x, unsigned char y);   //读出AC指定地址的数据
void LCD_pos_CG(unsigned char x, unsigned char *CGRAM_dat);    //指定地址(x: 0-7)写入8bytes数据CGRAM


/*-------------------------------------------------------------*/
//光标、画面移动,不影响DDRAM
#define LCD_LEFT_MOVE   LCD_cmd(0x18); //LCD显示左移一位
#define LCD_RIGHT_MOVE   LCD_cmd(0x1c); //LCD显示右移一位
#define LCD_CURSOR_LEFT_MOVE LCD_cmd(0x10); //光标左移一位
#define LCD_CURSOR_RIGHT_MOVE LCD_cmd(0x14); //光标右移一位


/*--------------------------------------------------------------*/
//设置显示、光标及闪烁开、关
#define LCD_DISPLAY_ON    LCD_cmd(0x0c); //LCD开显示
#define LCD_DISPLAY_OFF   LCD_cmd(0x08); //LCD关显示
#define LCD_CURSOR_ON   LCD_cmd(0x0e); //光标显示
#define LCD_CURSOR_OFF   LCD_cmd(0x0c); //光标不显示
#define LCD_CURSOR_BLINK_ON  LCD_cmd(0x0f); //光标闪烁
#define LCD_CURSOR_BLINK_OFF LCD_cmd(0x0e); //光标不闪烁


#define LCD_GO_HOME    LCD_cmd(0x02); //AC=0,光标、画面回HOME位, DDRAM内容不变
#define LCD_CLR     LCD_cmd(0x01); //LCD清屏, 清除DDRAM, 清除屏幕, 置AC为0, 光标回位?


/*--------------------------------------------------------------*/
//工作方式设置
#define LCD_DISPLAY8_DOUBLE_LINE LCD_cmd(0x38); //两行显示8-bits
#define LCD_DISPLAY8_SINGLE_LINE LCD_cmd(0x30); //单行显示8-bits
#define LCD_DISPLAY4_DOUBLE_LINE LCD_cmd(0x28); //两行显示4-bits
#define LCD_DISPLAY4_SINGLE_LINE LCD_cmd(0x20); //单行显示4-bits



/*--------------------------------------------------------------*/
//输入方式设置
#define LCD_AC_AUTO_INCREMENT LCD_cmd(0x06); //数据读、写操作后,AC自动加 1
#define LCD_AC_AUTO_DECREASE LCD_cmd(0x04); //数据读、写操作后,AC自动减 1
#define LCD_MOVE_ENABLE   LCD_cmd(0x07); //数据读、写操作,画面平移
#define LCD_MOVE_DISENABLE  LCD_cmd(0x06); //数据读、写操作,画面不动


 


以下是液晶驱动头文件:


/*--------------------------------------------------------------*/
//File: LCD1602_8A.H
//Time: 20:10
//Modi: 09-5-17



/*--------------------------------------------------------------*/
//防止被重复定义
#ifndef __LCD1602_8A_H__   
#define __LCD1602_8A_H__



/*--------------------------------------------------------------*/
//模式选择(条件编译)
#define Port_Type_Select 1 //=1, 选择八位数据模式
        //=0, 选择四位数据模式, LCD高四位接MCU端口高四位
#define Int_Transfer  1 //=1,   允许中断服务函数调用
        //=0, 不允许中断服务函数调用



/*--------------------------------------------------------------*/
//LCD1602与单片机接口定义
sfr  LCD_IO = 0x80;   //P0-0x80,P1-0x90,P2-0xA0,P3-0xB0;
sbit LCD_RS = P2^0;   //LCD数据/命令选择端(H/L)
sbit LCD_RW = P2^1;   //LCD  读/写  选择端(H/L)
sbit LCD_EN = P2^2;   //LCD使能控制端


 


/*--------------------------------------------------------------*/
//工作方式设置
#define LCD_DISPLAY8_DOUBLE_LINE LCD_cmd(0x38); //两行显示8-bits
#define LCD_DISPLAY8_SINGLE_LINE LCD_cmd(0x30); //单行显示8-bits
#define LCD_DISPLAY4_DOUBLE_LINE LCD_cmd(0x28); //两行显示4-bits
#define LCD_DISPLAY4_SINGLE_LINE LCD_cmd(0x20); //单行显示4-bits



/*--------------------------------------------------------------*/
//输入方式设置
#define LCD_AC_AUTO_INCREMENT LCD_cmd(0x06); //数据读、写操作后,AC自动加 1
#define LCD_AC_AUTO_DECREASE LCD_cmd(0x04); //数据读、写操作后,AC自动减 1
#define LCD_MOVE_ENABLE   LCD_cmd(0x07); //数据读、写操作,画面平移
#define LCD_MOVE_DISENABLE  LCD_cmd(0x06); //数据读、写操作,画面不动


 


/*--------------------------------------------------------------*/
//设置显示、光标及闪烁开、关
#define LCD_DISPLAY_ON    LCD_cmd(0x0c); //LCD开显示
#define LCD_DISPLAY_OFF   LCD_cmd(0x08); //LCD关显示
#define LCD_CURSOR_ON   LCD_cmd(0x0e); //光标显示
#define LCD_CURSOR_OFF   LCD_cmd(0x0c); //光标不显示
#define LCD_CURSOR_BLINK_ON  LCD_cmd(0x0f); //光标闪烁
#define LCD_CURSOR_BLINK_OFF LCD_cmd(0x0e); //光标不闪烁


#define LCD_GO_HOME    LCD_cmd(0x02); //AC=0,光标、画面回HOME位, DDRAM内容不变
#define LCD_CLR     LCD_cmd(0x01); //LCD清屏, 清除DDRAM, 清除屏幕, 置AC为0, 光标回位?


 


/*--------------------------------------------------------------*/
//光标、画面移动,不影响DDRAM
#define LCD_LEFT_MOVE   LCD_cmd(0x18); //LCD显示左移一位
#define LCD_RIGHT_MOVE   LCD_cmd(0x1c); //LCD显示右移一位
#define LCD_CURSOR_LEFT_MOVE LCD_cmd(0x10); //光标左移一位
#define LCD_CURSOR_RIGHT_MOVE LCD_cmd(0x14); //光标右移一位


 


/*--------------------------------------------------------------*/
//LCD1602地址相关
/*
#define LINE1_HEAD  0x80  //第一行DDRAM起始地址
#define LINE2_HEAD  0xc0  //第二行DDRAM起始地址
#define LINE1   0   //第一行
#define LINE2   1   //第二行
#define LINE_LENGTH  16   //每行的最大字符长度(40-DDRAM)


 


/*--------------------------------------------------------------*/
//函数声明
void LCD_busy  (void);             //检测LCD是否忙
void LCD_init  (void);             //LCD初始化
void LCD_cmd   (unsigned char cmd);          //写入指令
void LCD_dat   (unsigned char dat);          //写入数据
void LCD_pos   (unsigned char x, unsigned char y);      //显示定位
void LCD_printc(unsigned char x, unsigned char y, unsigned char c);  //定位输出字符
void LCD_prints(unsigned char x, unsigned char y, unsigned char *s); //定位输出字符串
void LCD_printn(unsigned char x, unsigned char y, unsigned int num); //定位输出16位二进制数字


unsigned char LCD_current_addr(void);         //读出AC当前地址(DB6~DB0)或忙标志位DB7
unsigned char LCD_current_addr_dat(void);        //读出AC当前地址的数据
unsigned char LCD_addr_dat(unsigned char x, unsigned char y);   //读出AC指定地址的数据
void LCD_pos_CG(unsigned char x, unsigned char *CGRAM_dat);    //指定地址(x: 0-7)写入8bytes数据CGRAM



/*--------------------------------------------------------------*/
//读出AC当前地址(DB6~DB0)或忙标志位DB7
#if Port_Type_Select //选择八位数据模式
unsigned char LCD_current_addr(void)
{
 unsigned char ac_addr;


 LCD_EN = 0;
 LCD_RS = 0;   //指令
 LCD_RW = 1;   //读出
 LCD_IO = 0xff;  //端口置为输入方式(P0)
 LCD_EN = 1;
 ac_addr = LCD_IO;
 LCD_EN = 0;


 return (ac_addr);
}


#else     //选择四位数据模式
unsigned char LCD_current_addr(void)
{
 unsigned char ac_addr;


 LCD_EN = 0;
 LCD_RS = 0;     //指令
 LCD_RW = 1;     //读出
 LCD_IO |= 0xf0;    //端口置为输入方式(P0)
 LCD_EN = 1;
 ac_addr = LCD_IO & 0xf0; //高四位
 LCD_EN = 0;


 LCD_EN = 1;
 ac_addr |= LCD_IO >> 4;  //低四位
 LCD_EN = 0;


 return (ac_addr);
}
#endif



/*--------------------------------------------------------------*/
//检测LCD忙状态
#if Int_Transfer   //允许中断服务函数调用  
void LCD_busy(void)
{
 unsigned char ac_dat;
 unsigned char busy_flag;


 do
 {
  ac_dat = LCD_current_addr();
  busy_flag = ac_dat & 0x80;
 }while(busy_flag);  //=1表示忙, =0表示空闲
}


#else      //不允许中断服务函数调用
void LCD_busy(void)
{
 unsigned char ac_dat;
 bit busy_flag;


 do
 {
  ac_dat = LCD_current_addr();
  busy_flag = (bit)(ac_dat & 0x80);
 }while(busy_flag);  //=1表示忙, =0表示空闲
}
#endif



/*--------------------------------------------------------------*/
//读出AC当前地址的数据
#if Port_Type_Select  //选择八位数据模式
unsigned char LCD_current_addr_dat(void)
{
 unsigned char addr_dat;
// unsigned char i;
 LCD_busy();    //或者检查忙最可靠
// for(i = 0; i < 3; i++) //要连续读出三次才会有效
 {
  LCD_EN = 0;
  LCD_RS = 1;   //数据
  LCD_RW = 1;   //读出
  LCD_IO = 0xff;  //端口置为输入方式(P0)
  LCD_EN = 1;
  addr_dat = LCD_IO;
  LCD_EN = 0;
 }


 return (addr_dat);
}


#else      //选择四位数据模式
unsigned char LCD_current_addr_dat(void)
{
 unsigned char addr_dat;
// unsigned char i;
 LCD_busy();      //或者检查忙最可靠
// for(i = 0; i < 3; i++)   //要连续读出三次才会有效
 {
  LCD_EN = 0;
  LCD_RS = 1;     //数据
  LCD_RW = 1;     //读出


  LCD_IO |= 0xf0;    //端口置为输入方式(P0)
  LCD_EN = 1;
  addr_dat = LCD_IO & 0xf0; //高四位
  LCD_EN = 0;


  LCD_EN = 1;
  addr_dat |= LCD_IO >> 4; //低四位
  LCD_EN = 0;
 }


 return (addr_dat);
}
#endif



/*--------------------------------------------------------------*/
//写入指令
#if Port_Type_Select  //选择八位数据模式
void LCD_cmd(unsigned char cmd)
{
 LCD_busy();    //检测忙
 LCD_RS = 0;    //指令
 LCD_RW = 0;    //写入
 LCD_EN = 1;
 LCD_IO = cmd;   //传指令
 LCD_EN = 0;    //下降沿有效
}


#else      //选择四位数据模式
void LCD_cmd(unsigned char cmd)
{
 LCD_busy();    //检测忙
 LCD_IO &= 0x0f;   //清高四位
 LCD_RS = 0;    //指令
 LCD_RW = 0;    //写入
 LCD_EN = 1;
 LCD_IO |= cmd & 0xf0; //写高四位
 LCD_EN = 0;    //下降沿有效


 cmd <<= 4;    //低四位移到高四位
 LCD_IO &= 0x0f;   //清高四位
 LCD_EN = 1;
 LCD_IO |= cmd & 0xf0; //写高四位
 LCD_EN = 0;    //下降沿有效
}
#endif



/*--------------------------------------------------------------*/
//写入数据
#if Port_Type_Select  //选择八位数据模式
void LCD_dat(unsigned char dat)
{
 LCD_busy();    //检测忙
 LCD_RS = 1;    //数据
 LCD_RW = 0;    //写入
 LCD_EN = 1;
 LCD_IO = dat;   //传数据
 LCD_EN = 0;    //下降沿有效
}


#else      //选择四位数据模式
void LCD_dat(unsigned char dat)
{
 LCD_busy();    //检测忙
 LCD_IO &= 0x0f;   //清高四位
 LCD_RS = 1;    //数据
 LCD_RW = 0;    //写入
 LCD_EN = 1;
 LCD_IO |= dat & 0xf0; //写高四位
 LCD_EN = 0;    //下降沿有效


 dat <<= 4;    //低四位移到高四位
 LCD_IO &= 0x0f;   //清高四位
 LCD_EN = 1;
 LCD_IO |= dat & 0xf0; //写高四位
 LCD_EN = 0;    //下降沿有效
}
#endif



/*--------------------------------------------------------------*/
//显示定位DDRAM
void LCD_pos(unsigned char x, unsigned char y)
{
 if(y) LCD_cmd(x|0xc0);//y=1第二行显示,y=0第一行显示 0<=x<16(40-DDRAM)
 else LCD_cmd(x|0x80);//数据指针=80+地址码(00H~27H,40H~67H)
}



/*--------------------------------------------------------------*/
//指定地址(x: 0-7)写入8bytes数据CGRAM
void LCD_pos_CG(unsigned char x, unsigned char *CGRAM_dat)
{
 unsigned char i;
  
 x <<= 3;    //转化为6位数据的高三位
 x |=  0x40;
 LCD_cmd(x);    //写入地址
 for(i = 0; i < 8; i++) 
 LCD_dat(CGRAM_dat); //写入数据
}



/*--------------------------------------------------------------*/
//读出AC指定地址的数据
unsigned char LCD_addr_dat(unsigned char x, unsigned char y)
{
 unsigned char addr_dat;
 
 LCD_pos(x, y);      //定位
 addr_dat = LCD_current_addr_dat(); //读出数据


 return (addr_dat);
}



/*--------------------------------------------------------------*/
//定位输出字符
void LCD_printc(unsigned char x, unsigned char y, unsigned char c)
{
 LCD_pos(x, y);
 LCD_dat(c);
}



/*--------------------------------------------------------------*/
//定位输出字符串
void LCD_prints(unsigned char x, unsigned char y, unsigned char *s)
{
 LCD_pos(x, y);
 while(*s)
 {
  LCD_dat(*s);
  s++;
 }
}



/*--------------------------------------------------------------*/
//定位输出16位二进制数字
// 0<= num <65536
void LCD_printn(unsigned char x, unsigned char y, unsigned int num)
{
 char i;
 unsigned char ii;
 unsigned char dat[6];
 for(i = 0; i < 6; i++) dat = 0; i = 0; //初始化数据
 while(num / 10)        //拆位
 {
  dat = num % 10;      //最低位
  num /= 10; i++;  
 }
 dat = num;        //最高位
 ii = i;          //保存dat的位数
 for(; i >= 0; i--) dat += 48;   //转化成ASCII
 LCD_prints(x, y, "     ");     //清显示区域
 LCD_pos(x, y);
 for(i = ii; i >= 0; i--) LCD_dat(dat); //输出数字字符
}



/*--------------------------------------------------------------*/
//LCD初始化
void LCD_init(void)
{
#if Port_Type_Select   //选择八位数据模式
 LCD_DISPLAY8_DOUBLE_LINE //设置LCD为16X2显示,5X7点阵,八位数据接口
#else
 LCD_DISPLAY4_DOUBLE_LINE //设置LCD为16X2显示,5X7点阵,四位数据接口
#endif
 LCD_AC_AUTO_INCREMENT  //LCD显示光标移动设置(光标地址指针加1,整屏显示不移动)
 LCD_DISPLAY_ON    //LCD开显示及光标设置(光标不闪烁,不显示"_")
 LCD_CLR      //清屏
}



/*--------------------------------------------------------------*/
#endif



 

文章评论14条评论)

登录后参与讨论

用户307424 2010-12-7 23:42

hao

用户120337 2010-1-25 21:30

得顶一下

用户223635 2009-6-20 21:50

不错不错。加油。。共同进步。

用户1258202 2009-6-8 19:08

路过,支持一下。。。

用户1640843 2009-5-29 13:05

支持,我也想用用

用户544588 2009-5-28 10:55

楼主很强,佩服你

用户1461177 2009-5-27 16:52

好啊,谢谢

用户149863 2009-5-26 09:03

O(∩_∩)O~,楼上的朋友,您好,我还不会菜单设计,佩服你,比我强,我会继续努力的,网上有很多资料的,你可以搜索得到,我把12864搞定了,就会搞菜单的,加油\(^o^)/~

用户169648 2009-5-25 09:20

我现在在使用LCD320240,用单片机控制,四级菜单,有没有算法啊? 看到你在搞过LCD界面的程序 算法, 能否发给我让我也学习下,谢谢 我的邮箱sw_ge@126.com

用户149863 2009-5-23 23:53

呵呵,1602画点也可以,但是1602字符之间的间距太大了,不好看呀,12864就好些,还可以滚屏,呵呵,我们玩12864吧,我现在还在写12864(KS0108)的显示驱动(我的12864是图形点阵液晶,什么都不带),哈哈,可以显示光标的,全部是由单片机虚拟控制的,可以选择三种字体,两种字体大小8*16/8*8,蛮爽的,而且还可以把字库烧到STC里面EEPROM里面,那就更完美了,明天开始写图形函数,加油↖(^ω^)↗
相关推荐阅读
用户149863 2010-05-22 22:40
LCD简单菜单显示
LCD简单菜单显示显示器件为图形型LCD12864(主控芯片KS0108)什么都不带!包含以下文件:LCD菜单(测试)LCD菜单(简单)LCD菜单(界面)LCD菜单(遥控器)希望对大家有用^_^感兴趣...
用户149863 2010-05-22 14:33
LCD12864(KS0108)液晶演示程序
LCD12864(KS0108)液晶演示程序LCD12864(KS0108)液晶演示程序视频: LCD12864演示程序(什么都不带的液晶) 视频演示网址:http://v.youku.com/v_s...
用户149863 2009-10-22 18:27
AVR代码
AVR单片机程序代码集,给需要的朋友们参考呵呵,都是自己一边学一边写的,一个一个字符从键盘敲出来的^_^希望对大家有用:-)呵呵,编译软件为:  ICCAVR V6.31A版本一共七个压缩包,呵呵,分...
用户149863 2009-10-22 15:18
VGA相关资料
VGA相关资料呵呵^_^如果你想玩的就请下载,有很多东西,都是花了我好几个夜晚才搜到的都是网上的资料:-)有兴趣的可以做做哦 包含以下文件夹:├─VGA+2051│  │  共享-----国外优秀电子...
用户149863 2009-10-10 14:46
PS/2 键盘与单片机
程序打包PS/2 键盘与单片机接口用LCD1602显示调试成功所以拿出来给大家分享,希望对大家有用,呵呵^_^用PS/2键盘做系统输入部分蛮方便的哦!可以使用Backspace/Esc/Tab/Cap...
用户149863 2009-08-17 19:54
AVR端口操作宏定义,便于移植
AVR端口操作宏定义头文件(ICCAVRIO.H),便于移植(ICCAVR编译环境) 压缩包里面有网上的相关资料,把它看完,相信你会更加了解红宏定义的^_^还有头文件在ICCAVRIO.H在Inclu...
我要评论
14
7
关闭 站长推荐上一条 /2 下一条