#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/fb.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
static int fd_fb;
static struct fb_var_screeninfo var; /* Current var */
static int screen_size;
static unsigned char *fb_base;
static unsigned int line_width;
static unsigned int pixel_width;
/**********************************************************************
* 函数名称: lcd_put_pixel
* 功能描述: 在LCD指定位置上输出指定颜色(描点)
* 输入参数: x坐标,y坐标,颜色
* 输出参数: 无
* 返 回 值: 会
* 修改日期 版本号 修改人 修改内容
* -----------------------------------------------
* 2020/05/12 V1.0 zh(angenao) 创建
***********************************************************************/
void lcd_put_pixel(int x, int y, unsigned int color)
{
unsigned char *pen_8 = fb_base+y*line_width+x*pixel_width;
unsigned short *pen_16;
unsigned int *pen_32;
unsigned int red, green, blue;
pen_16 = (unsigned short *)pen_8;
pen_32 = (unsigned int *)pen_8;
switch (var.bits_per_pixel)
{
case 8:
{
*pen_8 = color;
break;
}
case 16:
{
/* 565 */
red = (color >> 16) & 0xff;
green = (color >> 8) & 0xff;
blue = (color >> 0) & 0xff;
color = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
*pen_16 = color;
break;
}
case 32:
{
*pen_32 = color;
break;
}
default:
{
printf("can't surport %dbpp\n", var.bits_per_pixel);
break;
}
}
}
int main(int argc, char **argv)
{
int i;
fd_fb = open("/dev/fb0", O_RDWR);
if (fd_fb < 0)
{
printf("can't open /dev/fb0\n");
return -1;
}
if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var))
{
printf("can't get var\n");
return -1;
}
line_width = var.xres * var.bits_per_pixel / 8;
pixel_width = var.bits_per_pixel / 8;
screen_size = var.xres * var.yres * var.bits_per_pixel / 8;
fb_base = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
if (fb_base == (unsigned char *)-1)
{
printf("can't mmap\n");
return -1;
}
/* 清屏: 全部设为白色 */
memset(fb_base, 0xff, screen_size);
/* 随便设置出100个为红色 */
for (i = 0; i < 100; i++)
lcd_put_pixel(var.xres/2+i, var.yres/2, 0xFF0000);
munmap(fb_base , screen_size);
close(fd_fb);
return 0;
}
在嵌入式系统开发中,经常需要对LCD显示屏进行像素级的控制。Linux Framebuffer是一个强大的接口,它允许开发者直接操作显示内存。本文将通过一个简单的C语言程序示例,解析如何在基于Linux Framebuffer的嵌入式系统中控制LCD像素。
一、程序功能概述
本示例程序的功能是在LCD屏上绘制100个红色像素点。程序首先打开Framebuffer设备,获取当前屏幕信息,然后通过内存映射访问Framebuffer,最后在指定位置绘制像素点,并在绘制完成后清理资源。
二、Framebuffer基础
Framebuffer是一个内存区域,其中包含了当前显示的图像数据。通过读写这个内存区域,可以控制显示在屏幕上的图像。
关键结构体和接口
fb_var_screeninfo
:描述屏幕的当前变量配置,如分辨率、颜色深度等。ioctl()
:用于执行设备控制请求,如获取屏幕信息。mmap()
:内存映射,允许程序直接操作Framebuffer内存。
三、程序代码解析
1. 包含头文件
#include <sys/mman.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> ...
这些头文件提供了Framebuffer操作所需的函数和类型定义。
2. 定义全局变量
static int fd_fb; static struct fb_var_screeninfo var; static int screen_size; static unsigned char *fb_base; static unsigned int line_width; static unsigned int pixel_width;
这些变量用于存储Framebuffer文件描述符、屏幕信息、屏幕大小、Framebuffer内存地址等。
3. lcd_put_pixel函数
void lcd_put_pixel(int x, int y, unsigned int color) { ... }
该函数根据屏幕的颜色深度,将指定颜色的像素点绘制到指定位置。
4. main函数
int main(int argc, char **argv) { ... }
main
函数是程序的入口点,它执行以下步骤:
- 打开Framebuffer设备。
- 获取屏幕变量信息。
- 计算每行的字节数和每个像素的字节数。
- 内存映射Framebuffer。
- 清屏并绘制100个红色像素点。
- 清理资源,包括munmap和close。
四、Framebuffer设备操作
程序通过open
函数打开/dev/fb0
设备文件,然后使用ioctl
函数获取屏幕信息,最后通过mmap
将Framebuffer内存映射到用户空间,以便直接访问。
五、绘制像素点
根据屏幕的颜色深度,程序计算每个像素在Framebuffer中的位置,并将其设置为指定颜色。这里考虑了8位、16位和32位颜色深度的情况。
六、资源清理
绘制完成后,程序使用munmap
函数取消Framebuffer的内存映射,并使用close
函数关闭Framebuffer设备。
七、总结
本文通过一个简单的示例程序,展示了如何在Linux Framebuffer上进行像素级的控制。这在嵌入式系统开发中非常有用,尤其是在需要直接操作显示内存的场景。
通过本示例,读者可以了解到Framebuffer的基本使用方法,以及如何在实际开发中应用这些技术。Framebuffer提供了一种灵活且强大的方式,用于控制嵌入式系统中的显示输出