STM32并行驱动CH12864B液晶屏(ST7920控制器)方案
一、硬件连接配置
1. 引脚映射表
| STM32引脚 | 功能 | ST7920引脚 | 说明 |
|---|---|---|---|
| PA0 | RS(寄存器选择) | RS | 数据/指令选择 |
| PA1 | RW(读写控制) | R/W | 读操作时需拉高 |
| PA2 | E(使能信号) | E | 上升沿锁存数据 |
| PA3 | RST(复位) | RST | 低电平有效复位 |
| PD0-PD7 | 数据总线 | D0-D7 | 并行数据传输 |
| 3.3V | VDD | VDD | 电源供电 |
| GND | GND | GND | 共地 |
2. 硬件连接注意事项
- 电平匹配:STM32的GPIO输出为3.3V,需确保ST7920支持3.3V电平(部分型号需电平转换器)。
- 总线驱动:数据总线PD0-PD7需连接上拉电阻(建议4.7kΩ)防止信号漂移。
- 背光控制:若需控制背光,可连接PB0至LED+/-引脚。
二、软件驱动实现
1. GPIO初始化
void LCD_GPIO_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
// 使能GPIOA和GPIOD时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOD, ENABLE);
// 配置控制引脚(PA0-PA2, PA3)
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
// 配置数据总线(PD0-PD7)
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_All;
GPIO_Init(GPIOD, &GPIO_InitStruct);
}
2. 忙信号检测
uint8_t LCD_CheckBusy(void) {
GPIO_ResetBits(GPIOA, GPIO_Pin_0); // RS=0(指令寄存器)
GPIO_ResetBits(GPIOA, GPIO_Pin_1); // RW=1(读模式)
GPIO_SetBits(GPIOA, GPIO_Pin_2); // E=1(使能)
volatile uint8_t busy = (GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_7) << 7);
GPIO_ResetBits(GPIOA, GPIO_Pin_2); // E=0
return busy;
}
3. 指令与数据写入
void LCD_WriteCmd(uint8_t cmd) {
while(LCD_CheckBusy()); // 等待空闲
GPIO_ResetBits(GPIOA, GPIO_Pin_1); // RW=0(写模式)
GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET); // RS=0(指令)
// 发送高4位
GPIO_Write(GPIOD, (cmd & 0xF0) | (GPIO_ReadOutputData(GPIOD) & 0x0F));
DelayUs(100);
GPIO_ResetBits(GPIOA, GPIO_Pin_2); // E=0
// 发送低4位
GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET); // RS=0
GPIO_Write(GPIOD, (cmd << 4) | (GPIO_ReadOutputData(GPIOD) & 0xF0));
DelayUs(100);
GPIO_ResetBits(GPIOA, GPIO_Pin_2); // E=0
DelayMs(2); // 指令执行时间
}
void LCD_WriteData(uint8_t data) {
while(LCD_CheckBusy());
GPIO_SetBits(GPIOA, GPIO_Pin_1); // RW=0(写模式)
GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET); // RS=1(数据)
// 发送高4位
GPIO_Write(GPIOD, (data & 0xF0) | (GPIO_ReadOutputData(GPIOD) & 0x0F));
DelayUs(100);
GPIO_ResetBits(GPIOA, GPIO_Pin_2);
// 发送低4位
GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);
GPIO_Write(GPIOD, (data << 4) | (GPIO_ReadOutputData(GPIOD) & 0xF0));
DelayUs(100);
GPIO_ResetBits(GPIOA, GPIO_Pin_2);
DelayMs(1);
}
4. 初始化流程
void LCD_Init(void) {
DelayMs(50); // 上电延时
// 复位操作
GPIO_ResetBits(GPIOA, GPIO_Pin_3); // RST=0
DelayMs(10);
GPIO_SetBits(GPIOA, GPIO_Pin_3); // RST=1
DelayMs(10);
// 功能设置:8位数据接口,基本指令集
LCD_WriteCmd(0x30); // 0011 N=1 F=0
DelayMs(10);
// 显示控制:开显示,关光标
LCD_WriteCmd(0x0C); // 0000 1100
DelayMs(10);
// 清屏
LCD_WriteCmd(0x01); // 0000 0001
DelayMs(2);
// 地址指针归零
LCD_WriteCmd(0x06); // 0000 0110(自动增量)
}
三、关键功能实现
1. 显示字符串
void LCD_DisplayString(uint8_t x, uint8_t y, const char* str) {
uint8_t addr;
if(y == 0) addr = 0x80 + x; // 第一行
else if(y == 1) addr = 0x90 + x; // 第二行
else if(y == 2) addr = 0x88 + x; // 第三行
else addr = 0x98 + x; // 第四行
LCD_WriteCmd(addr); // 设置显示位置
while(*str) {
LCD_WriteData(*str++);
}
}
2. 自定义字符
void LCD_CreateChar(uint8_t location, uint8_t charmap[]) {
uint8_t i;
LCD_WriteCmd(0x40 + location * 8); // 设置CGRAM地址
for(i=0; i<8; i++) {
LCD_WriteData(charmap[i]); // 写入字符点阵
}
}
参考代码 CH12864B的STM32并行驱动程序 ST7920控制器 www.youwenfan.com/contentcsr/101815.html
四、调试与验证
-
逻辑分析仪抓取时序
- 监控RS、RW、E信号与数据总线变化
- 验证E信号上升沿是否与数据同步
-
常见问题处理
现象 解决方案 显示乱码 检查数据总线连接与电平匹配 无法写入指令 确认忙信号检测逻辑正确 背光不亮 检查GPIO配置与电源连接
通过上述方案,可实现STM32与CH12864B液晶屏的高效并行通信。建议首次开发时使用J-Link调试器进行单步验证,重点关注忙信号检测与数据同步机制。