目录
一 背景说明
二 驱动原理
三 LCD接线
四 屏幕初始化
五 显示字符/汉字
六 实际效果
七 附录
拿到一款由ST7567驱动的128×64点阵液晶屏,准备连接STM32主控连接它并点亮屏幕。
我用的这款LCD屏幕,驱动IC是ST7567。其原理是通过驱动芯片与128×64的液晶模组进行交互,结合背光板,就能指定哪些点阵被点亮,从而得到想要的图形。驱动芯片与屏幕、背光的原理图如下:
【1】驱动IC——ST7567
(i)驱动引脚:
驱动引脚如下,其中主要用到了SDA/SCL/RS/RES/CS这5个引脚进行屏幕配置和数据交互:
(ii)驱动时序:
驱动时序如下,其中:
CSB即引脚CS,片选引脚,为低电平的时候,才能写入数据或命令;
A0即引脚RS,数据或命令选择引脚;
SCL时钟引脚,为低电平期间,写入数据,
SDA数据引脚,数据低位在前,高位在后;
复位时序如下,其中:
RSTB也就是RES,复位引脚,拉低即可复位,但是要注意拉低再拉高后要延时一段时间才能操作LCD。
(iii)驱动命令:
驱动命令如下,通过RS脚来实现数据与命令的切换:
【2】128×64液晶模组
一共128列,64行(其中每8行作为一页,共8页):
【3】BL背光模块
由背光正极性端LED+(LEDA)和背光负极性端LED-(LEDK)控制背光亮灭。
驱动芯片的引脚加上背光的引脚则形成了用户需要外接的所有引脚,其中主要关注CS0/RST/A0/SCK/SDA几个引脚,另外V0和XV0之间接1uf电容 VG和VSS之间接1uF电容:
【1】IO口初始化:
//12864点阵屏引脚定义
#define LDZ_CS_PORT (GPIOC)
#define LDZ_CS_PIN (GPIO_Pin_5)
#define LDZ_RE_PORT (GPIOB)
#define LDZ_RE_PIN (GPIO_Pin_0)
#define LDZ_DC_PORT (GPIOB)
#define LDZ_DC_PIN (GPIO_Pin_1)
#define LDZ_SCK_PORT (GPIOB)
#define LDZ_SCK_PIN (GPIO_Pin_2)
#define LDZ_SDA_PORT (GPIOC)
#define LDZ_SDA_PIN (GPIO_Pin_7)
#define LDZ_CS_L() GPIO_ResetBits(LDZ_CS_PORT, LDZ_CS_PIN)
#define LDZ_CS_H() GPIO_SetBits(LDZ_CS_PORT, LDZ_CS_PIN)
#define LDZ_RE_L() GPIO_ResetBits(LDZ_RE_PORT, LDZ_RE_PIN)
#define LDZ_RE_H() GPIO_SetBits(LDZ_RE_PORT, LDZ_RE_PIN)
#define LDZ_DC_L() GPIO_ResetBits(LDZ_DC_PORT, LDZ_DC_PIN)
#define LDZ_DC_H() GPIO_SetBits(LDZ_DC_PORT, LDZ_DC_PIN)
#define LDZ_SCK_L() GPIO_ResetBits(LDZ_SCK_PORT, LDZ_SCK_PIN)
#define LDZ_SCK_H() GPIO_SetBits(LDZ_SCK_PORT, LDZ_SCK_PIN)
#define LDZ_SDA_L() GPIO_ResetBits(LDZ_SDA_PORT, LDZ_SDA_PIN)
#define LDZ_SDA_H() GPIO_SetBits(LDZ_SDA_PORT, LDZ_SDA_PIN)
/**************************************************************************
* 函数名称: LDZ_Init
* 功能描述: LDZ初始化
**************************************************************************/
void LDZ_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB | RCC_AHBPeriph_GPIOC, ENABLE);
GPIO_InitStructure.GPIO_Pin = LDZ_CS_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(LDZ_CS_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = LDZ_RE_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(LDZ_RE_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = LDZ_DC_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(LDZ_DC_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = LDZ_SCK_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(LDZ_SCK_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = LDZ_SDA_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(LDZ_SDA_PORT, &GPIO_InitStructure);
LDZ_CS_H();
LDZ_SCK_H();
LDZ_SDA_H();
LDZ_RE_H(); Ddl_Delay1ms(10);
LDZ_RE_L(); Ddl_Delay1ms(10);
LDZ_RE_H(); Ddl_Delay1ms(50);
}
【2】写命令/写数据(通过DC口即上面的A0引脚来控制,其中高电平为写数据,低电平为写命令):
void LDZ_SendBit(u8 bit)
{
u8 i;
for(i = 0;i < 8;i ++)
{
LDZ_SCK_L();
if(bit & 0x80)
LDZ_SDA_H();
else
LDZ_SDA_L();
LDZ_SCK_H();
bit <<= 1;
}
}
/**************************************************************************
* 函数名称: LDZ_WriteCMD/LDZ_WriteDAT
* 功能描述: 写命令/写数据
**************************************************************************/
void LDZ_WriteCMD(u8 cmd)
{
LDZ_CS_L();
LDZ_DC_L();
LDZ_SendBit(cmd);
LDZ_CS_H();
}
void LDZ_WriteDAT(u8 dat)
{
LDZ_CS_L();
LDZ_DC_H();
LDZ_SendBit(dat);
LDZ_CS_H();
}
【3】配置屏幕
/**************************************************************************
* 函数名称: LDZ_Cfg
* 功能描述: 配置屏幕
**************************************************************************/
void LDZ_Cfg(void)
{
LDZ_WriteCMD(0xE2); //reset
Ddl_Delay1ms(10);
LDZ_WriteCMD(0xA2); //设置偏压比为1/9
LDZ_WriteCMD(0xA0); //设置seg扫描正向seg0~seg131
LDZ_WriteCMD(0xC8); //设置com扫描反向com63~com0
LDZ_WriteCMD(0x24); //对比度粗调
LDZ_WriteCMD(0x81); //对比度双指令
LDZ_WriteCMD(0x2B); //对比度微调
LDZ_WriteCMD(0x2F); //电源控制
LDZ_WriteCMD(0xB0); //设置页地址
LDZ_WriteCMD(0xAF); //显示打开
LDZ_WriteCMD(0xA6); //正常显示不反转
}
【4】几个功能接口,包括设置地址/清整屏/清整页:
/**************************************************************************
* 函数名称: LDZ_SetAddr/LDZ_ClearPage/LDZ_Clear
* 功能描述: 设置地址/清整页/清全屏
**************************************************************************/
void LDZ_SetAddr(u8 page, u8 col)
{
LDZ_WriteCMD(0xB0|page);
LDZ_WriteCMD((col >> 4)| 0x10);
LDZ_WriteCMD(col & 0x0F);
}
void LDZ_ClearPage(u8 page)
{
u8 i;
LDZ_SetAddr(page, 0);
for(i = 0;i < 128;i ++)
LDZ_WriteDAT(0x00);
}
void LDZ_Clear(void)
{
u8 i;
for(i = 0;i < 8;i ++)
LDZ_ClearPage(i);
}
至此,屏幕初始化便完成了,下面准备显示内容。
需要用到16和32两种大小的字体,根据ASC字符与汉字的差异可以分别放在如下的数组中:
(i)小字符(8×16)放到数组ASC16[ ];
(ii)小汉字(16×16)放到数组CHN16[ ];
(iii)大字符(16×32)放到数组ASC32[ ];
(iv)大汉字(32×32)放到数组CHN32[ ];
【1】字体取模:
要想显示字符/汉字,需要预先进行字体取模。我这边用到了 PCtoLCD2002 这款软件。软件的具体使用不再赘述,我这边设置是这样的:
生成的字库如下:
const unsigned char ASC16[]={
0x00,0xE0,0x18,0x08,0x08,0x08,0x18,0xE0,0x00,0x07,0x18,0x10,0x10,0x10,0x18,0x07,/*"0",0*/
0x00,0x00,0x20,0x20,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x00,0x00,/*"1",1*/
0x00,0x10,0x08,0x08,0x08,0x08,0x98,0x70,0x00,0x10,0x18,0x18,0x14,0x12,0x11,0x10,/*"2",2*/
0x00,0x10,0x08,0x88,0x88,0x88,0x70,0x00,0x00,0x08,0x10,0x10,0x10,0x10,0x09,0x07,/*"3",3*/
0x00,0x00,0x80,0x40,0x20,0x10,0xF8,0x00,0x06,0x05,0x04,0x04,0x04,0x04,0x1F,0x04,/*"4",4*/
0x00,0xC0,0xB8,0x88,0x88,0x88,0x88,0x08,0x00,0x09,0x10,0x10,0x10,0x10,0x10,0x0F,/*"5",5*/
0x00,0xE0,0x10,0x88,0x88,0x88,0x88,0x10,0x00,0x07,0x09,0x10,0x10,0x10,0x10,0x0F,/*"6",6*/
0x00,0x08,0x08,0x08,0x08,0xC8,0x38,0x08,0x00,0x00,0x00,0x1C,0x03,0x00,0x00,0x00,/*"7",7*/
0x00,0x70,0x90,0x88,0x88,0x88,0x98,0x60,0x00,0x0F,0x11,0x10,0x10,0x10,0x19,0x0F,/*"8",8*/
0x00,0xF0,0x98,0x08,0x08,0x08,0x90,0xE0,0x00,0x08,0x11,0x11,0x11,0x11,0x08,0x07,/*"9",9*/
};
const unsigned char CHN16[]={
0x40,0x40,0x42,0xCC,0x00,0x40,0xA0,0x9E,0x82,0x82,0x82,0x9E,0xA0,0x20,0x20,0x00,
0x00,0x00,0x00,0x3F,0x90,0x88,0x40,0x43,0x2C,0x10,0x28,0x46,0x41,0x80,0x80,0x00,/*"设",0*/
0x00,0x17,0x15,0xD5,0x55,0x57,0x55,0x7D,0x55,0x57,0x55,0xD5,0x15,0x17,0x00,0x00,
0x40,0x40,0x40,0x7F,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x7F,0x40,0x40,0x40,0x00,/*"置",1*/
};
const unsigned char ASC32[]={
0x00,0x00,0x00,0x00,0x80,0x80,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x80,0x80,0x00,
0x00,0xF0,0xFE,0xFF,0x07,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x03,0x07,0xFF,
0x00,0x0F,0x7F,0xFF,0xE0,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0xE0,0xFF,
0x00,0x00,0x00,0x00,0x01,0x01,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x01,0x01,0x00,/*"0",0*/
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xC0,0xC0,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x18,0x1C,0x0C,0x0E,0x06,0x07,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,0x03,0x00,0x00,0x00,0x00,/*"1",1*/
0x00,0x00,0x00,0x80,0x80,0x80,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x80,0x80,0x80,
0x00,0x06,0x07,0x07,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x81,0xE3,0xFF,
0x00,0x00,0x80,0xC0,0xE0,0x60,0x70,0x38,0x18,0x1C,0x0E,0x07,0x07,0x03,0x01,0x00,
0x00,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,/*"2",2*/
0x00,0x00,0x00,0x80,0x80,0x80,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x80,0x80,0x00,
0x00,0x04,0x07,0x07,0x03,0x01,0x00,0x80,0xC0,0xC0,0xC0,0xC0,0xE1,0xF3,0xBF,0xBF,
0x00,0x60,0xE0,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x81,0xC3,0xFF,
0x00,0x00,0x00,0x01,0x01,0x01,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x01,0x01,0x00,/*"3",3*/
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xC0,0xC0,0x00,
0x00,0x00,0x00,0x00,0x80,0xC0,0xE0,0xF0,0x78,0x3C,0x1E,0x0F,0xFF,0xFF,0xFF,0x00,
0x00,0x1C,0x1E,0x1F,0x1F,0x1B,0x19,0x18,0x18,0x18,0x18,0x18,0xFF,0xFF,0xFF,0x18,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,0x03,0x00,/*"4",4*/
0x00,0x00,0x00,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
0x00,0xE0,0xFF,0xFF,0x6F,0x61,0x30,0x30,0x30,0x30,0x30,0x30,0x70,0x60,0xE0,0xC0,
0x00,0x60,0xE0,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0xE0,0xFF,
0x00,0x00,0x00,0x01,0x01,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x01,0x01,0x00,/*"5",5*/
0x00,0x00,0x00,0x00,0x00,0x80,0x80,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x80,0x80,
0x00,0xF0,0xFC,0xFE,0x8F,0xC3,0xC1,0x60,0x60,0x60,0x60,0x60,0x60,0xC1,0xC3,0x87,
0x00,0x0F,0x7F,0xFF,0xE1,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xC1,0xFF,
0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x03,0x03,0x03,0x03,0x03,0x03,0x01,0x01,0x00,/*"6",6*/
0x00,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xE0,0xF8,0x3C,0x0E,0x07,0x03,
0x00,0x00,0x00,0x00,0x00,0x80,0xF0,0xFE,0x7F,0x0F,0x01,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x03,0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"7",7*/
0x00,0x00,0x00,0x00,0x80,0x80,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x80,0x80,0x00,
0x00,0x00,0x1E,0x3F,0xFF,0xE1,0xE1,0xC0,0xC0,0xC0,0xC0,0xC0,0xE1,0xE1,0xFF,0x3F,
0x00,0x3C,0xFF,0xFF,0xC3,0x81,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x81,0xC3,0xFF,
0x00,0x00,0x00,0x00,0x01,0x01,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x01,0x01,0x00,/*"8",8*/
0x00,0x00,0x00,0x00,0x80,0x80,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x80,0x80,0x80,0x00,
0x00,0x7C,0xFE,0xFF,0x87,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x83,0xFF,
0x00,0x60,0xE1,0xE1,0xC3,0x83,0x06,0x06,0x06,0x06,0x06,0x06,0x83,0xC3,0xF1,0x7F,
0x00,0x00,0x00,0x01,0x01,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x01,0x01,0x00,0x00,/*"9",9*/
};
const unsigned char CHN32[]={
0x00,0x00,0x00,0x00,0x00,0x04,0x18,0xF8,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,
0xF8,0x08,0x08,0x08,0x08,0x08,0xF8,0xFC,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x10,0x10,0x10,0x10,0x10,0xF8,0xF0,0x10,0x40,0x40,0x20,0x58,0x4E,0xC7,
0x40,0x40,0x40,0x40,0x40,0x40,0x47,0x4F,0xEC,0xCC,0x4C,0x0C,0x0C,0x0C,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x80,0x40,0x20,0x10,0x00,0x00,
0x07,0x18,0x60,0xC0,0xC0,0xE0,0x78,0x1F,0x07,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x47,0x43,0x41,0x20,0x20,0x30,0x10,0x18,
0x08,0x0C,0x06,0x03,0x03,0x06,0x0E,0x0C,0x1C,0x18,0x38,0x30,0x10,0x10,0x00,0x00,/*"设",0*/
0x00,0x00,0x00,0x00,0x00,0xFC,0xF8,0x08,0x08,0x08,0x08,0x08,0xF8,0xF8,0x08,0x08,
0x08,0x08,0xF8,0xF8,0x08,0x08,0x08,0x08,0x08,0xFC,0xFC,0x08,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x10,0x13,0x13,0x51,0x91,0x91,0x91,0x91,0x91,0x91,0xF3,0xFD,
0x95,0x95,0x91,0x91,0x91,0x91,0xD1,0xD1,0x91,0x1B,0x1B,0x10,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x44,0x44,0x44,0x44,0x44,0x44,
0x44,0x44,0x44,0x44,0x44,0x44,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3F,0x3F,0x22,0x22,0x22,0x22,0x22,0x22,
0x22,0x22,0x22,0x22,0x22,0x22,0x3F,0x3F,0x20,0x20,0x20,0x30,0x30,0x20,0x00,0x00,/*"置",1*/
};
【2】显示字符/汉字接口:
用四个定制化的接口,来显示上面不同字体的字库内容:
/**************************************************************************
* 函数名称: LDZ_ShowASC16/LDZ_ShowASC32/LDZ_ShowCHN16/LDZ_ShowCHN32
* 功能描述: 显示字符
* 参数说明: [1]页地址 / [2]列地址 / [3]字符位于对应数组中的序号
**************************************************************************/
void LDZ_ShowASC16(u8 page, u8 col, u8 id)
{
u8 i,j;
for(i = 0;i < 2;i ++)//一共2行
{
LDZ_SetAddr(page++, col);
for(j = 0;j < 8;j ++) //一行8字节
LDZ_WriteDAT(ASC16[j + i*8 + id*16]);
}
}
void LDZ_ShowCHN16(u8 page, u8 col, u8 id)
{
u8 i,j;
for(i = 0;i < 2;i ++) //一共2行
{
LDZ_SetAddr(page++, col);
for(j = 0;j < 16;j ++) //一行16字节
LDZ_WriteDAT(CHN16[j + i*16 + id*32]);
}
}
void LDZ_ShowASC32(u8 page, u8 col, u8 id)
{
u8 i,j;
for(i = 0;i < 4;i ++) //一共4行
{
LDZ_SetAddr(page++, col);
for(j = 0;j < 16;j ++) //一行16字节
LDZ_WriteDAT(ASC32[j+ i*16 + id*64]);
}
}
void LDZ_ShowCHN32(u8 page, u8 col, u8 id)
{
u8 i,j;
for(i = 0;i < 4;i ++) //一共4行
{
LDZ_SetAddr(page++, col);
for(j = 0;j < 32;j ++) //一行32字节
LDZ_WriteDAT(CHN32[j + i*32 + id*128]);
}
}
至此,定制化的字符/汉字显示接口已经完成,接下来就是在主函数中使用。
在主函数中调用初始化以及字符显示接口:
int main(void)
{
//LCD初始化/配置命令/清屏
LDZ_Init();
LDZ_Cfg();
LDZ_Clear();
while(1)
{
LDZ_ShowASC16(0, 0, 0); //显示0
LDZ_ShowASC16(0, 8, 1); //显示1
LDZ_ShowASC16(0, 16, 2); //显示2
LDZ_ShowASC16(0, 24, 3); //显示3
LDZ_ShowCHN16(2, 0, 0); //显示“设”
LDZ_ShowCHN16(2, 16, 1); //显示“置”
LDZ_ShowASC32(4, 0, 4); //显示4
LDZ_ShowASC32(4, 16, 5); //显示5
LDZ_ShowCHN32(4, 32, 0); //显示“设”
LDZ_ShowCHN32(4, 64, 1); //显示“置”
}
}
实际运行屏幕效果如下:
【1】【嵌入式】MCU(HC32F460)+SPI接口LCD液晶屏ILI9341 移植emWin记录1----点亮LCD屏_ili9341是spi 还是i2c-CSDN博客
【2】【开源】使用HK32F030驱动ST7567 LCD-CSDN博客
【3】LX12864P1屏幕使用介绍(ST7567驱动),显示横线、字符、图形-CSDN博客
【4】[STM32F1]使用STM32F103驱动ST7567液晶屏_st7567单片机驱动程序-CSDN博客