翻箱倒柜时,那块落满灰尘的小熊派开发板突然映入眼帘——去年双十一冲动消费的"学习利器",如今却成了电子垃圾。但别急着扔掉!今天我们就用CubeMX这个神器,配合SPI接口,让这块板子重获新生,驱动LCD屏幕实现炫酷的图形显示效果。整个过程就像给老房子做智能改造,既保留了硬件基础,又注入了全新活力。
从抽屉深处找出小熊派开发板时,建议先做个"体检":检查板载STM32芯片型号(通常是STM32L4系列)、SPI接口位置和LCD屏幕规格。我那块板子的LCD是1.3寸IPS屏,分辨率240×240,通过SPI接口通信。准备好USB数据线、ST-Link调试器和杜邦线,硬件阵容就齐活了。
打开STM32CubeMX,新建工程时有个容易踩的坑:务必选择与开发板完全匹配的芯片型号。小熊派常用STM32L431RCT6,选错会导致后续引脚配置对不上。时钟配置是第一个关键点:
c复制/* 时钟树典型配置 */
HCLK = 80MHz
PCLK1 = 80MHz
PCLK2 = 80MHz
SPI配置要特别注意三点:
引脚重映射是新手常忽略的步骤。小熊派的SPI2_SCK默认引脚PB10需要改为PB13,就像给电器换插头一样简单:在Pinout视图找到对应引脚,右键选择SPI2_SCK功能即可。
拿到厂家提供的LCD驱动代码包后,别急着全盘照搬。我习惯先建立/Hardware/LCD目录,把.c/.h文件分类存放。驱动文件中这几个函数需要重点检查:
c复制void LCD_WriteCommand(uint8_t cmd);
void LCD_WriteData(uint8_t data);
void LCD_Reset(void);
SPI传输函数要加上超时保护,就像给管道加装压力阀:
c复制uint8_t SPI2_WriteByte(uint8_t* data, uint16_t size) {
HAL_StatusTypeDef status = HAL_SPI_Transmit(&hspi2, data, size, 100);
return (status == HAL_OK) ? 0 : 1;
}
字体处理是显示效果的关键。我推荐使用开源字体库,比如U8g2的字模提取工具,可以生成多种大小的点阵字体。将字体数据存放在单独的font.c文件中,通过条件编译管理不同字号:
c复制#ifdef FONT_16x16
const uint8_t Font16_Table[] = {...};
#endif
#ifdef FONT_24x24
const uint8_t Font24_Table[] = {...};
#endif
清屏操作看似简单,但优化后能提升3倍速度。传统的逐像素填充太慢,改用memset配合DMA传输:
c复制void LCD_FastClear(uint16_t color) {
uint16_t buffer[240];
for(int i=0; i<240; i++) buffer[i] = color;
HAL_SPI_Transmit_DMA(&hspi2, (uint8_t*)buffer, 240*2);
}
绘制同心圆时,Bresenham算法比标准圆方程效率高得多。下面是优化后的画圆函数核心:
c复制void LCD_Draw_Circle(int x0, int y0, int r) {
int x = 0, y = r;
int d = 3 - 2 * r;
while(x <= y) {
DrawCirclePoints(x0, y0, x, y); // 八对称画点
if(d < 0) d += 4*x +6;
else {
d += 4*(x-y) +10;
y--;
}
x++;
}
}
多字体混排要注意基线对齐。中文字体通常比同等point的英文字体视觉上更大,需要微调Y坐标:
| 字体类型 | 推荐Y偏移 | 适用场景 |
|---|---|---|
| 16x16英文 | +0 | 状态栏小字 |
| 24x24中文 | -2 | 主标题 |
| 32x32数字 | +1 | 突出显示数据 |
用逻辑分析仪抓取SPI波形时,发现默认配置的传输速率只有1MHz。通过修改CubeMX中的Prescaler参数,可以轻松提升到10MHz:
code复制SPI2->CR1 |= SPI_BAUDRATEPRESCALER_8; // 10MHz @ 80MHz PCLK
双缓冲技术能有效解决画面闪烁问题。建立两个显示缓冲区,一个用于绘制,一个用于显示,通过指针交换实现无缝切换:
c复制uint16_t buffer1[240][240];
uint16_t buffer2[240][240];
uint16_t *activeBuf = buffer1;
uint16_t *drawBuf = buffer2;
void SwapBuffers() {
uint16_t *temp = activeBuf;
activeBuf = drawBuf;
drawBuf = temp;
LCD_Refresh(activeBuf); // DMA传输整个缓冲区
}
当遇到显示乱码时,建议按这个顺序排查:
最后分享一个实用技巧:在while(1)循环中加入按键检测,通过不同按键切换显示模式,让demo更具交互性。我常用这种方案给学生演示时增加趣味性:
c复制if(HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == GPIO_PIN_RESET) {
current_mode = (current_mode + 1) % TOTAL_MODES;
HAL_Delay(200); // 消抖
}