ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

STM32F4+OV2640+DCMI+DMA摄像头采集实战与避坑指南

STM32F4+OV2640+DCMI+DMA摄像头采集实战与避坑指南 做嵌入式这几年STM32F4 OV2640 DCMI DMA这套组合我前前后后折腾过好几轮从最早对着寄存器手册硬啃到后来用 CubeMX 一把梭踩过的坑能堆满一抽屉。说句实在话OV2640 这颗传感器虽然老但它的灵活性和可玩性至今没落伍尤其是配合 STM32F4 内置的 DCMI 接口做图像采集、简易机器视觉、视频传输绰绰有余。这次我把整套配置流程完整走一遍从硬件接线、CubeMX 配置、DMA 搬运逻辑到常见翻车现场全部摊开来讲希望能帮你少走点弯路。这篇文章适合刚接触摄像头采集的嵌入式爱好者也适合项目里临时要加图像功能的工程师。我会尽量直白地讲清楚“为什么这么配”“DMA 到底在忙什么”而不是单纯丢一堆寄存器操作让你抄。1. 整体设计思路与核心机制拆解1.1 为什么是 OV2640 STM32F4 这套组合市面上常见的小尺寸摄像头传感器无非就那几颗OV7670、OV2640、GC0308再高端点就是 OV5640、MT9V034 这种。OV7670 虽然便宜、资料多但输出分辨率最高也就 VGA640x480而且对时序要求比较敏感布线一乱图像就花。OV5640 性能和分辨率都强但寄存器配置复杂对 FIFO 和时序要求也高新手容易懵。OV2640 卡在中间这个位置其实最舒服支持 200 万像素UXGA1600x1200但实际常用 VGA、QVGA 分辨率输出格式支持 JPEG 压缩和 RGB565、YUV422 等原始格式。这意味着它既能玩“裸数据 图像处理”也能出“JPEG 直接存 SD 卡或者通过串口传给上位机显示”。STM32F4 这边内置 DCMIDigital Camera Interface外设专门用来接收并行摄像头数据配合 DMA 可以做到不占 CPU 核心时间地把图像数据搬到内存里。F4 的主频一般是 168MHz 或 180MHz处理 VGA 分辨率的 RGB565 数据流带宽完全够用。1.2 DCMI 与 DMA 是怎么协同工作的很多人第一次看 DCMI 会觉得绕其实是没把它的工作流理清楚。DCMI 本质上就是一个并行数据接收器它从摄像头模块拿到 PCLK像素时钟、HSYNC行同步、VSYNC帧同步以及 D0-D78 位像素数据然后在它的内部时钟驱动下把像素数据拼成 32 位一个字再往内存搬。这里有个关键点DCMI 本身不带存储功能它收到的数据必须实时搬走否则下一笔数据一来就把上一笔覆盖了。所以 DMA 在这里不是“优化手段”而是“必需品”。DCMI 每凑够一个字就会向 DMA 发一个请求DMA 响应请求把这个字搬到指定的内存地址然后 DCMI 继续收下一个字。这个流程完全不需要 CPU 介入CPU 只在 DMA 搬运完一整帧后收到一个中断。我把这个过程用一个不太严谨但好理解的类比说明一下。DCMI 就像一个高速流水线上的分拣员摄像头是上游供货商不断把零件像素递过来分拣员飞快地把零件装进箱子32 位寄存器每装满一箱就按铃通知 DMA 这个搬运工来搬走。DMA 只负责搬不负责数箱子等这一整批货一帧图像搬完DMA 才举手报告“老板这批货搬完了”这时候 CPU 才过来处理。1.3 传输模式的选择对图像完整性的影响DMA 在 DCMI 场景下有两种常见模式单次模式和循环模式。我刚开始做的时候选的循环模式想着省事不用每帧重新启动 DMA。但循环模式有个隐患如果你处理图像数据的时间超过了下一帧到来的时间DMA 会把新数据覆盖到老数据上而你 CPU 还在读老数据图像就会撕裂、花屏。后来我改成单次模式每次 DMA 传输完成中断里重新配置 DMA虽然多了几步操作但每一帧数据都是完整的稳得很。对于图像采集来说“完整”远比“连续”重要除非你在做实时视频流且每一帧的处理时间能够严格控制在帧间隔以内那可以考虑循环模式否则我建议用单次模式。提示如果你确实需要连续采集并且对实时性要求很高可以考虑 DMA 双缓冲也叫乒乓缓冲让 DMA 在两个内存区域之间轮流搬运CPU 处理一块的同时 DMA 往另一块写。F4 系列多数型号支持这种模式但这篇文章先以最常见的中断方式展开双缓冲我放到后面单独讲。2. 项目准备与 CubeMX 配置全流程2.1 硬件接线与模块选型注意事项我手头用的 OV2640 模块是常见的带 FIFO 的版本也有不带 FIFO 的裸感光芯片模块两者接线略有不同。带 FIFO 的模块内部集成了 AL422B 存储芯片摄像头先把数据写入 FIFO再通过 FIFO 往外面传好处是时序要求低、不容易花屏坏处是实时性差不适合视频流。不带 FIFO 的模块直接引出 D0-D7、PCLK、HSYNC、VSYNC 等信号时序要求严格但配合 STM32F4 的 DCMI 是官方推荐做法。接线建议如下以 STM32F4 系列 不带 FIFO 的 OV2640 模块为例OV2640 引脚STM32F4 引脚以 F407VET6 为例说明D0-D7PC6-PC11PB8-PB9DCMI 数据线复用功能 AF13PCLKPA6像素时钟输入复用 AF13HSYNCPA4行同步信号复用 AF13VSYNCPB7帧同步信号复用 AF13SCCB_SCLSIOCPB6时钟线复用 I2C1或者用 GPIO 模拟时序SCCB_SDASIODPB9此处注意可能与 D7 冲突数据线同样可以复用 I2C 或 GPIO 模拟XCLKPA8给摄像头提供主时钟一般用定时器或 MCO 输出 24MHzRESET任意 GPIO 或悬空低电平复位模块上一般有上拉PWDN任意 GPIO 或接地高电平休眠正常工作时接地3.3V / GND3.3V / GND注意供电电流模块最好单独供电需要特别注意的是STM32F407VET6 的 DCMI 引脚中D7 复用在 PB8 或 PB9而 SCCB 的 SDA 很多模块默认接到 PB9这就冲突了。我踩过这个坑最后改成用软件模拟 SCCB 时序才同时保住了 D7 和 SDA。如果你用的是其他型号或封装建议先查数据手册确认引脚复用别一上来就照抄网上的接线图。2.2 CubeMX 中 DCMI、DMA、定时器的配置步骤打开 CubeMX先选好单片机型号然后按下面步骤配置。第一步配置时钟树。摄像头的 XCLK 一般推荐 24MHz单片机主频 168MHz 的情况下可以让 APB2 定时器时钟为 84MHz然后用定时器输出 24MHz 的 PWM 波形或者用 MCOPA8输出 24MHz 信号。我习惯用 TIM1 的通道 1通过 PWM 模式产生 24MHz 方波。在 CubeMX 里把 PA8 复用为 TIM1_CH1把定时器时钟源设为内部时钟Prescaler 设为 0Counter Period 算一下84MHz / 24MHz 3.5这个除不尽所以我配置为 84MHz / 3 28MHz再用 PWM 模式设置占空比 50%凑合能用实际上 OV2640 对 XCLK 频率不苛刻20~26MHz 都能工作。后来我嫌麻烦直接用 MCO 输出 24MHzPA8 旁路接过去就行省一个定时器但 CubeMX 里要勾选 MCO2 并选 HSE 分频。第二步配置 DCMI。在 Categories 里选 Multimedia → DCMI勾选 Enable然后设置像素时钟极性PCLK Polarity建议先选 Rising Edge后面不行再试 Falling Edge水平同步极性HSYNC PolarityActive Low垂直同步极性VSYNC PolarityActive Low像素时钟分频看情况一般先用除以 2因为 OV2640 输出 PCLK 可能在 24MHz 左右F4 的 DCMI 最大时钟是 27MHz必须分频否则采样不稳。数据格式8-bit 模式这里补充个“为什么分频”的关键点。DCMI 内部工作的上限时钟依赖芯片型号F407 是 27MHzOV2640 在 UXGA 模式下的 PCLK 通常会超过这个值所以硬件上必须接一个时钟分频器。CubeMX 里这个分频选项分的是对外部 PCLK 的预分频选 /2 可以有效留出时序裕量。第三步配置 DMA。在 DCMI 配置页里滚动到 DMA Settings点击 Add选择 DCMI 对应的 DMA 流Stream 1 或 Stream 0 要看具体型号F407 上是 DMA2 Stream 1。模式选 Circular 或 Normal这里我建议先用 Circular后续在代码里按需改 Normal。数据宽度 Peripheral 和 Memory 都选 Word32 位DCMI 一次产生一个字。第四步配置中断。在 NVIC Settings 里使能 DCMI 全局中断和 DMA 中断。很多人会把这两个搞混DCMI 中断用于帧同步和错误标志DMA 中断用于传输完成。如果不用 DMA 中断而是靠 DCMI 中断去读数据那 DMA 就白配了。第五步配置 SCCB。OV2640 的寄存器配置通过 SCCB 协议完成类似 I2C。CubeMX 里可以复用 I2C1 外设但要注意引脚冲突。如果冲突或者你想减少外设开销可以用 GPIO 模拟时序代码网上很多我后面也会提关键点。2.3 初始化代码的关键细节CubeMX 生成的初始化代码基本能跑但有几个地方必须手动补。一是 XCLK 使能。如果用的是 MCO2 输出调用HAL_RCC_MCOConfig(RCC_MCO2, RCC_MCO2SOURCE_HSE, RCC_MCODIV_3);这行代码必须放在摄像头初始化之前。如果用的是定时器 PWM记得调用HAL_TIM_PWM_Start(htim1, TIM_CHANNEL_1);。我遇到过两次芯片上电后摄像头完全无输出检查半天发现就是忘了启动 XCLK 信号。二是 OV2640 寄存器初始化。CubeMX 只配置了 MCU 外设摄像头寄存器需要单独写。这一步最坑的是 OV2640 的寄存器初始化序列特别长差不多一百多个字节网上流传的初始化数组五花八门有专门针对 JPEG 模式的有专门针对 RGB565 的混着用很容易翻车。我建议的做法是先从官方 datasheet 抄一份标准初始化序列然后按应用场景修改几个关键寄存器。比如要出 JPEG 格式就得写寄存器 0xDA0x08、0xD70x03、0xE00x00等要出 RGB565就得写 0xDA0x0F、0xD70x23、0xE00x04。这些寄存器的含义如果不清楚对照 datasheet 文档查别瞎试。三是初始化顺序。必须先给 OV2640 供电、提供 XCLK等待稳定后再通过 SCCB 写寄存器。复位引脚拉低 10ms 再拉高等待 20ms 以上否则寄存器写入可能失败。我习惯在摄像头初始化函数开头加一个延时 100ms。3. 采集一帧图像的核心实现与调试方法3.1 JPEG 模式还是 RGB565 模式这个选择会直接影响 DMA 配置和后续处理流程。JPEG 模式下OV2640 内置压缩引擎输出压缩后的码流DCMI 收到的数据大小不固定你需要根据帧中断和 DMA 传输计数判断一帧有多长。RGB565 模式下一帧大小是固定的宽 x 高 x 2 字节比如 320x240 就是一帧 153600 字节DMA 搬运数量可以直接算出来。我的经验是如果只是拍照存图、串口传图JPEG 模式最省事数据量小传输快如果要做图像处理颜色识别、边缘检测、灰度变换必须用 RGB565 或 YUV422因为这些算法需要逐像素运算JPEG 压缩后没法直接处理。JPEG 模式下还有一个隐患有些 OV2640 的初始化序列默认输出带 JPEG 头0xFF 0xD8和尾0xFF 0xD9你需要在软件里判断起始和结束否则会串帧。我在第一次做 JPEG 采集时在 PC 端打开图片老是提示文件损坏排查半天发现在一帧数据的开头和结尾混进了其他帧的碎片原因是 DMA 传输完成中断处理不及时老数据没读完新数据就来了。后来加了帧起始检测问题才解决。3.2 帧采集逻辑双缓冲与中断的配合我目前用的采集方案是这样的定义两个帧缓冲区frame_buffer_a和frame_buffer_b各自大小按一帧数据量分配。初始化时先让 DMA 指向 buffer_a采集过程中在 DMA 传输完成中断里切换指针到 buffer_b并把 buffer_a 标记为“有数据待处理”。主循环检测到“有数据”标志后处理图像处理完再交还 buffer_a 给 DMA 使用。这本质就是乒乓缓冲。好处是 DMA 搬运和 CPU 处理并行不会互相等。坏处是逻辑稍微复杂一点尤其要处理好“DMA 正在往哪里写”的状态管理不能出现 CPU 在改 buffer_a 的同时 DMA 也往 buffer_a 写的情况。代码框架大致如下#define IMAGE_WIDTH 320 #define IMAGE_HEIGHT 240 #define IMAGE_SIZE (IMAGE_WIDTH * IMAGE_HEIGHT * 2) // RGB565 uint8_t frame_buffer_a[IMAGE_SIZE] __attribute__((aligned(4))); uint8_t frame_buffer_b[IMAGE_SIZE] __attribute__((aligned(4))); volatile uint8_t frame_ready 0; volatile uint8_t current_buffer 0; // 0: a, 1: b void DCMI_DMA_IRQHandler(void) { if (__HAL_DMA_GET_FLAG(hdma_dcmi, DMA_FLAG_TCIF1)) { __HAL_DMA_CLEAR_FLAG(hdma_dcmi, DMA_FLAG_TCIF1); HAL_DMA_Abort_IT(hdma_dcmi); // 先停掉 DMA // 切换到另一块缓冲区 if (current_buffer 0) { current_buffer 1; frame_ready_bit 1; // buffer_a 已满通知主循环处理 // 重新启动 DMA目标改为 buffer_b HAL_DCMI_Start_DMA(hdcmia, DCMI_MODE_SNAPSHOT, (uint32_t)frame_buffer_b, IMAGE_SIZE / 4); } else { current_buffer 0; // 重新启动 DMA目标改为 buffer_a HAL_DCMI_Start_DMA(hdcmia, DCMI_MODE_SNAPSHOT, (uint32_t)frame_buffer_a, IMAGE_SIZE / 4); } } }有几个细节要注意。第一HAL_DCMI_Start_DMA的参数里地址是内存地址数据长度单位是“字”32 位所以传IMAGE_SIZE / 4而不是IMAGE_SIZE。第二DMA 中断里调用HAL_DMA_Abort_IT是比较暴力的做法正常应该在 DMA 传输完成中断里直接调用HAL_DCMI_Stop和HAL_DCMI_Start_DMA但有些人反馈直接 Start 会卡死我才改用 Abort 再 Start。这个跟 HAL 库的版本有关系旧版确实需要手动清标志新版库函数处理得好一些。其实更优雅的方案是用 DMA 的 Transfer Complete 中断配合 DCMI 的 Frame 中断。DCMI 在收到一帧 VSYNC 后会触发帧中断这时候表示“新的一帧开始”你可以在这个中断里把 DMA 的 buffer 切到空闲缓冲区。DMA 传输完成中断表示“一帧数据搬完了”可以置标志。两个中断配合使用能精确控制帧同步。后来我遇到一个奇怪的现象VSYNC 中断触发的时间点比 DMA 开始搬运的时间点晚几个像素周期而且在行与行之间还会有短暂的停顿。查数据手册发现 DCMI 的 FIFO 深度是 4 个字如果 DMA 响应不及时FIFO 溢出就会丢数据。所以帧中断里切 buffer 不是万能的DMA 总线带宽不够的话照样丢数据。3.3 用串口把图像发给上位机的调试方案图像采集调试的过程中最快验证方案的方式就是把图像通过串口传到上位机。我用的是 USB-TTL 串口模块波特率 921600OV2640 出 JPEG 时一帧 VGA 图像大概 15~30KB921600 波特率大概每秒能传 92KB勉强够用。发送端代码很简单就是把一帧数据通过串口 DMA 发送HAL_UART_Transmit_DMA(huart1, (uint8_t *)frame_buffer_a, jpeg_data_len);上位机我用的是普通的串口助手 图像显示插件或者写个 Python 脚本读取串口数据存成 JPG 文件。Python 脚本的思路监听串口读到 0xFF 0xD8 开始缓存数据读到 0xFF 0xD9 结束缓存然后写入文件。这个办法对于 JPEG 模式特别灵因为 JPEG 的起始标记和结束标记很独特不容易误判。如果用的是 RGB565 模式上位机显示会更麻烦需要自己写显示代码。我写过一个小脚本把 RGB565 字节流转成 BMP 图片核心代码就一行处理一个像素网上也有现成的工具。一般调试 RGB565 模式建议用开发板自带的 LCD 屏直接显示会直观很多。4. 常见问题排查与避坑指南4.1 摄像头初始化失败和 SCCB 时序问题OV2640 初始化失败的典型表现是读回摄像头 ID 寄存器0x0A/0x0B的时候值一直不对或者读出来是 0xFF。这件事我排查过很多次最常见的坑就是 XCLK 没有启动。你想想OV2640 内部所有时序都依赖 XCLK没有时钟它连 SCCB 接口都不响应。所以我建议初始化第一步就验证 SCCB 能否读到正确的 ID读不到就不往下走快速定位问题。其次就是 SCCB 时序问题。我前面提到过引脚冲突的问题如果硬件上 SDA 和 D7 共用了一个引脚那 SCCB 模拟时序还能勉强工作但一旦 DCMI 开始采集引脚被复用SCCB 就废了。所以凡是用到 DCMI 的工程我基本都用 GPIO 模拟 SCCB避免冲突。模拟 SCCB 时序时注意起始条件、停止条件、ACK 信号这些和 I2C 几乎一样网上代码很多我验过是能用的。第三个坑是上电时序。OV2640 需要先上电然后拉低 RESET延时再拉高再延时最后配置寄存器。有人在初始化时不控制 RESET只靠模块上的自动复位电路在某些板子上没问题但在供电波动大的环境下初次上电极易失败。我习惯在进入摄像头初始化函数前先手动复位一次。4.2 DMA 卡死和数据错位DMA 卡死是个很经典的问题。表现是程序跑着跑着 DMA 不再搬运DCMI 中断也不触发图像完全卡住。我遇到的几个原因逐一列出来DMA 配置的中断优先级太低。DCMI 和 DMA 中断必须抢占优先级设置得比系统节拍中断高否则定时器中断频繁打断会导致 DMA 传输超时或 FIFO 溢出。DMA 在传输过程中被反复 Abort 和 Start中间没有延时导致状态机错乱。解决办法是在 Abort 后等 DMA 状态变成 Ready 再重新 Start可以用HAL_DMA_PollForTransfer或者轮询hdma_dcmi.State。内存地址没有 4 字节对齐。DCMI 和 DMA 是 32 位总线访问如果缓冲区地址不是 4 的倍数DMA 工作会异常。定义缓冲区时要加__attribute__((aligned(4)))。数据错位的问题通常是 PCLK 极性设置不对。OV2640 输出数据是在 PCLK 上升沿还是下降沿稳定不同初始化序列下表现可能不同。如果图像看起来有规律地偏移或者颜色通道互换把 CubeMX 里的 PCLK 极性从 Rising 改成 Falling 试一次大概率能解决。4.3 图像花屏、偏色和条纹问题花屏的原因比较多样我按概率排个序第一PCLK 分频不对采样时钟太快寄存器里有毛刺。把分频调大一点比如从 /1 改成 /2花屏概率会明显下降。第二摄像头供电不稳。OV2640 对供电很敏感3.3V 稍有波动就会在图像上表现为横向条纹。如果是用开发板的 3.3V 直接供电同时还有屏、电机等其他负载很容易出现这种情况。我后来给摄像头模块单独加了 LDO 供电问题就消失了。第三SCONSCCB在配置过程中受到干扰。如果使用模拟 SCCB在摄像头工作状态下 GPIO 被占用偶尔会误触发写操作导致寄存器被改成奇怪的值。解决办法是 SCCB 引脚配置为开漏输出并接上拉电阻降低干扰概率。偏色问题比较典型的是 RGB565 模式下红色和蓝色互换。这通常是摄像头输出的字节序Byte Order和你的显示端不一致。DCMI 的 32 位寄存器中字节排列顺序是可以调整的HAL_DCMI_Config里的DataPack参数控制了打包方式我一开始用默认配置图像里红色所有成了蓝色后来切换成DCMI_PACKING_RGB888或者手动交换高低字节才正常。如果你在 LCD 上显示图像也可以检查 LCD 驱动的颜色定义是否和实际数据匹配。4.4 OV2640 寄存器配置的经典组合速查我整理一张常用的 OV2640 配置对照表方便你根据自己的应用快速选择对应的寄存器设置方向功能需求寄存器地址hex典型值hex说明输出格式JPEG0xDA0x08开启 JPEG 输出输出格式RGB5650xDA0x0F关闭压缩输出 RGB565输出格式YUV4220xDA0x0DYUV 色彩空间输出分辨率UXGA0x110x011600x1200分辨率SVGA0x110x01800x600待确认分辨率VGA0x110x03640x480分辨率QVGA0x110x03320x240配合窗口裁剪时钟分频0xD30x04内部 PLL 分频要根据 XCLK 和分辨率调整镜像翻转0x010x80水平镜像0x40 为垂直翻转饱和度 / 亮度0x7C / 0x7D0x00 / 0x10调节图像效果这张表只是大方向实际使用时不同厂商的 OV2640 模块默认寄存器序列可能有差异不能完全照搬。我的建议是先读回模块默认序列再用“修改差异寄存器”的方式而不是用网上的整套配置覆盖这样兼容性最好。4.5 性能优化建议帧率与 CPU 占用率的平衡OV2640 在 QVGA 分辨率下理论上能跑到 30fps 以上但实际受限于 DCMI 时钟、DMA 带宽和你的处理逻辑。想要更高的帧率有几个优化方向使用 DCMI 的裁剪功能只采集感兴趣区域。OV2640 可以先输出整个画面但 DCMI 可以通过设置窗口相关寄存器只读取中间一块区域这样 DMA 搬运的数据量大幅减少。提高 DCMI 的像素时钟分频配置但前提是信号质量能保证。时钟越高花屏概率越大建议采集时先确认图像稳定再逐步提高时钟。使用 DMA 双缓冲配合“半传输完成中断”实现真正的流水线处理。在半传输中断里处理前半帧在完全传输中断里处理后半帧。这样做的好处是数据搬运和处理的等待时间更均匀CPU 不至于在传输完成瞬间被密集型任务卡死。如果只是看实时画面优先用 JPEG 模式并降低分辨率比如 320x240 分辨率的 JPEG 一帧只有几 KB串口和 DMA 的压力都小很多。CPU 占用率方面如果使用单缓冲非乒乓CPU 需要等待 DMA 搬运完成后才能开始处理白白浪费大量时间。双缓冲能把处理时间和传输时间重叠CPU 占用率明显下降但逻辑复杂度上升。想省事的话也可以采用“采集一帧 处理一帧 再采集下一帧”的串行方式帧率低但仍可用。5. 串口 DMA 与拓展应用的一点经验提到 DMA你可能也注意到了摄像头采集用 DMA串口传输图像也用 DMA这都是同一套 DMA 控制器的不同通道。F4 的 DMA2 有两个控制器DMA2 Stream1 常用于 DCMIDMA2 Stream7 常用于 UART 的 TX。当它们同时工作时总线上会争夺带宽可能导致图像帧率下降或串口传输卡顿。我的建议是在同一个 DMA 控制器上给不同的 Stream 分配不同的优先级。比如 DCMI 的 Stream 优先级设置为 Very High串口 TX 设置为 Medium这样摄像头采集不会被串口频繁打断。如果串口数据量大而摄像头处理不及时可以反过来调整优先级。记住一点DMA 优先级高不代表“独占”只是总线仲裁时更有利最终还是看整个系统的时序设计。除了走串口这套方案还经常扩展去驱动 SPI 接口的屏幕、保存到 SD 卡、或者通过以太网传图。原理都是一样的DMA 把数据从摄像头搬运到内存再由另一条 DMA 通道从内存搬运到外设。理解了这个数据流你就能在任意接口之间灵活迁移这套架构。我目前的摄像头项目里XCLK 用 MCO 输出SCCB 用 GPIO 模拟DCMI 工作在 8 位 RGB565 模式DMA 使用双缓冲 QVGA 分辨率处理端是一个简单的颜色识别算法运行在 STM32F407 上能稳定跑 20fps 左右。如果你要做更重的处理比如人脸识别、二维码识别建议把 F4 换成带硬件浮点和更高主频的 F7/H7 系列或者直接在 F4 上只负责采集把原始图像通过 DMA 以太网/串口传到上位机处理。最后再说点个人感受OV2640 这套方案最大的价值不在于性能数据而在于它让你把一个完整的数据链路——传感器采集、DMA 搬运、CPU 处理、接口输出——从头到尾打通一遍。这个过程里你踩的每一个坑都是在加深对嵌入式系统本质的理解。以后你再做任何带数据流的产品都会比别人多一分从容。上面这些问题覆盖了我在实际项目中遇到的绝大部分翻车场景照着排查基本都能解决。如果还有没讲透的地方欢迎在评论区交流。
返回列表