我爱点屏之:神奇的“单色RGB屏幕”
最近从老王店铺里入手了一块很神奇的单色屏幕:它拥有RGB三个背光LED,可以通过屏幕显示的内容配合背光的切换,实现伪彩色显示。
一般的RGB屏幕,都是使用白色的背光,通过液晶的偏转控制RGB三种颜色的通过率来显示彩色的,但是这次我们玩的屏幕,却换了一个方法:使用一块单色的液晶面板,配合不断变换的RGB背光,通过在某种颜色背光点亮的瞬间显示对应内容的方式,用单色屏幕实现了伪彩色。
从正面看,这块屏幕好像就是一块平平无奇的单色TN屏幕。但是翻到背面之后,会发现这块屏幕有三个背光LED,并且有各自的驱动电路连接到主控芯片。通过查阅手册得知,这块屏幕使用的驱动芯片是ST7049A
,它具有4
x320
点的驱动电路,并且可以输出RGB背光的驱动信号。通过在三种颜色背光点亮的同时点亮液晶像素,这颗驱动芯片最多可以模拟8种颜色,实现了彩色的显示。
数据 | 颜色 |
---|---|
000 | 白色 |
001 | 黄色 |
010 | 紫色 |
011 | 红色 |
100 | 青色 |
101 | 绿色 |
110 | 蓝色 |
111 | 黑色 |
使用群友提供的初始化代码,初始化好LCD,并向其中写入不同的颜色数据,可以看到如下图的效果。
点亮全部像素之后,可以数出屏幕的物理像素数量是128
x32
,是一块标准的TN屏幕面板。但是通过尝试更改写入屏幕的数据可以发现,屏幕上半部分与下半部分只能显示16个像素高的色条,并不能按照像素点显示不同的内容。通过研究,发现群友发的驱动是针对ST7045驱动芯片的,但屏幕的实际驱动芯片是ST7049A。ST7045
相比ST7049A
,少了3组COM引脚,也就是只能支持1
x320
个像素点的驱动。因此,本来纵向应该分成4个像素的上半部分,被合成了一个像素,造成了上下半部分色带的现象。同时,该显示器物理上将四个像素合为一个,128
x32
的物理分辨率变成了64
x16
的逻辑分辨率。
通过比对ST7045与ST7049A的手册,发现ST7049A多了一个B0H
寄存器,功能为Duty set
。该寄存器在群友提供的代码中被设置了0
,因此4个COM引脚均保持了统一电平,将该寄存器设置为3
之后,终于可以让上半屏的16个像素显示8个不同的内容了。但是由于Duty大于1,驱动芯片工作在扫描模式下,所有的参数(LCD面板驱动电压、设置LCD驱动模式等)都需要重新调试,才能达到一个比较好的显示状态。
随着调试,更多问题被暴露了出来:这块屏幕的像素连接顺序非常奇怪,向连续的地址写入连续的数据,会显示在屏幕的各个位置上。通过依次向屏幕写入数据,试探各个块的边界,最终得到了下图所示的显示映射表。其中,数字代表该位置的像素,在4
x320
/2
大小的显存中所处的位置(纵向相同颜色的行中的两个像素,共同使用一个字节表示,高低4位分别表示两个像素)。由于控制芯片支持最大1280点显示,但是屏幕本身只有16x64=1024个点,因此从0开始表示的显存地址会有一些空像素。
代码表示如下:
esp_err_t lcd_set_point(uint8_t x, uint8_t y, lcd_color_t color)
{
ESP_RETURN_ON_FALSE(x < LCD_X_PIXELS && y < LCD_Y_PIXELS, ESP_ERR_INVALID_ARG, TAG, "invalid point position");
ESP_RETURN_ON_FALSE(color < lcd_color_max, ESP_ERR_INVALID_ARG, TAG, "invalid point color");
uint8_t *gram_target = NULL;
if (y < LCD_Y_PIXELS/2) { //上半屏比较复杂
if (x < LCD_X_PIXELS/2) { //左半屏
if (y == 3 || y == 4) {
gram_target = &lcd_gram[112] + x;
} else if (y == 2 || y == 5) {
gram_target = &lcd_gram[272] + x;
} else if (y == 1 || y == 6) {
gram_target = &lcd_gram[432] + x;
} else if (y == 0 || y == 7) {
gram_target = &lcd_gram[592] + x;
}
} else { //右半屏
if (y == 3 || y == 4) {
gram_target = &lcd_gram[16] + (x-LCD_X_PIXELS/2);
} else if (y == 2 || y == 5) {
gram_target = &lcd_gram[176] + (x-LCD_X_PIXELS/2);
} else if (y == 1 || y == 6) {
gram_target = &lcd_gram[336] + (x-LCD_X_PIXELS/2);
} else if (y == 0 || y == 7) {
gram_target = &lcd_gram[496] + (x-LCD_X_PIXELS/2);
}
}
} else { //是下半屏
if (y == 11 || y == 12) {
gram_target = &lcd_gram[48] + (LCD_X_PIXELS-1-x);
} else if (y == 10 || y == 13) {
gram_target = &lcd_gram[208] + (LCD_X_PIXELS-1-x);
} else if (y == 9 || y == 14) {
gram_target = &lcd_gram[368] + (LCD_X_PIXELS-1-x);
} else if (y == 8 || y == 15) {
gram_target = &lcd_gram[528] + (LCD_X_PIXELS-1-x);
}
y -= LCD_Y_PIXELS/2; //方便后续处理
}
if (x < LCD_X_PIXELS/2) { //是左半屏
if (y < 4) { //前半个像素
*gram_target &= 0xF0;
*gram_target |= color;
} else { //后半个像素
*gram_target &= 0x0F;
*gram_target |= color<<4;
}
} else { //是右半屏
if (y < 4) { //前半个像素
*gram_target &= 0x0F;
*gram_target |= color<<4;
} else { //后半个像素
*gram_target &= 0xF0;
*gram_target |= color;
}
}
return ESP_OK;
}
最终的点亮效果如下。
注:为方便搜索,在文末放上该屏幕的淘宝宝贝名“全新3.2寸12864 LCD rgb三色背光 貌似主控带rgb控制器”以及“清仓 以前买过的rgb点阵屏 旧链接找不到了新上”,背面PCB上的丝印为“GV6416GFSL011-16677A_V02(PCB)”。