4. 绘制像素点

任务目标

在LCD屏幕上指定坐标(x, y)绘制一个像素点,并验证写入的颜色值正确。本案例基于Linux Framebuffer驱动接口,通过mmap映射显存后直接操作像素地址,实现单点绘制。

环境与依赖

  • Linux系统(含/dev/fb0设备节点)
  • LCD驱动已启用Framebuffer(分辨率如800×480,32位色)
  • 编译依赖:linux/fb.h(内核头文件)、libc

核心实现

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <linux/fb.h>

#define FB_DEV "/dev/fb0"

int main(int argc, char *argv[]) {
    if (argc != 4) {
        fprintf(stderr, "用法: %s <x> <y> <颜色值(0xRRGGBB)>\n", argv[0]);
        return 1;
    }

    int x = atoi(argv[1]);
    int y = atoi(argv[2]);
    unsigned int color = (unsigned int)strtoul(argv[3], NULL, 0);

    int fb_fd = open(FB_DEV, O_RDWR);
    if (fb_fd < 0) { perror("open"); return 1; }

    struct fb_var_screeninfo vinfo;
    if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &vinfo) < 0) {
        perror("ioctl"); close(fb_fd); return 1;
    }

    // 计算显存大小并映射
    size_t screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
    unsigned char *fbp = mmap(NULL, screensize, PROT_READ | PROT_WRITE,
                              MAP_SHARED, fb_fd, 0);
    if (fbp == MAP_FAILED) { perror("mmap"); close(fb_fd); return 1; }

    // 坐标边界检查
    if (x < 0 || x >= (int)vinfo.xres || y < 0 || y >= (int)vinfo.yres) {
        fprintf(stderr, "坐标超出范围 (0~%u, 0~%u)\n", vinfo.xres-1, vinfo.yres-1);
        munmap(fbp, screensize); close(fb_fd); return 1;
    }

    // 计算像素偏移(32位色:每像素4字节)
    long offset = (x + y * vinfo.xres) * (vinfo.bits_per_pixel / 8);
    unsigned int *pixel = (unsigned int *)(fbp + offset);

    // 写入颜色(RGB888 → 内存布局需匹配驱动格式)
    *pixel = color;

    // 验证:读回并比较
    unsigned int readback = *pixel;
    munmap(fbp, screensize);
    close(fb_fd);

    if (readback == color) {
        printf("像素点(%d,%d)写入成功,颜色值 0x%06X 验证通过\n", x, y, color);
        return 0;
    } else {
        printf("验证失败:写入 0x%06X,读回 0x%06X\n", color, readback);
        return 1;
    }
}

编译与运行

# 编译
gcc -o draw_pixel draw_pixel.c

# 在(100, 200)处绘制红色像素
./draw_pixel 100 200 0xFF0000

# 在(400, 300)处绘制绿色像素
./draw_pixel 400 300 0x00FF00

验证方法

  • 程序输出:若显示“写入成功,颜色值验证通过”,说明像素写入与读回一致。
  • 视觉确认:在LCD屏幕上对应坐标应出现一个单色亮点(若背景为黑色则更明显)。
  • 边界测试:尝试./draw_pixel 0 0 0xFFFFFF(左上角白点)和超出分辨率的值,程序应正确报错。

注意事项

  • 若LCD驱动使用16位色(RGB565),需将color转换为对应格式,且每像素字节数为2。
  • 部分驱动要求先设置FBIOGET_FSCREENINFO获取固定信息,但本案例仅需可变信息即可完成单点绘制。
  • 若屏幕内容被其他进程刷新覆盖,视觉验证可能不明显,以程序读回验证为准。
(100,200) x y 100 400 200 0xFF0000 红色像素 0x00FF00 绿色像素 mmap 映射显存 → 直接写地址 offset = (x + y × xres) × bpp/8