上一篇,原文链接:https://blog.csdn.net/qq_44829055/article/details/127022197中均是RGB888小端模式和RGB565小端模式的互转。这个适用于应用层处理。
本案例特别适用于LCD屏的RGB888小端原始数据转换为RGB565大端模式(LCD屏基本上均是大端模式)。
1、为什么RGB888要转RGB565呢,这个问题尤其在嵌入式lcd屏中,因为RGB888占用24位,RGB565占用16位及2个字节。
2、例如嵌入式中的LCD屏接口一般位IIC、SPI、8080等,如果传送RGB888每个像素点就要多送一个字节,320*240的LCD屏就要多送76800字节的数据。
3、我看到的一般驱动代码中均是将RGB888进行相与移位等操作得到R,G、B类似操作。速度慢代码不精简。如何优化呢,这里我就开门见山了,使用结构体就能很好解决RGB888和RGB565互转。单使用结构体还不够好,就把结构体和共用体结合了。
4、以下是测试部分,使用原始方案RGB888转RGB565,及原始方案RGB565转RGB888,及新的方案。不难发现新方案测试结果和旧方案一样。
5、至于速度方面我没有太研究过位域处理和计算处理的效能,但从代码结构上,位域更加清晰及精简。
6、备注:51单片机基本上均是大端模式。32位单片机及更高的大部分均是小端模式。
附加源码:
//作者:金丝草
//时间:2022/09/24
#include <iostream>
//这里重申下,RGB888为小端模式,RGB565为大端模式(外设SPI LCD屏均是大端模式的,有利于发送数据)
/***********************************RGB888 RGB565*************************************/
typedef union
{
uint32_t RGB888;
struct
{
uint32_t :3;
uint32_t RGB_B :5;
uint32_t :2;
uint32_t RGB_G :6;
uint32_t :3;
uint32_t RGB_R :5;
uint32_t :8;
}Work;
}RGB888_struct;
typedef union
{
uint16_t RGB565;
struct
{
uint16_t RGB_R :5;
uint16_t RGB_G :6;
uint16_t RGB_B :5;
}Work;
}RGB565_struct;
//输入一个RGB888的32位数据地址,返回转换后的RGB565
static uint16_t RGB888_To_RGB565(const RGB888_struct *RGB888)
{
RGB565_struct RGB565 = { 0 };
RGB565.Work.RGB_R = RGB888->Work.RGB_R;
RGB565.Work.RGB_G = RGB888->Work.RGB_G;
RGB565.Work.RGB_B = RGB888->Work.RGB_B;
return RGB565.RGB565;
}
//输入一个RG565的16位数据地址,返回转换后的RGB888
static uint32_t RGB565_To_RGB888(const RGB565_struct *RGB565)
{
RGB888_struct RGB888 = { 0 };
RGB888.Work.RGB_R = RGB565->Work.RGB_R;
RGB888.Work.RGB_G = RGB565->Work.RGB_G;
RGB888.Work.RGB_B = RGB565->Work.RGB_B;
return RGB888.RGB888;
}
/***********************************RGB888 RGB565*************************************/
static void test_RGB888_To_RGB565(void)
{
uint32_t color888 = 0;
uint32_t i;
for (i = 1; i <= 50; i++)
{
printf("新RGB888->RGB565 =%5d ", RGB888_To_RGB565((RGB888_struct*)&color888));
color888 += 100;
if ((i % 5) == 0)
printf("\r\n");
}
printf("\r\n");
}
static void test_RGB565_To_RGB888(void)
{
uint16_t color565 = 0;
uint32_t i;
for (i = 1; i <= 50; i++)
{
printf("新RGB565->RGB888 =%8d ", RGB565_To_RGB888((RGB565_struct*)&color565));
color565 += 100;
if((i%5) == 0)
printf("\r\n");
}
printf("\r\n");
}
int main()
{
uint32_t test_data = 0;
uint32_t i;
uint32_t color888 = 0;
uint16_t color565 = 0;
uint8_t R = 0;
uint8_t G = 0;
uint8_t B = 0;
for (i = 1; i <= 50; i++)//原始方案计算伤脑子
{
R = (color888 & 0xff0000) >> (16 + 3);
G = (color888 & 0x00ff00) >> (8 + 2);
B = (color888 & 0x0000ff) >> 3;
//test_data = (R << (5 + 6)) | (G << 5) | B;
test_data = (B << (5 + 6)) | (G << 5) | R;
printf("旧test__888->565 =%5d ", test_data);
color888 += 100;
if ((i % 5) == 0)
printf("\r\n");
}
printf("\r\n");
test_RGB888_To_RGB565();//新方案速度更快还不伤脑子
for (i = 1; i <= 50; i++)//原始方案计算伤脑子
{
R = (color565 & 0xf800) >> (5 + 6);
G = (color565 & 0x07e0) >> 5;
B = (color565 & 0x001f) >> 0;
//test_data = (R << (16 + 3)) | (G << 8 + 2) | (B << 3);
test_data = (B << (16 + 3)) | (G << 8 + 2) | (R << 3);
printf("旧test__565->888 =%8d ", test_data);
color565 += 100;
if ((i % 5) == 0)
printf("\r\n");
}
printf("\r\n");
test_RGB565_To_RGB888();//新方案速度更快还不伤脑子
std::cout << "Hello World!\n";
}
运行结果: