在嵌入式系统的开发中,我们经常需要在液晶屏上显示一些信息,如文本、图片等。在本篇文章中,我将解析两个C语言的例程,这些例程分别用于在液晶屏上显示不同的RGB颜色和显示BMP图片。
RGB颜色想必大家都懂吧,简单介绍一下:
RGB是一种用于表示颜色的色彩模型,它是英文单词"Red(红色)"、"Green(绿色)"和"Blue(蓝色)"的缩写。在RGB色彩模型中,每种颜色由红色、绿色和蓝色三个分量的不同强度组成,通过调整这三个分量的数值,可以得到各种不同的颜色。
在RGB色彩模型中,每个颜色分量的取值范围通常是0到255。数值为0表示没有该颜色分量,而数值为255表示该颜色分量的最大强度。因此,RGB颜色可以用一个三元组(R, G, B)来表示,其中R表示红色分量的强度,G表示绿色分量的强度,B表示蓝色分量的强度。
例如,纯红色的RGB颜色表示为(255, 0, 0),即红色分量为最大强度,而绿色和蓝色分量均为0。类似地,纯绿色的RGB颜色表示为(0, 255, 0),纯蓝色的RGB颜色表示为(0, 0, 255),我们通常在编程中用0x00ff0000的十六进制表示红色。
通过调整RGB颜色的三个分量的数值,可以得到各种不同的颜色,包括所有可见的颜色。由于RGB色彩模型在计算机图形和显示技术中得到广泛应用,所以它是最常用的色彩模型之一。
下面来看一下综合例程:
//在屏幕上交替的显示红绿蓝三色
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include //帧缓冲设备的结构体定义在这个里面
#define LCDDEV "/dev/fb0"
#define LCDSIZE 800*480*4
struct color {
unsigned int red;
unsigned int green;
unsigned int blue;
};
void input_color(int *lcd_buf, int color)
{
int x, y;
for ( y=0; y<480; y++)
{
for(x=0; x<800; x++)
{
lcd_buf[y*800 + x] = color;
}
}
}
void output_color(int color)
{
// 1. 打开液晶屏设备
int lcd_fd = open(LCDDEV, O_RDWR);
if(lcd_fd == -1)
{
perror("open lcd fail");
exit(errno);
}
// 给液晶屏文件映射一块内存
// void *mmap(void *addr, size_t len, int prot, int flags,int fildes, off_t off);
int *fb = mmap(NULL, LCDSIZE, PROT_READ|PROT_WRITE, MAP_SHARED, lcd_fd, 0);
if(fb == MAP_FAILED)
{
perror("mmap fail");
exit(errno);
}
int lcd_buf[800*480] ={0};
input_color(lcd_buf,color);
memcpy(fb,lcd_buf,LCDSIZE);
// 3. 关闭液晶屏
munmap(fb, LCDSIZE);
close(lcd_fd);
}
int main(int argc, char *argv[])
{
// 2. 初始化颜色值
struct color rgb = { .red = 0x00ff0000, .green = 0x0000ff00, .blue = 0x000000ff };
while(1)
{
output_color(rgb.red);
sleep(1);
output_color(rgb.green);
sleep(1);
output_color(rgb.blue);
sleep(1);
}
return 0;
}
这个代码的主要思路是,首先定义一个颜色结构体,然后创建一个颜色缓冲区,将颜色数据填充到缓冲区中,最后将缓冲区的内容写入到液晶屏设备中。
在代码中,我们首先定义了一个颜色结构体struct color
,它包含了3个成员:红色、绿色和蓝色。然后,我们定义了一个input_color
函数,该函数的主要作用是将颜色数据填充到颜色缓冲区中。output_color
函数则负责将颜色缓冲区的内容写入到液晶屏设备中。
在main
函数中,我们首先初始化了颜色的值,然后在一个无限循环中,不断的将红色、绿色和蓝色的颜色信息写入到液晶屏设备中,每次写入后暂停1秒。
这个操作就像把大象放进冰箱需要几步这个问题一样,第一步打开液晶屏,第二步导入bmp格式的图片,第三步关闭液晶屏,顺着这个思路我们很快就能写出如下程序,当然细节处怎么做到还需自己研究一下哦,其实很简单,主要用到了像素转换的思想:
像素转换代码:color = bmp_buf[k] | bmp_buf[k+1]<<8 | bmp_buf[k+2]<<16;
i
和j
变量遍历每个像素点的行和列,同时使用k
变量来遍历bmp_buf
缓冲区,处理每个像素的BGR颜色数据。另外还需搞清楚,BMP图片的像素数据是从左到右,从下到上存储的,而液晶屏的读取是从左往右,从上往下,刚好是上下颠倒。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include //帧缓冲设备的结构体定义在这个里面
#define LCDDEV "/dev/fb0"
void show_bmp(char *name)
{
// 1. 打开液晶屏设备
int lcd_fd = open(LCDDEV, O_RDWR);
if(lcd_fd == -1)
{
perror("open lcd fail");
exit(errno);
}
int bmp_fd = open(name, O_RDONLY);
if(bmp_fd == -1)
{
perror("open bmp fail");
exit(errno);
}
// 给液晶屏文件映射一块内存
// void *mmap(void *addr, size_t len, int prot, int flags,int fildes, off_t off);
//
int *fb = mmap(NULL, 800*480*4, PROT_READ|PROT_WRITE, MAP_SHARED, lcd_fd, 0);
if(fb == MAP_FAILED)
{
perror("mmap fail");
exit(errno);
}
// 先跳过54字节的文件头和信息头
lseek(bmp_fd, 54, SEEK_SET);
// 读取位图数据(图像的BGR颜色数据))
char bmp_buf[800*480*3] = {0};
read(bmp_fd, bmp_buf, 800*480*3);
int i, j, k = 0;
int color = 0;
//液晶屏的扫描方式是:从上到下,从左到右
//而bmp图像数据的存储方式是:从左到右,从下到上
//所以要反着写入,就能解决翻转问题
for (i = 479; i >= 0; i--) {
for (j = 0; j < 800; j++) {
color = bmp_buf[k] | bmp_buf[k + 1] << 8 | bmp_buf[k + 2] << 16;// 像素转换
k += 3;
fb[i * 800 + j] = color;// 写入液晶屏
}
}
munmap(fb, 800*480*4);
close(bmp_fd);
// 3. 关闭液晶屏
close(lcd_fd);
}
int main(int argc, char *argv[])
{
if (argc != 2) {
printf("Usage: %s
例程的主要思路是,首先打开BMP图片文件和液晶屏设备,然后读取BMP图片的像素数据,将这些像素数据写入到液晶屏的缓冲区中,最后将缓冲区的内容写入到液晶屏设备中。
在代码中,我们首先打开了液晶屏设备和BMP图片文件,然后创建了一个映射,这个映射将液晶屏设备的内存映射到了进程的地址空间。接着,我们从BMP图片文件中读取像素数据,将这些数据写入到液晶屏的缓冲区中。最后,我们将缓冲区的内容写入到液晶屏设备中。
有了代码那怎么运行呢,其实之前的博客里也教过,但是还是凑点字数,多说说,只要需要用 rz -y命令把可执行文件传给开发板就行。
什么?又不会编译了,看这里:
传统就是arm-linux-gcc ,那么快捷方法就是用alias命令把它变成一个快捷指令ag。
通过这两个例程,我们可以看到在C语言中如何操作液晶屏设备,如何将颜色和图片显示到液晶屏上。这些例程提供了一个很好的起点,让我们能够理解如何在嵌入式系统中进行液晶屏的编程。希望这个文章能对你有所帮助,如果你有任何问题,欢迎在评论区留言。
更多C语言和Linux系统相关文章,关注专栏:
手撕C语言
玩转linux
一键三连喔
~