用CubeMX+Keil5快速搞定1.8寸LCD屏驱动:从零配置到显示‘Hello World’
STM32CubeMX与Keil5实战1.8寸LCD屏驱动开发全流程解析第一次点亮LCD屏幕的瞬间那种成就感是难以言喻的。作为嵌入式开发的经典入门项目LCD驱动不仅能帮助新手快速理解硬件交互原理更是掌握STM32图形化开发工具链的绝佳切入点。本文将使用STM32CubeMX和Keil5这对黄金组合带你从零开始实现1.8寸SPI接口LCD屏的驱动开发最终完成Hello World显示。不同于传统寄存器操作方式我们全程采用HAL库和图形化配置工具即使没有任何底层开发经验也能轻松上手。1. 硬件准备与环境搭建1.1 硬件选型与连接市面上常见的1.8寸TFT LCD屏大多采用ST7735S驱动芯片通过SPI接口通信。这种屏幕价格低廉约15-30元、分辨率通常为128x160非常适合入门学习。以下是典型硬件配置方案主控芯片STM32F103C8T6蓝色药丸开发板显示屏1.8寸TFT LCDST7735S驱动接口类型4线SPI模拟SPI也可实现硬件连接需要特别注意电平匹配。虽然STM32的IO口可承受5V输入但建议统一使用3.3V供电以确保稳定性。典型接线方式如下LCD引脚STM32连接功能说明VCC3.3V电源正极GNDGND电源地SCLPA5SPI时钟线SDAPA7SPI数据线RESPB0复位信号DCPB1数据/命令选择CSPB10片选信号BLPB11背光控制提示若使用硬件SPISCLK应连接到PA5(SPI1_SCK)MOSI连接到PA7(SPI1_MOSI)。本文为简化操作采用模拟SPI实现。1.2 开发环境安装确保已安装以下软件工具STM32CubeMX6.5.0或更高版本Keil MDK-ARM5.30以上需安装STM32F1xx Device Family PackST-Link驱动用于程序下载调试安装完成后建议在CubeMX中检查更新确保HAL库为最新版本。Keil的license管理也不容忽视社区版有32KB代码限制但对于本实验完全够用。# 验证Keil安装成功的简单方法 armcc --version # 应输出类似: MDK-ARM Plus Version: 5.302. CubeMX工程配置2.1 新建工程与时钟配置启动CubeMX选择Access to MCU Selector在搜索框中输入STM32F103C8选择对应型号后进入配置界面系统时钟配置在RCC选项卡中将HSE设置为Crystal/Ceramic Resonator时钟配置图中将系统时钟源选择为HSE输入8MHz调节PLL倍频使系统时钟达到72MHz最大频率调试接口配置在SYS选项卡中将Debug设为Serial Wire这样可保留SWD下载接口避免占用用户IO// 生成的时钟配置代码示例system_stm32f1xx.c #define PLL_MUL 9 #define PLL_SRC RCC_PLLSRC_HSE_DIV1 #define PLL_NODE RCC_PLLMul_92.2 GPIO配置根据接线表配置各GPIO引脚在Pinout视图中找到对应引脚右键选择GPIO_Output为每个引脚设置用户自定义标签PB0 → LCD_RESPB1 → LCD_DCPB10 → LCD_CSPB11 → LCD_BLPA5 → LCD_SCL (模拟SPI时钟)PA7 → LCD_SDA (模拟SPI数据)GPIO参数保持默认Mode: Output Push PullPull-up/Pull-down: No pull-up and no pull-downMaximum output speed: Low注意CubeMX会自动生成宏定义如#define LCD_RES_Pin GPIO_PIN_0后续编程可直接使用这些宏。2.3 工程生成设置进入Project Manager选项卡进行以下关键设置Project输入工程名称如LCD_ST7735选择工程存储路径Toolchain/IDE选择MDK-ARM V5Code Generator勾选Generate peripheral initialization as a pair of .c/.h files选择Copy only the necessary library files勾选Generate peripheral initialization as a pair of .c/.h files点击GENERATE CODE按钮生成工程完成后点击Open Project自动启动Keil。3. Keil工程开发3.1 工程结构概览CubeMX生成的Keil工程包含以下关键部分Application/User用户代码区main.c主程序入口stm32f1xx_it.c中断服务程序stm32f1xx_hal_msp.c硬件抽象层初始化DriversHAL库驱动MDK-ARM启动文件和链接脚本我们需要在Application/User组中添加新的源文件右键User组 → Add New Item → User Code Template创建lcd.c和lcd.h文件用于存放LCD驱动代码3.2 LCD驱动实现在lcd.h中定义基本宏和函数原型#ifndef __LCD_H #define __LCD_H #include main.h // 颜色定义(RGB565) #define WHITE 0xFFFF #define BLACK 0x0000 #define BLUE 0x001F #define RED 0xF800 #define GREEN 0x07E0 // 函数声明 void LCD_Init(void); void LCD_WriteCmd(uint8_t cmd); void LCD_WriteData(uint8_t data); void LCD_SetWindow(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2); void LCD_Clear(uint16_t color); void LCD_DrawPixel(uint16_t x, uint16_t y, uint16_t color); void LCD_ShowChar(uint16_t x, uint16_t y, char ch, uint16_t color); #endif在lcd.c中实现核心驱动函数#include lcd.h #include delay.h // 需要实现简单的延时函数 // 模拟SPI写数据 static void SPI_Write(uint8_t data) { for(uint8_t i0; i8; i) { HAL_GPIO_WritePin(LCD_SCL_GPIO_Port, LCD_SCL_Pin, GPIO_PIN_RESET); if(data 0x80) HAL_GPIO_WritePin(LCD_SDA_GPIO_Port, LCD_SDA_Pin, GPIO_PIN_SET); else HAL_GPIO_WritePin(LCD_SDA_GPIO_Port, LCD_SDA_Pin, GPIO_PIN_RESET); HAL_GPIO_WritePin(LCD_SCL_GPIO_Port, LCD_SCL_Pin, GPIO_PIN_SET); data 1; } } // 写命令 void LCD_WriteCmd(uint8_t cmd) { HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_RESET); HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_RESET); SPI_Write(cmd); HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_SET); } // 写数据 void LCD_WriteData(uint8_t data) { HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_SET); HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_RESET); SPI_Write(data); HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_SET); }3.3 LCD初始化序列ST7735S驱动芯片需要特定的初始化序列才能正常工作。在LCD_Init()函数中添加以下代码void LCD_Init(void) { // 硬件复位 HAL_GPIO_WritePin(LCD_RES_GPIO_Port, LCD_RES_Pin, GPIO_PIN_RESET); HAL_Delay(100); HAL_GPIO_WritePin(LCD_RES_GPIO_Port, LCD_RES_Pin, GPIO_PIN_SET); HAL_Delay(120); // 软件复位 LCD_WriteCmd(0x01); HAL_Delay(120); // 睡眠模式退出 LCD_WriteCmd(0x11); HAL_Delay(120); // 内存数据访问控制 LCD_WriteCmd(0x36); LCD_WriteData(0xC0); // MY1, MX1, MV0, RGB顺序 // 接口像素格式 LCD_WriteCmd(0x3A); LCD_WriteData(0x05); // 16位/pixel // 显示开 LCD_WriteCmd(0x29); // 背光开启 HAL_GPIO_WritePin(LCD_BL_GPIO_Port, LCD_BL_Pin, GPIO_PIN_SET); }4. 基础显示功能实现4.1 清屏与像素绘制在lcd.c中添加以下基础显示函数// 设置显示窗口 void LCD_SetWindow(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) { LCD_WriteCmd(0x2A); // 列地址设置 LCD_WriteData(x1 8); LCD_WriteData(x1 0xFF); LCD_WriteData(x2 8); LCD_WriteData(x2 0xFF); LCD_WriteCmd(0x2B); // 行地址设置 LCD_WriteData(y1 8); LCD_WriteData(y1 0xFF); LCD_WriteData(y2 8); LCD_WriteData(y2 0xFF); LCD_WriteCmd(0x2C); // 内存写入 } // 清屏 void LCD_Clear(uint16_t color) { uint32_t i; LCD_SetWindow(0, 0, 127, 159); for(i0; i128*160; i) { LCD_WriteData(color 8); LCD_WriteData(color 0xFF); } } // 画点 void LCD_DrawPixel(uint16_t x, uint16_t y, uint16_t color) { LCD_SetWindow(x, y, x1, y1); LCD_WriteData(color 8); LCD_WriteData(color 0xFF); }4.2 字符显示实现显示字符需要先定义字模数据。我们使用8x16点阵ASCII字符集// 在lcd.c中添加字模数据 static const uint8_t font8x16[] { // 空格(0x20) 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ! (0x21) 0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18, 0x18,0x18,0x00,0x00,0x18,0x18,0x00,0x00, // 更多字符数据... }; // 显示单个字符 void LCD_ShowChar(uint16_t x, uint16_t y, char ch, uint16_t color) { uint8_t i,j; uint8_t mask; const uint8_t *p font8x16[(ch-32)*16]; for(i0; i16; i) { mask 0x80; for(j0; j8; j) { if(*p mask) LCD_DrawPixel(xj, yi, color); mask 1; } p; } } // 显示字符串 void LCD_ShowString(uint16_t x, uint16_t y, const char *str, uint16_t color) { while(*str) { LCD_ShowChar(x, y, *str, color); x 8; if(x 120) { x 0; y 16; } } }5. 主程序实现与调试5.1 main函数实现在main.c中添加以下代码#include lcd.h int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); // LCD初始化 LCD_Init(); LCD_Clear(BLUE); // 显示Hello World LCD_ShowString(40, 72, Hello World!, WHITE); while(1) { // 可添加其他功能 } }5.2 常见问题排查屏幕无任何显示检查背光控制引脚是否拉高测量各引脚电压确认电源正常用逻辑分析仪或示波器检查SPI信号显示花屏或错乱确认初始化序列正确检查GPIO配置是否正确降低SPI时钟频率测试Keil编译错误确保包含路径设置正确检查HAL库版本兼容性清理工程后重新编译调试技巧在初始化过程中添加延时逐步排查各阶段问题。可使用HAL_GPIO_TogglePin()函数配合示波器验证GPIO操作。5.3 效果优化建议双缓冲技术减少屏幕闪烁DMA传输提高SPI传输效率硬件SPI替换模拟SPI提升速度图形库集成移植u8g2或LVGL等图形库// 使用硬件SPI的示例修改 void SPI_Write(uint8_t data) { HAL_SPI_Transmit(hspi1, data, 1, HAL_MAX_DELAY); }通过本项目的完整实践你不仅掌握了LCD驱动的基本原理更重要的是建立了使用STM32CubeMX进行图形化配置的信心。这种开发模式可以扩展到其他外设开发中大幅提高开发效率。当看到屏幕上首次显示出清晰的Hello World时相信你已经为后续更复杂的嵌入式图形开发打下了坚实基础。