ST MCU Finder
安装免费手机应用,
寻找理想的ST MCU

[STM32F1] STM32基础篇——LCD- -C FSMC 实验

[复制链接]
422|26
 楼主 | 2018-1-11 19:15 | 显示全部楼层 |阅读模式
在本次试验中,我们将利用 STM32 开发板上的 LCD 接口,来点亮 TFTLCD,并实现 ASCII 字符和彩色的显示等功能。
试验目标:
1、懂得 LCD 屏的操作
2、懂得使用 LCD 屏显示字符
3、了解 FSMC 模式

 楼主 | 2018-1-11 19:16 | 显示全部楼层
LCD  屏 简介
TFT-LCD 又叫做薄膜晶体管液晶显示器,常用的液晶屏接口很多种,8 位、 9 位、16位、18 位都有。而常用的通信模式呢,主要有 6800 模式和 8080 模式两种,这次试验,我们的LCD屏是 8080 模式。
 楼主 | 2018-1-11 19:20 | 显示全部楼层
8080 模式的时序跟 LCD1602 或者 LCD12864 的读写时序是差不多的。8080 接口有 5 条基本的控制线和多条数据线,数据线的数量主要看液晶屏使用的是几位模式,有 8 根、9 根、16 根、18 根四种类型。它们的功能如下:




本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册 手机登录

x
 楼主 | 2018-1-11 19:22 | 显示全部楼层
接下来我们来看一下 8080 接口模式的时序,如图所示

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册 手机登录

x
 楼主 | 2018-1-11 19:23 | 显示全部楼层
从上面的时序图可以看出:
1) 在 WR 跳变为低电平之后,液晶屏开始读取总线上面的数据。如果使用 IO 口模拟写入的时候,可以先在总线上面写入数据,然后在跳变 WR,以保证当读取的时候,总线上面的数据是稳定的。
2) 在 RD 跳变为低电平之后,液晶屏放置数据到总线上面。从上图,我们就可以很清晰的看得出,液晶屏的读写时序了,大家操作的时候,可以使用单片机 IO 口模拟它的时序进行操作。不过我们开发板上面的单片机自带有 FSMC 模块,我们可以直接使用 FSMC模块来操作液晶屏,接下来我们给大家介绍一下 FSMC 模块。

 楼主 | 2018-1-11 19:25 | 显示全部楼层
FSMC 简介
1. FSMC  模拟 LCD  彩屏 8080  模式引脚数在 100 脚以上的 STM32F103 芯片都带有 FSMC 的接口,而什么是 FSMC 呢?FSMC 即灵活的静态存储控制器,能够与同步或异步存储器和 16 位 PC 存储卡接口,FSMC 的接口支持包括 SRAM、NAND FLASH、NOR FLASH、 PSRAM 等存储器。说白了呢,就是可以当操作 SRAM、NAND FLASH、NOR FLASH 和 PSRAM 等存储器的时候,我们不必自己操作 IO 口模拟这些存储器的操作时序了,使用 FSMC 模块可以直接帮我们读写这些存储器。而为什么可以用 FSMC 来控制 LCD 液晶屏呢?我们知道用来控制LCD 液晶屏的信号线主要有:
1) CS:用于片选的选择。
2) RS:用于选择命令或者数据。
3) WR:写使能。
4) RD:读使能。
5) RESET:复位端。
 楼主 | 2018-1-11 19:33 | 显示全部楼层
而 NOR FLASH 主要使用的信号线主要有:


大家对照,就可以发现两者之间的信号线,还是很相似的。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册 手机登录

x
 楼主 | 2018-1-11 19:35 | 显示全部楼层
接下来我们观察它的操作时序,那么大家就可以看得更加清晰:




这个时序是 FSMC 在 NOR 模式下的写操作, 大家对照上面的 LCD 液晶屏的读写时序,就会发现它们是通用的,而读操作时的时序,
这里就不贴出来了,大家参考 STM32 的数据参考手册。而这里使用 NORSRAM 的地址线作 LCD 彩屏的 RS 呢,大家任意选择,
地址线 0~地址线 25 都可以,我们开发板上面使用的是地址线 10(即 A10) 。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册 手机登录

x
 楼主 | 2018-1-11 19:37 | 显示全部楼层
LCD 液晶电路原理图



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册 手机登录

x
 楼主 | 2018-1-11 19:38 | 显示全部楼层
明白了FMC之后,通过上面的 FSMC 如何能够模拟 LCD 彩屏 8080 模式之后,我们对照,我们开
发板上面的彩屏接口,就可以很好的理解了。我们这里使用 FSMC_NE4 作片选 CS,使用
FSMC_A10(即地址线 10)作数据命令选择 RS。

 楼主 | 2018-1-11 19:40 | 显示全部楼层
FSMC  操作
从 FSMC 的角度看,可以把外部存储器划分为固定大小为 256M 字节的四个存储块,如下图:


也就是说,当我们操作外部存储器的时候,只要操作单片机中对应的地址,那么 FSMC
模块,就可以自动帮我们操作外部存储器,相当于把外部存储器挂在了单片机的地址总线上
面了。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册 手机登录

x
 楼主 | 2018-1-11 19:43 | 显示全部楼层
而我们这里使用的是 NOR 模式来模拟 LCD 液晶屏的 8080 时序,而在 NOR/PSRAM中,有四块存储块,我们使用的是 FSMC_NE4,所以使用的是第四块存储块,就是地址从0x6C000000 到 0x6FFFFFFF 的存储块。现在我们使用地址线 A10 来作数据命令选择端RS,那么当我们要写入数据的时候,地址线 A10 就要输出为 1,无论地址是什么,只要地址线 A10 输出为 1,就可以了;而当我们要写入命令的时候,正好相反,地址线 A10 输出为 0。我们例程上面使用结构定义的方式,我们定义一个结构体:
* TFT 地址结构体 */ typedef struct
{
u16 TFT_CMD;
u16 TFT_DATA;
} TFT_TypeDef;
然后定义一个 TFT 的结构体,映射到(0x6C000000 | 0x000007FE)地址上面:
#define TFT_BASE ((uint32_t)(0x6C000000 | 0x000007FE))

#define TFT ((TFT_TypeDef *) TFT_BASE)

 楼主 | 2018-1-11 19:44 | 显示全部楼层
TFT 这个结构体的 TFT_CMD 就映射在(0x6C000000 | 0x000007FE)这个地址上面, 这个时候, 地址线 A10 是为 0 的, 同时, TFT 这个结构体的 TFT_DATA 自动映射到了地址 0x6C000800 上面, 0x6C000800 也就是(0x6C000000 | 0x000007FE) + 2,为什么加 2 呢?也因为我们定义的 TFT_CMD 是 16 位,在 FSMC 上面的地址对应的存储长度是 8 位,16 位也就 2 地址。不过结构体的对齐方式很复杂,并不是上面说的这么简单,上面说的只是其中的一种对齐方式,大家感兴趣的话,可以去查找相应的资料学习。过现在我们知道例程上面的映射是这样子了。当然,简单点,大家可以直接将 TFT_CMD和 TFT_DATA 映射到具体的地址上面去。

 楼主 | 2018-1-11 19:52 | 显示全部楼层
FSMC_NORSRAMInit() 函数:
我 们 使 用 的 是 NORSRAM 模 式 , 所 以 我 们 使 用 的 初 始 化 函 数 是FSMC_NORSRAMInit()函数。
这 个 函 数 有 一 个 输 入 参 数 , 这 个 输 入 参 数 是 一 个FSMC_NORSRAMInitTypeDef 结构体,这个结构体很复杂,它一共有 15 个成员。



 楼主 | 2018-1-11 19:53 | 显示全部楼层
1) FSMC_Bank:选择你要使用的 bank,我们使用的是 NOR 模式的 FSMC_NE4,也就是第 1 个 bank 的第 4 个存储块,所以这里我们设置为: FSMC_Bank1_NORSRAM4。
2) FSMC_MemoryType:选择你要使用的内存类型,我们使用的是 NOR FLASH 或 者SRAM 都 可 以 , 我 们 选 择 设 置 为 : FSMC_MemoryType_SRAM。
3) FSMC_MemoryDataWidth:选择你使用的内存数据宽度,我们这里选择 16 位长度:FSMC_MemoryDataWidth_16b。
4) FSMC_WriteOperation:这里设置是是否打开写使能,这个肯定要打开,所以设置为:FSMC_WriteOperation_Enable。
5) FSMC_ExtendedMode:是否使用拓展模块,也就是读写的数据是否需要不一样,LCD彩屏读取的速度,一般都比写入慢,为了写入的效率最高,所以我们这里选择使用拓展模块:FSMC_ExtendedMode_Enable
6) FSMC_DataAddressMux:是否复用地址线和数据线,我们这里不复用:FSMC_DataAddressMux_Disable。
7) FSMC_ReadWriteTimingStruct:当没有使用拓展模块时,也就是读写时序不分开时,设置读写时序,也就是速度。
8) FSMC_WriteTimingStruct:设置写时序,这个设置其实也是使用上面FSMC_ReadWriteTimingStruct 这个成员的结构体参数来设置。
9) 剩 下 的 还 有 7 个 参 数 , FSMC_BurstAccessMode 、FSMC_WaitSignalPolarity、FSMC_AsynchronousWait、FSMC_WrapMode、 FSMC_WaitSignalActive、FSMC_WaitSignal、FSMC_WriteBurst。这些参数在成组模式同步模式才需要设置,大家可以参考中文参考手册了解我们这里不用设置。

 楼主 | 2018-1-11 19:54 | 显示全部楼层
FSMC_NORSRAMTimingInitTypeDef 结构,这个结构体有 7 个成员:
a) FSMC_AddressSetupTime:设置地址建立时间:我们设置为 3 个时钟周期,即:0x02。注意这里没错,3 个时钟周期是 0x02,因为这里设置是从 0x00 开始的,表示一个时钟周期。
b) FSMC_AddressHoldTime:地址保持时间,为了方面外部存储器,更精确的读取地址的设置。这里我们设置为一个时钟周期得了:0x00。
c) FSMC_DataSetupTime:数据建立时间,我们这里设置为 6 个时钟周期,即:0x05。
d) FSMC_DataLatency:数据保持时间,我们这里设置为 1 个时钟周期: 0x00。
e) FSMC_BusTurnAroundDuration:总线恢复时间,我们也设置为 1 个时钟周期:0x00。
f) FSMC_CLKDivision:设置 FSMC 的时钟分频,我们设置为:0x01。
g) FSMC_AccessMode:设置异步访问模式,也就是读写时序分开时的模式,我们使用 B模式,所以设置为:FSMC_AccessMode_B。


 楼主 | 2018-1-11 19:56 | 显示全部楼层
FMSC GPIO初始化void TFT_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* 打开时钟使能 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE| RCC_APB2Periph_GPIOG, ENABLE);
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
/* FSMC_A10(G12) 和 RS(G0)*/
GPIO_Init(GPIOG, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = (GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_4| GPIO_Pin_5 | GPIO_Pin_8 | GPIO_Pin_8| GPIO_Pin_9 | GPIO_Pin_10 |GPIO_Pin_11| GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14| GPIO_Pin_15 );
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = (GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9| GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12| GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15);
GPIO_Init(GPIOE, &GPIO_InitStructure);
}


 楼主 | 2018-1-11 19:56 | 显示全部楼层
  初始化 FSMC  程序
void TFT_FSMC_Config(void)
{
/* 初始化函数 */
FSMC_NORSRAMInitTypeDef FSMC_NORSRAMInitStructure;
FSMC_NORSRAMTimingInitTypeDef FSMC_NORSRAMTiming;
/* 设置读写时序,给 FSMC_NORSRAMInitStructure 调用 */
/* 地址建立时间,3 个 HCLK 周期 */
FSMC_NORSRAMTiming.FSMC_AddressSetupTime = 0x02;
/* 地址保持时间,1 个 HCLK 周期 */
FSMC_NORSRAMTiming.FSMC_AddressHoldTime = 0x00;
/* 数据建立时间,6 个 HCLK 周期 */
FSMC_NORSRAMTiming.FSMC_DataSetupTime = 0x05;
/* 数据保持时间,1 个 HCLK 周期 */
FSMC_NORSRAMTiming.FSMC_DataLatency = 0x00;
/* 总线恢复时间设置 */
FSMC_NORSRAMTiming.FSMC_BusTurnAroundDuration = 0x00;
/* 时钟分频设置 */
FSMC_NORSRAMTiming.FSMC_CLKDivision = 0x01;
/* 设置模式,如果在地址/数据不复用时,ABCD 模式都区别不大 */
FSMC_NORSRAMTiming.FSMC_AccessMode = FSMC_AccessMode_B;
/*设置 FSMC_NORSRAMInitStructure 的数据*/
/* FSMC 有四个存储块(bank),我们使用第一个(bank1) */
/* 同时我们使用的是 bank 里面的第 4 个 RAM 区 */
FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM4;
/* 这里我们使用 SRAM 模式 */
FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_SRAM;
/* 使用的数据宽度为 16 位 */
FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;
/* 设置写使能打开 */
FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable;
/* 选择拓展模式使能,即设置读和写用不同的时序 */
FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Enable;
/* 设置地址和数据复用使能不打开 */
FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable;
/* 设置读写时序 */
FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &FSMC_NORSRAMTiming;
/* 设置写时序 */
FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &FSMC_NORSRAMTiming;
/* 打开 FSMC 的时钟 */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, ENABLE);
FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure);
/*!< Enable FSMC Bank1_SRAM Bank */
FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM4, ENABLE);
}

 楼主 | 2018-1-11 19:57 | 显示全部楼层
写命令程序
void TFT_WriteCmd(uint16_t cmd)
{
TFT->TFT_CMD = cmd >> 8;
TFT->TFT_CMD = cmd & 0x00FF;
}
我们的 LCD 彩屏使用的是 8 位数据口,所以要写两次。
写数据程序
void TFT_WriteData(u16 dat)
{
TFT->TFT_DATA = dat >> 8;
TFT->TFT_DATA = dat & 0x00FF;
}
 楼主 | 2018-1-11 19:58 | 显示全部楼层
TFT初始化函数
初始化函数比较长,这里就不必要写出来了,大家可以查看例程里面的初始化函数,TFT_Init()。在初始化函数里面要设置很多东西,一般来说我们就不用一一去详细了解了,而且每一种屏幕的初始化也不一样,如果想要修改相应的设置,可以去翻查 LCD 彩屏的数据手册,进行设置。

扫描二维码,随时随地手机跟帖
您需要登录后才可以回帖 登录 | 注册 手机登录

本版积分规则

快速回复

您需要登录后才可以回帖
登录 | 注册 手机登录
高级模式

论坛热帖

分享 快速回复 返回顶部 返回列表