我买的是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 <sys/time.h> //时间类型 #include <sys/types.h> //基本系统数据类型 #include <asm/types.h> //原系统数据类型 #include <sys/stat.h> // 文件状态 #include <fcntl.h> // 文件控制 #include <sys/ioctl.h> #include <unistd.h> //符号常数 #include <stdlib.h> #include <stdio.h> #include <string.h> #include <sys/mman.h> //内存管理声明 #include <errno.h> #include <linux/fs.h> #include <linux/kernel.h> #include "videodev.h" #include "videodev2.h" #include <linux/fb.h> #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; }