1. 项目背景与硬件选型在嵌入式开发领域SPI接口的LCD屏因其接线简单、刷新速度快等优势成为人机交互界面的首选方案。这次我选用上海航芯的ACM32F403RET7作为主控芯片搭配ST7735驱动的1.44寸LCD屏进行开发测试。ACM32F403RET7是国产MCU中的佼佼者主频高达120MHz内置硬件SPI控制器完全能满足中小尺寸LCD屏的驱动需求。选择ST7735驱动的LCD屏主要基于三点考虑首先ST7735是经过市场验证的成熟方案资料丰富其次1.44寸128×128分辨率的屏幕在显示效果和功耗之间取得了良好平衡最后SPI接口只需4-5根线即可驱动大大简化了硬件设计。2. 硬件连接与SPI配置2.1 引脚定义与连接ST7735 LCD模块通常包含以下关键引脚VCC3.3V电源输入GND地线SCLSPI时钟线SDASPI数据线RES复位信号DC数据/命令选择CS片选信号BLK背光控制具体到ACM32F403RET7的连接方案如下LCD引脚ACM32引脚功能备注VCC3.3V必须3.3VGNDGND共地SCLPA5SPI1_SCKSDAPA7SPI1_MOSIRESPB10硬件复位DCPB11数据/命令CSPB12片选BLKPB1背光控制特别注意ST7735是3.3V器件绝对不能接5V电源否则会永久损坏模块。2.2 SPI外设初始化ACM32F403RET7的SPI控制器配置需要关注以下几个关键参数void SPI1_Init(void) { hspi1.Instance SPI1; hspi1.Init.Mode SPI_MODE_MASTER; hspi1.Init.Direction SPI_DIRECTION_2LINES; hspi1.Init.DataSize SPI_DATASIZE_8BIT; hspi1.Init.CLKPolarity SPI_POLARITY_LOW; // CPOL0 hspi1.Init.CLKPhase SPI_PHASE_1EDGE; // CPHA0 → Mode 0 hspi1.Init.NSS SPI_NSS_SOFT; // 软件控制CS hspi1.Init.BaudRatePrescaler SPI_BAUDRATEPRESCALER_4; // 30MHz hspi1.Init.FirstBit SPI_FIRSTBIT_MSB; if (HAL_SPI_Init(hspi1) ! HAL_OK) { Error_Handler(); } }ST7735默认支持SPI Mode 0和Mode 3大多数模块出厂设置为Mode 0。实测发现当SPI时钟超过15MHz时显示可能会出现雪花噪点因此将预分频设为4在120MHz系统时钟下得到30MHz的SPI时钟实际使用中稳定可靠。3. ST7735驱动实现3.1 基础通信函数与ST7735的通信需要两种基本操作发送命令和发送数据。通过DC引脚区分两者void ST7735_WriteCommand(uint8_t cmd) { HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_RESET); // DC0:命令 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET); // CS0:选中 HAL_SPI_Transmit(hspi1, cmd, 1, HAL_MAX_DELAY); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET); // CS1:释放 } void ST7735_WriteData(uint8_t data) { HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_SET); // DC1:数据 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET); // CS0 HAL_SPI_Transmit(hspi1, data, 1, HAL_MAX_DELAY); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET); }对于连续写入多个数据的情况可以优化为批量传输void ST7735_WriteDataBuffer(uint8_t *data, uint32_t len) { HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET); HAL_SPI_Transmit(hspi1, data, len, HAL_MAX_DELAY); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET); }3.2 初始化序列ST7735需要一系列初始化命令才能正常工作。不同厂商的模块可能略有差异以下是一个典型的初始化流程void ST7735_Init(void) { // 硬件复位 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET); HAL_Delay(10); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET); HAL_Delay(120); // 等待复位完成 ST7735_WriteCommand(0x11); // Sleep out HAL_Delay(120); ST7735_WriteCommand(0xB1); // 帧率控制 ST7735_WriteData(0x05); // RTNA ST7735_WriteData(0x3C); // 前端周期 ST7735_WriteData(0x3C); // 后端周期 ST7735_WriteCommand(0xB2); // 帧率控制 ST7735_WriteData(0x05); ST7735_WriteData(0x3C); ST7735_WriteData(0x3C); ST7735_WriteCommand(0xB3); // 帧率控制 ST7735_WriteData(0x05); ST7735_WriteData(0x3C); ST7735_WriteData(0x3C); ST7735_WriteData(0x05); ST7735_WriteData(0x3C); ST7735_WriteData(0x3C); ST7735_WriteCommand(0xB4); // 显示反转控制 ST7735_WriteData(0x03); ST7735_WriteCommand(0x36); // 内存数据访问控制 ST7735_WriteData(0xC8); // 行地址顺序、列地址顺序、RGB顺序 // 更多初始化命令... ST7735_WriteCommand(0x29); // 开启显示 }经验分享初始化失败最常见的原因是复位后等待时间不足。ST7735复位后需要至少120ms的稳定时间否则后续命令可能无法正确执行。3.3 显示区域设置ST7735采用GRAM图形内存架构需要先设置显示窗口再写入像素数据void ST7735_SetWindow(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1) { ST7735_WriteCommand(0x2A); // 列地址设置 ST7735_WriteData(0x00); ST7735_WriteData(x0 2); // 部分模块需要偏移 ST7735_WriteData(0x00); ST7735_WriteData(x1 2); ST7735_WriteCommand(0x2B); // 行地址设置 ST7735_WriteData(0x00); ST7735_WriteData(y0 3); ST7735_WriteData(0x00); ST7735_WriteData(y1 3); ST7735_WriteCommand(0x2C); // 内存写入 }4. 图形绘制与优化4.1 基本绘图函数基于上述基础可以实现各种绘图功能。首先是清屏函数void ST7735_Clear(uint16_t color) { uint8_t buff[40]; uint16_t i; // 将颜色拆分为高8位和低8位 uint8_t hi color 8; uint8_t lo color 0xFF; // 填充缓冲区 for(i0; isizeof(buff); i2) { buff[i] hi; buff[i1] lo; } ST7735_SetWindow(0, 0, 127, 127); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET); // 分批次传输减少单次传输数据量 for(i0; i128*128; isizeof(buff)/2) { HAL_SPI_Transmit(hspi1, buff, sizeof(buff), HAL_MAX_DELAY); } HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET); }绘制单个像素点void ST7735_DrawPixel(uint8_t x, uint8_t y, uint16_t color) { ST7735_SetWindow(x, y, x, y); uint8_t data[2] {color 8, color 0xFF}; ST7735_WriteDataBuffer(data, 2); }4.2 显示优化技巧直接操作像素点效率较低实际应用中可以采用以下优化策略局部刷新只更新屏幕上发生变化的部分减少数据传输量双缓冲在内存中维护一个屏幕缓冲区完成所有绘制操作后一次性更新到屏幕DMA传输利用ACM32F403RET7的DMA控制器释放CPU资源以下是使用DMA进行屏幕刷新的示例// 定义屏幕缓冲区 uint16_t frameBuffer[128][128]; void ST7735_Refresh(void) { ST7735_SetWindow(0, 0, 127, 127); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET); // 启动DMA传输 HAL_SPI_Transmit_DMA(hspi1, (uint8_t*)frameBuffer, 128*128*2); // 等待传输完成 while(HAL_SPI_GetState(hspi1) ! HAL_SPI_STATE_READY); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET); }5. 实际应用与问题排查5.1 显示异常排查在开发过程中可能会遇到各种显示问题以下是常见问题及解决方法屏幕全白或全黑检查背光是否正常测量BLK引脚电压确认复位时序是否正确复位脉冲宽度至少10μs验证电源电压是否稳定3.3V±10%显示内容错位检查窗口设置命令的参数确认内存数据访问控制寄存器0x36配置是否正确部分模块需要设置偏移量如x2, y3显示花屏或雪花噪点降低SPI时钟频率尝试SPI_BAUDRATEPRESCALER_8或更大检查PCB布线确保SCK和MOSI线长度匹配在SPI线上增加33Ω串联电阻5.2 性能优化建议SPI时钟优化在保证稳定的前提下尽可能提高时钟频率批量传输将多个像素点数据打包传输减少CS切换开销智能更新只刷新屏幕上发生变化的部分区域硬件加速利用ACM32F403RET7的硬件加速模块处理图形操作经过实际测试在120MHz系统时钟下使用SPI时钟30MHz预分频4配合DMA传输可以实现全屏刷新率超过30fps完全满足大多数嵌入式GUI应用的需求。