【Tiny6410 And Linux】—(6.2)—LCD 驱动测试程序(BMP 显示位图)——代码

刚才看个小视频,关于华山游客滞留的,哎,真是花钱买罪吃,下回一定得选好旅游地点!

 

少点废话,上一篇文章是关于 LCD 测试程序(BMP 显示位图)的基本原理的介绍,今天就发一下代码吧,由于中间遇到点小问题,我的测试程序总是出现Segmentation Fault这样的错误,上网查了查也没有看到什么好的解决方法,最后还是找的国嵌的源码来对应的,是一个关于指针和传递函数的问题,这里我会在我的代码中指出,说实话,我还是不明白为什么我那样做就不行!

1、测试程序

①、tiny6410_ bmp_lib.h

#ifndef __TINY6410_BMP_LIB_H__
#define __TINY6410_BMP_LIB_H__


#include <string.h>

/* bitmap 格式的位图文件会带有 54 字节的信息头,这些信息是固定不变的,可以通过read 来读取 */

/* 文件信息头(14字节) */
typedef struct {
	char type[2];			/* 文件类型,必须为"BMP" (0X4D42) */
	char size[4];			/* 文件的大小(字节) */
	char reserved[4];		/* 保留,必须为0 */
	char off[4];			/* 位图阵列相对于文件头的偏移量(字节) */
} bmp_file_header_t;

/* 位图信息头(40字节) */
typedef struct {
	char size[4];			/* 说明BITMAPINFOHEADER 结构所需要的字数 */
	char width[4];			/* 位图宽度(像素) */
	char height[4];			/* 位图高度(像素),如果该值是一个正数,说明图像是倒像的,大多数BMP 文件都是倒像的 */
	char planes[2];			/* 目标设备的位平面数,必须置为1 */
	char bitcount[2];		/* 每个像素的位数,1, 4, 8, 16, 24, 32 */
	char compress[4];		/* 位图阵列的压缩方法,0表示不压缩 */
	char img_size[4];		/* 图像大小(字节) */
	char xpel[4];			/* 说明水平分辨率,用 像素/米 表示 */
	char ypel[4];			/* 垂直 */
	char clr_used[4];		/* 位图实际使用的颜色表的颜色数 */
	char clr_important[4];	/* 重要颜色索引的个数 */
} bmp_info_header_t;

/* 这里应用程序可以兼容24 位和32位的位图,其中red,green,blue这三个颜色所占的位置应该倒置 */
typedef struct {
	char blue;
	char green;
	char red;
	char reserved;
} rgb_32_t;

/* 对位图操作进行封装 */
typedef struct {
	int fd;					/* 图像文件描述符 */
	rgb_32_t *curp;			/* 指向当前的像素点 */
	int width;				/* 图像宽度 */
	int height;				/* 图像高度 */
	int bitcount;			/* 图像每个像素的位数 */
	int size;				/* 图像大小 */
	void *data;				/* 图像有效数据指针 */
} bmp_t;

/* 由于开发板帧缓冲在驱动中被设置为16 位数据表示一个像素点(16bpp),这里需要对24 位或者32 位的位图进行转化 */
static short transfer_to_16bit(char red,char green,char blue)
{
	return ((red>>3)<<11) | ((green>>2)<<5) | (blue>>3);
}

/* 获取一个被转化为16 位的像素值 */
static short bmp_get_pixel_16bit(bmp_t *bmp)
{
	return transfer_to_16bit(bmp->curp->red, bmp->curp->green, bmp->curp->blue);
}

/* 字符串变成整形的函数 */
static long char_to_int(char *str)
{
	return *((int *)str);
}

/* 使bmp->curp 指向下一个像素点 */
static void bmp_next_pixel(bmp_t *bmp)
{
    if (24 == bmp->bitcount)
	    bmp->curp = (rgb_32_t*)((int)bmp->curp + 3);
    else if (32 == bmp->bitcount)
        bmp->curp = (rgb_32_t*)((int)bmp->curp + 4);
}

/* 使bmp->curp 指向图像有效数据的初始位置 */
static void bmp_reset_pixel(bmp_t *bmp)
{
	bmp->curp = (rgb_32_t*)bmp->data;
}


extern int bmp_open(bmp_t *bmp, char *bmpn);
extern void bmp_close(bmp_t *bmp);


#endif

②、tiny6410_ bmp_lib.c

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>

#include "tiny6410_bmp_lib.h"

int bmp_open(bmp_t *bmp, char *bmpn)
{
    int ret;
	bmp_file_header_t fhr;
	bmp_info_header_t ihr;

	printf("[Call bmp_open.]\n");
	
	if (-1 == (bmp->fd=open(bmpn, O_RDONLY))) {
        printf("Error: cannot open framebuffer device.\n");
        _exit(EXIT_FAILURE);
    }

//	printf("Open done!\n");
	
	read(bmp->fd, &fhr, sizeof(bmp_file_header_t));					/* 读取文件信息头 */
	read(bmp->fd, &ihr, sizeof(bmp_info_header_t));					/* 读取位图信息头 */

	bmp->width = char_to_int(ihr.width);
	bmp->height = char_to_int(ihr.height);
	bmp->bitcount = char_to_int(ihr.bitcount); 
	bmp->size = (bmp->width * bmp->height * bmp->bitcount) / 8; 
	
	printf("bmp->width = %d\n", bmp->width);
	printf("bmp->height = %d\n", bmp->height);
	printf("bmp->bitcount = %d\n", bmp->bitcount);
	printf("bmp->siz = %d\n", bmp->size);

	bmp->data = malloc(bmp->size);
	ret = read(bmp->fd, bmp->data, bmp->size);						/* 读取实际的图像数据 */
	bmp->curp = (rgb_32_t*)bmp->data;								/* 指向当前图像有效数据,即指向图像的起始数据 */
	
	return 0;
}

void bmp_close(bmp_t *bmp)
{
	close(bmp->fd);
	free(bmp->data);}

 ③、tiny6410_ bmp_app.c

 

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>

#include "tiny6410_bmp_lib.h"

#define FB_DEVICE_NAME "/dev/fb0"


#define RED_COLOR565		0X0F100
#define GREEN_COLOR565		0X007E0
#define BLUE_COLOR565		0X0001F

typedef struct fb_dev	{
	int fd;				/* 帧缓冲设备硬件描述符 */
	void *pfb;			/* 指向帧缓冲映射到用户空间的首地址 */
	int xres;			/* 一帧图像的宽度 */
	int yres;			/* 一帧图像的高度 */
	int size;			/* 一帧图像的大小 */
	int bits_per_pixel;	/* 每个像素的大小 */
} fb_dev_t;

int fb_open(fb_dev_t *fbd, char *fbn)
{
	struct fb_var_screeninfo vinfo;

	if((fbd->fd = open(fbn, O_RDWR)) == -1)	{
		printf("Error: Cannot open framebuffer device.\n");
		_exit(EXIT_FAILURE);
	}

	/* 获取LCD 的可变参数 */
	ioctl(fbd->fd, FBIOGET_VSCREENINFO, &vinfo);

	fbd->xres = vinfo.xres;
	fbd->yres = vinfo.yres;
	fbd->bits_per_pixel = vinfo.bits_per_pixel;

	/* 计算一帧图像的大小 */
	fbd->size = fbd->xres * fbd->yres * fbd->bits_per_pixel / 8;

	printf("%d * %d,%d bits_per_pixel,screensize = %d.\n",fbd->xres,fbd->yres,fbd->bits_per_pixel,fbd->size);

	/* 将帧映射到内存 */
	/* mmap的应用 */
	/* mmap可以把文件内容映射到一段内存中,准确说是虚拟内存,通过对这段内存的读取和修改,实现对文件的读取和修改。 */
	/* addr:指定映射的起始地址,通常为NULL,由系统指定 */
	/* length:将文件的多大长度映射到内存 */
	/* prot:映射区的保护方式,可以是可被执行(PROT_EXEC),可被写入(PROT_WRITE),可被读取(PROT_READ),映射区不能存取(PROT_NONE) */
	/* flags:映射区的特性,对映射区的写入数据会复制回文件,且允许其他映射文件的进城共享(MAP_SHARED),对映射区的写入操作会产生一个映射的复制,对此区域所做的修改不会写会源文件(MAP_PRIVATE) */
	/* fd:由open返回的文件描述符,代表要映射的文件 */
	/* offset:以文件开始出的偏移,必须是分页大小的整数倍,通常为0,表示从头开始映射 */

	/* 注意:在修改映射文件时,只能在原长度上修改,不能增加文件长度,因为内存是已经分配好的 */
	
	fbd->pfb = mmap(NULL, fbd->size, PROT_READ | PROT_WRITE, MAP_SHARED, fbd->fd, 0);

	if((int)fbd->pfb == -1)	{
		printf("Error: Failed to map frambuffer device to memory!\n");
		_exit(EXIT_FAILURE);
	}

	return 0;
}

void fb_close(fb_dev_t *fbd)
{
	/* 解除映射 */
	munmap(fbd->pfb,fbd->size);

	/* 关闭设备文件 */
	close(fbd->fd);
}

int fb_drawrect(fb_dev_t *fbd, int x0, int y0, int w, int h, int color)
{
	int x,y;

	for(y=y0; y<y0+h; y++)	{
		for(x=x0; x<x0+w; x++)	{
			*((short *)(fbd->pfb) + y*fbd->xres +x) = color;
		}
	}

	return 0;
}

/* 用于屏幕显示图片函数 */
int fb_drawbmp(fb_dev_t *fbd, int x0, int y0, char *bmpn)
{
	int x, y, x1, y1;
	bmp_t bmpt;         /* 就是这里,我如果定义一个指针型的变量就会出现我一开始说的问题,当然我传递的时候是个地址,但是还是不行! */
	
	bmp_open(&bmpt, bmpn);

	x1 = x0 + bmpt.width;
	y1 = y0 + bmpt.height;

	for(y=y1; y>y0; y--) {
		for(x=x0; x<x1; x++) {
			if(x1>fbd->xres || y1>fbd->yres) {
				bmp_next_pixel(&bmpt);
				continue;
			}

			*((short *)(fbd->pfb) + y*fbd->xres + x) = bmp_get_pixel_16bit(&bmpt);
			bmp_next_pixel(&bmpt);
		}
	}

	bmp_close(&bmpt);

	return 0;
}

int main(int argc, char **argv)
{
	fb_dev_t *fbd;

	fbd = (fb_dev_t *)malloc(sizeof(fb_dev_t));

	fb_open(fbd, FB_DEVICE_NAME);

	if(fbd->bits_per_pixel == 16)	{
		printf("Red/Green/Blue Screen And a picture!\n");

		fb_drawrect(fbd, 0, 0, fbd->xres, fbd->yres/3, RED_COLOR565);
		fb_drawrect(fbd, 0, fbd->yres/3, fbd->xres, fbd->yres/3, GREEN_COLOR565);
		fb_drawrect(fbd, 0, fbd->yres*2/3, fbd->xres, fbd->yres/3, BLUE_COLOR565);

		
		fb_drawbmp(fbd, 0, 0, argv[1]);
	}

	else	
		printf("16 bits only!");

	fb_close(fbd);

	free((void *)fbd);
	
	return 0;
}


 2、测试结果

 不得不说现在CSDN真心该修理一下 Bug 问题了!

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值