1. 程式人生 > >【Tiny6410 And Linux】—(6.2)—LCD 驅動測試程式(BMP 顯示點陣圖)——程式碼

【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 問題了!