共计 2169 个字符,预计需要花费 6 分钟才能阅读完成。
背景痛点:新手常见问题分析
刚开始接触 C51 单片机目标检测时,最常遇到两类问题:

- 硬件连接不稳定 :传感器信号时有时无,ADC 采样值跳动剧烈。常见原因是未做信号调理电路,或接线过长引入干扰。
- 算法资源不足 :直接移植 PC 端复杂算法导致内存溢出,或者检测延迟高达秒级,完全失去实时性。
这两个问题往往相互影响——硬件采集的信号质量差,又被迫用复杂算法做补偿,最终系统无法正常工作。
技术选型:传感器对比
根据检测距离和成本要求,主流方案有:
- 红外对管(3-80cm)
- 优点:成本低(<5 元),电路简单
-
缺点:易受环境光干扰
-
超声波模块(2cm-4m)
- 优点:测距准,不受光线影响
-
缺点:需要 40kHz 方波驱动,占用定时器资源
-
激光 TOF(最远 10m)
- 优点:精度毫米级
- 缺点:价格高(>50 元)
推荐选择 :室内场景用红外对管(如 E18-D80NK),室外或需要精确测距时用超声波(HC-SR04)。
核心实现
硬件连接示意图
以红外对管为例的典型电路:
VCC ──┬─── 红外对管 +
│ ▲
10kΩ │
│ └─── P1.0(ADC 输入)GND ──┴─── 红外对管 -
关键参数 :
– 限流电阻选 10kΩ(根据传感器规格调整)
– 信号线长度建议 <20cm
– 必要时在 VCC 与 GND 间并联 100nF 电容抗干扰
算法伪代码
# 带阈值的去抖动检测算法
def detect_object(raw_adc):
# 滑动窗口均值滤波
filter_buf.push(raw_adc)
avg = sum(filter_buf) / len(filter_buf)
# 动态阈值计算(历史均值±20%)threshold_high = baseline * 1.2
threshold_low = baseline * 0.8
# 状态机防抖动
if avg > threshold_high:
if stable_count > 5: # 连续 5 次超阈值才确认
return True
stable_count += 1
else:
stable_count = 0
return False
关键逻辑 :
1. 用滑动窗口滤波消除瞬时噪声
2. 动态阈值适应环境变化
3. 状态机机制避免误触发
性能优化技巧
滤波算法选择
-
移动平均滤波 :占用内存少,适合 C51
#define FILTER_SIZE 5 uint16_t filter(uint16_t new_val) {static uint16_t buf[FILTER_SIZE]; static uint8_t idx = 0; buf[idx++] = new_val; if(idx >= FILTER_SIZE) idx = 0; uint32_t sum = 0; for(uint8_t i=0; i<FILTER_SIZE; i++) sum += buf[i]; return sum / FILTER_SIZE; } -
IIR 低通滤波 :计算量更小
// 系数 alpha=0.2 uint16_t iir_filter(uint16_t new_val) { static uint16_t last = 0; last = 0.8*last + 0.2*new_val; return last; }
中断服务例程
void Timer0_ISR() interrupt 1 {
TH0 = 0xFC; // 重装定时值(1ms)TL0 = 0x18;
static uint8_t cnt = 0;
if(++cnt >= 100) { // 每 100ms 检测一次
cnt = 0;
adc_val = read_adc();
if(detect_object(adc_val)) {P2 ^= 0x01; // 触发 LED 指示}
}
}
避坑指南
- 电源干扰 :
- 单片机与传感器分别加 0.1μF 去耦电容
-
避免与大功率器件共用电源
-
安装位置 :
- 红外对管与被测物距离保持在标称范围的 50%-80%
-
超声波传感器避开柔软吸音材料(如泡沫)
-
环境干扰 :
- 红外方案需避开直射阳光
- 超声波在高温环境下需做温度补偿
完整代码示例
Keil 工程主要文件结构:
Project/
├─ MAIN.C # 主循环与初始化
├─ ADC.C # ADC 采集驱动
├─ FILTER.C # 滤波算法
└─ DETECT.C # 检测逻辑
关键函数示例(detect.c):
/**
* @brief 带状态机的目标检测
* @param adc_val 当前 ADC 采样值
* @return 1- 检测到目标 0- 无目标
*/
uint8_t object_detect(uint16_t adc_val) {
static uint8_t state = 0;
static uint16_t baseline = 512; // 初始阈值
uint16_t filtered = moving_avg(adc_val); // 滤波
// 动态基线更新(慢衰减)baseline = baseline * 0.99 + filtered * 0.01;
// 状态转移
switch(state) {
case 0: // 等待状态
if(filtered > baseline + 50) {
state = 1;
return 1; // 首次触发
}
break;
case 1: // 防抖确认
if(filtered < baseline + 30) {state = 0; // 返回等待}
break;
}
return 0;
}
总结与拓展
建议尝试用不同传感器实现同一功能:
- 用红外对管和超声波分别测距,对比响应速度
- 在算法中加入温度补偿(DS18B20 采集环境温度)
- 尝试用 PWM 调制红外发射管强度以扩展检测范围
通过这样的对比实践,能更深入理解不同传感器的特性差异,为实际项目选型积累经验。
正文完
