很多朋友第一次接触STM32开发板时,都会遇到一个经典问题:明明照着教程操作,为什么LCD屏幕就是不亮?这个问题我当年也遇到过,折腾了整整两天才解决。其实核心原因在于,正点原子提供的例程是基于标准库开发的,而我们现在使用STM32CubeMX+HAL库新建的工程,两者在底层实现上有不少差异。
举个生活中的例子,就像你从安卓手机换到iPhone,虽然都能打电话发短信,但操作方式和应用商店完全不同。STM32的标准库和HAL库也是类似的关系。正点原子的LCD驱动代码就像是为安卓设计的APP,我们需要做一些适配工作才能让它跑在iPhone(HAL库环境)上。
具体来说,移植过程中会遇到几个关键问题:
以正点原子常用的2.8寸LCD为例,通过查看开发板原理图可以发现几个关键信息:
这就像给LCD分配了一个"门牌号":当STM32访问Bank1的第四个区域(NE4)时,实际上就是在和LCD通信。A10地址线则用来区分是发送命令(A10=0)还是数据(A10=1)。
FSMC把外部设备分成了4个大区(Bank),每个Bank有256MB地址空间:
我们的LCD接在NE4上,所以对应的是Bank1的第四个区域。在CubeMX配置时,要特别注意选择正确的Bank和片选信号。
首先打开STM32CubeMX,选择STM32F103ZET6芯片,按照以下步骤操作:
这里有个实用技巧:时序参数可以先按默认值设置,如果屏幕显示不正常再微调。我实测发现写时序的BusTurnAroundDuration参数特别敏感,设置为0最稳定。
在Clock Configuration页面:
建议新手直接使用CubeMX的自动时钟配置功能,它能确保各时钟树关系正确。我曾经因为APB1时钟超频导致FSMC工作异常,排查了好久才发现问题。
从正点原子例程中复制以下文件到新工程:
在Keil/IAR中添加这些文件到工程时,要注意:
原代码中大量使用了u8/u16等自定义类型,我们需要批量替换为HAL库标准类型:
有个坑要注意:替换时选择"匹配整个单词",避免误改变量名中包含这些字符的情况。我曾经把"lcd_user"变量误替换成了"lcd_uint8_ter",导致编译报错。
最常见的需要修改的函数包括:
c复制void delay_us(uint32_t us)
{
uint32_t start = DWT->CYCCNT;
uint32_t cycles = us * (SystemCoreClock / 1000000);
while((DWT->CYCCNT - start) < cycles);
}
按照以下顺序检查:
我遇到过一个奇葩情况:开发板的LCD排线接触不良,导致时好时坏。用酒精擦拭排线接口后问题解决。
这类问题通常与时序配置有关:
有个实用调试技巧:在初始化代码中加入延时,逐步观察屏幕变化。比如在每一条初始化命令后加100ms延时,这样能直观看到初始化过程。
当需要刷屏或显示动画时,可以采取以下优化措施:
在我的一个气象站项目中,通过优化FSMC时序,将屏幕刷新率从15FPS提升到了35FPS,效果非常明显。
移植完成后,建议保存一份配置好的工程模板。以后新建项目时,可以直接复用这些配置,省去重复劳动。我在自己的开发中建立了一套模块化工程模板,新项目平均能节省2-3天的初始化时间。