在我们常用的人机交互显示界面中,除了数码管,LED,以及我们之前已经提到的LCD1602之外,还有一种液晶屏用的比较多。相信接触过单片机的朋友都知道了,那就是12864液晶。顾名思义,12864表示其横向可以显示128个点,纵向可以显示64个点。我们常用的12864液晶模块中有带字库的,也有不带字库的,其控制芯片也有很多种,如KS0108
T6963,ST7920等等。在这里我们以ST7920为主控芯片的12864液晶屏来学习如何去驱动它。(液晶屏采用金鹏的OCMJ4X8C)

关于这个液晶屏的更多信息,请参考它的DATASHEET,附件中有下载。
我们先来了解一下它的并行连接情况。
下面是电路连接图

从上面的图可以看出,液晶模块和单片机的连接除了P0口的8位并行数据线之外,还有RS,RW,E等几根线。其中R/S是指令和数据寄存器的选择控制线(串行模式下为片选),R/W是读写控制线(串行模式下是数据线),E是使能线(串行模式下为时钟线)。
通过这几根控制线和数据线,再结合它的时序图,我们就可以编写出相应的驱动程序啦。
看看并行模式下的写时序图:

根据这个时序图,我们就可以写出写数据或者写命令到LCD12864液晶的子程序。
读时序图如下:

根据这个时序图我们就可以从LCD12864液晶模块内部RAM中读出相应的数据,我们的忙检测函数就是根据这个时序图写出来的。以及后面章节中讲的画点函数等都要用到读时序。
有了这两个时序图,然后我们再看看OCMJ4X8C的相关指令集,就可以编写出驱动程序了。
这里要注意的是指令集分为基本指令集和扩充指令集,其中扩充指令集主要是与绘图相关,在此后的章节中会有相应的介绍。
下面让我们根据这些编写出它的驱动程序吧。
我的硬件测试条件为:STC89C516(11.0592MHz) + OCMJ4X8C
实际显示效果图片如下:

程序部分如下,请结合液晶模块的DATASHEET看程序,这样能够更加快速的弄懂程序的流程。大致有如下几个函数:写数据,写指令,忙检测,初始化,指定地址显示字符串等等。
- #include "reg52.h"
- #include "intrins.h"
- sbit io_LCD12864_RS = P1^0 ;
- sbit io_LCD12864_RW = P1^1 ;
- sbit io_LCD12864_EN = P1^2 ;
- #define io_LCD12864_DATAPORT P0
- #define SET_DATA io_LCD12864_RS = 1 ;
- #define SET_INC io_LCD12864_RS = 0 ;
- #define SET_READ io_LCD12864_RW = 1 ;
- #define SET_WRITE io_LCD12864_RW = 0 ;
- #define SET_EN io_LCD12864_EN = 1 ;
- #define CLR_EN io_LCD12864_EN = 0 ;
- void v_Lcd12864CheckBusy_f( void ) //忙检测函数
- {
- unsigned int nTimeOut = 0 ;
- SET_INC
- SET_READ
- CLR_EN
- SET_EN
- while( ( io_LCD12864_DATAPORT & 0x80 ) &&
( ++nTimeOut != 0 ) ) ;
- CLR_EN
- SET_INC
- SET_READ
- }
- void v_Lcd12864SendCmd_f( unsigned char byCmd )
//发送命令
- {
- v_Lcd12864CheckBusy_f() ;
- SET_INC
- SET_WRITE
- CLR_EN
- io_LCD12864_DATAPORT = byCmd ;
- _nop_();
- _nop_();
- SET_EN
- _nop_();
- _nop_();
- CLR_EN
- SET_READ
- SET_INC
- }
- void v_Lcd12864SendData_f( unsigned char byData )
//发送数据
- {
- v_Lcd12864CheckBusy_f() ;
- SET_DATA
- SET_WRITE
- CLR_EN
- io_LCD12864_DATAPORT = byData ;
- _nop_();
- _nop_();
- SET_EN
- _nop_();
- _nop_();
- CLR_EN
- SET_READ
- SET_INC
- }
- void v_DelayMs_f( unsigned int nDelay )
//延时
- {
- unsigned int i ;
- for( ; nDelay > 0 ; nDelay-- )
- {
- for( i = 125 ; i > 0 ; i--
) ;
- }
- }
- void v_Lcd12864Init_f( void )
//初始化
- {
- v_Lcd12864SendCmd_f( 0x30 ) ;
//基本指令集
- v_DelayMs_f( 50 ) ;
- v_Lcd12864SendCmd_f( 0x01 ) ;
//清屏
- v_DelayMs_f( 50 ) ;
- v_Lcd12864SendCmd_f( 0x06 ) ;
//光标右移
- v_DelayMs_f( 50 ) ;
- v_Lcd12864SendCmd_f( 0x0c ) ;
//开显示
- }
- void v_Lcd12864SetAddress_f( unsigned char x, y ) //地址转换
- {
- unsigned char byAddress ;
- switch( y )
- {
- case 0 :
byAddress = 0x80 + x ;
- break;
- case 1 :
byAddress = 0x90 + x ;
- break ;
- case 2 :
byAddress = 0x88 + x ;
- break ;
- case 3 :
byAddress = 0x98 + x ;
- break ;
- default :
- break ;
- }
- v_Lcd12864SendCmd_f( byAddress ) ;
- }
- void v_Lcd12864PutString_f( unsigned char x, unsigned char y,
unsigned char *pData )
- {
- v_Lcd12864SetAddress_f( x, y ) ;
- while( *pData != '\0' )
- {
- v_Lcd12864SendData_f(
*pData++ ) ;
- }
- }
- void main( void )
- {
- v_Lcd12864Init_f() ;
- v_Lcd12864PutString_f( 0,0, "电子工程师之家") ;
- v_Lcd12864PutString_f( 2,1, "欢迎光临") ;
- v_Lcd12864PutString_f( 0,2, "*LCD12864ST7920*") ;
- v_Lcd12864PutString_f( 0,3, "★○◇◆※☆■△") ;
- while( 1 ) ;
- }
复制代码怎么样,你弄出来了吗,很简单吧~~
下一章节内容将学习如何在LCD12864液晶屏上画图。尽请期待^_^