了解屏幕驱动
在 Ubuntu 系统下,屏幕驱动文件一般位于:/dev/ubuntu_lcd。
我们都知道,屏幕都是由一个个像素点构成的,而一个像素点由三原色构成(红绿蓝),简称 RGB。
假如是在 800 * 480 的分辨率下,像素分布如下:屏幕横向有 800 个像素格,纵向有 480 个像素格。每个像素格由 RGB 颜色组成。
然而,每个像素点由 4 个字节组成:
- A:代表透明度
- R:red,红色
- G:green,绿色
- B:blue,蓝色
当你想表示蓝色时,只需要将表示蓝色的那个字节置为全1,其它颜色表示的位置零即可。那么,蓝色就可表示为:00000000 00000000 00000000 11111111。用16进制表示为 0x000000ff。
下面我们按照以下步骤来测试一下LCD示例代码:主要做的事情是:
1.安装触摸屏驱动
cd /mnt/hgfs/embed/Lcd/event_drv
make
sudo insmod event_drv.ko
2.安装屏幕驱动
cd /mnt/hgfs/embed/Lcd/mmap_drv
make
sudo insmod mmp_drv.ko
3.运行模拟器
cd /mnt/hgfs/embed/Lcd
sudo ./VTSLcd
4.打开新的终端(Ctrl+Alt+T)
cd /mnt/hgfs/embed/Lcd/lcd_event
gcc lcd_event_ui.c bmp.c -o lcd_event_ui
sudo ./lcd_event_ui
5. 运行结果如下:
你点一下灯泡,会变成粉色:
但是,这里会有一个问题就是这些驱动文件都是临时的,当你关掉虚拟机或者重启虚拟机上,如果你还想运行一下示例代码,那你仍然要乖乖按照步骤再来一遍,这样子做会感觉很繁琐。所以我写了一个脚本(auto_config.sh),可以一步到位。
在文章第一句有提到,ubuntu 的 屏幕驱动文件位于:/dev/ubuntu_lcd。那我们可不可以写一个应用程序来设置屏幕的颜色呢?答案肯定是可以的。
前文已经提到过:蓝色的十六进制为 0x000000ff。那我们可不可以将屏幕改为蓝色呢?在编写程序之前,我们首先要清除的是:一切设备皆文件,包括屏幕也是。那我们要操作一个文件,首先得打开这个文件,然后向文件中写入相应的数据,即可改变这个文件的状态。所以,代码如下:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <assert.h>
int main()
{
int wfd;
wfd = open("/dev/ubuntu_lcd", O_RDWR); // 打开屏幕设备文件
assert(wfd > 0);
int blue = 0x000000ff; // 蓝色的十六进制
for(int i = 0; i < 800 * 480; i++) // 因为屏幕是 800 * 480,所以需要循环写入
{
int w = write(wfd, &blue, 4); // 一个字节一个字节地写入
assert(w > 0);
}
close(wfd);
return 0;
}
然后先运行 sudo ./VTSLcd
,然后再编译执行上面的应用程序(应用程序需要root权限执行)。运行结果如下:
可以看到整个屏幕变成了蓝色。当然你可以改变成你喜欢的任何颜色,只需要知道该颜色的十六进制即可。
下面我将用共享内存来修改屏幕的颜色。如果大家还不懂共享内存的知识,可以参考这篇Linux线程通信之共享映射区。
代码如下:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <assert.h>
#include <sys/mman.h>
int main()
{
int lcd;
lcd = open("/dev/ubuntu_lcd", O_RDWR);
assert(lcd > 0);
unsigned int *lcd_p = mmap(NULL, 800*480*4, PROT_READ | PROT_WRITE, MAP_SHARED, lcd, 0); // 建立共享映射区
assert(lcd != MAP_FAILED);
int color = 0x0000A2E8;
int x, y;
for(y = 0; y < 480; y++)
{
for(int x = 0; x < 800; x++)
{
//把颜色数据写入屏幕驱动文件中
*(lcd_p + 800 * y + x) = color;
}
}
close(lcd);
return 0;
}
运行结果如下:
利用共享内存,我们可以设置屏幕任意一个区域的颜色。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
int main()
{
//以读写的方式打开屏幕驱动文件
int lcd_fd = open("/dev/ubuntu_lcd", O_RDWR);
if(lcd_fd == -1) //打开文件失败,结束程序
{
perror("open lcd_fd fail!");
return -1;
}
printf("lcd_fd = %d\n", lcd_fd);
unsigned int *lcd_p = mmap(NULL, 800*480*4, PROT_READ|PROT_WRITE, MAP_SHARED, lcd_fd, 0);
if(lcd_p == MAP_FAILED ) //打开文件失败,结束程序
{
perror("mmap lcd fail!");
return -1;
}
int blue = 0x0000A2E8;
int x, y;
for(y=0; y<480; y++)
{
for(x=0; x<800; x++)
{
//把颜色数据写入屏幕驱动文件
*(lcd_p+800*y+x) = blue;
}
}
//在屏幕三分之一的地方显示红色
for(y=0; y<160; y++)
{
for(x=0; x<800; x++)
{
//把颜色数据写入屏幕驱动文件
*(lcd_p+800*y+x) = 0x00ff0000;
}
}
//从坐标x=400, y=240的地方开始,显示一个100像素点的正方形
for(y=240; y<340; y++)
{
for(x=400; x<500; x++)
{
//把颜色数据写入屏幕驱动文件
*(lcd_p+800*y+x) = 0x0000ff00;
}
}
//解除屏幕映射
munmap(lcd_p, 800*480*4);
//关闭文件
close(lcd_fd);
return 0;
}
运行结果如下: