基于STM32F407与OV2640摄像头模块实现图像采集并存储到SD卡

一、软件实现流程

1.1 硬件初始化(HAL库)

// I2C初始化(OV2640配置)
void MX_I2C1_Init(void)
{
    hi2c1.Instance = I2C1;
    hi2c1.Init.ClockSpeed = 400000;  // 400kHz
    hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
    HAL_I2C_Init(&hi2c1);
}

// DCMI初始化
void MX_DCMI_Init(void)
{
    DCMI_HandleTypeDef hdcmi;
    
    hdcmi.Instance = DCMI;
    hdcmi.Init.CaptureMode = DCMI_CaptureMode_Continuous;
    hdcmi.Init.SynchroMode = DCMI_SynchroMode_Hardware;
    hdcmi.Init.PCKPolarity = DCMI_PCKPolarity_Rising;
    hdcmi.Init.VSPolarity = DCMI_VSPolarity_Low;
    hdcmi.Init.HSPolarity = DCMI_HSPolarity_Low;
    HAL_DCMI_Init(&hdcmi);
}

// SDIO初始化
void MX_SDIO_Init(void)
{
    SD_HandleTypeDef hsd;
    
    hsd.Instance = SDIO;
    hsd.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;
    hsd.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE;
    hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE;
    hsd.Init.BusWide = SDIO_BUS_WIDE_4B;
    HAL_SD_Init(&hsd);
}

1.2 OV2640驱动代码

// OV2640复位
void OV2640_Reset(void)
{
    HAL_I2C_Mem_Write(&hi2c1, 0x21<<1, 0x12, I2C_MEMADD_SIZE_8BIT, (uint8_t*)0x80, 1, 100);
    HAL_Delay(100);
}

// 设置JPEG模式
void OV2640_JPEGConfig(void)
{
    uint8_t config[] = {
        0x12, 0x80,  // 软复位
        0x17, 0x20,  // 设置时钟分频
        0x30, 0x60,  // 调整时钟频率
        0x12, 0x04,  // 启用JPEG模式
        0x70, 0xA0   // 设置JPEG质量
    };
    HAL_I2C_Master_Transmit(&hi2c1, 0x21<<1, config, sizeof(config), 100);
}

// DCMI DMA传输回调
void HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef *hdcmi)
{
    uint32_t *buffer = (uint32_t*)0x20001000;  // 1MB DMA缓冲区
    HAL_DCMI_Stop_DMA(hdcmi);
    
    // 保存到SD卡
    FRESULT res = f_open(&sdFile, "IMG_001.jpg", FA_CREATE_ALWAYS | FA_WRITE);
    if(res == FR_OK) {
        UINT bytes_written;
        f_write(&sdFile, buffer, 1024 * 33, &bytes_written);  // 320x240 JPEG约65KB
        f_close(&sdFile);
    }
}

1.3 SD卡文件系统

// FATFS初始化
FRESULT SD_Init(void)
{
    FRESULT res;
    res = f_mount(&SDFatFS, "", 1);  // 挂载SD卡
    if(res != FR_OK) return res;
    
    // 创建文件
    res = f_open(&sdFile, "IMG_001.jpg", FA_CREATE_ALWAYS | FA_WRITE);
    return res;
}

// JPEG数据写入
void Save_JPEG(uint8_t *data, uint32_t size)
{
    UINT bytes_written;
    f_write(&sdFile, data, size, &bytes_written);
}

二、主程序流程

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    
    MX_I2C1_Init();
    MX_DCMI_Init();
    MX_SDIO_Init();
    MX_FATFS_Init();
    
    // 初始化摄像头
    OV2640_Reset();
    OV2640_JPEGConfig();
    
    // 启动DMA传输
    HAL_DCMI_Start_DMA(&hdcmiHandle, DCMI_MODE_SNAPSHOT, (uint32_t)DMA_Buffer, 1024);
    
    while(1)
    {
        if(FrameReadyFlag) {
            FrameReadyFlag = 0;
            Save_JPEG(DMA_Buffer, 1024 * 33);  // 320x240 JPEG
        }
    }
}

三、关键参数配置

参数 配置值 说明
DCMI时钟 24MHz 通过外部晶振提供
JPEG分辨率 320x240 设置寄存器0x5A=0x91
DMA缓冲区 1MB 位于内部SRAM
SD卡文件系统 FAT32 兼容性最佳
JPEG压缩质量 80% 寄存器0x70=0xA0

四、性能优化方案

  1. 双缓冲机制

    volatile uint8_t *dma_buffer[2] = {0x20001000, 0x20002000};
    volatile uint8_t buffer_index = 0;
    
    void HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef *hdcmi)
    {
        buffer_index ^= 1;
        HAL_DCMI_Stop_DMA(hdcmi);
        HAL_DCMI_Start_DMA(hdcmi, DCMI_MODE_SNAPSHOT, (uint32_t)dma_buffer[buffer_index], 1024);
    }
    
  2. SD卡写入优化

    #define SD_BLOCK_SIZE 512
    void Write_SD_Block(uint32_t addr, uint8_t *data)
    {
        HAL_SD_WriteBlocks(&hsd, data, addr, SD_BLOCK_SIZE, 1000);
    }
    
  3. DMA配置

    static DMA_HandleTypeDef hdma_dcmi_rx;
    
    void MX_DMA_Init(void)
    {
        __HAL_RCC_DMA2_CLK_ENABLE();
        
        hdma_dcmi_rx.Instance = DMA2_Stream1;
        hdma_dcmi_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
        hdma_dcmi_rx.Init.PeriphInc = DMA_PINC_DISABLE;
        hdma_dcmi_rx.Init.MemInc = DMA_MINC_ENABLE;
        hdma_dcmi_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
        hdma_dcmi_rx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
        HAL_DMA_Init(&hdma_dcmi_rx);
        __HAL_LINKDMA(&hdcmiHandle, hdmarx, hdma_dcmi_rx);
    }
    

五、调试与验证

  1. 逻辑分析仪检查时序

    • 验证PCLK频率是否稳定在24MHz
    • 检查VSYNC/HREF信号与数据对齐
  2. SD卡测试命令

    # 查看文件大小
    ls -l IMG_001.jpg
    # 查看文件内容
    hexdump -C IMG_001.jpg | head -n 32
    
  3. 典型问题解决

    问题现象 解决方法
    无图像数据 检查DCMI_CROPCmd是否启用
    JPEG文件损坏 验证文件头是否包含0xFFD8和0xFFD9
    SD卡写入失败 检查FATFS挂载状态和文件权限

六、扩展功能实现

  1. 实时预览(通过SPI屏幕)

    void Display_JPEG(uint8_t *data)
    {
        // 使用ST7735驱动显示JPEG缩略图
        SPI_SendCommand(0x11);  // 退出睡眠
        SPI_SendData(data, 1024);
    }
    
  2. 无线传输(ESP8266模块)

    #include "esp8266.h"
    
    void Send_Image()
    {
        char cmd[64];
        sprintf(cmd, "AT+CIPSEND=%d\r\n", jpeg_size);
        ESP8266_Send(cmd);
        ESP8266_Transmit(jpeg_data, jpeg_size);
    }
    

七、完整工程资源

  1. STM32CubeMX配置
    • 启用DCMI、I2C1、SDIO外设
    • 配置DMA2_Stream1用于DCMI
    • 设置系统时钟为168MHz
  2. 参考代码库
    • OV2640驱动:ov2640.c/h
    • SD卡操作:sdio_sdcard.c/h
    • 代码 : stm32f407使用OV2640摄像头进行拍照存储到sd卡中 www.youwenfan.com/contentcnl/57192.html
    • JPEG处理:jpeg_encoder.c/h
posted @ 2025-11-10 11:48  chen_yig  阅读(44)  评论(0)    收藏  举报