外观
十四、屏幕显示实验
屏幕显示基础知识
屏幕显示原理
TFT屏主要的构成包括:背光源、导光板、扩散膜、棱镜膜、配向膜、液晶材料、薄膜晶体管等。
屏幕通电的时候,背光源发出白光,经过导光板的发射照亮整个屏幕,扩散膜让光跟家柔和,棱镜模确保光线能往正确的方向走,然后偏光片滤掉其他方向的光。只让垂直方向的偏振光通过。TFT根据需要来控制子像素电压的大小,影响液晶分子的扭曲程度,控制光的亮度。光穿过液晶,穿过彩色滤光膜,就有红光、绿光、蓝光。最后一层的偏光片只让水平偏振光通过,LCD就显示出了画面。
TFT屏驱动方式
通用TFT屏幕厂商为了降低开发难度,一般会在屏幕中内置驱动芯片,同时引出引脚与外界进行通信,常见的驱动芯片有ST7735S、ILI9163、ST7789等等。
同时,TFT屏幕在引出引脚方面,也分为SPI串口引出(四线通信)、以及8080并口引出(8位)等方式。
SPI总线包括四条逻辑线,定义如下:
- MISO:Master Input slave output 主机输入,从机输出(数据来自从机);
- MOSI:Master output slave input 主机输出,从机输入(数据来自主机);
- SCLK:Serial Clock 串行时钟信号,由主机产生发送给从机;
- NSS:Slave Select 片选信号,由主机发送,以控制与哪个从机通信,通常是低电平有效信号。
屏幕厂商一般会根据自己所用驱动芯片,写好驱动案例,大家在购买屏幕时可以找厂商要对应的资料,根据板子引脚与时序进行修改即可。
GD32E230-SPI主要特性
简易示波器底板屏幕原理图
从原理图中可以看出,该屏幕使用的是ST7735驱动芯片,引脚接口为四线SPI通信方式。
虽然看起来像IIC通信方式,但实则不是,SCL是SPI的时钟线,SDA是SPI的MOSI数据线,由于内部芯片无需向外部主控发送数据,所以使用MISO数据线就没有引出。
点亮1.8寸TFT屏幕
项目介绍
通过本次实验,实现1.8寸TFT屏幕显示白色背景。
配置流程
一般使用TFT屏幕驱动,都需要有以下几个步骤:
- 配置TFT屏幕引脚GPIO&时钟;
- 配置SPI驱动引脚&时钟;
- 配置SPI通信参数;
- 使能SPI;
- 编写SPI发送数据函数;
- 编写TFT屏幕发送数据函数;
- 编写TFT屏幕发送命令函数;
- 编写TFT屏幕设置起始地址函数;
- 编写TFT屏幕初始化函数;
- 移植厂商屏幕驱动函数
配置TFT屏幕引脚GPIO&时钟
从上方的原理介绍中了解到,底板实验的是SPI驱动的屏幕,除了SPI通信引脚,还有复位、片选、背光、命令四个引脚。
这里需要对这四个引脚进行配置,配置方式与普通IO无异。
C
//使能时钟
rcu_periph_clock_enable(RCU_GPIOB);
//设置输出模式,不上下拉
gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8);
//设置输出类型,推挽输出,50Mhz
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8);
//设置引脚高电平,默认拉高
gpio_bit_set(GPIOB,GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8);
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
配置SPI驱动引脚&时钟
使用GPIO引脚功能与SPI功能,需要打开其时钟,然后对GPIO引脚进行配置,使其映射到对应的SPI功能上。
相关引脚映射说明可查找《GD32E230数据手册》
C
//使能GPIOA时钟
rcu_periph_clock_enable(RCU_GPIOA);
//使能SPI0时钟
rcu_periph_clock_enable(RCU_SPI0);
//设置复用功能
gpio_af_set(GPIOA, GPIO_AF_0, GPIO_PIN_5 | GPIO_PIN_7);
//模式设置
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_5 | GPIO_PIN_7);
//输出设置
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5 | GPIO_PIN_7);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
配置SPI通信参数
在配置SPI参数前,需要在函数最开始声明SPI参数结构体。
在开始配置前,需要对SPI与参数进行复位初始化,确保其在初始状态。
C
//spi结构体参数
spi_parameter_struct spi_init_struct;
1
2
2
C
//SPI0复位
spi_i2s_deinit(SPI0);
//SPI参数初始化
spi_struct_para_init(&spi_init_struct);
1
2
3
4
5
2
3
4
5
以下依次来对SPI参数进行讲解:
- trans_mode:传输模式,SPI有四种工作模式,这里使用双线单向全双工模式,详细描述请前往
- device_mode:设备模式,有主机模式与从机模式两种,其中从机模式不可产生时钟,并且不可主动向主机发送信息,这里单片机作为主机与芯片进行通信。
- frame_size:帧长度,此处使用的是SPI0,根据GD32E230 SPI特性,支持8位、16为位宽选择;
- clock_polarity_phase:时钟极性与相位设置,GD32将其综合为一个参数,该参数建议参考屏幕驱动芯片时序图进行设置,也可直接参考屏幕厂商提供的案例。详细描述请前往:
- nss:片选信号控制,分为软件控制与硬件控制,软件控制需要在SPI发送、接收数据时通过代码将其拉低,硬件控制则是SPI控制器自行操作。
- prescale:时钟分频,SPI0挂载在APB2总线上,最快频率为72Mhz,SPI时钟频率不仅与主机有关,也要考虑从机的处理能力,若发现数据发送出现问题,可尝试降低时钟频率。
- endian:字节序,设置传输数据高位在前还是低位在前。
C
spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX;//双线单向全双工模式
spi_init_struct.device_mode = SPI_MASTER; //主机模式
spi_init_struct.frame_size = SPI_FRAMESIZE_8BIT; //8位数据位宽
spi_init_struct.clock_polarity_phase = SPI_CK_PL_HIGH_PH_2EDGE; //极性高,第2个边缘采样
spi_init_struct.nss = SPI_NSS_SOFT; //NSS软件控制
spi_init_struct.prescale = SPI_PSC_2; //2分频
spi_init_struct.endian = SPI_ENDIAN_MSB; //高位在前
spi_init(SPI0, &spi_init_struct);
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
自此,SPI参数配置完成
使能SPI
在参数配置完成后,需要打开总开关,才能使用SPI功能。
C
//使能SPI0
spi_enable(SPI0);
1
2
2
编写SPI发送数据函数
SPI发送数据非常简单,将待发送的数据放置在发送缓冲区即可,注意在发送前先等待缓冲区空闲。
C
/*
* 函数内容:SPI0发送数据
* 函数参数:无
* 返回值:无
*/
static void SPI0_Write(uint8_t data)
{
//等待发送缓冲区空闲
while(spi_i2s_flag_get(SPI0,SPI_FLAG_TBE)==RESET);
//发送数据
spi_i2s_data_transmit(SPI0, data);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
编写TFT屏幕发送数据函数
在SPI配置时,使用的是软件控制片选,所以在发送数据前,需要先拉低片选信号告知从机,否则发送数据无法被从机接收。
C
/*
* 函数内容:TFT发送单个字节数据
* 函数参数:无
* 返回值:无
*/
void TFT_WR_DATA8(uint8_t data)
{
gpio_bit_reset(GPIOB,GPIO_PIN_7); //拉低片选信号
SPI0_Write(data);
gpio_bit_set(GPIOB,GPIO_PIN_7); //拉高片选信号
}
/*
* 函数内容:TFT发送2个字节数据
* 函数参数:无
* 返回值:无
*/
void TFT_WR_DATA(uint16_t data)
{
gpio_bit_reset(GPIOB,GPIO_PIN_7); //拉低片选信号
SPI0_Write(data>>8);
SPI0_Write(data);
gpio_bit_set(GPIOB,GPIO_PIN_7); //拉高片选信号
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
编写TFT屏幕发送命令函数
在发送命令函数时,除了需要拉低片选信号,还需要拉低命令信号,该驱动芯片若命令信号为高时,认为发送的是数据,若命令信号为低则认为发送的是命令。
C
/*
* 函数内容:TFT发送命令数据
* 函数参数:无
* 返回值:无
*/
void TFT_WR_REG(uint8_t reg)
{
gpio_bit_reset(GPIOB,GPIO_PIN_6); //拉低命令信号
gpio_bit_reset(GPIOB,GPIO_PIN_7); //拉低片选信号
SPI0_Write(reg);
gpio_bit_set(GPIOB,GPIO_PIN_6); //拉高命令信号
gpio_bit_set(GPIOB,GPIO_PIN_7); //拉高片选信号
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
编写TFT屏幕设置起始地址函数
C
void TFT_Address_Set(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2)
{
if(USE_HORIZONTAL==0)
{
TFT_WR_REG(0x2a);//列地址设置
TFT_WR_DATA(x1);
TFT_WR_DATA(x2);
TFT_WR_REG(0x2b);//行地址设置
TFT_WR_DATA(y1);
TFT_WR_DATA(y2);
TFT_WR_REG(0x2c);//储存器写
}
else if(USE_HORIZONTAL==1)
{
TFT_WR_REG(0x2a);//列地址设置
TFT_WR_DATA(x1);
TFT_WR_DATA(x2);
TFT_WR_REG(0x2b);//行地址设置
TFT_WR_DATA(y1);
TFT_WR_DATA(y2);
TFT_WR_REG(0x2c);//储存器写
}
else if(USE_HORIZONTAL==2)
{
TFT_WR_REG(0x2a);//列地址设置
TFT_WR_DATA(x1);
TFT_WR_DATA(x2);
TFT_WR_REG(0x2b);//行地址设置
TFT_WR_DATA(y1);
TFT_WR_DATA(y2);
TFT_WR_REG(0x2c);//储存器写
}
else
{
TFT_WR_REG(0x2a);//列地址设置
TFT_WR_DATA(x1);
TFT_WR_DATA(x2);
TFT_WR_REG(0x2b);//行地址设置
TFT_WR_DATA(y1);
TFT_WR_DATA(y2);
TFT_WR_REG(0x2c);//储存器写
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
编写TFT屏幕初始化函数
在TFT屏幕初始化函数中,对TFT引脚与SPI引脚进行初始化,同时在其他操作前需要执行一次复位操作,确保屏幕处于初始状态,随后打开背光,确保屏幕显示数据能被正常观看。
最后设置一系列屏幕参数,即可完成屏幕初始化,屏幕参数设置可参考屏幕厂商的案例代码进行移植,若想对屏幕进行调整,也可自行查找ST7735S的驱动手册进行查看修改。
初始化代码过长,可下载项目源码进行查看,以下仅做演示。
C
void TFT_Init(void)
{
//初始化TFT屏幕引脚
TFT_GPIO_Init();
//初始化SPI0引脚
Init_SPI0_GPIO();
gpio_bit_reset(GPIOB,GPIO_PIN_5); //复位
delay_1ms(100);
gpio_bit_set(GPIOB,GPIO_PIN_5); //复位完成
delay_1ms(100);
gpio_bit_set(GPIOB,GPIO_PIN_8); //打开背光
delay_1ms(100);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
移植厂商屏幕驱动函数
TFT屏幕显示本质是通过在屏幕的每一个点设置RGB三种颜色来实现不同的显示效果,RGB颜色代码屏幕厂商都有提供,也可直接百度对应颜色十六进制代码。
屏幕厂商一般会提供填充颜色、显示字符、显示汉字、显示图片等函数,大家可自行移植。
代码过长,这里仅显示填充颜色函数做参考。
C
/*
* 函数内容: 在指定区域填充颜色
* 函数参数: xsta,ysta---起始坐标
* xend,yend---终止坐标
* color--------要填充的颜色
* 返回值: 无
*/
void TFT_Fill(uint16_t xsta,uint16_t ysta,uint16_t xend,uint16_t yend,uint16_t color)
{
uint16_t i=0,j=0;
TFT_Address_Set(xsta,ysta,xend-1,yend-1); //设置显示范围
for(i=ysta;i<yend;i++)
{
for(j=xsta;j<xend;j++)
{
TFT_WR_DATA(color);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
资料下载
工程代码可前往gitee下载资料包,简易数字示波器资料包