OV7725 内部时钟版本驱动代码例程

知识库
知识库文档
/firmware/传感器/OV7725 内部时钟版本/OV7725 内部时钟版本驱动代码例程.md

文档

OV7725 内部时钟版本驱动代码例程

一、平台说明

  • 主控平台:STM32F407 / OpenMV / ESP32-S3
  • 接口类型:DVP 8位并行
  • SCCB地址:0x42(7位 0x21)
  • 特点:无页寻址,直接寄存器访问

二、SCCB 驱动(无页寻址)

#include "stm32f4xx_hal.h"

// OV7725 SCCB 地址
#define OV7725_I2C_ADDR  0x42  // 7位地址0x21左移1位

I2C_HandleTypeDef hi2c1;

void OV7725_I2C_Init(void)
{
    __HAL_RCC_I2C1_CLK_ENABLE();
    hi2c1.Instance = I2C1;
    hi2c1.Init.ClockSpeed = 100000;
    hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
    hi2c1.Init.OwnAddress1 = 0;
    hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
    HAL_I2C_Init(&hi2c1);
}

// OV7725 寄存器写入(8位地址,无需页切换!)
uint8_t OV7725_WriteReg(uint8_t reg, uint8_t data)
{
    uint8_t buf[2];
    buf[0] = reg;
    buf[1] = data;
    return HAL_I2C_Master_Transmit(&hi2c1, OV7725_I2C_ADDR, buf, 2, 100);
}

uint8_t OV7725_ReadReg(uint8_t reg)
{
    uint8_t data = 0;
    HAL_I2C_Master_Transmit(&hi2c1, OV7725_I2C_ADDR, &reg, 1, 100);
    HAL_I2C_Master_Receive(&hi2c1, OV7725_I2C_ADDR | 0x01, &data, 1, 100);
    return data;
}

三、内部PLL时钟配置

// =============================================
// OV7725 内部PLL配置(VGA 60fps)
// XVCLK=24MHz → PCLK=24MHz (VGA 60fps)
// =============================================
void OV7725_ConfigPLL_Internal(void)
{
    printf("配置 OV7725 内部 PLL...\r\n");

    // COM4: PLL控制
    OV7725_WriteReg(0x0D, 0x41);  // COM4: PLL使能

    // 时钟控制
    OV7725_WriteReg(0x11, 0x01);  // CLKRC: 内部PLL使能, 不分频
    // bit[6]: 保留
    // bit[5]: 直接使用PLL输出
    // bit[4:0]: PCLK分频系数

    // PLL配置寄存器
    OV7725_WriteReg(0x2A, 0x00);  // PLL控制1
    OV7725_WriteReg(0x2B, 0x00);  // PLL控制2

    // PCLK分频: PCLK = SCLK / (CLKRC[4:0]+1)
    // 若SCLK=48MHz, CLKRC=1 → PCLK=24MHz
    OV7725_WriteReg(0x11, 0x01);  // PCLK = SCLK/2

    HAL_Delay(5);  // PLL锁定

    printf("OV7725 PLL配置完成: PCLK≈24MHz\r\n");
}

四、VGA 60fps 高速初始化序列

// =============================================
// OV7725 硬件上电
// =============================================
void OV7725_HardwareInit(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();

    GPIO_InitStruct.Pin = GPIO_PIN_8;   // PWDN
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_0;   // RESET
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);  // PWDN=0
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);  // RESET=0
    HAL_Delay(10);

    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);    // PWDN=1
    HAL_Delay(5);  // 内部PLL需锁定

    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);    // RESET=1
    HAL_Delay(20);
}

// =============================================
// OV7725 VGA 60fps RGB565 初始化
// =============================================
void OV7725_Init_VGA_60fps(void)
{
    printf("OV7725 VGA 60fps 初始化...\r\n");

    // ---- 软件复位 ----
    OV7725_WriteReg(0x12, 0x80);
    HAL_Delay(100);

    // ---- 输出格式: VGA RGB565 ----
    OV7725_WriteReg(0x12, 0x06);  // COM7: VGA分辨率, RGB格式

    // ---- 时钟配置(内部PLL)----
    OV7725_WriteReg(0x11, 0x01);  // CLKRC: PCLK=SCLK/2
    OV7725_WriteReg(0x0D, 0x41);  // COM4: PLL使能

    // ---- 分辨率窗口: VGA 640x480 ----
    OV7725_WriteReg(0x17, 0x21);  // HSTART
    OV7725_WriteReg(0x18, 0xA1);  // HSTOP
    OV7725_WriteReg(0x19, 0x01);  // VSTART
    OV7725_WriteReg(0x1A, 0xE1);  // VSTOP
    OV7725_WriteReg(0x32, 0x21);  // HREF
    OV7725_WriteReg(0x33, 0xA1);  // HREF
    OV7725_WriteReg(0x03, 0x01);  // VREF
    OV7725_WriteReg(0x04, 0xE1);  // VREF

    // ---- 输出窗口 640x480 ----
    OV7725_WriteReg(0x51, 0x02);  // OUTW高
    OV7725_WriteReg(0x52, 0x80);  // OUTW低 → 640
    OV7725_WriteReg(0x53, 0x01);  // OUTH高
    OV7725_WriteReg(0x54, 0xE0);  // OUTH低 → 480

    // ---- 时序 ----
    OV7725_WriteReg(0x55, 0x00);  // HTS
    OV7725_WriteReg(0x56, 0x00);  // HTS
    OV7725_WriteReg(0x57, 0x00);  // VTS

    // ---- 自动控制 ----
    OV7725_WriteReg(0x13, 0x07);  // COM8: AEC/AGC/AWB使能
    OV7725_WriteReg(0x14, 0x08);  // COM9: 增益上限4x
    OV7725_WriteReg(0x22, 0x00);  // AWB控制
    OV7725_WriteReg(0x24, 0x78);  // AGC/AEC稳定
    OV7725_WriteReg(0x25, 0x68);  // AEC目标
    OV7725_WriteReg(0x26, 0xD0);  // AGC增益上限
    OV7725_WriteReg(0x2C, 0x00);  // 亮度

    // ---- 图像质量 ----
    OV7725_WriteReg(0x41, 0x00);  // 锐度
    OV7725_WriteReg(0x4F, 0x80);  // 矩阵系数
    OV7725_WriteReg(0x50, 0x80);  // 矩阵系数
    OV7725_WriteReg(0x51, 0x00);  // 矩阵系数
    OV7725_WriteReg(0x52, 0x22);  // 矩阵系数
    OV7725_WriteReg(0x53, 0x5E);  // 矩阵系数
    OV7725_WriteReg(0x54, 0x80);  // 矩阵系数

    // ---- 高速优化 ----
    OV7725_WriteReg(0x2D, 0x00);  // 高速模式
    OV7725_WriteReg(0x2E, 0x00);  // 高速模式

    // ---- COM3: 输出使能 ----
    OV7725_WriteReg(0x0C, 0x00);  // COM3: 正常输出

    // ---- 最终启动 ----
    OV7725_WriteReg(0x12, 0x06);  // COM7: 启动输出

    printf("OV7725 VGA 60fps 初始化完成\r\n");
}

五、高速采集示例

#define FRAME_WIDTH   640
#define FRAME_HEIGHT  480
#define FRAME_SIZE    (FRAME_WIDTH * FRAME_HEIGHT * 2)

__attribute__((aligned(4))) uint8_t frame_buffer[FRAME_SIZE];
volatile uint8_t frame_ready = 0;

DCMI_HandleTypeDef hdcmi;
DMA_HandleTypeDef hdma_dcmi;

void DCMI_Init(void)
{
    __HAL_RCC_DCMI_CLK_ENABLE();
    __HAL_RCC_DMA2_CLK_ENABLE();

    hdcmi.Instance = DCMI;
    hdcmi.Init.SynchroMode = DCMI_SYNCHRO_HARDWARE;
    hdcmi.Init.PCKPolarity = DCMI_PCKPOLARITY_FALLING;
    hdcmi.Init.VSPolarity = DCMI_VSPOLARITY_LOW;
    hdcmi.Init.HSPolarity = DCMI_HSPOLARITY_LOW;
    hdcmi.Init.CaptureRate = DCMI_CR_ALL_FRAME;
    hdcmi.Init.ExtendedDataMode = DCMI_EXTEND_DATA_8B;
    hdcmi.Init.JPEGMode = DCMI_JPEG_DISABLE;
    HAL_DCMI_Init(&hdcmi);

    hdma_dcmi.Instance = DMA2_Stream1;
    hdma_dcmi.Init.Channel = DMA_CHANNEL_1;
    hdma_dcmi.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_dcmi.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_dcmi.Init.MemInc = DMA_MINC_ENABLE;
    hdma_dcmi.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
    hdma_dcmi.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
    hdma_dcmi.Init.Mode = DMA_CIRCULAR;  // 高速连续采集
    hdma_dcmi.Init.Priority = DMA_PRIORITY_VERY_HIGH;
    HAL_DMA_Init(&hdma_dcmi);
    __HAL_LINKDMA(&hdcmi, DMA_Handle, hdma_dcmi);
}

void HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef *hdcmi)
{
    frame_ready = 1;
}

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    UART_Init();

    printf("=== OV7725 内部时钟版本 VGA 60fps ===\r\n");

    OV7725_I2C_Init();
    OV7725_HardwareInit();
    OV7725_ConfigPLL_Internal();
    OV7725_Init_VGA_60fps();

    DCMI_Init();
    HAL_DCMI_Start_DMA(&hdcmi, DCMI_MODE_CONTINUOUS,
                       (uint32_t)frame_buffer, FRAME_SIZE / 4);

    uint32_t frame_count = 0;
    uint32_t last_tick = HAL_GetTick();

    while (1)
    {
        if (frame_ready)
        {
            frame_ready = 0;
            frame_count++;

            if (HAL_GetTick() - last_tick >= 1000)
            {
                printf("FPS: %lu\r\n", frame_count);
                frame_count = 0;
                last_tick = HAL_GetTick();
            }
        }
    }
}

六、ESP32 平台示例

#include "esp_camera.h"

static camera_config_t camera_config = {
    .pin_pwdn       = 32,
    .pin_reset      = 33,
    .pin_xclk       = 0,         // 24MHz
    .pin_sccb_sda   = 26,
    .pin_sccb_scl   = 27,
    .pin_d7         = 35,
    .pin_d6         = 34,
    .pin_d5         = 39,
    .pin_d4         = 36,
    .pin_d3         = 21,
    .pin_d2         = 19,
    .pin_d1         = 18,
    .pin_d0         = 5,
    .pin_vsync      = 25,
    .pin_href       = 23,
    .pin_pclk       = 22,

    .xclk_freq_hz   = 24000000,
    .ledc_timer     = LEDC_TIMER_0,
    .ledc_channel   = LEDC_CHANNEL_0,

    .pixel_format   = PIXFORMAT_RGB565,
    .frame_size     = FRAMESIZE_VGA,

    .fb_count       = 2,
    .grab_mode      = CAMERA_GRAB_WHEN_EMPTY,
};

void OV7725_ESP32_Init(void)
{
    esp_err_t err = esp_camera_init(&camera_config);
    if (err != ESP_OK) {
        printf("OV7725 init fail: 0x%x\n", err);
        return;
    }

    sensor_t *s = esp_camera_sensor_get();
    s->set_framesize(s, FRAMESIZE_VGA);
    s->set_pixformat(s, PIXFORMAT_RGB565);
    s->set_vflip(s, 0);
    s->set_hmirror(s, 0);
    printf("OV7725 ESP32 就绪, 60fps VGA\n");
}

七、常见问题

问题 解决方案
帧率不到60fps 检查PLL和PCLK分频,确认0x11配置
低照度噪点 OV7725大像素低照度好,检查AGC增益上限
SCCB无应答 检查I2C地址0x42
图像偏暗 调整AEC目标寄存器0x25

信息

路径
/firmware/传感器/OV7725 内部时钟版本/OV7725 内部时钟版本驱动代码例程.md
更新时间
2026/5/26