文章目录
1. 准备工作
1.1. 硬件准备
本章节会采用两种不同的方式驱动LCD屏。
第一种:FSMC接口
所用开发板:普中-准瑞-Z100 STM32F103开发板,主控STM32F103ZET6。
第二种:软件模拟 8080通信协议
所用开发板:正点原子Mini开发板,主控STM32F103RCT6。
所用显示屏:正点原子 2.8英寸 TFTLCD屏。
- 大小:2.8 英寸;
- 分辨率:320× 240;
- 16 位真彩显示;
- 接口:16位 8080 总线;
- 自带触摸屏。
1.2. 8080总线
8080 并行接口由 INTEL 发明,被广泛应用于各类液晶显示器。
该接口可以选择 8位 或 16位数据线通信。
如果选择 8位数据线通信,则需要以下信号线,一共 13根线:
- CS: OLED 片选信号;
- WR:向 OLED 写入数据;
- RD:从 OLED 读取数据;
- D[7: 0]: 8 位双向数据线;
- RST(RES):硬复位 OLED;
- DC:命令/数据标志(0,读写命令; 1,读写数据)。
如果选择 16位数据线通信,则需要以下信号线,一共 21根线:
- CS: TFTLCD 片选信号;
- WR:向 TFTLCD 写入数据;
- RD:从 TFTLCD 读取数据;
- D[15:0]: 16 位双向数据线;
- RST:硬复位 TFTLCD;
- RS:命令/数据标志(0,读写命令; 1,读写数据)。
8080 并口 读 / 写的过程为:
- 拉低片选CS,选中 存储设备;
- 根据要写入 / 读取的数据的类型,设置 DC / RS 为高(数据)/ 低(命令);
- 接着我们根据是 读数据,还是要 写数据 置 RD / WR为低;
- 在 RD 的上升沿, 使数据锁存到数据线(D[7:0])/ D[15:0]上;
- 在 WR 的上升沿,使数据写入到 存储设备 里面;
时序图(8位和16为除了数据位数不一样,其他的都一样)
8080 并口写时序图
8080 并口读时序图
不难。
1.3. TFT_LCD
这里LCD采用的存储芯片是 ILI9341 液晶控制器,自带显存,其显存总大小为 172800 字节(240 * 320 * 18 / 8)
。
- 320*240 对应到屏幕上是屏幕分辨率;
- 18 表示18 位模式,RGB 3个颜色分别 6个位,每个颜色就是 64个灰阶,然后三个颜色自由组合 就是 26万色,也就是说每个像素点的颜色可以有26万种;
- 8 表示前面的单位是 bit, / 8 之后是字节。
但实际上,我们采用的是 16位
模式,在该模式下, ILI9341 采用 RGB565
格式存储颜色数据,此时 ILI9341 的 18 位数据线与 MCU 的 16 位数据线以及 LCD GRAM 的对应关系如图:
9341总线 | D17 | D16 | D15 | D14 | D13 | D12 | D11 | D10 | D9 | D8 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
MCU数据线(16位) | D15 | D14 | D13 | D12 | D11 | NC | D10 | D9 | D8 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | NC |
LCD GRAM(16位) | R[4] | R[3] | R[2] | R[1] | R[0] | NC | G[5] | G[4] | G[3] | G[2] | G[1] | G[0] | B[4] | B[3] | B[2] | B[1] | B[0] | NC |
可以看出,对于 ILI9341 芯片来说,有用的数据线是:D17-D13 和 D11-D1。但是,把有用的16根数据线引出来之后,刚好可以对应到 D0-D15。
然后看 LCD模块 的原理图。
不管模块的内部结构,直接看这个引出来的引脚(红框中间的标号),最下面的29-34号引脚是触摸屏相关的,这里先不管:
- 1-4号引脚是对应的信号控制线;
- 5号引脚是复位线,接在开发板的复位按钮上;
- 6-21号引脚,也就是红框中间的 D0-D15,就是通信用的16根数据线;
- 剩下的伸出去比较短的是 VCC 和 GND;
- 23号引脚BL 和 28号引脚BL_VDD 是给LCD提供背光用的。
BL_VDD是电源输入,BL的输入电压大小决定亮度,可以用PWM控制,也可以直接输入高电平拉满即可。
注意:这里方框中间的标号,是以上面表格中MCU的数据位进行标注的。可以按照上面的表格对应到 ILI9341 芯片上。
简单来说用的是8080通信接口,不算RESET线的话,一共需要21根线。其他的内部原理不重要。
指令(简单看几个,了解了解意思就行,不用深究,挺多的也记不住):
- 指令1:0XD3,用于读取 LCD 控制器的 ID。
- 指令2:0X36,这是存储访问控制指令,可以控制 ILI9341 存储器的读写方向,简单的说,就是在连续写 GRAM 的时候,可以控制 GRAM 指针的增长方向,从而控制显示方式(读 GRAM 也是一样)。
0X36 指令后面,紧跟一个参数,这里我们主要关注: MY、 MX、 MV 这三个位,通过这三个位的设置,我们可以控制整个 ILI9341 的全部扫描方向。
就先这几个吧,知道有就行,具体的可以查看芯片手册。
1.4. FSMC
FSMC(Flexible Static Memory Controller,可变静态存储控制器):是STM32系列采用的一种新型的存储器扩展技术。能够与同步或异步存储器和 16 位 PC 存储器卡连接。在外部存储器扩展方面具有独特的优势,可根据系统的应用需要,方便地进行不同类型大容量静态存储器的扩展。
一般引脚数大于100的芯片才会有 FSMC 接口。
FSMC框图
可以看出,STM32 的 FSMC 将外部设备分为 3 类:
- NOR/PSRAM 设备;
- NAND设备;
- PC 卡设备。
他们共用地址数据总线等信号,他们具有不同的 CS 以区分不同的设备。也可以将TFTLCD 当成 SRAM 来控制,实现LCD显示的效果。
STM32 的 FSMC 将外部存储器划分为固定大小为 256M 字节的四个存储块,共有1G。
2. 创建工程
2.1. 选择主控
选择开发板上对应的主控即可。
- 如果使用正点原子Mini开发板,就选STM32F103RCT6;
- 如果使用普中的开发板,就选STM32F103ZET6。
ZET6 有 FSMC接口,可以使用FSMC进行驱动,软件模拟8080接口也行(但是何必呢)。
RCT6 没有 FSMC接口的,只能使用软件模拟8080接口。
2.2. 系统配置
配置时钟源
配置debug模式(如果需要ST-Link下载及调试可以勾选)
配置时钟树(可以直接在HCLK那里输入72,然后敲回车会自动配置)
2.3. 配置工程目录
3. FSMC驱动LCD
3.1. FSMC配置
再看一下LCD引出的引脚的原理图,里面的标号已经说过了。
外面的标号是开发板上插座的 Label,对应到主控相应的接口引脚。
配置FSMC
参数默认。
背光引脚设置,直接保持高电平即可,也可以配置为PWM调节亮度。
生成工程。
3.2. 添加驱动
在工程目录添加 icode
文件夹,在文件夹中创建LCD
文件夹,在文件夹中创建lcd.c
、lcd.h
、font.h
三个文件。
全部的代码文件在文章开头
添加源文件
添加头文件路径
全部的代码文件在文章开头
3.3. 测试程序
#include "lcd.h"
// 其他的初始化完成之后
LCD_Init();
POINT_COLOR = RED; // 画笔颜色
LCD_ShowString(0, 0, 120, 20, 24, "Haozi");
LCD_ShowNum(0, 24, 1234567, 7, 24);
LCD_ShowChar(0, 48, 'A', 24, 0);
LCD_Draw_Circle(100, 100, 20);
LCD_DrawRectangle(80, 80, 40, 40);
LCD_DrawLine(60, 60, 70, 70);
全部的代码文件在文章开头
4. 软件模拟8080并口驱动LCD
针对没有配备 FSMC 的主控,就只能采用软件模拟的方式进行驱动了。
4.1. 引脚配置
看一下正点原子手册LCD的原理图,在官方手册上,方框中间的标号是对应到 ILI9341 控制器上的标号。
但是我们不看这个,和上面保持一致,我把原理图重新画一下。
然后我们看看每个引脚都接到哪了,这里不管触摸功能,和上一章节一样,只需要看1-28号引脚,最下面的六个是 触摸功能有关的,先不管。
- 1号引脚 LCD_CS 对应 PC9
- 2号引脚 LCD_RS 对应 PC8
- 3号引脚 LCD_WR 对应 PC7
- 4号引脚 LCD_RD 对应 PC6
- 5号引脚 LCD_RST 对应 开发板复位键
- 6-21号引脚 LCD_D[17:1] 对应 PB[15:0]
- 23号引脚 LCD_LED 对应 PC10
- 剩下的都是 VCC 或者 GND
然后在CubeMX中配置这些引脚。PB0 - PB15、PC6 - PC10.
全部都是 推挽输出,上拉,输出速度High。
一共21个引脚。
4.2. 添加驱动
在工程目录添加 icode
文件夹,在文件夹中创建LCD
文件夹,在文件夹中创建lcd.c
、lcd.h
、font.h
三个文件。
并在keil中添加.c文件和头文件。
其实,这里的驱动和上面的驱动,在对外的接口上基本都是一样的,只是函数内传输数据的实现方式不一样。
全部的代码文件在文章开头
4.3. 测试程序
测试程序和上面的一样。
#include "lcd.h"
// 其他的初始化完成之后
LCD_Init();
POINT_COLOR = RED; // 画笔颜色
LCD_ShowString(0, 0, 120, 20, 24, "Haozi");
LCD_ShowNum(0, 24, 1234567, 7, 24);
LCD_ShowChar(0, 48, 'A', 24, 0);
LCD_Draw_Circle(100, 100, 20);
LCD_DrawRectangle(80, 80, 40, 40);
LCD_DrawLine(60, 60, 70, 70);
全部的代码文件在文章开头
5. 补充说明
经过更改,两种驱动方式的工程,只有 lcd.c 和 lcd.h 中函数的内部实现不一样,不管你采用哪种驱动方式,在其他程序中调用的接口是一样一样的。
比如,在8080模拟驱动的程序中,写寄存器函数是这样的。
而在,FSMC驱动的代码中是这样的。
可以看到,函数名称是一样的,可以用相同的方式进行调用。其余的函数也都是一样的。
因此,在移植的时候也不用想太多,都可以一样的用。
最后,后面会用这个LCD屏做一个简易的示波器项目,只需要一个开发板,和这个LCD屏即可实现,
代码也开源,欢迎去主页置顶文章中查看。