正点原子Linux学习笔记(八)LCD 横屏切换为竖屏

2024-05-11 20:44

本文主要是介绍正点原子Linux学习笔记(八)LCD 横屏切换为竖屏,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

LCD 横屏切换为竖屏

  • 横屏显示如何切换为竖屏显示
  • 22.2 编写示例代码

之前在技术交流群里边有人提到了 LCD 横屏切换为竖屏的问题,笔者觉得还是很有必要给大家讲一下,所以这里单独做一章内容来讲一讲怎么样实现 LCD 横屏切换为竖屏,其实个人觉得还是非常简单地。首先给大家普及一个基本的知识点,这种横屏、竖屏的切换与驱动程序无关,是应用层需要去解决的一个问题!
本章将会讨论如下主题。
⚫ 横屏显示如何切换为竖屏显示;
⚫ 编写代码验证;

横屏显示如何切换为竖屏显示

开发板配套使用的这些 LCD 屏都是横屏显示的,包括正点原子 4.3 寸 480272、4.3 寸 800480、7 寸 800480、7 寸1024600 以及 10.1 寸 1280800 等这些 RGB LCD 屏;LCD 屏正向放置情况下(以 800480分辨率为例),它的左上角就是坐标(0, 0)、左下角坐标是(0, 480-1)、右上角坐标是(800-1, 0)、右下角坐标是(800-1, 480-1),如下所示:
在这里插入图片描述
这是硬件上固定的,它是一种不可修改的硬件属性,譬如你不能对 LCD 硬件进行配置,将屏幕左下角设置为起点(0, 0),这是不可以的;像素点的排列顺序是从左到右、从上到下,我们对 LCD 上不同像素点进行操作时,需要找到该像素点对应的显存地址,同样也是基于这种标准来的;假设显存基地址为(unsignedchar *)base,那么定位一个(x, y)坐标像素点对应的地址的公式为 base + (y * width + x) * pix_bytes,其中pix_bytes 表示一个像素点使用 pix_bytes 个字节来描述。
示意图如下所示:
在这里插入图片描述
上图已经很直观、明了的说明了 LCD 屏上各个像素点与显存空间的对应关系。
但是在很多的应用场合中,往往需要以竖屏的方式来显示画面,譬如手机就是一个很好的例子,相信大家的手机都是竖屏方式显示的;甚至还有一些电子产品既能支持横屏也能支持竖屏显示,当然这是针对应用程序而言。

那我们的应用程序中如何将 LCD 屏修改为竖屏显示呢?其实原理上非常简单,我相信大家都可以想到,图 22.1.1 所示屏幕,如果我们要将其作为竖屏显示,譬如在应用程序中将左下角作为起点(0, 0),那么左上角对应就是(480-1, 0)、右下角对应就是(0, 800-1)、右上角对应就是(480-1, 800-1),如下图所示:
在这里插入图片描述
以上便是竖屏显示情况下,其中的一种坐标分布情况,当然这是应用程序认为的一种坐标分布,对于LCD 硬件来说,实际物理上的起点坐标依然是图 22.1.1 中左上角的位置。

那么在上图中竖屏这种情况下,应用程序的坐标对应的像素点,它的显存地址就不能使用 base + (y * width + x) * pix_bytes 公式进行计算了;譬如上图竖屏方式下,起点坐标(0, 0)对应的实际物理坐标是(0, 480-1),同理它的显存地址也是通过实际物理坐标(0, 480-1)这个坐标计算而来、而不是通过(0, 0)计算。

在上图中竖屏方式下,应用程序的(x, y)坐标点对应的显存地址可通过如下公式进行计算:

base + ((height - 1- x) * width + y)) * pix_bytes;

公式中的 x 和 y 分别表示竖屏方式下的(x, y)坐标,当然这个公式仅适用于上图这种竖屏方式;你也可以把图 22.1.3 旋转 180 度倒过来,同样也是竖屏,这种情况就不能用上面这条公式了。公式推导非常简单,没什么可解释的。

22.2 编写示例代码

通过上小节的介绍,我们已经知道了如何将横屏切换为竖屏显示,本小节我们将对示例代码 19.4.1 进行修改,将其修改为竖屏显示,示例代码笔者已经给出,如下所示。

示例代码 22.2.1 LCD 横屏切换为竖屏显示
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <linux/fb.h>
#define argb8888_to_rgb565(color) ({ \unsigned int temp = (color); \((temp & 0xF80000UL) >> 8) | \((temp & 0xFC00UL) >> 5) | \((temp & 0xF8UL) >> 3); \})
static int lcd_width; //LCD X 分辨率
static int lcd_height; //LCD Y 分辨率
static int lcd_max_y; //LCD Y 坐标最大值
static int user_width; //竖屏模式下 X 分辨率
static int user_height; //竖屏模式下 Y 分辨率
static unsigned short *screen_base = NULL; //映射后的显存基地址
/********************************************************************
* 函数名称: lcd_draw_point
* 功能描述: 打点
* 输入参数: x, y, color
* 返 回 值: 无
********************************************************************/
static void lcd_draw_point(unsigned int x, unsigned int y, unsigned int color) {unsigned short rgb565_color = argb8888_to_rgb565(color);//得到 RGB565 颜色值/* 对传入参数的校验 */if (x >= user_width)x = user_width - 1;if (y >= user_height)y = user_height - 1;/* 填充颜色 */screen_base[(lcd_max_y-x) * lcd_width + y] = rgb565_color; }
/********************************************************************
* 函数名称: lcd_draw_line
* 功能描述: 画线(水平或垂直线)
* 输入参数: x, y, dir, length, color
* 返 回 值: 无
********************************************************************/
static void lcd_draw_line(unsigned int x, unsigned int y, int dir,unsigned int length, unsigned int color) {unsigned short rgb565_color = argb8888_to_rgb565(color);//得到 RGB565 颜色值unsigned int end;unsigned long temp;/* 对传入参数的校验 */if (x >= user_width)x = user_width - 1;if (y >= user_height)y = user_height - 1;/* 填充颜色 */temp = (lcd_max_y-x) * lcd_width + y;if (dir) { //水平线end = x + length - 1;if (end >= user_width)end = user_width - 1;for ( ; x <= end; x++, temp -= lcd_width)screen_base[temp] = rgb565_color;}else { //垂直线end = y + length - 1;if (end >= user_height)end = user_height - 1;for ( ; y <= end; y++, temp++)screen_base[temp] = rgb565_color;} }
/********************************************************************
* 函数名称: lcd_draw_rectangle
* 功能描述: 画矩形
* 输入参数: start_x, end_x, start_y, end_y, color
* 返 回 值: 无
********************************************************************/
static void lcd_draw_rectangle(unsigned int start_x, unsigned int end_x,unsigned int start_y, unsigned int end_y,unsigned int color) {int x_len = end_x - start_x + 1;int y_len = end_y - start_y - 1;lcd_draw_line(start_x, start_y, 1, x_len, color);//上边lcd_draw_line(start_x, end_y, 1, x_len, color); //下边lcd_draw_line(start_x, start_y + 1, 0, y_len, color);//左边lcd_draw_line(end_x, start_y + 1, 0, y_len, color);//右边
}
/********************************************************************
* 函数名称: lcd_fill
* 功能描述: 将一个矩形区域填充为参数 color 所指定的颜色
* 输入参数: start_x, end_x, start_y, end_y, color
* 返 回 值: 无
********************************************************************/
static void lcd_fill(unsigned int start_x, unsigned int end_x,unsigned int start_y, unsigned int end_y,unsigned int color) {unsigned short rgb565_color = argb8888_to_rgb565(color);//得到 RGB565 颜色值unsigned long temp;unsigned long step_size_count;int x;/* 对传入参数的校验 */if (end_x >= user_width)end_x = user_width - 1;if (end_y >= user_height)end_y = user_height - 1;/* 填充颜色 */temp = (lcd_max_y-start_x) * lcd_width + start_y;for ( ; start_y <= end_y; start_y++, temp++) {step_size_count = 0;for (x = start_x; x <= end_x; x++, step_size_count += lcd_width)screen_base[temp - step_size_count] = rgb565_color;} }
int main(int argc, char *argv[])
{struct fb_fix_screeninfo fb_fix;struct fb_var_screeninfo fb_var;unsigned int screen_size;int fd;/* 打开 framebuffer 设备 */if (0 > (fd = open("/dev/fb0", O_RDWR))) {perror("open error");exit(EXIT_FAILURE);}/* 获取参数信息 */ioctl(fd, FBIOGET_VSCREENINFO, &fb_var);ioctl(fd, FBIOGET_FSCREENINFO, &fb_fix);screen_size = fb_fix.line_length * fb_var.yres;lcd_width = fb_var.xres;lcd_height = fb_var.yres;lcd_max_y = lcd_height - 1;user_width = fb_var.yres;user_height = fb_var.xres;/* 将显示缓冲区映射到进程地址空间 */screen_base = mmap(NULL, screen_size, PROT_WRITE, MAP_SHARED, fd, 0);if (MAP_FAILED == (void *)screen_base) {perror("mmap error");close(fd);exit(EXIT_FAILURE);}/* 画正方形方块 */int w = user_height * 0.25;//方块的宽度为 1/4 屏幕高度lcd_fill(0, user_width-1, 0, user_height-1, 0x0); //清屏(屏幕显示黑色)lcd_fill(0, w, 0, w, 0xFF0000); //红色方块lcd_fill(user_width-w, user_width-1, 0, w, 0xFF00); //绿色方块lcd_fill(0, w, user_height-w, user_height-1, 0xFF); //蓝色方块lcd_fill(user_width-w, user_width-1, user_height-w, user_height-1, 0xFFFF00);//黄色方块/* 画线: 十字交叉线 */lcd_draw_line(0, user_height * 0.5, 1, user_width, 0xFFFFFF);//白色水平线lcd_draw_line(user_width * 0.5, 0, 0, user_height, 0xFFFFFF);//白色垂直线/* 画矩形 */unsigned int s_x, s_y, e_x, e_y;s_x = 0.25 * user_width;s_y = w;e_x = user_width - s_x;e_y = user_height - s_y;for ( ; (s_x <= e_x) && (s_y <= e_y);s_x+=5, s_y+=5, e_x-=5, e_y-=5)lcd_draw_rectangle(s_x, e_x, s_y, e_y, 0xFFFFFF);/* 退出 */munmap(screen_base, screen_size); //取消映射close(fd); //关闭文件exit(EXIT_SUCCESS); //退出进程
}

示例代码中自定义的 4 个函数:lcd_draw_point()、lcd_draw_line()、lcd_draw_rectangle()、lcd_fill()都是基于竖屏显示方式进行定义的,我们传入的坐标都是竖屏坐标,函数内部会将其转为实际的物理坐标,然后操作写对应的显存地址。

代码就不在讲解了,没什么好说,主要是一些转换上的逻辑代码,理解了上小节所介绍的内容,这个代码是不难理解的。

接着我们编译示例代码,将编译得到的可执行文件拷贝到开发板 Linux 系统家目录下,执行测试程序,此时 LCD 显示效果如下所示:
在这里插入图片描述
大家可以与图 19.4.3 进行对比,画面的显示的效果,一个是横向显示、另一个是竖向显示。

这篇关于正点原子Linux学习笔记(八)LCD 横屏切换为竖屏的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/980605

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

linux-基础知识3

打包和压缩 zip 安装zip软件包 yum -y install zip unzip 压缩打包命令: zip -q -r -d -u 压缩包文件名 目录和文件名列表 -q:不显示命令执行过程-r:递归处理,打包各级子目录和文件-u:把文件增加/替换到压缩包中-d:从压缩包中删除指定的文件 解压:unzip 压缩包名 打包文件 把压缩包从服务器下载到本地 把压缩包上传到服务器(zip

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss