TQ2440实验板OV9650测试程序的详解

我买的是TQ2440实验板,LCD是480*272。实验板给的测试程序是针对320x240的,下面给出详细注解,并且改成480*272显示。修改后的程序在板子上成功运行。

程序中的注解只是我作为一个初学者的角度来理解的,有什么不对的地方还望指教。

/*
 *   TQ2440 camera test program
 *
 *   preview : 480*272 overlay on 480*272 16bpp LCD
 *  原测试程序针对320x240 屏幕,以下代码我改成480*272
 *
 *   TFT LCD size : 480*272 
*/
#include    //时间类型
#include   //基本系统数据类型
#include  //原系统数据类型
#include     // 文件状态
#include          // 文件控制
#include 
#include     //符号常数
#include 
#include 
#include 
#include   //内存管理声明
#include 

#include 
#include 
#include "videodev.h"
#include "videodev2.h"
#include 

#define PIXFMT_NUM			5
#define INPUT_NUM 			5
#define CTRL_NUM 			100

#define V4L2_DEV_NODE			"/dev/camera"                //OV9650设备文件
#define FB_DEV_NODE			"/dev/fb0"                      //LCD设备文件


//-----------------------

//ioctl cmd arg
#define EMBEDSKY_RGB565 0
#define EMBEDSKY_YUV		1
#define EMBEDSKY_RGB24	2	
#define EMBEDSKY_PREVIEW 3

//cmd,通过ioctl传送

#define	CAMERA_SET_WIDTH	0
#define CAMERA_SET_HEIGHT 1
#define CAMERA_SET_FORMAT 2	
#define CAMERA_SET_CHANNEL	3
#define CAMERA_SET_X	12
#define CAMERA_SET_Y	13

#define CAMERA_GET_WIDTH 4
#define CAMERA_GET_HEIGHT	5
#define CAMERA_GET_FORMAT 6
#define CAMERA_GET_CHANNEL 7
#define CAMERA_GET_MAX_WIDTH 8
#define CAMERA_GET_MAX_HEIGHT 9
#define CAMERA_GET_MAX_CHANNEL 10
#define	CAMERA_GET_VALIDATE_FORMAT 11
#define CAM_IOCTL_CAM_SETGAMMA 14
#define CAM_IOCTL_CAM_STOP 15
#define CAM_IOCTL_CAM_START 16
#define CAM_IOCTL_SET_MAX_WIDTH 17
#define CAM_IOCTL_SET_MAX_HEIGHT 18
#define CAMERA_SET_BRIGHT 20
#define CAMERA_SET_CONTRAST 21
#define CAMERA_SET_SATURATION 22
#define CAMERA_GET_TYPE	25

//ov9650 only
#define CAMERA_SET_RED	23
#define CAMERA_SET_BLUE	24


//#define DISP_Width 640
//#define DISP_Height 480
#define DISP_Width 1280
#define DISP_Height 1024

//-----------------------

//typedef struct v4l2_input    V_INPUT;
//typedef struct v4l2_format   V_FORMAT;
//typedef struct v4l2_fmtdesc  V_FMTDESC;
//typedef struct v4l2_queryctrl V_QRYCTRL;

typedef struct fb_var_screeninfo F_VINFO; // fb_var_screeninfo是一个结构类型,用于Framebuffer设备的可变信息

unsigned int x_lcd_size, y_lcd_size;

int init_cam(int v4l2_fd,unsigned int pix_x,unsigned int pix_y)    //camera初始化函剩,使用ioctl函数发送命令给摄像头驱动
{
	int i;
	
	ioctl(v4l2_fd,CAMERA_SET_WIDTH,pix_x);
	ioctl(v4l2_fd,CAMERA_SET_HEIGHT,pix_y);
	ioctl(v4l2_fd,CAMERA_SET_FORMAT,EMBEDSKY_PREVIEW);
	ioctl(v4l2_fd,CAMERA_SET_X,0);
	ioctl(v4l2_fd,CAMERA_SET_Y,0);

	ioctl(v4l2_fd,CAM_IOCTL_CAM_STOP,0);	
	ioctl(v4l2_fd,CAM_IOCTL_SET_MAX_WIDTH,pix_x);
	ioctl(v4l2_fd,CAM_IOCTL_SET_MAX_HEIGHT,pix_y);

	ioctl(v4l2_fd,CAMERA_SET_BRIGHT,0x80);

	printf("camera type :%d ov9650==%d,saa7113==%d\n",i=ioctl(v4l2_fd,CAMERA_GET_TYPE,0),0,1);
	if(i==0)
	{
		ioctl(v4l2_fd,CAMERA_SET_RED,0x40);
		ioctl(v4l2_fd,CAMERA_SET_BLUE,0x40);	
	}
	else if(i==1)
	{
		ioctl(v4l2_fd,CAMERA_SET_CONTRAST,0x40);
		ioctl(v4l2_fd,CAMERA_SET_SATURATION,0x40);
	}
	
	return 0;
}

static void v4l2_show_on_fb(int fd, char *fbmem, int frames)        //LCD显示函数
{
	int i;
	int ret;
	char preview_buf[272*480*2];
	
	init_cam(fd,480,272);                                 //初始化OV9650
	ioctl(fd,CAM_IOCTL_CAM_START,0);
	while(1) {                                                      //此处While循环实现连续显示
			if ((ret = read (fd, &preview_buf, 272*480*2)) < 0) {         //读一帧数据
				perror("read");
				return;
			}
	#if 1			//for 320*240,640*480,800*480
			{
			int y;
			for (y = 0; y < 272; y++) 
				memcpy(fbmem + x_lcd_size*2*y, preview_buf + 480*2*y, 272*2);     /*把preview_buf + 320*2*y开始的20*2字节复制到fbmem + x_lcd_size*2*y */
			}                                                                                                                  
	#else			//for 272*480
			memcpy(fbmem, &preview_buf, 272*480*2);
	#endif
			fflush(stdout);
	}
	
	printf("\n");
}

static unsigned int fb_grab(int fd, char **fbmem)   //完成LCD的内存映射,并且映射后地址赋给fbmem
{
	F_VINFO modeinfo;       //定义一个fb_var_screeninfo结构
	unsigned int length;

	if (ioctl(fd, FBIOGET_VSCREENINFO, &modeinfo) < 0) {                     //改变LCD的显示参数
		perror("FBIOGET_VSCREENINFO");
		exit (EXIT_FAILURE);
	}
	length = modeinfo.xres * modeinfo.yres * (modeinfo.bits_per_pixel >> 3);

	x_lcd_size=modeinfo.xres;             //width of tft lcd
	y_lcd_size=modeinfo.yres;             //height of tft lcd

	printf("fb memory info=xres (%d) x yres (%d), %d bpp\n",
			modeinfo.xres, modeinfo.yres, modeinfo.bits_per_pixel);

	*fbmem = mmap(0, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);   //将LCD的设备文件映射进内存
	if (*fbmem < 0) {
		perror("mmap()");
		length = 0;
	}

	return length;     //注意此处返回length
} 

static void fb_ungrab(char **fbmem, unsigned int length)
{
	if (*fbmem)
		munmap(*fbmem, length);   //解除内存映射,解除fbmem指向的长度为length的内存
}


int main(int argc, char *argv[])
{
	int v4l2_fd = -1; //摄像头文件描述符
	int fb_fd = -1;    //LCD文件描述符
	char *fbmem = NULL;
	unsigned int fb_length = 0;  //LCD内存空间长度

	int preview_frames = 180;  //预览帧
	int tmp;                            //控制台输入参数

	printf("TQ2440 Camera Test Program, Start !\n");    //输出字符
	if (argc > 1) {                 //假如输入参数大于1,则第二个参数是显示帧数
		if (sscanf(argv[1], "%d", &tmp) == 1)  //读取运行程序是控制台输入参数
			preview_frames = tmp;
	}

	v4l2_fd = open(V4L2_DEV_NODE, O_RDWR);     //打开设备文件"/dev/camera",返回的是文件描述符
	if (v4l2_fd < 0) {          //读取失败,输出错误
		perror(V4L2_DEV_NODE);
		goto out;
	}

	fb_fd = open(FB_DEV_NODE, O_RDWR);         //打开设备文件"/dev/fb0"
	if (fb_fd < 0) {             //读取失败,输出错误
		perror(FB_DEV_NODE);
		goto out;
	}
	
	fflush(stdout);                                                //清空缓冲区
	if ((fb_length = fb_grab(fb_fd, &fbmem)) == 0)         //得到LCD的内存长度fb_length 
		goto out;
	memset(fbmem, 0, fb_length);        //把fbmem指向的长度为fb_length的内存全部初始化为0             

	printf("Press Ctrl+C to stop !\n");
	fflush(stdout);                                                  //清空缓冲区

	v4l2_show_on_fb(v4l2_fd, fbmem, preview_frames);    //显示
	
	printf("\n");

out:    //异常处理

	if (v4l2_fd > 0)          //若摄像头已经打开,则关闭摄像头
		close(v4l2_fd);

	fb_ungrab(&fbmem, fb_length);           //

	return 0;
}


 

你可能感兴趣的:(linux,单片机,OV9650)