STM32CubeIDE实战:手把手教你将正点原子LCD驱动移植到F103精英板(附完整代码)
STM32CubeIDE实战:手把手教你将正点原子LCD驱动移植到F103精英板(附完整代码)
对于刚接触STM32 HAL库和CubeIDE的开发者来说,LCD屏幕的驱动移植往往是一个令人头疼的问题。特别是当你手头有一块正点原子的精英开发板,想要快速点亮LCD屏幕时,可能会遇到各种意想不到的挑战。本文将带你一步步完成从标准库到HAL库的驱动移植,避开那些常见的"坑",让你能够快速实现LCD显示功能。
1. 环境准备与硬件连接
在开始移植工作之前,我们需要确保开发环境已经正确搭建。以下是需要准备的软硬件资源:
硬件设备:
- 正点原子F103精英开发板
- 配套的LCD显示屏(如2.8寸TFT LCD)
- ST-Link调试器
软件工具:
- STM32CubeIDE(建议使用最新版本)
- 正点原子官方提供的标准库例程
注意:精英板和Mini板的LCD驱动有细微差别,请确认你使用的是精英板对应的驱动代码。
硬件连接方面,确保LCD模块已正确插入开发板的LCD接口。精英板通常使用FSMC接口连接LCD,具体引脚对应关系可以在开发板原理图中找到。
2. CubeMX基础配置
STM32CubeMX的图形化配置大大简化了外设初始化过程。以下是关键配置步骤:
2.1 创建新工程
- 打开STM32CubeIDE,选择"File"→"New"→"STM32 Project"
- 在MCU选择器中输入"STM32F103ZE"(精英板主控型号)
- 设置项目名称和保存路径
2.2 时钟配置
在"Clock Configuration"标签页中,按以下步骤配置时钟树:
- 选择外部晶振(HSE)作为时钟源
- 设置系统时钟为72MHz
- 确保FSMC时钟已使能
// 生成的时钟配置代码示例 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.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.3 FSMC接口配置
FSMC(Flexible Static Memory Controller)是STM32与LCD通信的关键接口。在CubeMX中按以下步骤配置:
- 左侧导航栏选择"Connectivity"→"FSMC"
- 启用"FSMC"并选择"LCD Interface"
- 配置参数如下表所示:
| 参数项 | 配置值 |
|---|---|
| Bank | Bank1_NORSRAM4 |
| Memory type | SRAM |
| Data width | 16-bit |
| Address setup time | 2 HCLK周期 |
| Data setup time | 5 HCLK周期 |
| Bus turnaround time | 0 HCLK周期 |
特别注意:LCD Register Select引脚在精英板上通常使用FSMC_A10(而非某些教程中的A6),这需要根据实际原理图确认。
3. 驱动文件移植与修改
正点原子提供的标准库驱动需要经过适当修改才能用于HAL库环境。以下是关键修改步骤:
3.1 文件结构准备
- 在项目"Core"目录下创建"LCD"文件夹
- 添加以下文件到项目中:
- lcd.c
- lcd.h
- font.h
3.2 关键代码修改
在lcd.c文件中,需要进行以下修改:
- 头文件调整:
// 注释掉标准库头文件 // #include "sys.h" // #include "delay.h" // 添加HAL库头文件 #include "main.h"- 数据类型替换:
// 将u8/u16/u32替换为标准类型 // 原代码:u8 -> uint8_t // u16 -> uint16_t // u32 -> uint32_t- 延时函数替换:
// 将delay_ms替换为HAL_Delay // 原代码:delay_ms(50) -> HAL_Delay(50)- FSMC初始化代码处理:
// 注释掉原有的FSMC初始化代码 // 因为CubeMX已经生成这部分配置 // void HAL_SRAM_MspInit(SRAM_HandleTypeDef *hsram) // { // ... // }- LCD初始化简化:
void LCD_Init(void) { // 保留LCD控制器初始化部分 // 但移除GPIO和FSMC的硬件初始化代码 // 因为这些已由CubeMX配置 // 示例保留部分: LCD_WR_REG(0xCF); LCD_WR_DATA(0x00); LCD_WR_DATA(0xC1); LCD_WR_DATA(0X30); // ...其他LCD控制器初始化命令 }3.3 背光控制调整
精英板的背光控制通常通过PB0引脚实现,需要在CubeMX中配置该引脚为GPIO输出:
// 在main.c的初始化部分添加背光控制 HAL_GPIO_WritePin(LCD_BL_GPIO_Port, LCD_BL_Pin, GPIO_PIN_SET);4. 主程序集成与测试
完成驱动移植后,需要在主程序中集成LCD功能并进行测试。
4.1 头文件包含
在main.c中添加必要的头文件:
/* USER CODE BEGIN Includes */ #include "lcd.h" #include <stdio.h> /* USER CODE END Includes */4.2 初始化调用
在main()函数中找到"/* USER CODE BEGIN 2 */"部分,添加LCD初始化代码:
/* USER CODE BEGIN 2 */ LCD_Init(); LCD_DisplayOn(); LCD_Clear(RED); HAL_GPIO_WritePin(LCD_BL_GPIO_Port, LCD_BL_Pin, GPIO_PIN_SET); /* USER CODE END 2 */4.3 测试代码
在main循环中添加简单的显示测试:
/* USER CODE BEGIN WHILE */ while (1) { LCD_ShowString(30, 40, 210, 24, 24, "Hello World"); HAL_Delay(1000); LCD_Clear(BLUE); HAL_Delay(1000); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */5. 常见问题与解决方案
在实际移植过程中,你可能会遇到以下问题:
5.1 屏幕无显示
检查步骤:
- 确认背光是否点亮
- 检查FSMC引脚配置是否正确
- 验证LCD初始化序列是否完整执行
解决方案:
// 可以添加调试输出,检查初始化流程 printf("LCD Init Start...\n"); LCD_Init(); printf("LCD Init Done.\n");5.2 显示内容错位
可能原因:
- 扫描方向设置不正确
- 显存地址映射错误
调整方法:
// 尝试不同的扫描方向 LCD_Scan_Dir(DFT_SCAN_DIR); // 默认方向 // 或 LCD_Scan_Dir(L2R_U2D); // 从左到右,从上到下5.3 性能优化
对于需要频繁刷新的应用,可以考虑以下优化:
- 使用DMA加速数据传输:
// 示例DMA配置(需在CubeMX中启用) hdma_memtomem_dma2.Init.Direction = DMA_MEMORY_TO_MEMORY; hdma_memtomem_dma2.Init.PeriphInc = DMA_PINC_ENABLE; hdma_memtomem_dma2.Init.MemInc = DMA_MINC_ENABLE;- 减少不必要的全屏刷新:
// 只更新需要改变的区域 LCD_Set_Window(x, y, width, height); LCD_Color_Fill(x, y, x+width-1, y+height-1, color_buf);- 使用硬件加速功能:
// 某些LCD控制器支持硬件加速 LCD_WriteReg(0x36, 0x48); // 设置内存访问控制在实际项目中,LCD驱动移植只是第一步。后续你可能还需要添加触摸屏支持、GUI界面等更多功能。通过这次移植实践,你应该已经掌握了HAL库下LCD驱动的基本原理和调试方法。
