ov5640摄像头,头文件
#ifndef OV5640_H
#define OV5640_H
#include <stdint.h>
#include <stdbool.h>
/* Camera image resolution */
#define CAMERA_WIDTH 640
#define CAMERA_HEIGHT 480
/**
* Initialize the OV5640 camera via V4L2.
* @param device The V4L2 device path (e.g., "/dev/video1").
* @return 0 on success, -1 on failure.
*/
int ov5640_init(const char * device);
/**
* Capture a frame from the camera.
* @param buf Pointer to the buffer where the frame data will be stored.
* The buffer must be at least CAMERA_WIDTH * CAMERA_HEIGHT * 2 bytes (for RGB565).
* @return 0 on success, -1 on failure.
*/
int ov5640_capture_frame(void * buf);
/**
* Deinitialize the camera.
*/
void ov5640_uninit(void);
#endif /* OV5640_H */
ov5640摄像头,c文件
#include "ov5640.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <linux/videodev2.h>
#include <errno.h>
#define BUFFER_COUNT 4
struct buffer {
void *start;
size_t length;
};
static int cam_fd = -1;
static struct buffer *buffers = NULL;
static unsigned int n_buffers = 0;
int ov5640_init(const char *device) {
struct v4l2_capability cap;
struct v4l2_format fmt;
struct v4l2_requestbuffers req;
struct v4l2_buffer buf;
unsigned int i;
/* 1. Open device */
cam_fd = open(device, O_RDWR);
if (cam_fd == -1) {
perror("Opening video device");
return -1;
}
/* 2. Check capability */
if (ioctl(cam_fd, VIDIOC_QUERYCAP, &cap) == -1) {
perror("Querying Capabilities");
goto error;
}
if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
fprintf(stderr, "%s is no video capture device\n", device);
goto error;
}
/* 3. Set format (RGB565) */
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = CAMERA_WIDTH;
fmt.fmt.pix.height = CAMERA_HEIGHT;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB565; // LVGL native format
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
if (ioctl(cam_fd, VIDIOC_S_FMT, &fmt) == -1) {
perror("Setting Pixel Format");
goto error;
}
/* 4. Request buffers */
memset(&req, 0, sizeof(req));
req.count = BUFFER_COUNT;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
if (ioctl(cam_fd, VIDIOC_REQBUFS, &req) == -1) {
perror("Requesting Buffers");
goto error;
}
/* 5. Map buffers */
buffers = calloc(req.count, sizeof(*buffers));
for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = n_buffers;
if (ioctl(cam_fd, VIDIOC_QUERYBUF, &buf) == -1) {
perror("Querying Buffer");
goto error;
}
buffers[n_buffers].length = buf.length;
buffers[n_buffers].start = mmap(NULL, buf.length,
PROT_READ | PROT_WRITE, MAP_SHARED,
cam_fd, buf.m.offset);
if (buffers[n_buffers].start == MAP_FAILED) {
perror("mmap");
goto error;
}
}
/* 6. Queue buffers */
for (i = 0; i < n_buffers; ++i) {
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
if (ioctl(cam_fd, VIDIOC_QBUF, &buf) == -1) {
perror("Queueing Buffer");
goto error;
}
}
/* 7. Start streaming */
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl(cam_fd, VIDIOC_STREAMON, &type) == -1) {
perror("Starting Streaming");
goto error;
}
return 0;
error:
ov5640_uninit();
return -1;
}
int ov5640_capture_frame(void *dest_buf) {
struct v4l2_buffer buf;
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
/* 1. Dequeue buffer */
if (ioctl(cam_fd, VIDIOC_DQBUF, &buf) == -1) {
if (errno == EAGAIN) return 0; // No frame yet
perror("Dequeueing Buffer");
return -1;
}
/* 2. Copy data to user buffer (assuming it's RGB565) */
memcpy(dest_buf, buffers[buf.index].start, CAMERA_WIDTH * CAMERA_HEIGHT * 2);
/* 3. Re-queue buffer */
if (ioctl(cam_fd, VIDIOC_QBUF, &buf) == -1) {
perror("Re-queueing Buffer");
return -1;
}
return 0;
}
void ov5640_uninit(void) {
if (cam_fd != -1) {
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl(cam_fd, VIDIOC_STREAMOFF, &type);
for (unsigned int i = 0; i < n_buffers; ++i)
munmap(buffers[i].start, buffers[i].length);
free(buffers);
close(cam_fd);
cam_fd = -1;
}
}
lvgl调用摄像头
static void camera_timer_cb(lv_timer_t * timer)
{
lv_obj_t * canvas = (lv_obj_t *)timer->user_data;
void * buf = lv_canvas_get_img(canvas)->data;
ov5640_capture_frame(buf);
lv_obj_invalidate(canvas);
}
if (ov5640_init("/dev/video1") == 0) {
/* Create a canvas for camera display */
static lv_color_t cbuf[CAMERA_WIDTH * CAMERA_HEIGHT];
lv_obj_t * canvas = lv_canvas_create(lv_scr_act());
lv_canvas_set_buffer(canvas, cbuf, CAMERA_WIDTH, CAMERA_HEIGHT, LV_IMG_CF_TRUE_COLOR);
lv_obj_center(canvas);
lv_obj_set_style_border_width(canvas, 2, 0);
lv_obj_set_style_border_color(canvas, lv_palette_main(LV_PALETTE_RED), 0);
/* Create a timer to update the camera feed */
lv_timer_create(camera_timer_cb, 50, canvas); // 20 FPS
} else {
printf("Failed to initialize camera /dev/video1\n");
}