概念
系统层专门提供这个函数给应用层开发人员,控制,获取 所有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;
int lcd_h;
}CI,*P_CI;
实现的编码步骤:
P_CI Lcd_Cache_Init();
int Caching(P_CI p_ci);
int Caching_Test(P_CI p_ci);
int Lcd_Free(P_CI p_ci);
示例
#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*(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*(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切换一次
|