原创 玩转12864液晶:3串行驱动

2010-4-22 09:56 13318 7 17 分类: MCU/ 嵌入式

 玩转12864液晶:3串行驱动<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />


        驱动芯片是ST792012864液晶电路连接有两种,并行方式和串行方式。通常使用并行方式,但有时候为了节省I/O线,可以使用串行方式,串行方式的传输字节的速率会比并行的慢。


   


<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />

点击看大图


                                                                               串行连接时序图


 


/***********************************************************


函数名称:serial_write_byte


函数功能:负责串行写8bit


入口参数:dat 8bit


出口参数:无


注:


***********************************************************/


void serial_write_byte(unsigned char dat)


{


    unsigned char i;


              for(i=0;i<8;i++)


              {


                     if(dat&0x80)


                            LCD_SID = 1;


                     else


                            LCD_SID = 0;


                     LCD_SCLK = 0;                 //一个时钟周期


                     delay_1us();


                     LCD_SCLK = 1;


                     delay_1us();


                     LCD_SCLK = 0;


                     dat = dat << 1;


                     LCD_SID = 0; //


              }


}


 


串行数据传送共分三个字节完成 


第一字节 串口控制—格式 11111ABC


          A为数据传送方向控制 H表示数据从LCD MCU L表示数据从 MCULCD


          B为数据类型选择 H表示数据是显示数据 L表示数据是控制指令


          C固定为 0


第二字节 (并行)8 位数据的高4 位—格式 DDDD0000


第三字节 (并行)8 位数据的低4 位—格式 0000DDDD


 


/***********************************************************


函数名称:LCD_write_byte


函数功能:写一个字节的数据到12864液晶,包括指令或数据


入口参数:RWRSW_data


出口参数:无


注:RW=1,从液晶读数据到MCURW=0,写一个数据到液晶;


   (一般RW都设为0,即只向液晶写数据,不读数据)


          RS=1,写入的是数据;RS=0,写入的是指令;


    一般模式:RW=0RS=1;写数据


       RW="0"RS=0;写指令


***********************************************************/


void LCD_write_byte(unsigned char RW, unsigned char RS, unsigned char W_data)


{


    unsigned int H_data,L_data,S_ID = 0xf8;  //11111RWRS0


    if(RW == 0)                        //RW=0MCU写一个数据到液晶;


      {


          S_ID &=~ 0x04;


      }


    else                    //RW=1,从液晶读数据到MCU


      {


         S_ID |= 0X04;


      }


    if(RS == 0)                      //RS=1,写入的是数据


      {


         S_ID &=~ 0x02;


      }


    else                      //RS=0,写入的是指令;


      {


         S_ID |= 0X02;


      }


    H_data = W_data;


    H_data &= 0xf0;           //屏蔽低4位的数据


    L_data = W_data;          //xxxx0000格式


    L_data &= 0x<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />0f;           //屏蔽高4位的数据


    L_data <<= 4;             //xxxx0000格式


    LCD_CS = 1;


    serial_write_byte(S_ID);    //发送S_ID


    serial_write_byte(H_data);  //发送H_data


    serial_write_byte(L_data);  //发送L_data


    LCD_CS = 0;


}


 


 


      接着对12864进行初始化


/***********************************************************


函数名称:LCD_init


函数功能:12864液晶初始化


入口参数:dat 8bit


出口参数:无


注:


***********************************************************/


void LCD_Init(void)


{


  delay_1us();


  LCD_write_byte(0,0,0x30);     //功能设置 8位数据,基本指令


  delay_1us();


  LCD_write_byte(0,0,0x04);     //点设定:显示字符/光标从左到右移位,DDRAM地址加1


  delay_1us();


  LCD_write_byte(0,0,0x0C);  //显示设定:开显示,显示光标,当前显示位反白闪动


  delay_1us();


  LCD_write_byte(0,0,0x01);  //写指令:清除显示, DDRAM


  delay_1us();


  LCD_write_byte(0,0,0x02);  //写指令:DDRAM地址归位


  delay_1us();


  LCD_write_byte(0,0,0x80);  //写指令:设置DDRAM地址,把显示地址设为0X80,即为第一行的首位


  delay_1us();


}


 


   这个初始化话的过程可能与ST7920手册上的初始化流程不一样,至于为什么我也不知道,这个初始化参考了网上的程序,实验验证了行得通。


 


LCD12864的一些内部存储器


CGROMCharacter Generator ROM,内置8192个中文汉字(16*16),也就是说能显示4行每行8个汉字。这些汉字通过GB中文字型码表寻址。存储器只读不写。


HCGROMHalf CGROM半宽字型产生只读存储器,里面存储了供我们调用的英文,数字以及符号共128个字符ASCII字符库(8*16)。同样只读不写。


CGRAMCharacter Generator RAM字形产生随机存储器,12864允许我们自己自定义字符,CGRAM最多可以提高416*16的空间供我们存放自定义字符。这四组点阵空间的地址为0000H0002H0004H0006H。通过写读CGRAM,实现特殊字符图形的显示。要注意的是,数据掉电消失,所以要显示自定义的字符,每次MCU上电都需要写一次CGRAM空间。

GDRAMGraphicDynamic RAM动态图形随机存储器,用以存储供显示的图形。


 


DDRAMData DisplayRAM数据显示随机存储器,即用来存放将被显示的字符数据。
ICON RAM(IRAM)图标随机存储器,用以存储将被显示的图标数据。


 


 


(1)显示中文字库汉字(CGROM)和英文字库(HCGROM)


     首先确定汉字显示坐标,中文字库的汉字都是16*16点阵的,所以128*64的液晶能分为四行,每行能显示8个汉字。



 


点击看大图


 


/***********************************************************


函数名称:LCD_setxy 


函数功能:设置显示汉字位置    X(1~16),Y(1~4)


入口参数:X(1~16),Y(1~4) 


出口参数:无


注:                x坐标


Line1 |  80H  81H  82H  83H  84H  85H  86H  87H


Line2 |  90H  91H  92H  93H  94H  95H  96H  97H


Line3 |  88H  89H  8AH  8BH  8CH  8DH  8EH  8FH


Line4 |  98H  99H  9AH  9BH  9CH  9DH  9EH  9FH


***********************************************************/


void LCD_setxy(unsigned char x,unsigned char y)


{


       switch(y)


       {


              case 1:


                     LCD_write_byte(0,0,0X7F+x);break;              //Line1


              case 2:


                     LCD_write_byte(0,0,0X8F+x);break;              //Line2


              case 3:


                     LCD_write_byte(0,0,0X87+x);break;              //Line3


              case 4:


                     LCD_write_byte(0,0,0X97+x);break;              //Line4


              default:break;


       }


}


 


 


     中文占用两个标准字符,编码方式按照GB中文字型码表,具体可以参考12864手册的附录,其实程序中也不需要自己对显示汉字先编码,直接把汉字赋值到字符串数组中即可,c编译器直接把汉字转化为汉字对应的GB(16)。英文和标点占用一个字节,编码方式按照ASCII码表,在程序中也不需要写ASCII吗,而是直接把英文和标点赋值到字符串里面即可。


 



点击看大图


(代码02H~7FH)


 


/***********************************************************


函数名称:LCD_WriteStr


函数功能:在指定位置显示字符串


入口参数:dis_addr_x————汉字显示X坐标(1~16


          dis_addr_y————汉字显示Y坐标(1~4


                str———————————显示字符串 中文占两个标准字符,英文和标点占一个字符


出口参数:无


注:


***********************************************************/


void LCD_WriteStr(unsigned char dis_addr_x,unsigned char dis_addr_y,char* str)


{


    unsigned char LCD_temp;


    LCD_setxy(dis_addr_x,dis_addr_y);


    LCD_temp=*str;


    while(LCD_temp != 0x00)           //显示字符串子程序,字符码为0时退出


    {


        LCD_write_byte(0,1,LCD_temp);


        LCD_temp=*(++str);


    } 


}


 


(2)显示自定义字形 (CGRAM)


 


/****************************************************************


函数名称:LCD_CharCGRAM


函数功能:写自定义字形16x16点阵数据


入口参数:CGRAMAdd——(0~3)CGRAM地址bit5~bit4


          *s—————————16x16点阵数据数组


出口参数:无


注:


格式说明:                                              *


//*     RS  RW  DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0  *


//*     0   0   0   1   0   AC5 AC4 AC3 AC2 AC1      *


//*     设定CGRAM位址到地址计数器AC                *


//*     确保CGRAM有效(扩展指令SR=0              *


***********************************************************/


void LCD_CharCGRAM(unsigned char CGRAMAdd,unsigned char code *s)


{   unsigned char i;


    LCD_write_byte(0,0,0x34);                 //扩充指令集


    LCD_write_byte(0,0,0x02);                 //SR=0 激活CGRAM


    LCD_write_byte(0,0,0x30);                 //恢复为基本指令集


    LCD_write_byte(0,0,(CGRAMAdd<<4)|0x40);    //设置CGRAM地址


    for(i=0;i<16;i++)                                                       //写点阵数据


            { 


                  LCD_write_byte(0,0,((CGRAMAdd<<4)+i)|0x40);   //在相应CGRAM地址上写点阵数据


           LCD_write_byte(0,1,s[2*i]);               //先写高位(D15~d8)


                     LCD_write_byte(0,1,s[2*i+1]);                   //再写低位(D7~D0)


               }


}


 



d2904f3b-4f60-493d-a7bf-fa18654d7b41.jpg


 


        要注意的是CGRAMB5~B4为所要存放自定义字型的地址,而CGRAMB3~B0为点阵数据,先写高位点阵数据(8bit),再写低点阵数据(8bit)(MSB在前,LSB在后)。在字模提取软件v2.1中要设置“横向取模”,不选中“字节倒序”。


 



点击看大图


 


在主程序中调用:


LCD_CharCGRAM(3,CHAR1CGRAMTAB);      //装入自定义字符字符点阵


 


//3CGRAM地址(B5-B4),对应的编码地址为0x0006


/*CGRAM中的自定义字符地址只能是0x00000x00020x00040x0006*/


//显示自定义符地址0x06


          LCD_setxy(2,2);


          LCD_write_byte(0,1,0x00);


          LCD_write_byte(0,1,0x06);


 


 


(3)显示自定义字形 (GDRAM)


     绘图显示RAM提供128*64个点阵。写入绘图RAM(GDRAM)的步骤如下:


①关闭绘图显示功能;


(扩展扩展指令集)设置GDRAM垂直Y位置Y——(0~31)


(扩展扩展指令集)设置GDRAM水平X位置X——(0~15)


④将D15~D8数据写入GDRAM中;


⑤将D15~D8数据写入GDRAM中;


⑥打开绘图显示功能。


 


要注意的是有些12864液晶的手册上写的是先设置水平地址,再设置垂直地址,这是不对的。一切以ST7920手册上为准。先写Y,再写X



 

点击看大图


 


字模软件横向取模,不字节倒序。


 


/***********************************************************


函数名称:LCD_ImgDisplay


函数功能:全屏显示128*64个象素的图形


入口参数:unsigned char code *img 要显示的图形


出口参数:无


注:


//*液晶屏坐标说明:                                          *


//*_______________________________________________    *


//*     |(0,0)                                   (7,0) |       *


//*     |                                            |       *


//*     |                                            |       *


//*     |(0,31)                                  (7,31)|       *


//*     |(8,0)                                   (15,0)|       *


//*     |                                            |       *


//*     |                                            |       *


//*     |(8,31)                                 (15,31)|       *


//*     |________________________________________|       *


//                                                          *


******************************************************************/ 


void LCD_ImgDisplay(unsigned char code *img)  


{  


    unsigned char i,j;  


    LCD_Graph_Mode_Set(Graph_Mode_OFF);   //先关闭图形显示功能   


    for(j=0;j<32;j++)               //垂直坐标Y     


       {


          for(i=0;i<8;i++)                   //水平坐标X


          {                  


                  LCD_write_byte(0,0,0x80+j);   //(扩展扩展指令集)设置GDRAM垂直Y位置


                  LCD_write_byte(0,0,0x80+i);   //(扩展扩展指令集)设置GDRAM水平X位置         


            LCD_write_byte(0,1,img[j*16+i*2]);      //放入数据高字节   


            LCD_write_byte(0,1,img[j*16+i*2+1]);    //放入数据低字节   


         }  


     }


       for(j=32;j<64;j++)                  //垂直坐标Y


    {


           for(i=0;i<8;i++)              //水平坐标X


          {                         


       


                  LCD_write_byte(0,0,0x80+j-32); 


                  LCD_write_byte(0,0,0x88+i);      


            LCD_write_byte(0,1,img[j*16+i*2]);  


            LCD_write_byte(0,1,img[j*16+i*2+1]);  


         }  


     }             


    LCD_Graph_Mode_Set(Graph_Mode_ON);  //最后打开图形显示功能    


}


 

56d361c2-5bb0-4446-8c69-da1fb527f888.jpg 


 


每一块12864都分为两个半屏,上下两半或者左右两半,我是用的12864是分为上下两半的,注意GDRAM水平位址和垂直位址的排列。


程序下载(C8051F320驱动12864液晶(ST7920)):https://static.assets-stash.eet-china.com/album/old-resources/2010/4/22/c67ef541-8e64-48f9-bcac-b5d43831d170.rar


PARTNER CONTENT

文章评论10条评论)

登录后参与讨论

用户377235 2012-5-18 17:33

程序中故意有个错误大家发现了吗。哈哈哈,我试下发现了

用户1168877 2011-8-20 17:11

正要用这款LCD,打算用并行,串行也用,

用户362754 2011-8-3 20:58

很好的资源,太感谢了。

用户322840 2011-4-22 21:37

果然是好东西,谢谢楼主

用户563753 2011-2-14 10:40

呵呵呵,可以!挺详细的啊1!!!

用户234619 2010-4-26 12:46

谢谢博主!估计是电阻没焊好。学习板刚开始就少不了程序,把USB-blaster里的芯片重焊了一下,一切都好了。

用户195584 2010-4-26 10:30

博主:能否贴一张显示4行汉字的图片看看?我最近在选型评估,手上有个12832的模块,点了一下,才能显示两行16个字,太少,不晓得你手头这块是否是能显示4行汉字的?谢谢 andyangdy的问题很可能是博主说的原因,同样是7920驱动的模块,我的12832要是vo接了电压,则显示全无,悬空的话,显示即正常。但是有其他的模块,情况却是相反。

tengjingshu_112148725 2010-4-25 18:06

andyandy:有可能是没接那个可调电阻。你这个只是初始化,初始化后其实液晶是没变化的,所以程序也有可能没问题

用户234619 2010-4-24 19:50

不好意思,很乱。有空的话,帮我看看。3Q!!!

用户234619 2010-4-24 19:41

能帮我看看这个程序吗?晶振是50MHz。 module LCD1602B(CLK50M,RS,RW,EN,DATA); input CLK50M; output RS,RW,EN; output reg[7:0]DATA; reg RS,EN; wire CLK_L; reg[19:0]MARK=0; reg[4:0]STATE=0; always @ (posedge CLK50M) MARK<=MARK+20'B1; assign CLK_L=MARK[19]; assign RW="0"; always @(posedge CLK_L) begin if(STATE==11) RS<=1; else RS<=0; case(STATE) 6: DATA=8'B0011_1000; 7: DATA=8'B0000_0110; 8: DATA=8'B0000_1100; 9: DATA=8'B0000_0001; 10: DATA=8'B1000_0001; 11: DATA=8'B0111_1110; default: DATA=DATA; endcase end always @(CLK_L) EN<=CLK_L; always @ (posedge CLK_L) case(STATE) 0: STATE=1; 1: STATE=2; 2: STATE=3; 3: STATE=4; 4: STATE=5; 5: STATE=6; 6: STATE=7; 7: STATE=8; 8: STATE=9; 9: STATE=10; 10: STATE=11; 11: STATE=12; 12: STATE=13; 13: STATE=14; 14: STATE=15; 15: STATE=11; 16: STATE=17; 17: STATE=18; 18: STATE=18; endcase endmodule 思路是这样的,50MHz分频2的20次方,大约是50Hz,周期约为20ms。不检忙。时钟上升沿送数,同时使能置1;下降沿使能赋0。前6个周期空转,然后依次设置38H、0CH、06H、清屏、写地址81H、写右箭头的地址码7EH。 无任何显示。 实在没办法了!3Q!
相关推荐阅读
藤井树 2015-10-12 14:43
印制电路板的抗干扰设计 zz
印制电路板的抗干扰设计     作者:中船重工集团第707所 肖麟芬   摘   要:本文以印制电路板的电磁兼容性为核心,分析了电磁干扰的产生机理...
藤井树 2013-10-22 15:32
2010.5.30 黄草梁上包饺子一日登山活动——摘韭菜篇
        上次桃花节的时候也有野韭菜,那时候的我连草和韭菜叶分不清,才回去的韭菜也不敢吃,哈哈,这次可算真正见识了韭菜,黄草梁也叫韭菜梁,因为满山遍野都是野韭菜而闻名,比较圆比较粗的就是野韭...
藤井树 2013-10-22 15:28
2010.5.30 黄草梁上包饺子一日登山活动——包饺子篇
摘韭菜回来,大家已经忙开了 我也装模作样地“工作着” 哈哈,还不让我包,包饺子是技术活,一定要皮薄馅厚才有资格包,像我这样的只能旁观了 摘的韭菜应该足够了,旁边那个袋子是我摘来带回学校的 ...
藤井树 2013-08-09 15:19
datasheet下载网站整理(查IC芯片手册)【原创】
*************************************************************************         作为电子工程师,芯片的dat...
藤井树 2010-06-04 00:21
陈伟宁王辉一家捐助渠道(北京菲亚特—英菲尼迪)
       王辉的最新消息请关注 http://chenweining.org/       目前事故责任认定已经出来了——陈家全责。        发信人: program (程序), 信区: D...
藤井树 2010-06-01 13:43
2010.5.30 黄草梁上包饺子一日登山活动——美景篇
这天不得不说的是天空,蓝蓝的天空,白白的云    绿油油的山脊  我、洪涛哥哥、huangna妹妹还有她同事小艾走在黄草梁上    在蓝天白云下合影       阳光照过来,景色真美 象鼻山,走不...
我要评论
10
7
关闭 站长推荐上一条 /3 下一条