3. 硬件触发同步:外部触发信号设计、GPIO中断同步、硬件帧同步信号
多摄像头同步,最可靠的方式是什么?
我个人会毫不犹豫地回答:硬件触发。软件同步再精准,也逃不过操作系统调度抖动和USB总线延迟。真正要做到微秒级、甚至纳秒级的帧对齐,必须走硬件路线。
3.1 为什么需要硬件触发?
先看一个实际场景。你架了4个摄像头,要同时抓拍高速运动的物体。如果用软件发指令,每个摄像头收到命令的时间差可能达到几毫秒。对于时速100公里的目标,这几毫秒意味着目标已经移动了十几厘米。图像对齐?根本不可能。
硬件触发的核心思路很简单:用一根物理信号线,同时告诉所有摄像头“开始曝光”。信号传播延迟只取决于线长和电路速度,通常在纳秒级别。
| 同步方式 | 典型抖动 | 适用场景 |
|---|---|---|
| 软件触发(UDP/API) | 1~10 ms | 非实时监控、帧率要求低 |
| 硬件触发(GPIO) | 100 ns ~ 1 µs | 机器视觉、高速检测 |
| 专用帧同步(Genlock) | < 10 ns | 广播级、科研高速摄像 |
3.2 外部触发信号设计
触发信号怎么设计?说白了,就是决定用什么波形、什么电平、什么时序去唤醒摄像头。
3.2.1 信号类型选择
常见的触发信号有两种:
- 边沿触发(Edge Trigger):上升沿或下降沿触发一次。适合单帧采集。
- 电平触发(Level Trigger):高电平持续曝光,低电平停止。适合需要控制曝光时间的场景。
我个人习惯用上升沿触发。为什么?因为大多数摄像头的触发输入都内置了施密特触发器,对上升沿的响应最稳定。电平触发容易受噪声干扰,搞不好就出现“一直曝光”的尴尬情况。
3.2.2 电气参数
这里有个坑,我踩过。曾经用3.3V的MCU直接驱动一个5V触发的工业相机,结果相机死活不响应。查了半天才发现是电平不匹配。
| 参数 | 典型值 | 注意事项 |
|---|---|---|
| 触发电压 | 3.3V / 5V / 12V | 必须匹配摄像头IO电平 |
| 最小脉冲宽度 | 10 µs ~ 1 ms | 查阅摄像头datasheet |
| 上升/下降时间 | < 100 ns | 长线传输需加缓冲器 |
| 驱动能力 | ≥ 10 mA | 多路分配时需加驱动芯片 |
3.3 GPIO中断同步
触发信号到了嵌入式处理器这边,怎么响应?GPIO中断是最直接的方式。
3.3.1 中断响应流程
一个典型的GPIO中断同步流程是这样的:
- 外部触发信号上升沿到达GPIO引脚
- 处理器触发中断服务程序(ISR)
- ISR中记录时间戳(硬件定时器捕获)
- ISR中启动DMA传输或通知应用层
- 应用层根据时间戳对齐多路数据
嗯,这里要注意:ISR里不能做耗时操作。比如图像处理、文件写入、打印日志,这些都得放到任务上下文里做。ISR只做两件事:记录时间戳、触发DMA。
3.3.2 中断延迟控制
你想想看,如果中断响应延迟不稳定,那硬件触发还有什么意义?
影响中断延迟的因素主要有:
- 中断优先级设置(必须设为最高)
- 其他中断的屏蔽时间
- CPU缓存命中率
- 中断嵌套深度
我建议的做法:把触发中断设为最高优先级,并且在ISR入口处立即关闭其他中断。等时间戳捕获完成后再恢复。这样能把抖动控制在几个CPU周期内。
3.4 硬件帧同步信号
多摄像头系统里,光有触发信号还不够。每个摄像头曝光完成后,什么时候开始读数据?什么时候准备下一帧?这就需要帧同步信号来协调。
3.4.1 帧同步信号类型
常见的帧同步信号包括:
- VSYNC(垂直同步):表示一帧开始或结束
- HSYNC(水平同步):表示一行开始或结束
- PCLK(像素时钟):每个像素数据的同步时钟
- FSYNC(帧同步):自定义的帧起始信号
对于多摄像头同步,我们最关心的是VSYNC。所有摄像头的VSYNC必须对齐,才能保证每帧数据的时间戳一致。
3.4.2 主从同步模式
实际项目中,我常用主从同步模式:
- 主摄像头:输出触发信号和帧同步信号
- 从摄像头:接收主摄像头的信号,同步自己的曝光和读出时序
这种模式的好处是:所有摄像头都跟着一个时钟源走,不会出现累积误差。
3.5 完整硬件同步架构
下面这张图展示了我常用的多摄像头硬件同步架构:
3.6 实战:GPIO中断同步代码示例
最后,给一段我在STM32上实际用过的GPIO中断同步代码。你拿过去改改就能用。
// 硬件触发中断服务程序
// 假设触发信号接在PA0,上升沿触发
void EXTI0_IRQHandler(void)
{
// 1. 立即捕获时间戳(使用DWT周期计数器)
uint32_t timestamp = DWT->CYCCNT;
// 2. 清除中断标志
EXTI->PR |= EXTI_PR_PR0;
// 3. 将时间戳写入环形缓冲区(ISR-safe)
uint32_t next_idx = (ts_head + 1) & (TS_BUF_SIZE - 1);
if (next_idx != ts_tail) {
ts_buf[ts_head] = timestamp;
ts_head = next_idx;
}
// 4. 触发DMA传输(如果摄像头数据已准备好)
if (dma_ready_flag) {
DMA->CCR |= DMA_CCR_EN;
dma_ready_flag = 0;
}
// 注意:这里没有printf,没有延时,没有复杂计算
// ISR执行时间控制在1微秒以内
}
硬件触发同步,说白了就是用物理信号代替软件指令。它不依赖操作系统调度,不依赖网络延迟,只依赖电路本身的传播速度。这才是多摄像头同步的终极方案。