2026.03 VSCODE + ESP-IDF ST7789V液晶屏 显示 取模小知识
2026.03 VSCODE + ESP-IDF ST7789V液晶屏 显示 取模小知识
环境
开发环境:VSCODE + ESP-IDF
开发板:信盈达ESP32-S3-N16*R8开发板
使用的是D200C2407V0液晶屏,液晶屏的IC是ST7789V
屏幕是如何显示的
屏幕是由一个个像素组成的,一个像素一般由三原色组成,红绿蓝,RGB,要显示一张图片,实际上就是通过控制每个像素点中红、绿、蓝三个子像素的亮度,混合出不同的颜色。成千上万个像素点各自显示指定的颜色,拼在一起,就形成了我们看到的完整图像。

不过我们并不需要去分别把每一个RGB的亮度都定义好来决定颜色,显示IC已经帮我们完成了这件事,所以我们只需要输入色彩信息
色彩的位数
|
1位 |
2色 |
非黑即白,像老式电报 |
|
4位 |
16色 |
早期游戏机,色彩很"复古" |
|
8位 |
256色 |
调色板模式:从256个"油漆桶"里选颜色填充 |
|
16位 |
6.5万色 |
高彩:日常看图基本够用 |
|
24位 |
1677万色 |
真彩色:RGB各8位,人眼几乎分不出差别 |
|
32位 |
1677万色+透明 |
真彩色 + Alpha通道:多8位"透明度" |
为了节省存储量,最大化的利用位数的颜色还诞生出了
RGB233 即8位中 (B: 2 bits; G: 3 bits; R: 3 bits)。
RGB565 即16 位中(B: 5 bits, G: 6 bits, R: 5 bits)
ST7789V显示IC使用的就是RGB556进行显示
取个色把!

R = 178 1011 0010 取5
G = 121 0111 1001 取6
B = 240 1111 0000 取5
从高位开始取,相当于去掉小数点一样,低位的数字舍弃对颜色的影响相对较小
得到 1011 0011 1101 1110
0xB3DE 但这个邪门的屏幕需要颜色反转,所以使用0xDEB3

从RGB颜色到RGB565
根据上面
颜色就可以正确映射了。
uint16_t RGB_Convert(uint8_t R, uint8_t G, uint8_t B)
{
uint16_t r5 = (R >> 3) & 0x1F; // Keep 5 bits
uint16_t g6 = (G >> 2) & 0x3F; // Keep 6 bits
uint16_t b5 = (B >> 3) & 0x1F; // Keep 5 bits
uint16_t rgb565 = (r5 << 11) | (g6 << 5) | b5;
uint16_t swapped = ((rgb565 & 0xFF00) >> 8) | ((rgb565 & 0x00FF) << 8);
return swapped;
}
设置全屏颜色代码
void lcd_set_color(uint16_t color)
{
// 分配内存 这里分配了液晶屏一行数据需要的大小
uint16_t *buffer = (uint16_t *)heap_caps_malloc(BSP_LCD_H_RES * sizeof(uint16_t), MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);
if (NULL == buffer){
ESP_LOGE(TAG, "Memory for bitmap is not enough");
}else{
for (size_t i = 0; i < BSP_LCD_H_RES; i++){ // 给缓存中放入颜色数据
buffer[i] = color;
}
for (int y = 0; y < BSP_LCD_V_RES; y++){ // 显示整屏颜色
esp_lcd_panel_draw_bitmap(panel_handle, 0, y, BSP_LCD_H_RES, y+1, buffer);
}
free(buffer); // 释放内存
}
}
字库
其实我更愿意把这些都称之为点阵图,每个字/字母,都用一个固定大小的"像素网格"表示,不过为了方便存储,一般取8的倍数,通过16进制存储会很方便,如果你的字号是12或者19等的非8倍数,取模软件一般就会向上取整,
字号12会用16bit存储,剩下4bit就空出来了
字号20会用24bit存储。
使用的是PctoLCD2002这个小软件,需要设置一下,1那里是字号,3那里的点阵会影响数据的分行,可以修改看看导出的效果。


生成字模待用,创建一个数组。注意这里的48位,计算方法是按照24高 12宽,24*16/8 = 48(12按照8的倍数取16)

这里以24x12的字体为例。
void lcd_draw_char24(int x_start, int y_start, uint8_t Ch, uint16_t fc, uint16_t bc)
{
// 分配内存 分配了需要的字节大小 且指定在外部SPIRAM中分配
size_t pixels_byte_size = 24 * 16 * 2;
uint16_t *pixels = (uint16_t *)heap_caps_malloc(pixels_byte_size, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);
if (NULL == pixels){
ESP_LOGE(TAG, "Memory for char is not enough");
return;
}
unsigned char Temp;
Ch = Ch - '0';
for (int i=0;i<48;i++){
Temp = ascii_2412[Ch][i];
for(int j=0;j<8;j++){
if(Temp&(0x01<<j)) pixels[i*8+j] = fc;
else pixels[i*8+j] = bc;
}
}
esp_lcd_panel_draw_bitmap(panel_handle, x_start, y_start, x_start+16, y_start+24, (uint16_t *)pixels); // 显示一个字符数据
heap_caps_free(pixels); // 释放内存
}
如果用其他规格,需要改的地方挺多的,图中标出

汉字也一样,取模方法类似,如果太长可能会出现分行的情况,改点阵输入999就可以了,就不会分行了。

结束
然后最后差不多就有这样效果啦~

更多推荐



所有评论(0)