HS19264A-1是一款基于KS0107驱动芯片的192×64点阵LCD显示屏,在工业控制、仪器仪表等领域有广泛应用。这款LCD采用经典的8位并行接口,支持M6800时序,具有显示稳定、功耗低等特点。本文将详细介绍如何在STM32平台上驱动这款显示屏,包括硬件连接、底层驱动编写和显示功能实现。
HS19264A-1液晶显示屏外形尺寸为98.0mm×60.0mm×13.5mm(长×宽×高),显示区域为77.0mm×25.5mm。该显示屏由3片KS0107驱动芯片控制,每片驱动64×64点阵区域,共同组成192×64的显示分辨率。
该LCD采用20pin单排针接口,各引脚定义如下:
| 引脚号 | 符号 | 功能说明 |
|---|---|---|
| 1 | VSS | 电源地 |
| 2 | VDD | 逻辑电源(+5V) |
| 3 | VO | LCD驱动电压调节 |
| 4 | RS | 指令/数据选择(H:数据; L:指令) |
| 5 | R/W | 读写选择(H:读; L:写) |
| 6 | E | 使能信号(下降沿有效) |
| 7-14 | DB0-DB7 | 8位数据总线 |
| 15 | CS1 | 片选信号1(左区) |
| 16 | CS2 | 片选信号2(中区) |
| 17 | CS3 | 片选信号3(右区) |
| 18 | RST | 复位信号(低电平有效) |
| 19 | VOUT | 负压输出 |
| 20 | A | 背光阳极(+) |
| 21 | K | 背光阴极(-) |
注意:实际连接时,VO引脚通常连接10K可调电阻用于调节对比度,VOUT可连接电容滤波。
对于STM32F103系列单片机,推荐使用GPIOB端口连接LCD,具体引脚分配如下:
c复制#define LCD_RS_PIN GPIO_PIN_0 // PB0
#define LCD_RW_PIN GPIO_PIN_1 // PB1
#define LCD_E_PIN GPIO_PIN_2 // PB2
#define LCD_DB0_PIN GPIO_PIN_3 // PB3
// ... PB4-PB10依次对应DB1-DB7
#define LCD_CS1_PIN GPIO_PIN_11 // PB11
#define LCD_CS2_PIN GPIO_PIN_12 // PB12
#define LCD_CS3_PIN GPIO_PIN_13 // PB13
#define LCD_RST_PIN GPIO_PIN_14 // PB14
这种分配方式利用了GPIOB端口的连续引脚,便于编程控制。如果PB端口已被占用,也可以使用其他GPIO端口,但建议保持数据线在同一端口以提高访问速度。
电源连接:
信号线连接:
背光控制:
首先需要实现基本的GPIO读写函数:
c复制// 设置数据端口为输出
void LCD_DataOut(void) {
GPIOB->CRL = 0x33333333; // PB0-PB7推挽输出
}
// 设置数据端口为输入
void LCD_DataIn(void) {
GPIOB->CRL = 0x44444444; // PB0-PB7浮空输入
}
// 写入一个字节到数据总线
void LCD_WriteByte(uint8_t data) {
LCD_DataOut();
GPIOB->ODR = (GPIOB->ODR & 0xFF00) | data;
}
// 从数据总线读取一个字节
uint8_t LCD_ReadByte(void) {
LCD_DataIn();
return (GPIOB->IDR & 0x00FF);
}
KS0107驱动芯片遵循M6800时序,关键时序参数如下:
c复制// 写时序函数
void LCD_Write(uint8_t data, uint8_t isData) {
HAL_GPIO_WritePin(GPIOB, LCD_RS_PIN, isData ? GPIO_PIN_SET : GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB, LCD_RW_PIN, GPIO_PIN_RESET); // 写模式
LCD_WriteByte(data);
HAL_GPIO_WritePin(GPIOB, LCD_E_PIN, GPIO_PIN_SET); // 使能信号
Delay_us(1); // tEW > 450ns
HAL_GPIO_WritePin(GPIOB, LCD_E_PIN, GPIO_PIN_RESET);
Delay_us(1); // tEH > 10ns
}
// 读时序函数
uint8_t LCD_Read(uint8_t isData) {
uint8_t data;
HAL_GPIO_WritePin(GPIOB, LCD_RS_PIN, isData ? GPIO_PIN_SET : GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB, LCD_RW_PIN, GPIO_PIN_SET); // 读模式
HAL_GPIO_WritePin(GPIOB, LCD_E_PIN, GPIO_PIN_SET);
Delay_us(1);
data = LCD_ReadByte();
HAL_GPIO_WritePin(GPIOB, LCD_E_PIN, GPIO_PIN_RESET);
return data;
}
提示:实际应用中,Delay_us可以使用STM32的DWT计数器实现更精确的延时。
KS0107提供了一套简单的指令集,主要指令定义如下:
c复制#define LCD_CMD_DISP_ON 0x3F // 显示开
#define LCD_CMD_DISP_OFF 0x3E // 显示关
#define LCD_CMD_SET_Y_ADDR 0x40 // Y地址设置(0-63)
#define LCD_CMD_SET_PAGE 0xB8 // 页地址设置(0-7)
#define LCD_CMD_SET_START_LINE 0xC0 // 起始行设置(0-63)
#define LCD_CMD_STATUS_READ 0x40 // 状态读取
指令发送函数示例:
c复制void LCD_SendCmd(uint8_t cmd, uint8_t cs) {
// 选择对应的芯片
HAL_GPIO_WritePin(GPIOB, LCD_CS1_PIN, (cs & 0x01) ? GPIO_PIN_SET : GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB, LCD_CS2_PIN, (cs & 0x02) ? GPIO_PIN_SET : GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB, LCD_CS3_PIN, (cs & 0x04) ? GPIO_PIN_SET : GPIO_PIN_RESET);
LCD_Write(cmd, 0); // 发送指令
}
void LCD_SetPosition(uint8_t x, uint8_t y) {
uint8_t chip = x / 64; // 确定左右区域
uint8_t col = x % 64;
LCD_SendCmd(LCD_CMD_SET_Y_ADDR | col, 1<<chip);
LCD_SendCmd(LCD_CMD_SET_PAGE | (y/8), 1<<chip);
}
完整的初始化流程应包括以下步骤:
c复制void LCD_Init(void) {
// 硬件复位
HAL_GPIO_WritePin(GPIOB, LCD_RST_PIN, GPIO_PIN_RESET);
Delay_ms(10);
HAL_GPIO_WritePin(GPIOB, LCD_RST_PIN, GPIO_PIN_SET);
Delay_ms(10);
// 初始化所有区域
for(uint8_t i=0; i<3; i++) {
LCD_SendCmd(LCD_CMD_DISP_ON, 1<<i); // 显示开
LCD_SendCmd(LCD_CMD_SET_START_LINE, 1<<i); // 起始行=0
}
LCD_Clear(); // 清屏
}
实现基本的点、线、字符绘制函数:
c复制// 绘制一个点
void LCD_DrawPixel(uint8_t x, uint8_t y, uint8_t color) {
uint8_t chip = x / 64;
uint8_t data;
if(x >= 192 || y >= 64) return;
LCD_SetPosition(x, y);
data = LCD_Read(1); // 读取当前数据
if(color) {
data |= (1 << (y%8)); // 置位
} else {
data &= ~(1 << (y%8)); // 清零
}
LCD_SetPosition(x, y);
LCD_Write(data, 1); // 写回数据
}
// 显示一个字符(8x16)
void LCD_PutChar(uint8_t x, uint8_t y, char c) {
uint8_t i, j;
uint8_t *font = &Font8x16[(c-32)*16]; // 字模数据
for(i=0; i<16; i++) {
LCD_SetPosition(x, y+i);
LCD_Write(font[i], 1);
}
}
为提高刷新效率,可以添加显示缓存:
c复制uint8_t LCD_Buffer[8][192]; // 8页×192列
// 将缓存内容刷新到屏幕
void LCD_Refresh(void) {
for(uint8_t p=0; p<8; p++) {
for(uint8_t c=0; c<3; c++) {
LCD_SendCmd(LCD_CMD_SET_PAGE | p, 1<<c);
LCD_SendCmd(LCD_CMD_SET_Y_ADDR | 0, 1<<c);
for(uint8_t x=0; x<64; x++) {
LCD_Write(LCD_Buffer[p][c*64+x], 1);
}
}
}
}
通过减少片选切换次数提高写入速度:
c复制void LCD_FillRect(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint8_t color) {
uint8_t mask, data;
uint8_t start_page = y1 / 8;
uint8_t end_page = y2 / 8;
for(uint8_t p=start_page; p<=end_page; p++) {
// 计算页内掩码
mask = 0xFF;
if(p == start_page) mask &= (0xFF << (y1%8));
if(p == end_page) mask &= (0xFF >> (7 - y2%8));
// 设置起始位置
LCD_SendCmd(LCD_CMD_SET_PAGE | p, 0x07); // 全选
for(uint8_t x=x1; x<=x2; x++) {
LCD_SendCmd(LCD_CMD_SET_Y_ADDR | (x%64), 1<<(x/64));
data = LCD_Read(1);
if(color) {
data |= mask;
} else {
data &= ~mask;
}
LCD_Write(data, 1);
}
}
}
对于支持DMA的STM32型号,可以使用DMA加速数据传输:
c复制void LCD_DMA_Write(uint8_t *data, uint16_t len) {
// 配置DMA...
// 启动传输...
while(DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET);
}
排查步骤:
可能原因及解决:
解决方法:
基于该LCD驱动,可以实现多级菜单系统:
c复制typedef struct {
char *text;
void (*action)(void);
MenuItem *child;
} MenuItem;
void Menu_Show(MenuItem *menu) {
LCD_Clear();
for(uint8_t i=0; i<menu->count; i++) {
LCD_PutString(0, i*2, menu[i].text);
}
}
利用LCD的快速刷新特性,可以实现简易示波器功能:
c复制void Waveform_Update(uint8_t *data, uint8_t len) {
LCD_Clear();
for(uint8_t x=0; x<len; x++) {
LCD_DrawLine(x, 0, x, data[x]/4);
}
}
在STM32平台上成功驱动HS19264A-1液晶屏后,我发现以下几点经验特别值得分享: