【LCD应用编程】绘制点、线、矩形框

news2024/11/28 2:52:17

之前获取LCD屏幕参数信息时了解到,LCD屏是 FrameBuffer 设备,操作 FrameBuffer 设备 其实就是在读写 /dev/fb0 文件。除此之外,LCD屏上包含多个像素点,绘制点、线、矩形框本质是在修改这些像素点的颜色。


目录

1、定义 lcd_color 结构体

2、获取LCD设备参数信息

3、mmap 建立显存映射

(1) 为什么要建立显存映射?

(2) 代码实现  

3、定义绘制函数

4、完整代码


1、定义 lcd_color 结构体

为了后续方便传递颜色,这里定义一个 lcd_color 结构体,结构体声明如下。 

struct lcd_color
{
    u_int8_t red;
    u_int8_t green;
    u_int8_t blue;
};

我们要如何将颜色传递给LCD屏呢?根据我们之前获取到的屏幕信息,LCD屏颜色格式是RGB565。我们改变像素点颜色,实际上就是传递一个值。

这个值低5位表示蓝色,中间6位表示绿色,高5位表示红色,因此,我们拿到R、G、B对应的数值后需要将他们按下面的方式拼接。

#define RGB565(color) (color->blue & 0x05) | \
                      ((color->green & 0x06) << 5) | \
                      ((color->red & 0x05) << 11)

2、获取LCD设备参数信息

这里就不再赘述,请参考:获取LCD屏幕参数信息

struct fb_fix_screeninfo fb_fix; // 固定参数信息
struct fb_var_screeninfo fb_var; // 可变参数信息

int fd = open("/dev/fb0", O_RDWR);
if (fd < 0)
{
    perror("open fb failed");
    exit(-1);
}

ioctl(fd, FBIOGET_FSCREENINFO, &fb_fix);    // 获取固定参数信息
ioctl(fd, FBIOGET_VSCREENINFO, &fb_var);    // 获取可变参数信息

3、mmap 建立显存映射

(1) 为什么要建立显存映射?

建立显存映射的目的是提升IO效率。实际上使用read/write操作显存也是可以的,然而数据量较大的时候,普通IO的方式效率较低。一般显示的图像是动态变化的,图像数据需要不断被更新,这种情况下的数据量较大,建议采用存储映射IO方式。

mmap 函数的详细使用可以参考:mmap函数详解

(2) 代码实现  

值得一提的是,虽然最开始画的LCD示意图是一个矩形,但是在内存中还是线性存储的,显存的起始地址为 screen_base ,类型必须为 u_int16_t*  或者为 unsigned short*,因为指针类型决定了移动一次的步长,所以每次 screen_base + 1 的时候,实际上移动了16bit。(如果是 int,即32bit,screen_base + 1 时将会移动 32 bit)

u_int16_t *screen_base = NULL; // 映射基地址(全局变量)

int main(int args, char **argv)
{
    struct fb_fix_screeninfo fb_fix; // 固定参数信息
    struct fb_var_screeninfo fb_var; // 可变参数信息
    
    // ... ... 获取可变参数信息

    size_t len = fb_fix.line_length * fb_var.yres;
    screen_base = (u_int16_t *)mmap(NULL, len, PROT_WRITE, MAP_SHARED, fd, 0);
    if ((void*)screen_base == MAP_FAILED)
    {
        perror("mmap failed");
        exit(-2);
    }
}

3、定义绘制函数

绘制点

绘制点的关键在于确定像素点的位置,然后赋予颜色。

/********************************************************************
 * 函数名称: lcd_draw_point
 * 功能描述: 在LCD屏上绘制一个点
 * 输入参数: x, y, color
 * 返 回 值: 无
 ********************************************************************/
void lcd_draw_point(uint x, uint y, struct lcd_color* color)
{
    screen_base[y*width + x] = RGB565(color);    // 这里的 width 是全局变量,对应LCD屏的每行的像素点个数
}

绘制线

/********************************************************************
 * 函数名称: lcd_draw_line
 * 功能描述: 在LCD屏上绘制一根线
 * 输入参数: 其实就是绘制一个实心的矩形
            start_x: 起始横坐标     start_y: 起始纵坐标
            line_width: 线的宽度    line_height: 线的高度
            color: 线的颜色
 * 返 回 值: 无
 ********************************************************************/
void lcd_draw_line(uint start_x, uint start_y, uint line_width, uint line_height, struct lcd_color* color)
{
    for (size_t i = start_y; i < start_y + line_height; i++)
    {
        for (size_t j = start_x; j < start_x + line_width; j++)
        {
            lcd_draw_point(j, i, color);
        }
    }
}

绘制矩形框

/********************************************************************
 * 函数名称: lcd_draw_rect
 * 功能描述: 在LCD屏上绘制一个矩形框
 * 输入参数: 其实就是绘制一个实心的矩形
            start_x: 起始横坐标     start_y: 起始纵坐标
            rect_width: 矩形框的宽度    rect_height: 矩形框的高度
            line_width:线的粗细程度
            color: 线的颜色
 * 返 回 值: 无
 ********************************************************************/
void lcd_draw_rect(uint start_x, uint start_y, uint rect_width, uint rect_height, uint line_width, struct lcd_color* color)
{
    lcd_draw_line(start_x, start_y, rect_width, line_width, color);         // 上
    lcd_draw_line(start_x, start_y + rect_height - line_width - 1, rect_width, line_width, color);  // 下

    lcd_draw_line(start_x, start_y + line_width, line_width, rect_height - line_width, color);         // 左
    lcd_draw_line(start_x + rect_width - line_width - 1, start_y + line_width, line_width, rect_height - line_width, color);         // 右
}

4、完整代码

由于只分配了 5 bit来表示红色,所以显示出来的红色可能偏暗。

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

u_int16_t width = 0;
u_int16_t height = 0;

u_int16_t *screen_base = NULL; // 映射基地址

typedef unsigned int uint;
struct lcd_color
{
    u_int8_t red;
    u_int8_t green;
    u_int8_t blue;
};
#define RGB565(color) (color->blue & 0x05) | \
                      ((color->green & 0x06) << 5) | \
                      ((color->red & 0x05) << 11)

/********************************************************************
 * 函数名称: lcd_draw_point
 * 功能描述: 在LCD屏上绘制一个点
 * 输入参数: x, y, color
 * 返 回 值: 无
 ********************************************************************/
void lcd_draw_point(uint x, uint y, struct lcd_color* color)
{
    screen_base[y*width + x] = RGB565(color);
}

/********************************************************************
 * 函数名称: lcd_draw_line
 * 功能描述: 在LCD屏上绘制一根线
 * 输入参数: start_x, start_y, line_width, line_height, color
 * 返 回 值: 无
 ********************************************************************/
void lcd_draw_line(uint start_x, uint start_y, uint line_width, uint line_height, struct lcd_color* color)
{
    for (size_t i = start_y; i < start_y + line_height; i++)
    {
        for (size_t j = start_x; j < start_x + line_width; j++)
        {
            lcd_draw_point(j, i, color);
        }
    }
}

/********************************************************************
 * 函数名称: lcd_draw_rect
 * 功能描述: 在LCD屏上绘制一个矩形框
 * 输入参数: start_x, start_y, rect_width, rect_height, line_width, color
 * 返 回 值: 无
 ********************************************************************/
void lcd_draw_rect(uint start_x, uint start_y, uint rect_width, uint rect_height, uint line_width, struct lcd_color* color)
{
    lcd_draw_line(start_x, start_y, rect_width, line_width, color);         // 上
    lcd_draw_line(start_x, start_y + rect_height - line_width - 1, rect_width, line_width, color);  // 下

    lcd_draw_line(start_x, start_y + line_width, line_width, rect_height - line_width, color);         // 左
    lcd_draw_line(start_x + rect_width - line_width - 1, start_y + line_width, line_width, rect_height - line_width, color);         // 右
}

int main(int args, char **argv)
{
    struct fb_fix_screeninfo fb_fix; // 固定参数信息
    struct fb_var_screeninfo fb_var; // 可变参数信息

    int fd = open("/dev/fb0", O_RDWR);
    if (fd < 0)
    {
        perror("open fb failed");
        exit(-1);
    }

    ioctl(fd, FBIOGET_FSCREENINFO, &fb_fix);
    ioctl(fd, FBIOGET_VSCREENINFO, &fb_var);
    width = fb_var.xres;
    height = fb_var.yres;

    size_t len = fb_fix.line_length * fb_var.yres;
    screen_base = (u_int16_t *)mmap(NULL, len, PROT_WRITE, MAP_SHARED, fd, 0);
    if ((void*)screen_base == MAP_FAILED)
    {
        perror("mmap failed");
        exit(-2);
    }

    // 将整个屏幕填充成红色
    for (size_t i = 0; i < height; i++)
    {
        for (size_t j = 0; j < width; j++)
        {
            struct lcd_color color = {31, 0, 0};
            lcd_draw_point(j, i, &color);
        }
    }
    
    // 绘制一根长为width,宽为 height/2 的线
    struct lcd_color line_color = {0, 31, 0};
    lcd_draw_line(0, 0, width, height/2, &line_color);

    // 绘制一个长为width,宽为height,线粗为10的矩形框
    struct lcd_color rect_color = {31, 31, 0};
    lcd_draw_rect(0, 0, width, height, 10, &rect_color);

    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/577046.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

VS+Qt — Vistual Studio 2022+Qt6安装教程以及解决Qt Vistual Studio Tools下载慢和VS无法打开.ui进行设计的问题

目录 Vistual Studio 2022下载 Qt下载 Qt Vistual Studio Tools下载 方法1 方法2 方法3 方法4 Vistual Studio 2022配置Qt6 创建Qt项目 若VS无法打开.ui进行设计 Vistual Studio 2022下载 以前因为安装库的关系&#xff0c;已经下载过VS2022了&#xff0c;详细请看这…

C++ 学习 ::【基础篇:05】:C++ 函数重载认识及使用、简单介绍:C++ 支持函数重载的原因

本系列 C 相关文章 仅为笔者学习笔记记录&#xff0c;用自己的理解记录学习&#xff01;C 学习系列将分为三个阶段&#xff1a;基础篇、STL 篇、高阶数据结构与算法篇&#xff0c;相关重点内容如下&#xff1a; 基础篇&#xff1a;类与对象&#xff08;涉及C的三大特性等&#…

CSS之基础扫盲

博主简介&#xff1a;想进大厂的打工人博主主页&#xff1a;xyk:所属专栏: JavaEE初阶 目录 文章目录 二、CSS基础语法 2.1 CSS引入方式 2.1.1 内部样式 2.1.2 外部样式 2.1.3 内联样式 2.2 CSS选择器 2.2.1 标签选择器 2.2.2 类选择器 2.2.3 id选择器 2.2.4 通配符选择器 2.2…

HNU-操作系统OS-实验Lab7

OS_Lab7_Experimental report 湖南大学信息科学与工程学院 计科 210X wolf (学号 202108010XXX) 实验目的 理解操作系统的同步互斥的设计实现;理解底层支撑技术:禁用中断、定时器、等待队列;在ucore中理解信号量(semaphore)机制的具体实现;理解管程机制,在ucore内…

动力电池管理系统(BMS)

BMS技术 目录 BMS技术 一、BMS简介 二、BMS主要功能 1、参数检测 2、剩余电量&#xff08;SOC&#xff09;估计 3、充放电控制 4、热管理 5、均衡控制 6、故障诊断 7、信息监控 8、参数标定 9、CAN总线接口 三、BMS架构组成 1、BMS的拓扑架构 1、1集中式架构的B…

JavaEE进阶(5/27)Spring Boot

目录 1.认识Spring Boot 2.Spring Boot的优点 3.SpringBoot项目创建 4.resource文件夹 和test文件夹 5.使用一个Spring Boot项目 1.认识Spring Boot Spring Boot 中的Boot 是启动引导的意思 如果Spring相比于普通java开发是从走演变到了汽车&#xff0c;那么Spring boot 相比…

【博客历程】比起方法和技巧,我更想谈质量与坚持

【博客历程】比起方法和技巧&#xff0c;我更想谈质量与坚持 文章目录 【博客历程】比起方法和技巧&#xff0c;我更想谈质量与坚持[toc]我的第一篇博客为什么坚持写博客为什么选择CSDN何为质量未来 还没准备好&#xff0c;等我怎样怎样时再 还在犹豫什么时候开始&#xff0c;…

ssm+springboot+java高校图书馆图书借阅座位预约管理系统系统

陕理工图书馆管理系统包括多个功能模块&#xff1a;图书类别管理模块、图书管理模块、读者管理模块、借阅管理模块、预约管理、推荐管理。管理员登入后&#xff0c;维护图书借阅的信息。本文介绍了使用Java技术开发陕理工图书馆管理系统的设计与实现过程&#xff0c;首先对实现…

微信小程序 java+nodejs+vue美食定制个性化点餐推荐系统

社会的发展和科学技术的进步&#xff0c;互联网技术越来越受欢迎。手机也逐渐受到广大人民群众的喜爱&#xff0c;也逐渐进入了每个用户的使用。手机具有便利性&#xff0c;速度快&#xff0c;效率高&#xff0c;成本低等优点。 因此&#xff0c;构建符合自己要求的操作系统是非…

Deathnote

Deathnote 1.主机发现 arp-scan -l2.扫描端口 nmap -Pn -sV -P- -A 192.168.80.132开放了80、22端口 3.访问80端口 修改host文件访问80端口时进行了跳转到deathnote.vuln/wordpress&#xff0c;修改hosts文件&#xff0c;将该域名解析到靶机ip windows hosts文件路径&…

canal server 标准化集群搭建(完结)

4.2. 创建 server 所属集群&#xff1a;选择刚才添加的 “集群名称” server 名称&#xff1a; server_1、server_2、server_3 依次类推 server ip&#xff1a;server 的 ip 地址 admin 端口&#xff1a;canal server 与 canal admin 的通信端口&#xff0c;非生产环境从 2…

Android 12.0Launcher3 电话和短信app图标显示未读短信和未接来电的条数

1.概述 在12.0产品开发中,最近客户有需求要求在电话app图标显示未接来电的条数 在短信app图标上显示未读信息的条数 根据需求首选要在Launcher3的Launcher.java中,启动launcher时,查询未读短信和未接来电 在有未接来电时,更新未接来电的数量 在有未读短信时,更新未读短信的…

基于html+css的图展示95

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…

C++内存空间

1.内存空间 在 C 中&#xff0c;内存分为内核空间和用户空间&#xff0c;内核空间由操作系统管理&#xff0c;程序员写的程序在用户空间。 程序运行时&#xff0c;内存主要分成四个区&#xff0c;分别是栈、堆、数据段和代码段。 栈&#xff1a;存储局部变量、函数参数和返回…

今日餐饮美食推荐系统多商家 uniapp+vue微信小程序

此今日美食推荐小程序信息的设计主要有两个用户&#xff0c;会员客户端和管理员服务端两个部分&#xff1a;会员客户主要功能&#xff1b; &#xff08;1&#xff09;会员信息&#xff1a;包括&#xff1a;会员注册、会员登录&#xff0c;包括对个人信息进行修改。 &#xff08…

Redis的常用数据结构之哈希类型

首先这里说的哈希类型针对的是redis中的value的k-v结构 常见的操作命令 hset设置值 hsetnx命令&#xff0c;不存在可以设置&#xff0c;存在设置不成功 hget取值&#xff0c;这里与字符串类型不同是要精确到filed。前面的判断也是基于field来实现的 要是field没有就返回null h…

计算机视觉:卷积步长(Stride)

本文重点 我们前面学习了卷积操作,也学习了填充,本节课程我们学习卷积步长,之前我们使用卷积核进行卷积操作都是在图像的左上角开始,从左到右、从上到下每次移动一步,其实移动多少步是可以变化的,这个移动步数称为步长。 什么是步长 卷积操作中的步长(Stride)是指卷…

Qt自定义的ColorDialog--仿QColorDialog

Qt已经有了色板选择&#xff0c;但是它使用QDialog形成的&#xff0c;每次调用基本上都成了点一个按钮&#xff0c;谈一个模态框&#xff0c;选择好颜色之后再关掉模态框。 但是&#xff0c;如果想将颜色选择板放在窗口上&#xff0c;并不会有模态的功能就会比较麻烦&#xff…

【Python GUI编程】零基础也能轻松掌握的学习路线与参考资料

Python GUI编程是指使用Python语言及其相关的GUI框架来开发图形用户界面的程序。学习Python GUI编程需要具备一定的基础知识&#xff0c;如Python语言基础、面向对象编程、GUI编程等。下面给出详细的学习路线和参考资料。 一、Python基础 学习Python GUI编程的第一步需要具备…

代理模式 静态代理 动态代理

代理对象可以在客户端和目标对象之间起到中介的作用&#xff0c;并且可以通过代理对象去掉客户不应该看到的内容和服务或者添加客户需要的额外服务。 代理模式中的角色&#xff1a; 代理类目标类代理类和目标类的公共接口&#xff1a;客户端在使用代理类时就像在使用目标类&a…