手把手教你用STM32CubeMX配置SPI驱动ST7798液晶屏(附完整代码)

张开发
2026/4/19 13:02:09 15 分钟阅读
手把手教你用STM32CubeMX配置SPI驱动ST7798液晶屏(附完整代码)
STM32CubeMX实战零基础配置SPI驱动ST7798液晶屏全攻略第一次接触STM32的SPI外设时我被寄存器配置的复杂性吓到了——时钟分频、相位极性、数据对齐每个参数都像一道数学题。直到发现STM32CubeMX这个可视化配置工具才真正体会到图形化编程的威力。本文将带你用CubeMX完成SPI接口的ST7798液晶屏驱动开发从工程创建到显示效果调试全程避开我踩过的那些坑。1. 环境准备与工程创建在开始之前确保你的开发环境已经就绪。我推荐使用以下组合STM32CubeMX 6.5支持最新的HAL库Keil MDK 5.3或STM32CubeIDEST-Link V2调试器ST7798液晶模块240x320分辨率提示不同批次的ST7798可能存在初始化序列差异建议向供应商索取最新的数据手册。打开CubeMX后按照以下步骤创建基础工程点击New Project选择你的MCU型号如STM32F103C8T6在Pinout Configuration界面首先配置时钟源HSE选择Crystal/Ceramic Resonator在Clock Configuration标签页将系统时钟设置为72MHz// 生成的时钟配置代码示例自动生成 void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct {0}; // 配置HSE振荡器 RCC_OscInitStruct.OscillatorType RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState RCC_HSE_ON; RCC_OscInitStruct.HSEPredivValue RCC_HSE_PREDIV_DIV1; RCC_OscInitStruct.PLL.PLLState RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL RCC_PLL_MUL9; HAL_RCC_OscConfig(RCC_OscInitStruct); // 配置系统时钟 RCC_ClkInitStruct.ClockType RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider RCC_HCLK_DIV1; HAL_RCC_ClockConfig(RCC_ClkInitStruct, FLASH_LATENCY_2); }2. SPI外设图形化配置ST7798通常使用SPI接口的4线模式MOSI、SCK、CS、DC。在CubeMX中的配置要点2.1 SPI参数设置在Connectivity下选择SPI1或其它可用SPI接口配置参数如下表参数项推荐值说明ModeFull-Duplex Master全双工主模式Hardware NSSDisabled使用软件控制片选Prescaler256分频初始保守值后续可优化Clock PolarityHighCPOL1Clock Phase2 EdgeCPHA1First BitMSB数据传输从最高位开始Data Size8 bits8位数据帧2.2 GPIO引脚分配根据你的硬件连接分配对应的GPIO引脚。典型配置PA5SPI1_SCK时钟线PA6SPI1_MISO可省略ST7798通常不需要PA7SPI1_MOSI数据线PA4GPIO_Output片选CSPA8GPIO_Output数据/命令选择DCPA15GPIO_Output复位RESET注意如果使用硬件SPI务必选择MCU上带有AF复用功能标识的引脚。3. 生成代码与驱动集成点击Project Generate Code后CubeMX会自动生成初始化代码。接下来我们需要添加ST7798的驱动逻辑。3.1 创建LCD驱动文件在工程中新建st7798.c和st7798.h文件实现以下核心函数// st7798.h #define LCD_CS_PIN GPIO_PIN_4 #define LCD_CS_PORT GPIOA #define LCD_DC_PIN GPIO_PIN_8 #define LCD_DC_PORT GPIOA #define LCD_RESET_PIN GPIO_PIN_15 #define LCD_RESET_PORT GPIOA void ST7798_Init(void); void ST7798_WriteCommand(uint8_t cmd); void ST7798_WriteData(uint8_t data); void ST7798_SetWindow(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2);3.2 实现SPI传输函数在st7798.c中添加底层传输函数// 发送命令DC线拉低 void ST7798_WriteCommand(uint8_t cmd) { HAL_GPIO_WritePin(LCD_DC_PORT, LCD_DC_PIN, GPIO_PIN_RESET); HAL_GPIO_WritePin(LCD_CS_PORT, LCD_CS_PIN, GPIO_PIN_RESET); HAL_SPI_Transmit(hspi1, cmd, 1, HAL_MAX_DELAY); HAL_GPIO_WritePin(LCD_CS_PORT, LCD_CS_PIN, GPIO_PIN_SET); } // 发送数据DC线拉高 void ST7798_WriteData(uint8_t data) { HAL_GPIO_WritePin(LCD_DC_PORT, LCD_DC_PIN, GPIO_PIN_SET); HAL_GPIO_WritePin(LCD_CS_PORT, LCD_CS_PIN, GPIO_PIN_RESET); HAL_SPI_Transmit(hspi1, data, 1, HAL_MAX_DELAY); HAL_GPIO_WritePin(LCD_CS_PORT, LCD_CS_PIN, GPIO_PIN_SET); }4. ST7798初始化与功能实现ST7798的初始化序列较为复杂需要严格按照时序操作。以下是经过验证的初始化流程4.1 硬件复位序列void ST7798_Reset(void) { HAL_GPIO_WritePin(LCD_RESET_PORT, LCD_RESET_PIN, GPIO_PIN_RESET); HAL_Delay(120); HAL_GPIO_WritePin(LCD_RESET_PORT, LCD_RESET_PIN, GPIO_PIN_SET); HAL_Delay(120); }4.2 初始化命令序列void ST7798_Init(void) { ST7798_Reset(); /* Sleep Out */ ST7798_WriteCommand(0x11); HAL_Delay(120); /* Memory Data Access Control */ ST7798_WriteCommand(0x36); ST7798_WriteData(0x00); // MX0, MY0, MV0, RGB0 /* Interface Pixel Format */ ST7798_WriteCommand(0x3A); ST7798_WriteData(0x55); // 16-bit/pixel /* Display On */ ST7798_WriteCommand(0x29); HAL_Delay(50); }4.3 实现绘图函数基于SPI接口实现基本图形绘制功能// 设置显示窗口 void ST7798_SetWindow(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) { ST7798_WriteCommand(0x2A); // 列地址设置 ST7798_WriteData(x1 8); ST7798_WriteData(x1 0xFF); ST7798_WriteData(x2 8); ST7798_WriteData(x2 0xFF); ST7798_WriteCommand(0x2B); // 行地址设置 ST7798_WriteData(y1 8); ST7798_WriteData(y1 0xFF); ST7798_WriteData(y2 8); ST7798_WriteData(y2 0xFF); ST7798_WriteCommand(0x2C); // 写入RAM } // 填充矩形区域 void ST7798_FillRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color) { uint8_t hi color 8, lo color 0xFF; uint32_t pixels w * h; ST7798_SetWindow(x, y, x w - 1, y h - 1); HAL_GPIO_WritePin(LCD_DC_PORT, LCD_DC_PIN, GPIO_PIN_SET); HAL_GPIO_WritePin(LCD_CS_PORT, LCD_CS_PIN, GPIO_PIN_RESET); while(pixels--) { HAL_SPI_Transmit(hspi1, hi, 1, HAL_MAX_DELAY); HAL_SPI_Transmit(hspi1, lo, 1, HAL_MAX_DELAY); } HAL_GPIO_WritePin(LCD_CS_PORT, LCD_CS_PIN, GPIO_PIN_SET); }5. 性能优化与调试技巧当基础功能实现后可以通过以下方式提升显示性能5.1 SPI时钟优化初始保守使用256分频确认显示正常后可逐步提高时钟// 在main.c中调用 void SPI_SetSpeed(uint32_t prescaler) { hspi1.Instance-CR1 ~SPI_BAUDRATEPRESCALER_256; hspi1.Instance-CR1 | prescaler; } // 使用示例设置为8分频 SPI_SetSpeed(SPI_BAUDRATEPRESCALER_8);5.2 DMA传输优化对于全屏刷新等大数据量操作使用DMA可以显著提升效率在CubeMX中启用SPI的DMA传输修改发送函数// 使用DMA传输颜色数据 void ST7798_FillRect_DMA(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color) { static uint8_t colorBuf[2]; colorBuf[0] color 8; colorBuf[1] color 0xFF; ST7798_SetWindow(x, y, x w - 1, y h - 1); HAL_GPIO_WritePin(LCD_DC_PORT, LCD_DC_PIN, GPIO_PIN_SET); HAL_GPIO_WritePin(LCD_CS_PORT, LCD_CS_PIN, GPIO_PIN_RESET); for(uint32_t i 0; i w * h; i) { HAL_SPI_Transmit_DMA(hspi1, colorBuf, 2); while(HAL_SPI_GetState(hspi1) ! HAL_SPI_STATE_READY); } HAL_GPIO_WritePin(LCD_CS_PORT, LCD_CS_PIN, GPIO_PIN_SET); }5.3 常见问题排查当遇到显示异常时可以按照以下步骤排查检查电源确保3.3V供电稳定电流足够至少200mA验证信号时序用逻辑分析仪抓取SPI波形确认时钟频率是否符合预期数据在正确的时钟边沿采样检查初始化序列不同批次ST7798可能需要调整延迟时间测试GPIO状态确认CS、DC等控制信号的电平变化正确调试技巧在初始化失败时可以尝试降低SPI时钟频率或增加命令之间的延迟。

更多文章