IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> LCD的双缓冲显示原理及示例 -> 正文阅读

[嵌入式]LCD的双缓冲显示原理及示例

概念

系统层专门提供这个函数给应用层开发人员,控制,获取
所有Linux平台下的硬件的功能和信息。 控制设置:写入数据,控制硬件 put,set 获取信息:读取数据,获取硬件信息get
ioctl: 设置和获取,都是需要具体的命令(宏定义)
简单例子: 获取LCD 的简单参数,譬如显存大小,LCD的w和h; man 2 ioctl
#include <sys/ioctl.h> int ioctl(int fd, unsigned long request, …);

返回值: 成功:0 失败:-1
fd:目标文件
request:宏定义 (控制命令)

后面是有n个形参(n>=0),由request决定

获取信息有套路: 一般后面都是存缓存区的首地址

注意: 因为硬件多,获取信息种类多,固对应的宏定义多,存放宏定义的头文件也多 /usr/include/linux/fb.h。

双缓冲显示原理

缓存,缓冲的意思:在你没有显示像素点之前,提前已经把像素点存放到显存里面。
疑问:为什么你把像素点丢进显存,像素点不会显示 ------
(可见区一般势必显存小,LCD是显存的1/3)。 缓存的个数:两个缓存区拿去支持缓存显示。

如何有效的使用双缓冲:常用的双缓存机制,你只要保存你要显示的画面,提前扔进不可见区。

以显示手机图库的例子: 体现把所有图片的名字检索到链表里面。一个结点存放一个图片的名字(图片的名字就是图片的路径)

思路

注意:默认的可见区在第一个房间,1.bmp,2.bmp提前缓存在第2和第3个画面里面。后面循环切换可见区,从第2个画面切换到第3个画面

typedef struct cache_inf
{
	int lcd_fd;
	int * mmap_start;//映射指针
	int mmap_length;//即使显存大小,也是映射空间的大小
	int lcd_w;		//LCD硬件信息:长
	int lcd_h;		//LCD硬件信息:宽
}CI,*P_CI;

实现的编码步骤:

//第一步: 
P_CI Lcd_Cache_Init();
		//LCD初始化
		//打开文件:fb0
		//ioctl获取获取显存大小,在获取LCD的w和h
		//进行LCD映射(需要设置映射空间的大小)

//第二步:
int Caching(P_CI p_ci);
		//进行缓存缓冲

//第三步:
int Caching_Test(P_CI p_ci);
		//切换缓存区

//最后一步:
int Lcd_Free(P_CI p_ci);
		//LCD释放资源

示例

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

#define LCD_DEV_PATH "/dev/fb0"

typedef struct cache_inf
{
	int lcd_fd;
	int * mmap_start;
	int mmap_length;//即使显存大小,也是映射空间的大小
	int lcd_w;
	int lcd_h;
    int bmp_1;
    int bmp_2;
}CI,*P_CI;

P_CI Lcd_Init();
int  Caching(P_CI p_ci);
int Caching_Test(P_CI p_ci);
int Lcd_Free(P_CI p_ci);


P_CI Lcd_Init()
{
    P_CI p_ci = (P_CI)malloc(sizeof(CI));
    
    memset(p_ci,0,sizeof(CI));

    p_ci->lcd_fd = open(LCD_DEV_PATH,O_RDWR);
    if(p_ci->lcd_fd == -1)
    {
        perror("open failed");
        return (P_CI)-1;
    }

    struct fb_var_screeninfo v_inf;
    struct fb_fix_screeninfo f_inf;
    int ioctl_ret_1 = ioctl(p_ci->lcd_fd,FBIOGET_VSCREENINFO,&v_inf);
    int ioctl_ret_2 = ioctl(p_ci->lcd_fd,FBIOGET_FSCREENINFO,&f_inf);
    if(ioctl_ret_1 == -1 || ioctl_ret_2 == -1)
    {
        perror("ioctl failed ");
        return (P_CI)-1;
    }
    else
    {
        printf("获取底层信息成功!\n");
        p_ci->mmap_length = f_inf.smem_len;
        p_ci->lcd_w       = v_inf.xres;
        p_ci->lcd_h       = v_inf.yres;
        printf("显存:%d---显示器宽度:%d---显示器高度:%d\n",
                                                    p_ci->mmap_length,
                                                    p_ci->lcd_w,
                                                    p_ci->lcd_h);
    }

    p_ci->mmap_start = (int *)mmap(NULL,p_ci->mmap_length,PROT_READ | PROT_WRITE,MAP_SHARED,p_ci->lcd_fd,0);
    if(p_ci->mmap_start == MAP_FAILED)
    {
        perror("mmap lcd failed");

        return (P_CI)-1;
    }
    /*把可见区设置到第一个房间,虽然可见区默认是第一个房间*/
    v_inf.xoffset = 0;
    v_inf.yoffset = 0;
    int ioctl_ret_3 = ioctl(p_ci->lcd_fd,FBIOPUT_VSCREENINFO,&v_inf);
    if(ioctl_ret_3 == -1)
    {
        perror("ioctl lcd failed");
        return (P_CI)-1;
    }
    else
    {
        printf("设置LCD可见区位置成功!\n");
    }
    return p_ci;
}


int  Caching(P_CI p_ci)
{
    p_ci->bmp_1 = open("/IOT/001.bmp", O_RDONLY);
    p_ci->bmp_2 = open("/IOT/002.bmp", O_RDONLY);
    lseek(p_ci->bmp_1,54,SEEK_SET);
    lseek(p_ci->bmp_2,54,SEEK_SET);
    char bmp1[p_ci->lcd_w * p_ci->lcd_h * 3];
    char bmp2[p_ci->lcd_w * p_ci->lcd_h * 3];
    read(p_ci->bmp_1, bmp1, p_ci->lcd_w * p_ci->lcd_h * 3);
    read(p_ci->bmp_2, bmp2, p_ci->lcd_w * p_ci->lcd_h * 3);

    int * mmap_tmp_star = p_ci->mmap_start + p_ci->lcd_w*p_ci->lcd_h;//先跳到第二个房间

    for(int y=0,loop_num = 0; y<p_ci->lcd_h; y++)
    {
        for(int x=0; x<p_ci->lcd_w; x++,loop_num+=3)
        {
           // *(mmap_tmp_star + p_ci->lcd_w*y+x) = 1.bmp图片的像素点;
           *(mmap_tmp_star + p_ci->lcd_w*(p_ci->lcd_h - 1 - y)+x) = bmp1[loop_num]<<0|
                                                                    bmp1[loop_num+1]<<8|
                                                                    bmp1[loop_num+2]<<16;
        }
    }

    //跳到第三个房间
    mmap_tmp_star = p_ci->mmap_start + p_ci->lcd_w*p_ci->lcd_h *2;
    
    for(int y=0,loop_num = 0; y<p_ci->lcd_h; y++)
    {
        for(int x=0; x<p_ci->lcd_w; x++,loop_num+=3)
        {
           // *(mmap_tmp_star + p_ci->lcd_w*y+x) = 2.bmp图片的像素点;
           *(mmap_tmp_star + p_ci->lcd_w*(p_ci->lcd_h - 1 - y)+x) = bmp2[loop_num]<<0|
                                                                    bmp2[loop_num+1]<<8|
                                                                    bmp2[loop_num+2]<<16;
        }
    }

    return 0;
}

int Caching_Test(P_CI p_ci)
{
    struct fb_var_screeninfo v_inf;
    memset(&v_inf,0,sizeof(v_inf));
    int ret_1,ret_2;
    while(1)
    {
        //显示第二个房间的图片
        v_inf.xoffset=0;
        v_inf.yoffset=p_ci->lcd_h;
        ret_1 = ioctl(p_ci->lcd_fd,FB_ACTIVATE_NOW,&v_inf);//生效
        ret_2 = ioctl(p_ci->lcd_fd,FBIOPAN_DISPLAY,&v_inf);//重新扫描可见区,把新的可见区的像素点从新扫描显示
        if(ret_1 == -1 || ret_2 == -1)
        {
            perror("ioctl set failed");
            return -1;
        }

        sleep(1);//延时一秒
        //显示第三个房间的图片
        v_inf.xoffset=0;
        v_inf.yoffset=p_ci->lcd_h*2;
        ret_1 = ioctl(p_ci->lcd_fd,FB_ACTIVATE_NOW,&v_inf);//生效
        ret_2 = ioctl(p_ci->lcd_fd,FBIOPAN_DISPLAY,&v_inf);//重新扫描可见区,把新的可见区的像素点从新扫描显示
        if(ret_1 == -1 || ret_2 == -1)
        {
            perror("ioctl set failed");
            return -1;
        }
        sleep(1);//延时一秒
    }

    return 0;
}

int Lcd_Free(P_CI p_ci)
{
    close(p_ci->lcd_fd);
    close(p_ci->bmp_1);
    close(p_ci->bmp_2);
    free(p_ci);
}

int main()
{
    P_CI p_ci = Lcd_Init();
    if(p_ci == (P_CI)-1)
    {
        printf("LCD初始化失败!\n");
        return -1;
    }
    else
    {
        printf("LCD初始化成功!\n");
    }
    P_CI dis = Lcd_Init();
    Caching(dis);
    Caching_Test(dis);
    Lcd_Free(dis);
    return 0;
}

最后实现双缓冲显示bmp1和bmp2两张图片,每隔1s切换一次

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-09-06 11:19:00  更:2021-09-06 11:20:29 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 1:50:01-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码