做硬件开发,都会有使用点阵液晶的经历。我使用单色点阵液晶居多。点阵液晶,从字面理解就是把点排成阵列显示。你可以把这个点阵液晶想象成放大版的LED灯组。液晶中的每个点就是一个LED。给数字量1就是点亮,给0就是灭。所以我们驱动单色点阵液晶,其实就是按照显示屏的通讯协议,把点阵数据发给显示屏,完成字符、图像的显示。这个过程和老式的针式打印机的处理方式是一样的。单色点阵式显示屏,无论是什么颜色的,都是提供一个底色和显示色,常见的如绿屏黑字液晶、蓝屏白字液晶等。
但我们驱动彩色的液晶屏时,就不能简单地像驱动单色屏那样发送点阵显示数据了。因为彩色屏在每一个显示点上,需要配置好3原色的比例,以便在这个点上显示我们想要的颜色。我们都知道,白色的光,通过棱镜,会折射出各种颜色组成的光带,这些光的显示是有顺序的,而这顺序,是和光波的波长(其实就是不同颜色光的频率不一样,它俩刚好是反比关系)。从红色光到紫色光,按照红、橙、黄、绿、蓝、紫顺序(有没有注意到这个顺序是不是和色环电阻的数值有关系?色环按照棕、红、橙、黄、绿、蓝、紫、灰、白顺序依次加1),波长是逐渐减小的,而频率是逐渐增加的。从棱镜折射白光成彩色光,反过来说,就是说也可以用彩色的光可以合成为白光。但实际上,我们是不需要用这么多彩色光来合成,而只需要三个原色就能合成白光。这三个颜色是红、黄、蓝,因此称之为三原色。
这个三原色,是美术上的三原色。而在半导体中处理颜色时,使用红、绿、蓝三原色,这个是色光三原色。这三个基本颜色一样可以合成为白色。我们用到的TFT彩色液晶,就是使用这三种颜色来处理的。
用彩色屏显示彩色点时,就需要按照一定比例来配置红、绿、蓝的量。我们先看看在彩色屏中,驱动一个点颜色的方式。如果你用倍数足够大的放大镜观察彩色液晶屏,会看到屏幕里红绿蓝三种颜色均匀地排列着,
临近的三个色块,最为一个基本的显示点。只要我们做好配比量,把它们混合起来就会配成我们想要的颜色。但这不像我们用画笔可以混和颜色,这三个色块在屏幕里的位置是不变的,根本无法混到一起。那么为什么我们能看到混合后的颜色呢?由于这三个色块非常非常小,用肉眼很难分辨出来,再加上我们离得比较远,所以我们的眼睛被欺骗,以为是混在一起的。
现在我们知道了TFT彩色屏是利用控制色块及色块配比量来实现显示点的颜色的,那么在TFT中是如何设置这个配比量的呢?按照我们正常理解,每个色块发送一个字节数据,用以设置配比中的量就行。道理上是这样,但在实际处理上,还是有一些出入的。为了增加显示速度,实际处理时,会尽量减少每个色块的数据量。而对于不同颜色等级的显示屏,这个最低量也是不同的。以我最近买来的廉价TFT为例哈。这个TFT屏使用ST7789作为控制核心。在例程中,我们看看代码是如何传输数据,来显示点的颜色的。
颜色的定义:
#define WHITE 0xFFFF
#define BLACK 0x0000
#define BLUE 0x001F
#define BRED 0XF81F
#define GRED 0XFFE0
#define GBLUE 0X07FF
#define RED 0xF800
#define MAGENTA 0xF81F
#define GREEN 0x07E0
#define CYAN 0x7FFF //青色
#define YELLOW 0xFFE0
#define BROWN 0XBC40 //棕色
#define BRRED 0XFC07 //棕红色
#define GRAY 0X8430 //灰色
用到的函数:
//向液晶屏写一个8位数据
void SPI_SendByte(unsigned char byte) {
unsigned char counter;
for (counter = 0; counter < 8; counter++) {
SPI_SCK_0;
if ((byte & 0x80) == 0) {
SPI_SDA_0;
} else
SPI_SDA_1;
byte = byte << 1;
SPI_SCK_1;
}
SPI_SCK_0;
}
void TFT_SEND_CMD(unsigned char o_command) {
SPI_DC_0;
SPI_SendByte(o_command);
//SPI_DC_1;
}
//向液晶屏写一个8位数据
void TFT_SEND_DATA(unsigned char o_data) {
SPI_DC_1;
SPI_SendByte(o_data);
}
// 按照指定颜色填充背景
void TFT_full(unsigned int color) {
unsigned int ROW, column;
TFT_SEND_CMD(0x2a); // 设置列地址
TFT_SEND_DATA(0x00); // 开始列
TFT_SEND_DATA(0x00);
TFT_SEND_DATA(0x00); // 结束列
TFT_SEND_DATA(0xF0);
TFT_SEND_CMD(0x2b); // 设置行地址
TFT_SEND_DATA(0x00); // 开始行
TFT_SEND_DATA(0x00);
TFT_SEND_DATA(0x00); // 结束行
TFT_SEND_DATA(0xF0);
TFT_SEND_CMD(0x2C); // 写存储器
for (ROW = 0; ROW < TFT_LINE_NUMBER; ROW++) {
for (column = 0; column < TFT_COLUMN_NUMBER; column++) {
TFT_SEND_DATA(color >> 8);
TFT_SEND_DATA(color);
}
}
}
在函数TFT_full中,在设置底色之前,需要先设置传输目的地址,这个目的地址,你可以理解成和显示屏对应的一个缓冲池。在这个池子里设置成什么颜色,屏幕上就显示为什么颜色。在
for (ROW = 0; ROW < TFT_LINE_NUMBER; ROW++) {
for (column = 0; column < TFT_COLUMN_NUMBER; column++) {
TFT_SEND_DATA(color >> 8);
TFT_SEND_DATA(color);
}
}
中,对应每个点,每次传输一个字的数据量,16位。在这16位中,包含了三原色的数据量。
颜色配比占位就是图示中不同颜色占位。红色使用前5位,绿色使用中间6位,蓝色使用后面5位。比如对于
红色0xF800,二进制表达为1111100000000000
绿色0x07E0,二进制表达为0000011111100000
蓝色0x001F,二进制表达为0000000000011111
现在你是否已经明白如何用数据组合,来设置屏幕上点的颜色了吧?实际上,为了显现的色彩更艳丽,颜色更丰富,需要更复杂的处理。入了门,后面的再学习吧。