使用STM32CubeMX配置FSMC模块驱动LCD屏(基于正点原子历程)详解

前言

在学习STM32的过程中,刚好学到了LCD屏,我使用的是STM32F103ZET6,屏幕是正点原子的。但是在我自己新建工程点亮显示LCD屏时遇到了很多问题。解决之后分享在此,希望能帮助到遇到此困惑的朋友。
想要快速驱动LCD屏请直接跳转到CubeMX配置

FSMC简单介绍

FSMC全名叫可变静态存储控制器(Flexible Static Memory Controller,FSMC)是单片机的一种接口,它能够连接同步或异步存储器、16位PC存储卡和LCD模块。FSMC连接的所有外部存储器共享地址、数据和控制信号,但有各自的片选信号,所以,FSMC一次只能访问一个外部器件。
FSMC接口用于驱动外部存储器,也可以用于驱动8080接口的TFT LCD。
从FSMC的角度来看,外部存储器被划分为4个固定大小的存储区域,每个存储区域大小为256MB,各个区域的作用描述如下。

Bank1可连接多达4个NOR Flash或PSRAM/SRAM存储器件,因为它被分为4个子区(subbank),每个子区容量为64MB,有专用的片选信号。这些子区适合于连接TFT LCD。
Bank 1 -NOR/PSRAM 1,片选信号NE1。
Bank 1 -NOR/PSRAM 2,片选信号NE2。
Bank 1 -NOR/PSRAM 3,片选信号NE3。(开发板上用于连接外部SRAM)
Bank 1 -NOR/PSRAM 4,片选信号NE4。(开发板上用于连接TFT LCD)

Bank2 和 Bank3用于访问NAND Flash存储器,每个存储区域连接一个设备。

Bank4 用于连接PC卡设备。

TFT LCD简单介绍

TFT LCD 即薄膜晶体管(Thin Film Transistor)LCD,具有辐射低、功耗低、全彩色等优点, 是各种电子设备常用的一种显示设备。TFT LCD(后面也会简称为LCD)通常使用标准的8080并口,这种接口有16位数据线,还有几根控制线。TFTLCD的8080并行接口线的功能如下图所示。

CubeMX配置

FSMC子区配置

开发板上LCD原理图

通过原理图也可知要将子区配置为NE4。
LCD_Register Select寄存器根据原理图RS位可知设为A10.。
同时要将LCD_BL对应的引脚设置为输出模式即可(背光引脚)。(我这里对应的是PB0)
FSMC相关参数配置

RCC时钟配置

配置时钟树时默认将HCLK配置为72MHz(最大)即可。

LCD驱动程序改写

因为每块开发板对应的LCD历程会有所不一样,且为了保证不同芯片驱动的LCD都能够点亮。所以请下载正点原子资料下载中心的STM32F103最小系统板的TFT LCDHAL库历程进行改写。

将LCD相关文件导入到新建的例程中。

头文件的替换

(1)lcd.c文件中包含lcd.h、font.h和main.h即可
(2)lcd.h文件中只需包含main.h即可

基础数据类型的替换

使用快捷健CTRL+F来到替换界面。两个文件中将u8、u16和u32替换成uint8_t、uint16_t和uint32_t。

再将vuint16_t替换成__IO uint16_t。

函数的替换

采用上一点的方法将所有的delay_ms和delay_us替换成HAL_Delay(实测不影响程序运行)。

注释lcd.c中重复的代码

此环节说是重复代码注释,其实主要目的是为了便于移植程序。因为fsmc.
文件和原始的lcd.c文件中会有相同的初始化部分。
1.注释LCD_Init()函数最开始的fsmc初始化部分
即将以下部分的代码全部注释(此部分在MX_FSMC_Init()函数中已执行过)。

//    GPIO_InitTypeDef GPIO_Initure;
//    FSMC_NORSRAM_TimingTypeDef FSMC_ReadWriteTim;
//    FSMC_NORSRAM_TimingTypeDef FSMC_WriteTim;

//    __HAL_RCC_GPIOB_CLK_ENABLE();           //开启GPIOB时钟
//    GPIO_Initure.Pin=GPIO_PIN_0;            //PB0,背光控制
//    GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;  //推挽输出
//    GPIO_Initure.Pull=GPIO_PULLUP;          //上拉
//    GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH;//高速
//    HAL_GPIO_Init(GPIOB,&GPIO_Initure); 

//    TFTSRAM_Handler.Instance=FSMC_NORSRAM_DEVICE;                
//    TFTSRAM_Handler.Extended=FSMC_NORSRAM_EXTENDED_DEVICE;    

//    TFTSRAM_Handler.Init.NSBank=FSMC_NORSRAM_BANK4;                         //使用NE4
//    TFTSRAM_Handler.Init.DataAddressMux=FSMC_DATA_ADDRESS_MUX_DISABLE;      //地址/数据线不复用
//    TFTSRAM_Handler.Init.MemoryType=FSMC_MEMORY_TYPE_SRAM;                  //SRAM
//    TFTSRAM_Handler.Init.MemoryDataWidth=FSMC_NORSRAM_MEM_BUS_WIDTH_16;     //16位数据宽度
//    TFTSRAM_Handler.Init.BurstAccessMode=FSMC_BURST_ACCESS_MODE_DISABLE;    //是否使能突发访问,仅对同步突发存储器有效,此处未用到
//    TFTSRAM_Handler.Init.WaitSignalPolarity=FSMC_WAIT_SIGNAL_POLARITY_LOW;  //等待信号的极性,仅在突发模式访问下有用
//    TFTSRAM_Handler.Init.WaitSignalActive=FSMC_WAIT_TIMING_BEFORE_WS;       //存储器是在等待周期之前的一个时钟周期还是等待周期期间使能NWAIT
//    TFTSRAM_Handler.Init.WriteOperation=FSMC_WRITE_OPERATION_ENABLE;        //存储器写使能
//    TFTSRAM_Handler.Init.WaitSignal=FSMC_WAIT_SIGNAL_DISABLE;               //等待使能位,此处未用到
//    TFTSRAM_Handler.Init.ExtendedMode=FSMC_EXTENDED_MODE_ENABLE;            //读写使用不同的时序
//    TFTSRAM_Handler.Init.AsynchronousWait=FSMC_ASYNCHRONOUS_WAIT_DISABLE;   //是否使能同步传输模式下的等待信号,此处未用到
//    TFTSRAM_Handler.Init.WriteBurst=FSMC_WRITE_BURST_DISABLE;               //禁止突发写
//    
//    //FMC读时序控制寄存器
//    FSMC_ReadWriteTim.AddressSetupTime=0x06;        //地址建立时间(ADDSET)为7个HCLK 13.8ns*7=96.6ns
//    FSMC_ReadWriteTim.AddressHoldTime=0;
//    FSMC_ReadWriteTim.DataSetupTime=26;             //数据保存时间为27个HCLK	=13.8*27=372.6ns
//    FSMC_ReadWriteTim.AccessMode=FSMC_ACCESS_MODE_A;//模式A
//    //FMC写时序控制寄存器
//    FSMC_WriteTim.BusTurnAroundDuration=0;          //总线周转阶段持续时间为0,此变量不赋值的话会莫名其妙的自动修改为4。导致程序运行正常
//    FSMC_WriteTim.AddressSetupTime=3;               //地址建立时间(ADDSET)为4个HCLK =55.2ns 
//    FSMC_WriteTim.AddressHoldTime=0;
//    FSMC_WriteTim.DataSetupTime=0x06;               //数据保存时间为13.8ns*7个HCLK=96.6ns
//    FSMC_WriteTim.AccessMode=FSMC_ACCESS_MODE_A;    //模式A
//    HAL_SRAM_Init(&TFTSRAM_Handler,&FSMC_ReadWriteTim,&FSMC_WriteTim);	

//    HAL_Delay(50); // delay 50 ms 

2.注释函数void HAL_SRAM_MspInit(SRAM_HandleTypeDef *hsram)
此函数是对fsmc相关的引脚进行GPIO配置。

收尾工作

1.将LCD_Init()函数最后面的代码注释(如下)。

LCD_LED = 1; 

改为一下代码点亮背光(让屏幕亮起来)。

HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,1);

2.将LCD_Init()函数中的printf代码行注释,如下。

printf(" LCD ID:%x\r\n", lcddev.id); //打印LCD ID

因为原历程使用串口一进行串口调试,要是没有初始化串口一的话,运行时会一直卡在这里
3.最后在主函数中包含lcd.h头文件,添加以下代码即可运行。

  LCD_Init();
  LCD_ShowString(100,100,100,24,24,"114514");

4.大家以后要移植LCD程序时,复制相关文件到对应工程,包含头文件,调用初始化函数即可使用。节省时间!

物联沃分享整理
物联沃-IOTWORD物联网 » 使用STM32CubeMX配置FSMC模块驱动LCD屏(基于正点原子历程)详解

发表评论