我买的是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;
}