原子學習筆記7——FrameBuffer 應用編程

Frame 是幀的意思,buffer 是緩沖的意思,所以 Framebuffer 就是幀緩沖,這意味著 Framebuffer 就是一塊內存,里面保存著一幀圖像。
應用程序通過對 LCD 設備節點/dev/fb0(假設 LCD 對應的設備節點是/dev/fb0)進行 I/O 操作即可實現對 LCD 的顯示控制。
在應用程序中,操作/dev/fbX 的一般步驟如下:
①、首先打開/dev/fbX 設備文件。
②、使用 ioctl()函數獲取到當前顯示設備的參數信息,譬如屏幕的分辨率大小、像素格式,根據屏幕參數計算顯示緩沖區的大小。
③、通過存儲映射 I/O 方式將屏幕的顯示緩沖區映射到用戶空間(mmap)。
④、映射成功后就可以直接讀寫屏幕的顯示緩沖區,進行繪圖或圖片顯示等操作了。
⑤、完成顯示后,調用 munmap()取消映射、并調用 close()關閉設備文件。

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 <linux/fb.h>
int main(int argc, char *argv[])
{struct fb_fix_screeninfo fb_fix;struct fb_var_screeninfo fb_var;int fd;// /* 打開 framebuffer 設備 if (0 > (fd = open("/dev/fb0", O_WRONLY))) {perror("open error");exit(-1);}// /* 獲取參數信息 ioctl(fd, FBIOGET_VSCREENINFO, &fb_var);ioctl(fd, FBIOGET_FSCREENINFO, &fb_fix);printf("分辨率: %d*%d\n""像素深度 bpp: %d\n""一行的字節數: %d\n""像素格式: R<%d %d> G<%d %d> B<%d %d>\n",fb_var.xres, fb_var.yres, fb_var.bits_per_pixel,fb_fix.line_length,fb_var.red.offset, fb_var.red.length,fb_var.green.offset, fb_var.green.length,fb_var.blue.offset, fb_var.blue.length);// /* 關閉設備文件退出程序 close(fd);exit(0);
}

可以看出fb_fix_screeninfo、fb_var_screeninfo結構體與FBIOGET_VSCREENINFO、FBIOGET_FSCREENINFO通過ioctl()函數顯示出設備參數信息。
開發板上使用的是7 寸 1024*600的顯示屏
在這里插入圖片描述

2、LCD 基本操作

編寫應用程序,在 LCD 上實現畫點(俗稱打點)、畫線、畫矩形等基本 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 width; //LCD X 分辨率
static int height; //LCD 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 >= width)x = width - 1;if (y >= height)y = height - 1;/* 填充顏色 */screen_base[y * width + x] = 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 >= width)x = width - 1;if (y >= height)y = height - 1;/* 填充顏色 */temp = y * width + x;//定位到起點if (dir) { //水平線end = x + length - 1;if (end >= width)end = width - 1;for ( ; x <= end; x++, temp++)screen_base[temp] = rgb565_color;}else { //垂直線end = y + length - 1;if (end >= height)end = height - 1;for ( ; y <= end; y++, temp += width)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 int x;/* 對傳入參數的校驗 */if (end_x >= width)end_x = width - 1;if (end_y >= height)end_y = height - 1;/* 填充顏色 */temp = start_y * width; //定位到起點行首for ( ; start_y <= end_y; start_y++, temp+=width) {for (x = start_x; x <= end_x; x++)screen_base[temp + x] = 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;//一幀數據的數據量大小width = fb_var.xres;height = fb_var.yres;/* 將顯示緩沖區映射到進程地址空間 */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 = height * 0.25;//方塊的寬度為 1/4 屏幕高度lcd_fill(0, width-1, 0, height-1, 0x0); //清屏(屏幕顯示黑色)lcd_fill(0, w, 0, w, 0xFF0000); //紅色方塊lcd_fill(width-w, width-1, 0, w, 0xFF00); //綠色方塊lcd_fill(0, w, height-w, height-1, 0xFF); //藍色方塊lcd_fill(width-w, width-1, height-w, height-1, 0xFFFF00);//黃色方塊/* 畫線: 十字交叉線 */lcd_draw_line(0, height * 0.5, 1, width, 0xFFFFFF);//白色線lcd_draw_line(width * 0.5, 0, 0, height, 0xFFFFFF);//白色線/* 畫矩形 */unsigned int s_x, s_y, e_x, e_y;s_x = 0.25 * width;s_y = w;e_x = width - s_x;e_y = 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); //退出進程
}
  • 首先調用 open()打開 LCD 設備文件得到文件描述符 fd;
  • 接著使用 ioctl 函數獲取 LCD 的可變參數信息和固定參數信息,通過得到的信息計算 LCD 顯存大小、得到 LCD 屏幕的分辨率,ALPHA I.MX6U 開發板出廠系統將 LCD 實現為一個 RGB565 顯示設備,所以程序中自定義的 4 個函數在操作 LCD 像素點時、都是以 RGB565的格式寫入顏色值。
  • 接著使用 mmap 建立映射;
  • 映射成功之后就可以在應用層直接操作 LCD 顯存了,調用自定義的函數在 LCD 上畫線、畫矩形、畫方塊;
  • 操作完成之后,調用 munmap 取消映射,調用 close 關閉 LCD 設備文件,退出程序。

3、顯示 BMP 圖片

#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 <string.h>
#include <linux/fb.h>
#include <sys/mman.h>
/**** BMP 文件頭數據結構 ****/
typedef struct {unsigned char type[2]; //文件類型unsigned int size; //文件大小unsigned short reserved1; //保留字段 1unsigned short reserved2; //保留字段 2unsigned int offset; //到位圖數據的偏移量
} __attribute__ ((packed)) bmp_file_header;
/**** 位圖信息頭數據結構 ****/
typedef struct {unsigned int size; //位圖信息頭大小int width; //圖像寬度int height; //圖像高度unsigned short planes; //位面數unsigned short bpp; //像素深度unsigned int compression; //壓縮方式unsigned int image_size; //圖像大小int x_pels_per_meter; //像素/米int y_pels_per_meter; //像素/米unsigned int clr_used;unsigned int clr_omportant;
} __attribute__ ((packed)) bmp_info_header;
/**** 靜態全局變量 ****/
static int width; //LCD X 分辨率
static int height; //LCD Y 分辨率
static unsigned short *screen_base = NULL; //映射后的顯存基地址
static unsigned long line_length; //LCD 一行的長度(字節為單位)
/********************************************************************
* 函數名稱: show_bmp_image
* 功能描述: 在 LCD 上顯示指定的 BMP 圖片
* 輸入參數: 文件路徑
* 返 回 值: 成功返回 0, 失敗返回-1
********************************************************************/
static int show_bmp_image(const char *path)
{bmp_file_header file_h;bmp_info_header info_h;unsigned short *line_buf = NULL; //行緩沖區unsigned long line_bytes; //BMP 圖像一行的字節的大小unsigned int min_h, min_bytes;int fd = -1;int j;/* 打開文件 */if (0 > (fd = open(path, O_RDONLY))) {perror("open error");return -1;}/* 讀取 BMP 文件頭 */if (sizeof(bmp_file_header) != read(fd, &file_h, sizeof(bmp_file_header))) {perror("read error");close(fd);return -1;}if (0 != memcmp(file_h.type, "BM", 2)) {fprintf(stderr, "it's not a BMP file\n");close(fd);return -1;}/* 讀取位圖信息頭 */if (sizeof(bmp_info_header) != read(fd, &info_h, sizeof(bmp_info_header))) {perror("read error");close(fd);return -1;}/* 打印信息 */printf("文件大小: %d\n""位圖數據的偏移量: %d\n""位圖信息頭大小: %d\n""圖像分辨率: %d*%d\n""像素深度: %d\n", file_h.size, file_h.offset,info_h.size, info_h.width, info_h.height,info_h.bpp);/* 將文件讀寫位置移動到圖像數據開始處 */if (-1 == lseek(fd, file_h.offset, SEEK_SET)) {perror("lseek error");close(fd);return -1;}/* 申請一個 buf、暫存 bmp 圖像的一行數據 */line_bytes = info_h.width * info_h.bpp / 8;line_buf = malloc(line_bytes);if (NULL == line_buf) {fprintf(stderr, "malloc error\n");close(fd);return -1;}if (line_length > line_bytes)min_bytes = line_bytes;elsemin_bytes = line_length;/**** 讀取圖像數據顯示到 LCD ****//******************************************** 為了軟件處理上方便,這個示例代碼便不去做兼容性設計了* 如果你想做兼容, 可能需要判斷傳入的 BMP 圖像是 565 還是 888* 如何判斷呢?文檔里邊說的很清楚了* 我們默認傳入的 bmp 圖像是 RGB565 格式*******************************************/if (0 < info_h.height) {//倒向位圖if (info_h.height > height) {min_h = height;lseek(fd, (info_h.height - height) * line_bytes, SEEK_CUR);screen_base += width * (height - 1); //定位到屏幕左下角位置}else {min_h = info_h.height;screen_base += width * (info_h.height - 1); //定位到....不知怎么描述 懂的人自然懂!}for (j = min_h; j > 0; screen_base -= width, j--) {read(fd, line_buf, line_bytes); //讀取出圖像數據memcpy(screen_base, line_buf, min_bytes);//刷入 LCD 顯存}}else { //正向位圖int temp = 0 - info_h.height; //負數轉成正數if (temp > height)min_h = height;elsemin_h = temp;for (j = 0; j < min_h; j++, screen_base += width) {read(fd, line_buf, line_bytes);memcpy(screen_base, line_buf, min_bytes);}}/* 關閉文件、函數返回 */close(fd);free(line_buf);return 0;
}
int main(int argc, char *argv[])
{struct fb_fix_screeninfo fb_fix;struct fb_var_screeninfo fb_var;unsigned int screen_size;int fd;/* 傳參校驗 */if (2 != argc) {fprintf(stderr, "usage: %s <bmp_file>\n", argv[0]);exit(-1);}/* 打開 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;line_length = fb_fix.line_length;width = fb_var.xres;height = fb_var.yres;/* 將顯示緩沖區映射到進程地址空間 */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);}/* 顯示 BMP 圖片 */memset(screen_base, 0xFF, screen_size);show_bmp_image(argv[1]);/* 退出 */munmap(screen_base, screen_size); //取消映射close(fd); //關閉文件exit(EXIT_SUCCESS); //退出進程
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/12154.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/12154.shtml
英文地址,請注明出處:http://en.pswp.cn/web/12154.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

css如何實現邊框模糊的效果

其實并不難&#xff0c;用屬性 filter: blur(數字px); 即可。效果如下&#xff1a; 圖上的圓形內有色彩的漸變&#xff0c;同樣也是用filter: blur(數字px); 實現的&#xff0c;代碼如下&#xff1a;、 <template><div id"root" :style"{}">…

ros鍵盤控制程序teleop_twist_keyboard 鍵值含義及用法

在機器人仿真中&#xff0c; 經常會用到鍵盤控制程序teleop_twist_keyboard 對機器人進行控制。但是對各個鍵值是何種含義&#xff0c; 如何操作并沒有任何資料介紹,初次使用時會不知所措。 通過實踐&#xff0c; 發現各個鍵值的作用如下&#xff1a; u-- 向左前方前進 i-- 直…

RIP動態路由協議詳解

目錄 一&#xff1a;RIP協議的基本信息 二&#xff1a;RIP協議中的更新方式 三&#xff1a;RIP協議中的計時器 定時更新器&#xff08;UPDATE timer&#xff09; 無效定時器&#xff08;invalid Timer&#xff09; 垃圾收集定時器&#xff08;garbage collection timer&a…

第五課,輸入函數、布爾類型、比較運算和if判斷

一&#xff0c;輸入函數input() 與輸出函數print()相對應的&#xff0c;是輸入函數input()&#xff0c;前者是把程序中的數據展示給外界&#xff08;比如電腦屏幕上&#xff09;&#xff0c;而后者是把外界&#xff08;比如鍵盤&#xff09;的數據輸入進程序中 input()函數可…

Verilog代碼bug:一種特殊的組合邏輯環

Verilog代碼bug&#xff1a;一種特殊的組合邏輯環 組合邏輯環&#xff08;Combinational Loop&#xff09;是什么&#xff0c;別的文章已經寫的很多了&#xff0c;本文就不贅述了&#xff0c;本文主要記錄遇到過的一種特殊的邏輯環&#xff1b; 代碼如下所示&#xff1a; mo…

MacApp自動化測試之Automator初體驗

今天我們繼續講Automator的使用。 初體驗 啟動Automator程序&#xff0c;選擇【工作流程】類型。從資源庫區域依次將獲取指定的URL、從網頁中獲得文本、新建文本文件三個操作拖進工作流創建區域。 然后修改內容&#xff0c;將獲取指定的URL操作中的URL替換成https://www.cnb…

for循環 while循環

for循環 for循環格式 for 變量 in 取值列表 #for in &#xffe5; &#xff08;seq 1 10&#xff09; do 命令序列 .......... done 另一種 for &#xff08;&#xff08;變量初始值&#xff1b; 變量范圍&#xff0c; 變量迭代方…

JDK1.8 安裝并配置環境變量

一、Windows 配置 1 安裝文件 jdk-8u401-windows-i586.exe 2 環境變量 JAVA_HOME C:\Program Files (x86)\Java\jdk-1.8 CLASSPATH .;%JAVA_HOME%\lib\tools.jar;%JAVA_HOME%\lib\dt.jar; Path %JAVA_HOME%\bin 說明&#xff1a;Win7/Win8 中 Path 可能需要寫成 ;%JAVA_HO…

C#窗體程序設計筆記:按鈕控件的常用屬性和點擊事件設置

文章目錄 按鈕控件的常用屬性按鈕控件的點擊事件設置 按鈕控件的常用屬性 Text&#xff1a;設置按鈕上顯示的文本內容&#xff1b;Font&#xff1a;設置按鈕上顯示文本所使用的字體&#xff08;包括類型和大小&#xff09;&#xff1b;ForeColor&#xff1a;設置按鈕上顯示的文…

Edge瀏覽器自動翻譯功能按鈕不見了

前言&#xff1a; 平時偶爾會用到Edge的頁面翻譯功能&#xff0c;使用挺方便。突然發現Edge瀏覽器的翻譯功能不見 了。如下圖所示&#xff1a; 解決思路&#xff1a; 1、從網上找各種解決方案也沒有解決&#xff0c;其中有一個說到點右上角的三個點 2、點擊設置…

25_NumPy數組np.round將ndarray舍入為偶數

25_NumPy數組np.round將ndarray舍入為偶數 使用 np.round() 將 NumPy 數組 ndarray 的元素值舍入為任意位數。請注意&#xff0c;0.5 由于舍入到偶數而不是一般舍入而舍入為 0.0。 本文介紹了一般舍入的實現示例。 如何使用 np.round() 基本用法指定要舍入的位數&#xff1a…

30W 寬電壓輸入 AC/DC 導軌式開關電源——TPR/DG-30-XS 系列

TPR/DG-30-XS 系列導軌式開關電源&#xff0c;額定輸出功率為30W&#xff0c;產品輸入范圍&#xff1a;90-264VAC。提供12V、24V輸出&#xff0c;12V輸出時&#xff0c;工作溫度范圍 (-25℃~70℃)具有短路保護&#xff0c;過載保護等功能&#xff0c;并具備高效率&#xff0c;高…

Windows內核--Kernel API簡析(3.1)

如果所有的內核提供的功能&#xff0c;內核提供進程/線程創建和終止&#xff0c;內存分配和釋放&#xff0c;文件操作&#xff0c;網絡功能&#xff0c;驅動程序加載和卸載等功能。這些API將在后面陸續介紹&#xff0c;如下先介紹Kernel提供的基礎API(Kernel自身或Driver使用).…

視頻號小店,一個不用直播就可以變現的項目!創業首選!

大家好&#xff0c;我是電商小V 想要創業或者是想要利用視頻號變現的小伙伴可以說是很多的&#xff0c;因為視頻號這兩年的流量是非常大的&#xff0c;甚至即將超越抖音的流量&#xff0c;因為視頻號背靠騰訊平臺&#xff0c;也是不缺少流量的&#xff0c;并且視頻號的流量是可…

實時“秒回”,像真人一樣語音聊天,GPT-4o模型強到恐怖

今天凌晨OpenAl發布了 GPT-4o&#xff0c;這是一種新的人工智能模式&#xff0c;集合了文本、圖片、視頻、語音的全能模型。 能實時響應用戶的需求&#xff0c;并通過語音來實時回答你&#xff0c;你可以隨時打斷它。還具有視覺能力&#xff0c;能識別物體并根據視覺做出快速的…

6、Qt—Log4Qt使用小記1

開發平臺&#xff1a;Win10 64位 開發環境&#xff1a;Qt Creator 13.0.0 構建環境&#xff1a;Qt 5.15.2 MSVC2019 64位 一、Log4Qt簡介 Log4Qt是使用Trolltech Qt Framework的Apache Software Foundation Log4j包的C 端口。它旨在供開源和商業Qt項目使用。所以 Log4Qt 是Apa…

Java零拷貝技術實戰

文章目錄 引入傳統IO內存映射mmap文件描述符sendFile測試總結 引入 為什么要使用零拷貝技術&#xff1f; 傳統寫入數據需要4次拷貝&#xff0c;如下圖&#xff1a; 傳統IO import java.io.*; import java.net.Socket;public class TranditionIOClient {private static fina…

【機器學習300問】81、什么是動量梯度下降算法?

動量梯度下降算法&#xff08;Momentum&#xff09;是利用指數加權移動平均的思想來實現梯度下降的算法。讓我們先來回顧一下基礎的梯度下降方法以及看看它有哪些不足之處。接著引出動量梯度下降算法&#xff0c;在理解了它的原理后看看它是如何規避之前方法的不足的。 如果不知…

網絡安全ctf比賽_學習資源整理,解題工具、比賽時間、解題思路、實戰靶場、學習路線,推薦收藏!...

對于想學習或者參加CTF比賽的朋友來說&#xff0c;CTF工具、練習靶場必不可少&#xff0c;今天給大家分享自己收藏的CTF資源&#xff0c;希望能對各位有所幫助。 CTF在線工具 首先給大家推薦我自己常用的3個CTF在線工具網站&#xff0c;內容齊全&#xff0c;收藏備用。 1、C…

使用 RyTuneX 增強您的 Windows 10 和 11 體驗 – Rayen Ghanmi 的首選優化器。

&#x1f4dd; 關于 RyTuneX 是使用 WinUI 3 框架構建的尖端優化器&#xff0c;旨在增強 Windows 設備&#x1f680;的性能。 RyTuneX 專為 Windows 10 和 11 打造&#xff0c;使用戶能夠毫不費力地刪除頑固的預裝應用程序并優化系統資源&#x1f6e0;?。 &#x1f680; 功能…