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");
}