目录
一:使用STM32CubeMX配置工程
二、TFT_LCD液晶显示(FSMC接口使用)
三、效果展示
一:使用STM32CubeMX配置工程
进入MCU选择页面
选择自己芯片对应的型号(我的芯片型号是STM32F103ZET6)
配置为高速外部时钟
确定自己芯片的系统主频,配置时钟
配置sys_tick时基源
配置定时器TIM6,1ms中断1次,为LVGL心跳提供时钟节拍
TIM6的时钟频率为72Mhz定时器溢出时间:Tout = 1000/(72M/72) = 0.001S = 1ms
根据自己的板子,配置一个LED,作为系统运行的指示灯
定义工程名称、工程存储路径、IDE名称、将最小栈空间改到0x1000
注意:由于LVGL运行的硬件要求,故需要加大项目的栈空间到 2KB 和使能 C99 编译器功能,修改 Stack_Size 的值大于 2KB(0x00000800)
LL库与HAL库混合使用
HAL库对于不同芯片的兼容性好、对新手入门也很友好,但它对内存的占用比较大、执行效率也不高。HAL库对外设都设计了一套使用规则,理想环境中你按照它的规则用挺方便,但是如果要实现一些特殊的用法(比如串口使用DMA循环接收),或是应用的环境比较恶劣的话HAL库就不是那么好用了,这个时候LL库就比较好用了。LL差不多就是直接对寄存器的操作,你可以完全凭自己的想法来设计程序逻辑,在某些情况下会非常好用。其它系列的LL库在设计思路上也是差不多的。
打开生成的Keil工程,CubeMx生成的代码有些寄存器没有使能,我们不能直接使用,需要我们自己使能相关寄存器
定时器使能代码:LL_TIM_EnableCounter(TIM6); //使能计数LL_TIM_EnableIT_UPDATE(TIM6); //使能更新中断LL_TIM_EnableAllOutputs(TIM6); 更新中断标志获取与清除代码:if(LL_TIM_IsActiveFlag_UPDATE(TIM6) == SET){LL_TIM_ClearFlag_UPDATE(TIM6);}
二、TFT_LCD液晶显示(FSMC接口使用)
由于TFT_LCD的知识,比较多,我这里尽量简明扼要地讲讲我认为开发中需要用的部分
FSMC接口
FSMC,即灵活的静态存储控制器,能够与同步或异步存储器和16位PC存储器卡连接,STM32的FSMC接口支持包括SRAM、NAND FLASH、NOR FLASH和PSRAM等存储器。
FSMC的框图如下图所示:
TFTLCD通过RS信号来决定传送的数据是数据还是命令,本质上可以理解为一个地址信号,比如我们把RS接在A0上面,那么当FSMC控制器写地址0的时候,会使得A0变为0,对TFTLCD来说,就是写命令。而FSMC写地址1的时候,A0将会变为1,对TFTLCD来说,就是写数据了。这样,就把数据和命令区分开了,他们其实就是对应SRAM操作的两个连续地址。当然RS也可以接在其他地址线上,而这个板子是把RS接在A6上面。这里需要注意:FSMC接口驱动LCD时,其实是将LCD当作一个外部的SRAM来驱动的,唯一不同就是TFTLCD有RS信号,但是没有地址信号FSMC驱动外部SRAM时,外部SRAM的控制一般有:地址线(如A0-A25)、数据线(如D0-D15)、写信号(WE,即WR)、读信号(OE,即RD)、片选信号(CS),如果SRAM支持字节控制,那么还有UB/LB信号。
STM32的FSMC支持8/16/32位数据宽度,我们这里用到的LCD是16位宽度的,所以在设置的时候,选择16位宽就OK了。FSMC的外部设备地址映像,STM32的FSMC将外部存储器划分为固定大小为256M字节的四个存储块。
STM32的FSMC存储块1(Bank1)用于驱动NOR FLASH/SRAM/PSRAM,被分为4个区,每个区管理64M字节空间,每个区都有独立的寄存器对所连接的存储器进行配置。Bank1的256M字节空间由28根地址线(HADDR[27:0])寻址。
这里HADDR,是内部AHB地址总线,其中,HADDR[25:0]来自外部存储器地址FSMC_A[25:0],而HADDR[26:27]对4个区进行寻址。如下表所示:
当Bank1接的是16位宽度存储器的时候:HADDR[25:1]-> FSMC_A[24:0]
当Bank1接的是8位宽度存储器的时候:HADDR[25:0]->FSMC_A[25:0]
不论外部接8位/16位宽设备,FSMC_A[0]永远接在外部设备地址A[0]
STM32的FSMC存储块1 支持的异步突发访问模式包括:模式1、模式A~D等多种时序模型,驱动SRAM时一般使用模式1或者模式 A,这里我们使用模式A来驱动LCD(当SRAM用)
原理图
本人使用的是正点原子战舰开发板,芯片型号为STM32F103ZET6,LCD部分原理图如下
复位脚(RST)和单片机的复位脚是接到一起的,这样的做法可以节省一个IO
电源背光脚,打开了屏幕才能亮
三、CubeMX配置FSMC
打开上方我们配置好的CubeMX工程,按照如下步骤配置
这边的选择根据在FSMC介绍的时候都已经详细讲到了,这里就只进行大致的说明。
1.NOR Flash/PSRAM/SRAM/ROM/LCD 1,这里选择这个也就是STM32的FSMC存储块1(Bank1)了
2. Chip Select,选择Bank1的第四区,是根据原理图的映射管脚进行选择的,这里选择不同区对应的引脚是不同的
3. Memory Type,存储类型,这里当然是选择LCD接口,那么里面还可以选择其他的存储类型,如果需要使用其他类型的存储设备也可以详细了解
4. LCD Register Select,这里是选择RS脚,也就是命令/数据选择位,同样是根据原理图得知这里应该选择A10
5. Data,数据位,很明显从原理图看出有16个数据引脚,这里选择16bits就好
接下来这里有一件事情需要大家注意一下,就是最好将目前为止的引脚使能情况跟原理图中的一一对应,也就是检查一遍,虽然花不了多少时间,但是由于使能了大量的引脚,一旦出错那么整个工程就是失败的
参数配置如下:
地址建立的时钟周期数据建立的时钟周期总线转阶段持续时间扩展地址建立时间扩展数据建立时间扩展总线建立时间
这里扩展的意思就是写时序,而上面几条是读时序。
PS:这里计算我也不太懂的,有兴趣的可以自己去研究一下,我是直接参考正点原子的初始化代码部分配置,屏幕供应商一般都会提供驱动代码的,直接参考就可以了
最后配置背光引脚
配置为上拉高速,初始电平为低。
以上工作完成后,生成代码,打开新工程,编译
在原有的工程文件夹下增加User文件夹,把显示屏的驱动代码添加至里面,我用的是正点原子的屏幕,所以我把正点原子屏幕的驱动代码拷贝进来
打开工程,添加.c 文件和.h文件
注意:以下步骤局限于正点原子的屏幕驱动代码!!!
打开tim.c文件,增加两个延时函数
void delay_us(uint32_t nus){uint32_t i=0;for(i=0; i<nus; i++){__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();}}void delay_ms(uint32_t uiMS){uint32_t i=1000*uiMS;delay_us(i);}
打开lcd.c函数,void LCD_Init(void)屏蔽如下代码
并把程序中的printf函数屏幕掉!!!
并在lcd.c文件,屏蔽usart.h 和delay.h头文件,增加tim.h头文件
打开lcd.h文件,屏蔽sys.h头文件,增加#include "stm32f103xe.h"头文件
并在下方增加如下代码
typedef uint16_t u16;typedef uint8_t u8;typedef uint32_t u32;typedef __IO uint16_t vu16;
并修改背光控制引脚
回到main.c,增加以下代码,编译代码,烧录