51驱动LCD12864
LCD12864与LCD1602最大的区别在于LCD12864可以显示汉字,同时也可以拿来画图;当然,作为图形显示不推荐lcd12864,推荐NOKIA5110
12864引脚基本和1602的引脚吻合,大部分的模块多出来两个引脚,一个是RST复位引脚,另一个是PSB通讯模式选择引脚,具体描述见下图
12864指令基本和1602相同,读写时序也应当是先读取忙标志后进行写入,命令列表如下
一般来说,基本指令集用来显示汉字足够了,在开始配置12864之前先要让模块退出复位,然后选择PSB选择相应的通讯模式,接着还要写入相应的模式命令,确定是8位MPU通讯还是4位MPU通讯
对于12864指令集的详细描述代码中会有
#ifndef __LCD12864_H_ #define __LCD12864_H_ #include "common.h" #include "delay.h" # include <intrins.h> //12864基本指令集 /***************************************************************************/ #define LCD12864_SHOW_CLEAR 0X01 #define LCD12864_POINT_ZERO 0X02 #define LCD12864_ENTRY_MODE 0X04 //BIT1 指针自动+1 1 指针自动-1 0 //BIT0 屏幕跟随指针移动 1 屏幕不移动 0 #define LCD12864_DISPLAY_STATUS 0X08 //BIT0 1游标闪烁˸ 0游标不闪烁 //BIT1 1游标显示 0游标不显示 //BIT2 1开显示 0关显示 #define LCD12864_CURSOR_MODE 0X10 //BIT3 显示跟随移动 1 显示不跟随移动 0 //BIT2 游标右移 1 游标左移0 #define LCD12864_FUN_SET 0X20 //BIT4 1八位并口 0 四位通讯接口 //BIT2 1扩充指令集 0基础指令集 #define LCD12864_CGRAM_SET 0X40//CGRAM(绘图)基础地址 //BIT0-BIT5 CGRAM地址 #define LCD12864_DDRAM_SET 0X80//设定LCD地址 //BIT0-BIT5 DDRAM地址(显示字符) /***********************************************************************************************/ void Lcd12864Init(void); void Lcd12864SetPos(u8 x,u8 y); void Lcd12864ShowStr(u8 x,u8 y,u8* buffer);//不能进行中英文混合显示 #endif
#include "lcd12864.h" sbit LCD12864_RS_PIN = p07; sbit LCD12864_RW_PIN = p06; sbit LCD12864_EN_PIN = p05; sbit LCD12864_PSB_PIN = p04; sbit LCD12864_RST_PIN = p03; #define LCD12864_DATA P2 #define LCD_RS_CMD LCD12864_RS_PIN = 0 #define LCD_RS_DAT LCD12864_RS_PIN = 1 #define LCD_RW_WRITE LCD12864_RW_PIN = 0 #define LCD_RW_READ LCD12864_RW_PIN = 1 #define LCD_EN_HIGH LCD12864_EN_PIN = 1 #define LCD_EN_LOW LCD12864_EN_PIN = 0 #define LCD_PSB_COM LCD12864_PSB_PIN = 0 #define LCD_PSB_LPT LCD12864_PSB_PIN = 1 #define LCD_RST_LOW LCD12864_RST_PIN = 0 #define LCD_RST_HIGH LCD12864_RST_PIN = 1 static void delay(unsigned int m) { unsigned int i,j; for(i=0;i<m;i++) for(j=0;j<10;j++); } static bit Lcd12864ReadStatus(void) { bit result; LCD_RS_CMD; LCD_RW_READ; LCD_EN_HIGH; _nop_(); _nop_(); _nop_(); _nop_(); result = (bit)(LCD12864_DATA&0x80); LCD_EN_LOW; return result; } static void Lcd12864WriteCommand(u8 command) { while(Lcd12864ReadStatus()); LCD_RS_CMD; LCD_RW_WRITE; LCD_EN_LOW; _nop_(); _nop_(); LCD12864_DATA = command; _nop_(); _nop_(); _nop_(); _nop_(); LCD_EN_HIGH; _nop_(); _nop_(); _nop_(); _nop_(); LCD_EN_LOW; } static void Lcd12864WriteData(u8 dat) { while(Lcd12864ReadStatus()); LCD_RS_DAT; LCD_RW_WRITE; LCD_EN_LOW; _nop_(); _nop_(); LCD12864_DATA = dat; _nop_(); _nop_(); _nop_(); _nop_(); LCD_EN_HIGH; _nop_(); _nop_(); _nop_(); _nop_(); LCD_EN_LOW; } // 1 lpt 0 com static void Lcd12864SelMode(u8 mode) { delay(40); if(mode) { LCD_PSB_LPT; } else { LCD_PSB_COM; } delay(1); } static void Lcd12864Rst(void) { LCD_RST_LOW; delay(1); LCD_RST_HIGH; delay(10); } void Lcd12864Init(void) { Lcd12864SelMode(1); Lcd12864Rst(); Lcd12864WriteCommand(0x30); // delay(100); Lcd12864WriteCommand(0x30); //八位并口,基础指令集 delay(37); Lcd12864WriteCommand(0x08); //关闭显示和游标 delay(100); Lcd12864WriteCommand(0x10); //游标不跟随 delay(100); Lcd12864WriteCommand(0x0C); //开显示 delay(100); Lcd12864WriteCommand(0x01); //清屏 delay(10); Lcd12864WriteCommand(0x06); //AC自动+ 屏幕不移动 delay(100); } void Lcd12864SetPos(u8 x,u8 y) { u8 pos = 0; switch(y) { case 1: pos = 0x80; break; case 2: pos = 0x90; break; case 3: pos = 0x88; break; case 4: pos = 0x98; break; } if(x>=8)x = 8; pos += x; Lcd12864WriteCommand(pos); } void Lcd12864ShowStr(u8 x,u8 y,u8* buffer) { u8 i = 0; Lcd12864SetPos(x,y); for(i = 0; i < 16-2*x;i++) { if(*(buffer+i) == '\0')break; else { Lcd12864WriteData(*(buffer+i)); } } }
需要注意的是,12864每次写入的时候不能中英文同时混合写入,这样会造成乱码,因为就编码来讲,一个汉字空间,是可以容纳两个ascii码字符的,所以当一个英文字母和一个汉字在一起的时候,英文字符八位编码,汉字16位编码,LCD控制器将英文的八位编码和汉字的前八位编码当成一个汉字来显示,当然就会出错了
当然,这也就是说,显示汉字的时候一定要保证汉字的第一个字符一定得是当前地址写入的第一个字符,不能是第二个,而汉字的第一个编码一般都是大于0x80的,所以遇到大于0x80数据的时候进行判断是不是当前地址写入的第一个字符,不是则重新设置地址,就能防止汉字乱码出现了
另外,51编译器keil需要选择ansci编码,选择其他编码,汉字是会变成乱码的,这纯粹是编码格式问题,嗯,最好的办法是将汉字编码变成数组依次写入,这样就能避免编辑器造成的编码问题了