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

之前获取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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【LeetCode】12,整数转罗马数字。 难度等级:中等。易错点:使用 python 字典构建哈希表时要考虑哈希表是否有序

文章目录 一、题目二、我的解法&#xff1a;基于有序哈希表的贪心算法2.1 使用 dict 构建哈希表2.2 使用两个 list / tuple 构建有序哈希表 一、题目 二、我的解法&#xff1a;基于有序哈希表的贪心算法 2.1 使用 dict 构建哈希表 贪心法则&#xff1a;我们每次尽量使用最大的…

面试被问麻了....

前几天组了一个软件测试面试的群&#xff0c;没想到效果直接拉满&#xff0c;看来大家对面试这块的需求还是挺迫切的。昨天我就看到群友们发的一些面经&#xff0c;感觉非常有参考价值&#xff0c;于是我就问他还有没有。 结果他给我整理了一份非常硬核的面筋&#xff0c;打开…

轻松高效!三种方法教你音频转文字!

我们在日常生活中&#xff0c;总会遇到许多需要音频转文字的情况。这个时候大部分小伙伴会选择一边播放音频一边记录的方式来整理音频的内容&#xff0c;这样既麻烦又费时&#xff0c;整理的效率也不高。其实我们只需要使用软件来协助我们将音频转换成文字&#xff0c;就可以很…

java 注解学习

Java 语言中存在三类注解&#xff0c;分别是元注解&#xff08;Meta-annotations&#xff09;、Java 内置注解&#xff08;Built-in Annotations&#xff09;和自定义注解&#xff08;Custom Annotations&#xff09;。 1、元注解&#xff08;Meta-annotations&#xff09; 元…

【PyQt5】指示灯显示

【PyQt5】指示灯显示 1、背景2、代码示例3、QtDesigner绘制1、背景 利用Qt5写工业控制软件交互界面的时候,经常需要在界面上有指示灯功能。 例如下面的明暗表示串行端口的连接和断开。 我们本质是用Qt5的label文本标签来实现的,即通过设置标签的样式表来实现的。 假设labe…

使用Windbg静态分析dump文件的一般步骤详解

目录 1、概述 2、静态分析dump文件的一般步骤 2.1、查看异常类型 2.2、使用.ecxr命令切换到发生异常的线程上下文&#xff0c;查看发生异常的那条汇编指令 2.3、使用kn/kv/kp命令查看异常发生时的函数调用堆栈 2.4、使用lm命令查看模块的时间戳&#xff0c;找到对应的pdb…

8个升级到ChatGPT Plus的理由,不升级你就out了

​关注文章下方公众号&#xff0c;可免费获取AIGC最新学习资料 导读&#xff1a;ChatGPT Plus 是 OpenAI 聊天机器人的高级付费版本。以每月 20 美元的价格&#xff0c;该服务为您提供访问 GPT-4&#xff0c;您可以享有令人难以置信的稳定性和更快的响应时间。 本文字数&#…

img[:, :, ::-1] 通俗理解

&#x1f468;‍&#x1f4bb;个人简介&#xff1a; 深度学习图像领域工作者 &#x1f389;工作总结链接&#xff1a;https://blog.csdn.net/qq_28949847/article/details/128552785 链接中主要是个人工作的总结&#xff0c;每个链接都是一些常用demo&#xff0c…

知识付费小程序搭建 为有价值的知识买单

以前我们学习写作遇到难题的时候&#xff0c;总喜欢上网搜一下参考资料&#xff0c;但是不知具体从何时起&#xff0c;很多平台内容查看都要钱了。这说明知识付费已经深入到我们的生活中了。再加上疫情爆发这几年&#xff0c;很多教育培训机构都抓住风口&#xff0c;开发了线上…

Web应用技术(第十四周/END)

本次练习基于how2j和课本,初步认识Spring。 以后我每周只写一篇Web的博客&#xff0c;所有的作业内容会在这篇博客中持续更新。。。 一、Spring基础1.Spring概述:2.Sring组成&#xff1a;3.BeanFactory&#xff1a;4.控制反转&#xff1a;5.依赖注入&#xff1a;6.JavaBean与S…

【六一 iKun】Happy LiuYi, iKuns

六一了&#xff0c;放松下。 Python iKun from turtle import * screensize(1000,1000) speed(6)#把衣服画出来&#xff0c;从右肩膀开始#领子 penup() goto(-141,-179) pensize(3) fillcolor("black") pencolor("black") begin_fill() pendown() left(1)…

30天从入门到精通TensorFlow1.x 第二天,变量 tf.Variable()

文章目录 一&#xff0c;接前一天&#xff08;1&#xff09;.内容前先弄清楚 sess.run() 函数a. 该函数干嘛的b. 该函数有哪些参数c. 该函数的使用 &#xff08;2&#xff09;.由库函数创建张量&#xff08;3&#xff09;.由库函数创建张量 二、变量tf.Variable()&#xff08;1…

Dart语法学习

最近在学习flutter相关方面的知识&#xff0c;里面用到了Dart语言&#xff0c;于是写下这篇博客记录学习的一门过程。如果你有其他编程语言的经验&#xff08;尤其是Java和JavaScript&#xff09;&#xff0c;可以很快的上手Dart语言&#xff0c;Dart 在设计时应该是同时借鉴了…

AI注册流程

1、首先需要有一个OpenAI账号&#xff0c;如果有方法的&#xff0c;就可以自己先注册一下。如果没有方法的&#xff0c;还有一个付费版本的可以备选&#xff0c;亲测可用。 2、注册建议使用谷歌账号关联登录&#xff0c;最方便。微软账号太慢了&#xff0c;也可以使用。注册使用…

Git的安装和环境变量的配置

目录 前言一、下载Git二、安装Git三、检查是否安装成功四、 配置用户名和邮箱五、环境变量配置1. 获取git的安装路径2. 设置环境变量 前言 当我们第一次在新电脑上使用git命令的时候&#xff0c;会报错【git 不是内部或外部命令&#xff0c;也不是可运行的程序 或批处理文件】…

企业工程项目管理系统源码-专注项目数字化管理-Java工程管理-二次开发

工程项目各模块及其功能点清单 一、系统管理 1、数据字典&#xff1a;实现对数据字典标签的增删改查操作 2、编码管理&#xff1a;实现对系统编码的增删改查操作 3、用户管理&#xff1a;管理和查看用户角色 4、菜单管理&#xff1a;实现对系统菜单的增删改查操…

javaWeb 酒店民宿预定信息管理系统myeclipse开发mysql数据库MVC模式java编程计算机网页设计

一、源码特点 java ssh酒店民宿预定信息管理系统是一套完善的web设计系统&#xff08;系统采用ssh框架进行设计开发&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为T…

【十一】设计模式~~~结构型模式~~~代理模式(Java)

【学习难度&#xff1a;★★★☆☆&#xff0c;使用频率&#xff1a;★★★★☆】 6.1. 模式动机 在某些情况下&#xff0c;一个客户不想或者不能直接引用一个对 象&#xff0c;此时可以通过一个称之为“代理”的第三者来实现 间接引用。代理对象可以在客户端和目标对象之间起…

CTR预估之DNN系列模型:FNN/PNN/DeepCrossing

前言 在上一篇文章中 CTR预估之FMs系列模型:FM/FFM/FwFM/FEFM&#xff0c;介绍了FMs系列模型的发展过程&#xff0c;开启了CTR预估系列篇章的学习。FMs模型是由线性项和二阶交互特征组成&#xff0c;虽然有自动学习二阶特征组合的能力&#xff0c;一定程度上避免了人工组合特征…

Springboot中使用mail邮件

Springboot中使用mail邮件发送 1、配置邮箱的POP3/SMTP服务和IMAP/SMTP服务2、导入依赖和一些默认#配置新的3、发送邮件4、整合工具类 1、配置邮箱的POP3/SMTP服务和IMAP/SMTP服务 这里使用的是QQ邮箱,进入设置-账户&#xff0c;开启下服务。 开启后获取授权码&#xff0c;保存…