基于proteus的51单片机开发实例20-LCD12864液晶显示汉字

1. 基于proteus的51单片机开发实例20-LCD12864液晶显示汉字

1.1. 实验目的

基于proteus的51单片机开发实例20-LCD12864液晶显示汉字

图1 LCD128*64液晶电路

我们已经学习了数码管显示数字,LCD1602液晶显示字母和数字,本例中,我们来学习使用LCD12864液晶显示汉字。目的是了解LCD12864液晶的电路设计和编程方法。

1.2. 设计思路

本实例使用51单片机设计LCD128*64液晶的显示驱动电路,并编写汉字显示程序。液晶数据端口数据收发采用并行通信方式,单片机P2口的8位接到LCD126*64液晶的8个数据端口。然后使用单片机P3口的5个I/O口作为液晶读写控制信号的控制端口。

1.3. 基础知识

1.3.1. LCD128*64液晶简述

从字面来理解LCD128*64液晶:其横向可以显示128个点,纵向可以显示64个点。每一个点对应可以显示一个二进制位。一个数字或字母的显示需要8*8个点,一个汉字的显示则需要16*16个点。

使用LCD128*64液晶显示信息时,需要把显示信息先保存到液晶的数据存储器RAM中。

现在市面上的LCD128*64液晶有两大类:带字库和不带字库。这两个的最大区别是汉字显示的问题。如果不带字库,为了显示一个汉字,就需要传送一大批点阵数据。如果带字库,显示一个汉字,仅仅需要传送两个字节汉字内码。

具体到我们的实例都是在proteus环境下实现的,而proteus是英国人开发的软件,它里面的128*64液晶不带字库,所以我们要显示汉字就得用字模软件生成字库,然后编程驱动这一堆数据来显示汉字。

本例使用的128*64液晶的内部结构如下图所示。

基于proteus的51单片机开发实例20-LCD12864液晶显示汉字

LCD128*64内部结构

从图中可以看出,该液晶实际上是由左、右两块独立的64*64液晶拼接而成的。这两块液晶分别由CS1和CS2两个片选信号来选择。

LCD128*64的控制指令

1、显示控制指令

RW=0,RS=0时,向数据总线上发送0x3f表示打开液晶显示,发送0x3e表示关闭液晶显示。

2、显示起始行设置指令

RW=0,RS=0时,向数据向上发送11xx xxxx,低6位表示起始行的行号(0~63)。

3、页地址设置指令

RW=0,RS=0时,向数据总线发送1011 1xxx,低3位表示所要设置的页地址(0~7)。

4、列地址设置指令

RW=0,RS=0时,向数据总线发送01xx xxxx。低6位表示所要设置的列地址(0~63).页地址和列地址共同决定了显示的位置,设置了这两个地址,单片机就能用读、写指令对该地址进行数据读写。

5、读状态指令

RW=1,RS=0时,读取数据总线的状态。

尤其是DB7的状态,该状态指示液晶的空闲状态。改为读出为1,表示液晶处于忙状态,此时不宜对液晶进行读写操作。为0时,表示液晶处于空闲状态,可以对液晶进行读写操作。

6、写数据指令

RW=0,RS=1时,此时允许向总线写数据。

7、读数据

RW=1,RS=1时,可以读取显示的数据。

1.3.2. 汉字字模生成和提取

本例中我们使用的字模提取工具是“字模提取 V2.2”软件。下面介绍一下使用方法。

打开该软件,在文字输入区输入汉字,使用ctrl+enter组合键结束文字的输入。

基于proteus的51单片机开发实例20-LCD12864液晶显示汉字

输入汉字

然后在参数设置中,首先选择汉字的字体和大小。

基于proteus的51单片机开发实例20-LCD12864液晶显示汉字

选择字体和大小

在其它参数中,如下图所示选择。

基于proteus的51单片机开发实例20-LCD12864液晶显示汉字

其他参数

然后进入“提取方式”页面,选择C51格式,就会生成字模了。

基于proteus的51单片机开发实例20-LCD12864液晶显示汉字

生成字模

1.4. 电路设计

本实例电路如图1所示。对于LCD128*64的数据通信采用并行方式,P2口接液晶的D0~D7口,另外用单片机的P3.3~P3.7口连接液晶的控制端口E、RW、RS、CS1、CS2。

1.5. 程序设计

程序代码如下。


#include<at89s51.h>      //
#include<intrins.h>    //


//LCD128*64指令
#define  LCD_OFF                0x3E    //关显示
#define  LCD_ON                 0x3F    //开显示
#define  BEGIN                  0xC0    //设置起始行
#define  SET_PAGE               0xB8    //设置起始页
#define  SET_Y                  0x40    //设置起始列


//LCD控制引脚定义
sbit     CS1=P3^3;
sbit     CS2=P3^4;
sbit     RS=P3^5;
sbit     RW=P3^6;
sbit     E=P3^7; 

//字模:老马识途单片机
unsigned char code DisData1[]=
{0x20,0x20,0x24,0x24,0x24,0x24,0xBF,0x64,0x24,0x34,0x28,0x24,0x22,0x20,0x20,0x00,
0x10,0x08,0x04,0x02,0x3F,0x45,0x44,0x44,0x42,0x42,0x42,0x41,0x78,0x00,0x00,0x00};//

unsigned char code DisData2[]=
{0x00,0x02,0x02,0xF2,0x82,0x82,0x82,0x82,0x82,0x82,0xFE,0x80,0x80,0x80,0x00,0x00,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x48,0x80,0x40,0x3F,0x00,0x00};//

unsigned char code DisData3[]=
{0x40,0x40,0x42,0xCC,0x00,0x00,0x00,0xFC,0x04,0x04,0x04,0x04,0x04,0xFC,0x00,0x00,
0x00,0x00,0x00,0x3F,0x10,0x88,0x40,0x23,0x19,0x01,0x01,0x09,0x11,0x23,0xC0,0x00};//

unsigned char code DisData4[]=
{0x40,0x40,0x42,0xCC,0x00,0x90,0x88,0x94,0x92,0xF1,0x92,0x94,0x88,0x90,0x10,0x00,
0x00,0x40,0x20,0x1F,0x20,0x48,0x46,0x50,0x60,0x5F,0x40,0x40,0x42,0x4C,0x40,0x00};//

unsigned char code DisData5[]=
{0x00,0x00,0xF8,0x49,0x4A,0x4C,0x48,0xF8,0x48,0x4C,0x4A,0x49,0xF8,0x00,0x00,0x00,
0x10,0x10,0x13,0x12,0x12,0x12,0x12,0xFF,0x12,0x12,0x12,0x12,0x13,0x10,0x10,0x00};//

unsigned char code DisData6[]=
{0x00,0x00,0x00,0xFE,0x20,0x20,0x20,0x20,0x20,0x3F,0x20,0x20,0x20,0x20,0x00,0x00,
0x00,0x80,0x60,0x1F,0x02,0x02,0x02,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,0x00,0x00};//

unsigned char code DisData7[]=
{0x10,0x10,0xD0,0xFF,0x90,0x10,0x00,0xFE,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,0x00,
0x04,0x03,0x00,0xFF,0x00,0x83,0x60,0x1F,0x00,0x00,0x00,0x3F,0x40,0x40,0x78,0x00};//

unsigned char code DisData8[]=
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xEB,0x49,0x49,0x55,0x55,0x22,0x22,0x00,0x00};

unsigned char Y_i;      //列
unsigned char Page_i;   //页


//函数声明
//空闲状态检测
bit CheckBusy(void);

//向液晶写指令
void WriteInstruction(unsigned command);

//向液晶写数据
void WriteData(unsigned dat);

//清除屏幕显示
void ClearLCD(void);

//显示图形
void Draw(unsigned char page,unsigned char yi,unsigned char *ps,unsigned char n);

//显示汉字
void Display_Character(unsigned char *p);
  
//指定显示位置
void gotoxy(unsigned page_i,unsigned y_i);

//延时函数
void delay(void);   





 void main(void)
 {	
   
    ClearLCD();	 //清屏
		gotoxy(2,0);  //指定显示位置
 
	 Display_Character(DisData1);
	 delay();
	 Display_Character(DisData2);
	 delay();
	 Display_Character(DisData3);
	 delay();
	 Display_Character(DisData4);
	 delay();
	 Display_Character(DisData5);
	 delay();
	 Display_Character(DisData6);
	 delay();
	 Display_Character(DisData7);
	 delay();
	 
    while(1)               
	 { 	
 	  	    
	 }			  
}



bit CheckBusy(void)
{
   bit flag;
    RW=1;         //RW=1,RS=0时,E=1时,状态送到数据总线
    RS=0;
   E=1;
	 _nop_();
	 _nop_();
	 _nop_();
	 _nop_();
    P2=0x00;      
	flag=(bit)P2&0x80;   
 	E=0;          
    RS=1;     	 
    RW=1;
	 return flag;
}


void WriteInstruction(unsigned command)
{
  while(CheckBusy==1) ;            
   RW = 0;         
   RS = 0;         
  	P2=command;     
	_nop_();
	_nop_();
  	E=1;
	_nop_();
   _nop_();  
  	E=0;           
  	RS=1;          
  	RW=1;  
}


void WriteData(unsigned dat)
{
  while(CheckBusy==1) ;   
   RW=0;   
  	RS=1;   
  	E=1;
	_nop_();
   _nop_();
  	P2=dat;	
	_nop_();
   _nop_();
  	E=0;     
   _nop_();
   _nop_();
  	RS=0;   
  	RW=1;    
  	
}


void ClearLCD(void)
{
  unsigned char  i,j;
   CS1=1;	
   CS2=1; 
   WriteInstruction(LCD_ON);   
   WriteInstruction(BEGIN);    
  for(i=0;i<8;i++)
   {
     WriteInstruction(SET_PAGE+i);   
     WriteInstruction(SET_Y);       
      for(j=0;j<64;j++)
         WriteData(0x80);          
   } 
                    
}


void Draw(unsigned char page,unsigned char yi,unsigned char *ps,unsigned char n)
{
        unsigned char i;
        WriteInstruction(SET_PAGE+page); 
        WriteInstruction(SET_Y+yi);       
        for(i=0;i<n;i++)                 
        {
           WriteData(*ps);             
           ps++;                       
        }
}



void Display_Character(unsigned char *p)
{			
    if (Y_i<64)  
		{
       		CS1=0;                
       		CS2=1;                 
       		Draw(Page_i,Y_i,p,8);      
       		Draw(Page_i,Y_i+8,p+8,8);   
       		Draw(Page_i+1,Y_i,p+16,8);
       		Draw(Page_i+1,Y_i+8,p+24,8);  
     	} 
	else	 
     	{
       		CS1=1;	
       		CS2=0;                     
       		Draw(Page_i,Y_i-64,p,8);       
       		Draw(Page_i,Y_i-56,p+8,8);	
     		Draw(Page_i+1,Y_i-64,p+16,8);
     		Draw(Page_i+1,Y_i-56,p+24,8);
     	}
        Y_i=Y_i+16; 
}
  


void gotoxy(unsigned page_i,unsigned y_i)
{
     
	  Page_i=page_i;  
	  Y_i=y_i;       
} 



 void delay(void)   
{
   unsigned int m,n;
	
	 for(m=0;m<200;m++)
	  for(n=0;n<250;n++);
 }


LCD128*64液晶的工作流程如下:清屏(初始化)-指定显示位置(页地址和列地址的选择)-向指定区域RAM送待显示数据。

1.6. 实例仿真

将写好的程序编译生成HEX文件,然后将HEX文件转载到proteus电路中的单片机内,开始仿真。液晶会逐个显示“老马识途单片机”这几个字。

视频加载中...

1.7. 总结

通过本实例,我们了解LCD128*64液晶的工作原理、编程实现。至此我们已经学习了数码管,字符液晶、点阵液晶的知识,这对我们以后的综合实例的学习打下了坚实的基础。