STM32 控制LCD 12864 显示内容

📅 2026/7/18 11:50:43
STM32 控制LCD 12864 显示内容
一、工程基础信息硬件平台普中 A6 STM32F103屏幕型号12864 ST7920 8 位并行液晶屏标准库版本STM32F10x_StdPeriph_Lib V3.5.0开发环境Keil MDK代码规范全程使用标准固定宽度类型uint8_t / uint16_t无自定义u8 / uint8别名无多余强制类型转换二、硬件引脚分配表表格LCD 引脚STM32 引脚功能说明RSPB1数据 / 命令选择0 命令1 数据WRPB2写使能低电平有效EPB0锁存使能上升沿锁存数据PSBPA8并 / 串口选择高电平 8 位并行模式DB0~DB7PB8~PB158 位并行数据总线映射至 GPIOB 高 8 位VCC3.3V供电禁止接入 5VGNDGND共地V010K 电位器接地对比度调节BL3.3V背光供电三、文件划分与功能总览1. public.h 公共类型 延时声明依赖stm32f10x.h提供标准整数类型基础声明毫秒 / 微秒延时函数delay_ms()、delay_10us()底层由 SysTick 实现。2. lcd12864.h 驱动头文件引脚宏定义统一封装 GPIO 端口、时钟、引脚号、高低电平操作宏函数声明GPIO 初始化、读写底层、屏幕初始化、清屏、字符串显示、全屏图片绘制类型统一使用uint8_t标准类型无自定义简写避免编译警告。3. lcd12864.c 驱动底层实现GPIO 初始化开启 GPIOA/GPIOB 时钟控制脚 数据脚全部配置推挽输出上电初始化固定电平数据输出静态函数lcd12864_set_data将 8 位字节数据移位输出至 PB8~PB15保留低 8 位 IO 状态不被覆盖底层读写函数lcd12864_write_cmd写命令、lcd12864_write_data写显示数据匹配 ST7920 标准时序每条指令带 1ms 稳定延时屏幕初始化lcd12864_init上电切换并行模式依次发送基础指令集、开启显示、游标右移、清屏清屏函数lcd12864_clear发送 0x01 指令清空全部文字显示区字符串显示lcd12864_show_string支持指定坐标 (x 偏移 0~15y 行 0~3)自动计算 ST7920 文字地址循环打印字符直至字符串结束符\0全屏图片绘制lcd12864_show_pic适配 128×64 单色点阵切换扩展绘图指令集分上下两区写入 1024 字节点阵数组绘制完成切回文字模式。4. main.c 主业务逻辑实现三页自动循环分页切换每页停留 3000msPage0英文教学文字Page1中文课程标题Page2模拟环境监测数据每次页面刷新前执行清屏消除文字 / 画面重叠计数变量page_cnt控制页面切换溢出自动归零带 default 容错分支。四、核心函数详细说明1. lcd12864_gpio_init功能初始化所有 LCD 相关 GPIO 引脚开启 GPIOA、GPIOB 外设时钟PB0/PB1/PB2 (控制脚)、PA8 (PSB) 配置 50MHz 推挽输出PB8~PB15 数据总线配置 50MHz 推挽输出上电初始电平E 低、WR 高、RS 低、PSB 高锁定并行模式。2. static lcd12864_set_data(uint8_t dat)功能8 位数据映射到 PB8~PB15读取 GPIOB 原有输出值保留低 8 位 (PB0~PB7) 状态将输入字节左移 8 位写入 GPIOB 高 8 位 (PB8~PB15)不干扰控制引脚电平。3. lcd12864_write_cmd(uint8_t cmd)功能向屏幕写入控制指令RS 拉低 (命令模式)、WR 拉低、E 拉低调用数据输出函数装载指令延时 1ms 稳定总线E 拉高产生上升沿锁存指令再延时 1ms 后拉低 E。4. lcd12864_write_data(uint8_t dat)功能向屏幕写入显示字符 / 绘图点阵数据流程与写命令一致仅 RS 置高切换至数据模式。5. lcd12864_init上电初始化流程初始化 GPIO拉高 PSB 锁定并行0x30选择基础 8 位指令集0x0C开启屏幕显示关闭光标0x06写入数据后游标自动右移0x01清屏清除所有文字。6. lcd12864_clear发送清屏指令0x01清空文字缓存区。7. lcd12864_show_string(uint8_t x,uint8_t y,uint8_t *str)参数说明x行内字符偏移范围 0~15y显示行号固定 0/1/2/3 四行str待打印字符串指针执行逻辑限制 y 取值 0~3防止越界根据 y 计算 ST7920 对应行起始地址 (0x80/0x90/0x88/0x98)叠加偏移 x写入地址指令循环读取字符串每个字符调用写数据函数遇到\0停止。8. lcd12864_show_pic(const uint8_t *pic_buf)参数pic_buf 为 1024 字节点阵数组128×64 单色横向取模、高位在前绘图流程0x34切换扩展绘图指令集关闭绘图输出循环绘制上半屏绘图区 (X0~7地址 0x80)循环绘制下半屏绘图区 (X8~15地址 0x88)0x36开启绘图显示点阵生效0x30切回基础文字指令集保证后续文字正常显示。9. main 主循环分页逻辑page_cnt页面计数器初始值 0每次循环先清屏再根据计数器选择页面文字页面停留 3000ms 后计数器自增计数器≥3 时归零实现 0/1/2 三页无限循环default 分支捕获异常数值强制重置页面 0避免程序卡死。五、使用规范与注意事项1. 点阵图片使用规范点阵数组固定长度const uint8_t lcd_logo_pic[1024]取模软件配置分辨率 128×64、横向 8bit、高位在前、单色模式调用lcd12864_show_pic(lcd_logo_pic)无需坐标参数全屏覆盖。2. 字符串调用规范函数形参为uint8_t *str字面字符串调用格式c运行lcd12864_show_string((uint8_t)0,(uint8_t)0,(uint8_t *)测试文字);坐标数字统一添加(uint8_t)显式转换风格统一。3. 硬件避坑要点屏幕 VCC 必须接 3.3V5V 模块会出现电平不匹配、闪屏、零星亮点PSB 引脚必须硬件接 PA8代码持续拉高悬空会自动进入串口模式无显示V0 对比度电位器必须串联 10K 电阻接 GND上电缓慢调节才能看清文字杜邦线尽量缩短长线干扰会导致点阵错乱、文字闪烁消失每次切换页面必须调用lcd12864_clear()否则文字、图片重叠花屏。4. 编译警告处理全程使用uint8_t / uint16_t标准类型无自定义u8字符串传参添加(uint8_t *)显式转换消除char*与uint8_t*类型匹配警告坐标数值强制转换(uint8_t)数值变量转换(uint16_t)代码风格统一无类型提示告警。//main.c #include public.h #include SysTick.h #include lcd12864.h int main(void) { uint16 page_cnt 0; lcd12864_init(); lcd12864_clear(); while(1) { lcd12864_clear(); switch(page_cnt) { case 0: // 第1页 文字 lcd12864_show_string((uint8_t)0,(uint8_t)0,(uint8_t *)STM32 LCD12864); lcd12864_show_string((uint8_t)0,(uint8_t)1,(uint8_t *)Welcome ); lcd12864_show_string((uint8_t)0,(uint8_t)2,(uint8_t *)Nice to see you ); lcd12864_show_string((uint8_t)0,(uint8_t)3,(uint8_t *)First lession); break; case 1: lcd12864_show_string((uint8_t)0,(uint8_t)0,(uint8_t *)STM32 LCD12864); lcd12864_show_string((uint8_t)0,(uint8_t)1,(uint8_t *)工程技术学院); lcd12864_show_string((uint8_t)0,(uint8_t)2,(uint8_t *)嵌入式课程设计); lcd12864_show_string((uint8_t)0,(uint8_t)3,(uint8_t *)新引脚驱动完成); break; case 2: // 第3页 模拟监测数据 lcd12864_show_string((uint8_t)0,(uint8_t)0,(uint8_t *)环境监测数据); lcd12864_show_string((uint8_t)0,(uint8_t)1,(uint8_t *)温度: 26.3℃); lcd12864_show_string((uint8_t)0,(uint8_t)2,(uint8_t *)湿度: 47%RH); lcd12864_show_string((uint8_t)0,(uint8_t)3,(uint8_t *)电压: 3.30V); break; default: page_cnt (uint16_t)0; break; } delay_ms((uint16_t)3000); page_cnt; if(page_cnt (uint16_t)3) { page_cnt (uint16_t)0; } } }//lcd12864.h #ifndef _lcd12864_H #define _lcd12864_H #include stm32f10x.h #include delay.h // WR P2^5 → PB2 #define LCD_WR_PIN GPIO_Pin_2 #define LCD_WR_PORT GPIOB #define LCD_WR_RCC RCC_APB2Periph_GPIOB // RS P2^6 → PB1 #define LCD_RS_PIN GPIO_Pin_1 #define LCD_RS_PORT GPIOB #define LCD_RS_RCC RCC_APB2Periph_GPIOB // E P2^7 → PB0 #define LCD_E_PIN GPIO_Pin_0 #define LCD_E_PORT GPIOB #define LCD_E_RCC RCC_APB2Periph_GPIOB // PSB P3^2 → PA8 #define LCD_PSB_PIN GPIO_Pin_8 #define LCD_PSB_PORT GPIOA #define LCD_PSB_RCC RCC_APB2Periph_GPIOA // 数据口 P0 → PB8~PB15 #define LCD_DATA_PORT GPIOB #define LCD_DATA_RCC RCC_APB2Periph_GPIOB // 电平操作宏 #define LCD_RS_H() GPIO_SetBits(LCD_RS_PORT, LCD_RS_PIN) #define LCD_RS_L() GPIO_ResetBits(LCD_RS_PORT, LCD_RS_PIN) #define LCD_WR_H() GPIO_SetBits(LCD_WR_PORT, LCD_WR_PIN) #define LCD_WR_L() GPIO_ResetBits(LCD_WR_PORT, LCD_WR_PIN) #define LCD_E_H() GPIO_SetBits(LCD_E_PORT, LCD_E_PIN) #define LCD_E_L() GPIO_ResetBits(LCD_E_PORT, LCD_E_PIN) #define LCD_PSB_H() GPIO_SetBits(LCD_PSB_PORT, LCD_PSB_PIN) #define LCD_PSB_L() GPIO_ResetBits(LCD_PSB_PORT, LCD_PSB_PIN) // 函数声明全部使用STM32标准uint8_t删除自定义u8 void lcd12864_gpio_init(void); void lcd12864_write_cmd(uint8_t cmd); void lcd12864_write_data(uint8_t dat); void lcd12864_init(void); void lcd12864_clear(void); void lcd12864_show_string(uint8_t x,uint8_t y,uint8_t *str); // 在原有函数声明末尾添加 void lcd12864_show_pic(const uint8_t *pic_buf); #endif//lcd12864.c #include lcd12864.h /******************************************************************************* * 函 数 名 : lcd12864_gpio_init * 函数功能 : LCD12864 GPIO初始化 *******************************************************************************/ void lcd12864_gpio_init(void) { GPIO_InitTypeDef GPIO_InitStruct; //开启GPIO时钟 RCC_APB2PeriphClockCmd(LCD_RS_RCC | LCD_PSB_RCC, ENABLE); //控制脚 PB0 PB1 PB2 PA8 推挽输出 GPIO_InitStruct.GPIO_Mode GPIO_Mode_Out_PP; GPIO_InitStruct.GPIO_Speed GPIO_Speed_50MHz; // PB0 E GPIO_InitStruct.GPIO_Pin LCD_E_PIN; GPIO_Init(LCD_E_PORT, GPIO_InitStruct); // PB1 RS GPIO_InitStruct.GPIO_Pin LCD_RS_PIN; GPIO_Init(LCD_RS_PORT, GPIO_InitStruct); // PB2 WR GPIO_InitStruct.GPIO_Pin LCD_WR_PIN; GPIO_Init(LCD_WR_PORT, GPIO_InitStruct); // PA8 PSB GPIO_InitStruct.GPIO_Pin LCD_PSB_PIN; GPIO_Init(LCD_PSB_PORT, GPIO_InitStruct); //数据口 PB8~PB15 推挽输出 GPIO_InitStruct.GPIO_Pin GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; GPIO_Init(LCD_DATA_PORT, GPIO_InitStruct); //初始电平 LCD_E_L(); LCD_WR_H(); LCD_RS_L(); LCD_PSB_H(); } /******************************************************************************* * 函 数 名 : lcd12864_set_data * 函数功能 : 向PB8~PB15输出8位数据 *******************************************************************************/ static void lcd12864_set_data(uint8_t dat) { uint16_t temp GPIO_ReadOutputData(LCD_DATA_PORT); temp 0x00FF; temp | ((uint16_t)dat 8); GPIO_Write(LCD_DATA_PORT, temp); } /******************************************************************************* * 函 数 名 : lcd12864_write_cmd * 函数功能 : LCD12864写命令 *******************************************************************************/ void lcd12864_write_cmd(uint8_t cmd) { LCD_RS_L(); LCD_WR_L(); LCD_E_L(); lcd12864_set_data(cmd); delay_ms(1); LCD_E_H(); delay_ms(1); LCD_E_L(); } /******************************************************************************* * 函 数 名 : lcd12864_write_data * 函数功能 : LCD12864写数据 *******************************************************************************/ void lcd12864_write_data(uint8_t dat) { LCD_RS_H(); LCD_WR_L(); LCD_E_L(); lcd12864_set_data(dat); delay_ms(1); LCD_E_H(); delay_ms(1); LCD_E_L(); } /******************************************************************************* * 函 数 名 : lcd12864_init * 函数功能 : LCD12864初始化 *******************************************************************************/ void lcd12864_init(void) { lcd12864_gpio_init(); LCD_PSB_H(); lcd12864_write_cmd(0x30); lcd12864_write_cmd(0x0C); lcd12864_write_cmd(0x06); lcd12864_write_cmd(0x01); } /******************************************************************************* * 函 数 名 : lcd12864_clear * 函数功能 : LCD12864清屏 *******************************************************************************/ void lcd12864_clear(void) { lcd12864_write_cmd(0x01); } /******************************************************************************* * 函 数 名 : lcd12864_show_string * 函数功能 : LCD12864显示字符串 x(0~7) y(0~3) *******************************************************************************/ void lcd12864_show_string(uint8_t x,uint8_t y,uint8_t *str) { if(y 0) y 0; if(y 3) y 3; x 0x0F; switch(y) { case 0: x | 0x80; break; case 1: x | 0x90; break; case 2: x | 0x88; break; case 3: x | 0x98; break; } lcd12864_write_cmd(x); while(*str ! \0) { lcd12864_write_data(*str); str; } } void lcd12864_show_pic(const uint8_t *pic_buf) { uint8_t x,y; uint16_t idx0; // 切换扩展绘图指令集关闭绘图显示 lcd12864_write_cmd(0x34); // 上半屏绘图区 X0~7 (0x80 ~ 0x87) for(y0;y8;y) { lcd12864_write_cmd(0x80 y); lcd12864_write_cmd(0x80); for(x0;x16;x) { lcd12864_write_data(pic_buf[idx]); idx; } } // 下半屏绘图区 X8~15 (0x88 ~ 0x8F) for(y0;y8;y) { lcd12864_write_cmd(0x80 y); lcd12864_write_cmd(0x88); for(x0;x16;x) { lcd12864_write_data(pic_buf[idx]); idx; } } // 开启绘图显示 lcd12864_write_cmd(0x36); // 切回文字基础指令集 lcd12864_write_cmd(0x30); }