2、硬件触发基础:GPIO触发、PWM触发、外部中断与时间戳捕获
各位同学,咱们今天聊点硬核的。硬件触发,说白了就是让传感器自己喊一声「我准备好了」,而不是让CPU一遍遍去问「你好了没?」。我在做激光雷达和IMU融合的项目时,深刻体会到:没有硬件触发,时间同步就是空中楼阁。
嗯,这一节我们聚焦四个核心概念:GPIO触发、PWM触发、外部中断、时间戳捕获。它们就像四根柱子,撑起了多传感器同步的整个框架。
2.1 GPIO触发:最朴素的同步方式
GPIO触发,其实就是用一根线拉高拉低。你想想看,两个传感器之间,一根杜邦线就能搞定同步信号。我在早期做双目相机同步时,用的就是这招。
具体怎么玩?主传感器(比如IMU)输出一个上升沿,从传感器(比如相机)检测到这个边沿后立即开始曝光。代码实现其实很简单:
// 主传感器输出触发脉冲
void master_trigger_output(void) {
HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_SET);
delay_us(10); // 脉冲宽度10微秒
HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_RESET);
}
// 从传感器检测触发
void slave_trigger_callback(void) {
if (HAL_GPIO_ReadPin(TRIG_GPIO_Port, TRIG_Pin) == GPIO_PIN_SET) {
start_exposure(); // 开始曝光
}
}
⚠️ 我曾经踩过的坑:GPIO触发看似简单,但信号抖动是个大问题。有一次我在电机旁边跑GPIO触发,结果电机一启动,触发信号就乱跳。后来加了RC滤波才搞定。记住:工业现场,GPIO线一定要走屏蔽线,长度别超过30cm。
2.2 PWM触发:精度与灵活性的平衡
GPIO触发只能给一个脉冲,但PWM触发可以给一串。说白了,PWM就是方波,占空比和频率都能调。我个人习惯用PWM来做多传感器分时触发。
举个例子:你有三个相机,想让它们轮流曝光。用PWM的上升沿触发相机1,下降沿触发相机2,下一个上升沿触发相机3。这样一根线就搞定了三个传感器的同步。
| 参数 | GPIO触发 | PWM触发 |
|---|---|---|
| 信号复杂度 | 单脉冲 | 连续方波 |
| 触发次数 | 一次 | 可编程多次 |
| 适用场景 | 单次同步 | 周期性同步 |
| 抗干扰能力 | 较弱 | 较强(有固定频率) |
PWM配置代码示例:
// 配置PWM输出,频率1kHz,占空比50%
void pwm_trigger_init(void) {
TIM_HandleTypeDef htim;
htim.Instance = TIM2;
htim.Init.Prescaler = 84 - 1; // 84MHz / 84 = 1MHz
htim.Init.Period = 1000 - 1; // 1MHz / 1000 = 1kHz
htim.Init.CounterMode = TIM_COUNTERMODE_UP;
HAL_TIM_PWM_Init(&htim);
TIM_OC_InitTypeDef sConfigOC;
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 500; // 占空比50%
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
HAL_TIM_PWM_ConfigChannel(&htim, &sConfigOC, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim, TIM_CHANNEL_1);
}
💡 我的经验:PWM频率别选太高。我试过100kHz的PWM触发相机,结果相机跟不上,丢帧严重。一般1kHz到10kHz比较稳妥。具体看传感器数据手册里的「Trigger Input Frequency」参数。
2.3 外部中断:精准捕获触发时刻
外部中断,是硬件触发里最灵敏的机制。为什么?因为它是硬件级别的响应,不像轮询那样有延迟。我记得有一次做无人机飞控,IMU数据必须精确到微秒级,这时候外部中断就是救命稻草。
外部中断的工作原理:当GPIO引脚检测到边沿变化(上升沿或下降沿),CPU立即暂停当前任务,跳转到中断服务函数。这个响应时间通常在几十纳秒到几微秒之间。
// 外部中断配置(STM32 HAL库)
void exti_init(void) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING; // 上升沿触发
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}
// 中断服务函数
void EXTI0_IRQHandler(void) {
if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_0) != RESET) {
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0);
// 在这里记录时间戳
timestamp = get_system_time_us();
// 触发传感器采集
sensor_trigger();
}
}
⚠️ 注意:中断服务函数里别干太多活。我见过有人在中断里做浮点运算、打印日志,结果中断嵌套导致系统崩溃。记住:中断里只做最必要的事——记录时间戳、设置标志位。复杂处理放到主循环里。
2.4 时间戳捕获:给每个事件打上时间标签
时间戳捕获,是硬件触发的灵魂。你想想看,传感器采集到了数据,但不知道是什么时候采集的,那这数据还有什么用?
硬件时间戳捕获,通常有两种方式:
- CPU定时器捕获:外部中断发生时,直接读取定时器的当前计数值。精度取决于定时器时钟频率。
- 专用时间戳单元:一些高端MCU(比如STM32H7)有专门的Timestamp模块,精度可达纳秒级。
我个人更推荐用定时器捕获,因为通用性强,几乎所有MCU都支持。
// 定时器输入捕获配置
void tim_capture_init(void) {
TIM_HandleTypeDef htim;
htim.Instance = TIM5;
htim.Init.Prescaler = 84 - 1; // 1MHz计数
htim.Init.CounterMode = TIM_COUNTERMODE_UP;
htim.Init.Period = 0xFFFFFFFF; // 最大周期
HAL_TIM_IC_Init(&htim);
TIM_IC_InitTypeDef sConfigIC;
sConfigIC.ICPolarity = TIM_ICPOLARITY_RISING;
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
sConfigIC.ICFilter = 0; // 无滤波
HAL_TIM_IC_ConfigChannel(&htim, &sConfigIC, TIM_CHANNEL_1);
HAL_TIM_IC_Start_IT(&htim, TIM_CHANNEL_1);
}
// 捕获回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) {
if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1) {
uint32_t capture_value = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
// capture_value就是精确的时间戳
store_timestamp(capture_value);
}
}
🔑 核心要点:时间戳的精度取决于计数时钟频率。1MHz的时钟,精度是1微秒;100MHz的时钟,精度是10纳秒。选型时,根据你的传感器需求来定。比如激光雷达通常需要微秒级,而视觉惯性里程计可能需要纳秒级。
2.5 实战中的组合拳
好了,四个基础概念讲完了。但实际项目中,它们往往是组合使用的。我分享一个我做过的一个案例:
一个自动驾驶小车,需要同步激光雷达、摄像头和IMU。我的方案是:
- 用STM32的定时器输出PWM信号,频率1kHz
- PWM的上升沿触发激光雷达采集
- PWM的下降沿触发摄像头曝光
- IMU通过外部中断检测PWM边沿,记录时间戳
- 所有传感器数据都带上硬件时间戳,上传到主控
这样,三个传感器的数据就有了统一的时间基准。误差控制在10微秒以内。
💡 避坑指南:我曾经犯过一个错误——所有传感器都用同一个GPIO触发。结果信号反射导致误触发。后来我给每个传感器加了独立的触发线,问题解决。记住:共享触发线时,一定要加缓冲器(比如74HC245)。
嗯,这一节的内容就到这里。硬件触发看起来简单,但细节决定成败。下一节我们会讲更高级的触发方式——PPS同步和IEEE 1588协议。到时候你会发现,今天的基础知识都是铺垫。
记住:做多传感器同步,硬件触发是地基。地基不稳,上层算法再牛也白搭。