玩转12864液晶:3串行驱动<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
驱动芯片是ST7920的12864液晶电路连接有两种,并行方式和串行方式。通常使用并行方式,但有时候为了节省I/O线,可以使用串行方式,串行方式的传输字节的速率会比并行的慢。
<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />
串行连接时序图
/***********************************************************
函数名称:serial_write_byte
函数功能:负责串行写8个bit位
入口参数: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表示数据从 MCU到LCD
B为数据类型选择 H表示数据是显示数据 L表示数据是控制指令
C固定为 0
第二字节 (并行)8 位数据的高4 位—格式 DDDD0000
第三字节 (并行)8 位数据的低4 位—格式 0000DDDD
/***********************************************************
函数名称:LCD_write_byte
函数功能:写一个字节的数据到12864液晶,包括指令或数据
入口参数:RW、RS、W_data
出口参数:无
备 注:RW=1,从液晶读数据到MCU;RW=0,写一个数据到液晶;
(一般RW都设为0,即只向液晶写数据,不读数据)
RS=1,写入的是数据;RS=0,写入的是指令;
一般模式:RW=0,RS=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=0,MCU写一个数据到液晶;
{
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的一些内部存储器
CGROM,Character Generator ROM,内置8192个中文汉字(16*16),也就是说能显示4行每行8个汉字。这些汉字通过GB中文字型码表寻址。存储器只读不写。
HCGROM,Half CGROM,半宽字型产生只读存储器,里面存储了供我们调用的英文,数字以及符号共128个字符ASCII字符库(8*16)。同样只读不写。
CGRAM,Character Generator RAM,字形产生随机存储器,12864允许我们自己自定义字符,CGRAM最多可以提高4组16*16的空间供我们存放自定义字符。这四组点阵空间的地址为0000H、0002H、0004H、0006H。通过写读CGRAM,实现特殊字符图形的显示。要注意的是,数据掉电消失,所以要显示自定义的字符,每次MCU上电都需要写一次CGRAM空间。
GDRAM,GraphicDynamic RAM,动态图形随机存储器,用以存储供显示的图形。
DDRAM,Data 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)
}
}
要注意的是CGRAM的B5~B4为所要存放自定义字型的地址,而CGRAM的B3~B0为点阵数据,先写高位点阵数据(8bit),再写低点阵数据(8bit)(MSB在前,LSB在后)。在字模提取软件v2.1中要设置“横向取模”,不选中“字节倒序”。
在主程序中调用:
LCD_CharCGRAM(3,CHAR1CGRAMTAB); //装入自定义字符字符点阵
//3为CGRAM地址(B5-B4),对应的编码地址为0x0006
/*CGRAM中的自定义字符地址只能是0x0000、0x0002、0x0004、0x0006*/
//显示自定义符地址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); //最后打开图形显示功能
}
每一块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
用户377235 2012-5-18 17:33
用户1168877 2011-8-20 17:11
用户362754 2011-8-3 20:58
用户322840 2011-4-22 21:37
用户563753 2011-2-14 10:40
用户234619 2010-4-26 12:46
用户195584 2010-4-26 10:30
tengjingshu_112148725 2010-4-25 18:06
用户234619 2010-4-24 19:50
用户234619 2010-4-24 19:41