双红外反射式红外巡线传感器完全指南

一、传感器工作原理与类型

1. 红外巡线传感器基本原理

红外巡线传感器基于红外光的反射特性工作:

  • 发射管:发射特定波长(通常850-950nm)的红外光
  • 接收管:接收从地面反射回来的红外光
  • 检测原理
    • 白色表面:反射率高,接收管接收到较强信号
    • 黑色表面:吸收红外光,反射率低,接收信号弱
  • 输出信号:数字量(高低电平)或模拟量(电压值)

2. 双红外传感器配置优势

配置方式 优点 适用场景
并排安装 可检测线路位置偏差 精确巡线,PID控制
前后安装 可预测线路走向 高速巡线,提前转向
角度安装 扩大检测范围 复杂路径跟踪

3. 常见传感器型号对比

型号 类型 检测距离 输出方式 特点
TCRT5000 反射式 0.2-15mm 数字/模拟 常用,性价比高
RPR220 反射式 1-25mm 数字 抗干扰强
ITR20001 反射式 0-3mm 模拟 高精度
E18-D80NK 漫反射 3-80cm 数字 可调距离

二、硬件电路设计

1. TCRT5000传感器电路设计

1.1 发射电路

VCC (5V)
  │
  ├─[限流电阻R1]─┬─[红外发射管LED]─┐
  │              │                 │
  │              └─[单片机IO控制]─┘
  │
GND

计算公式

  • 限流电阻:R1 = (VCC - Vf) / If
  • 典型值:Vf=1.2V,If=20mA,R1=(5-1.2)/0.02=190Ω,取220Ω

1.2 接收电路(比较器输出)

VCC (5V)
  │
  ├─[上拉电阻10k]─┬─[输出信号]→ 单片机IO
  │               │
  │              [LM393比较器]输出
  │               │
  │              [电位器]─┬─[调整阈值]
  │                      │
  │              [红外接收管]─┬─[负载电阻]
  │                          │
  │                         GND

关键参数

  • 比较器:LM393或LM358
  • 负载电阻:通常1-10kΩ,影响灵敏度
  • 电位器:10kΩ可调,用于设置检测阈值

1.3 完整双传感器电路

/*
 * 双TCRT5000巡线传感器电路连接
 * 左传感器:OUT1 → P3.2
 * 右传感器:OUT2 → P3.3
 * 电源:VCC=5V,GND共地
 * 电位器:分别调节左右传感器灵敏度
 */

2. 直接ADC读取方案(无比较器)

对于需要模拟量读取的应用:

红外接收管
  │
  ├─[负载电阻R2]─┬─[ADC输入]→ 单片机ADC引脚
  │              │
  │             [滤波电容0.1uF]
  │              │
  │             GND

ADC值关系

  • 白色表面:ADC值高(接近1023)
  • 黑色线路:ADC值低(接近0)
  • 阈值:通常设为中间值512

三、STC15F104E接口设计

1. 引脚分配方案

STC15F104E只有6个I/O口,需合理分配:

P3.0 (RxD): 保留给串口通信
P3.1 (TxD): 保留给串口通信
P3.2 (INT0): 左传感器数字输出
P3.3 (INT1): 右传感器数字输出
P3.4 (T0):  左传感器PWM控制(可选)
P3.5 (T1):  右传感器PWM控制(可选)

2. 接口电路优化

由于STC15F104E资源有限,推荐以下方案:

方案A:纯数字输入(最简单)

// 直接读取数字电平
sbit LEFT_SENSOR = P3^2;   // 左传感器
sbit RIGHT_SENSOR = P3^3;  // 右传感器

// 传感器状态
#define ON_LINE    0  // 检测到黑线(低电平)
#define OFF_LINE   1  // 检测到白色(高电平)

方案B:ADC模拟读取(需外接ADC)

// 使用外部ADC芯片(如PCF8591)
// I2C接口连接
sbit SDA = P3^4;  // I2C数据线
sbit SCL = P3^5;  // I2C时钟线

四、软件编程实现

1. 基础巡线程序(数字传感器)

#include <STC15F104E.H>
#include <intrins.h>

// 传感器引脚定义
sbit LEFT_SENSOR = P3^2;   // 左传感器
sbit RIGHT_SENSOR = P3^3;  // 右传感器

// 电机控制引脚(假设通过L298N驱动)
sbit LEFT_MOTOR_F = P3^4;   // 左电机前进
sbit LEFT_MOTOR_B = P3^5;   // 左电机后退
sbit RIGHT_MOTOR_F = P3^0;  // 右电机前进(复用RxD)
sbit RIGHT_MOTOR_B = P3^1;  // 右电机后退(复用TxD)

// 延时函数
void DelayMS(uint ms) {
    uint i, j;
    for(i = ms; i > 0; i--)
        for(j = 114; j > 0; j--);
}

// 电机控制函数
void Motor_Stop() {
    LEFT_MOTOR_F = 0;
    LEFT_MOTOR_B = 0;
    RIGHT_MOTOR_F = 0;
    RIGHT_MOTOR_B = 0;
}

void Motor_Forward() {
    LEFT_MOTOR_F = 1;
    LEFT_MOTOR_B = 0;
    RIGHT_MOTOR_F = 1;
    RIGHT_MOTOR_B = 0;
}

void Motor_Left() {
    LEFT_MOTOR_F = 0;
    LEFT_MOTOR_B = 0;
    RIGHT_MOTOR_F = 1;
    RIGHT_MOTOR_B = 0;
}

void Motor_Right() {
    LEFT_MOTOR_F = 1;
    LEFT_MOTOR_B = 0;
    RIGHT_MOTOR_F = 0;
    RIGHT_MOTOR_B = 0;
}

void Motor_Backward() {
    LEFT_MOTOR_F = 0;
    LEFT_MOTOR_B = 1;
    RIGHT_MOTOR_F = 0;
    RIGHT_MOTOR_B = 1;
}

// 基础巡线算法
void Line_Following_Basic() {
    bit left_state, right_state;
    
    while(1) {
        left_state = LEFT_SENSOR;
        right_state = RIGHT_SENSOR;
        
        // 状态判断
        if(left_state == 0 && right_state == 0) {
            // 00: 都在线上 - 直行
            Motor_Forward();
        }
        else if(left_state == 0 && right_state == 1) {
            // 01: 左在线,右离线 - 左转
            Motor_Left();
            DelayMS(50);  // 小角度调整
        }
        else if(left_state == 1 && right_state == 0) {
            // 10: 左离线,右在线 - 右转
            Motor_Right();
            DelayMS(50);
        }
        else {
            // 11: 都离线 - 停止或搜索
            Motor_Stop();
            // 可选:小范围搜索
            Motor_Left();
            DelayMS(100);
        }
        
        DelayMS(10);  // 控制循环频率
    }
}

void main() {
    // 初始化I/O
    P3M0 = 0x00;  // 准双向模式
    P3M1 = 0x00;
    
    // 初始停止
    Motor_Stop();
    DelayMS(1000);  // 启动延时
    
    // 开始巡线
    Line_Following_Basic();
}

2. 改进型巡线算法(带记忆功能)

// 改进版巡线,记录上次状态
void Line_Following_Advanced() {
    static bit last_left = 1, last_right = 1;
    static uchar lost_count = 0;
    
    while(1) {
        bit left_state = LEFT_SENSOR;
        bit right_state = RIGHT_SENSOR;
        
        // 状态机处理
        switch((left_state << 1) | right_state) {
            case 0:  // 00: 都在线上
                Motor_Forward();
                lost_count = 0;
                break;
                
            case 1:  // 01: 左在线,右离线
                if(last_left == 0) {
                    // 上次左也在线,轻微右偏
                    Motor_Right();
                    DelayMS(30);
                } else {
                    // 新检测到,正常左转
                    Motor_Left();
                    DelayMS(50);
                }
                lost_count = 0;
                break;
                
            case 2:  // 10: 左离线,右在线
                if(last_right == 0) {
                    // 上次右也在线,轻微左偏
                    Motor_Left();
                    DelayMS(30);
                } else {
                    // 新检测到,正常右转
                    Motor_Right();
                    DelayMS(50);
                }
                lost_count = 0;
                break;
                
            case 3:  // 11: 都离线
                lost_count++;
                if(lost_count < 10) {
                    // 短暂丢失,按上次方向继续
                    if(last_left == 0) {
                        Motor_Left();
                    } else if(last_right == 0) {
                        Motor_Right();
                    } else {
                        Motor_Forward();  // 默认直行
                    }
                } else {
                    // 长时间丢失,停止并搜索
                    Motor_Stop();
                    Search_Line();
                    lost_count = 0;
                }
                break;
        }
        
        // 更新上次状态
        last_left = left_state;
        last_right = right_state;
        
        DelayMS(10);
    }
}

// 寻线搜索函数
void Search_Line() {
    uchar i;
    
    // 向左搜索
    for(i = 0; i < 5; i++) {
        Motor_Left();
        DelayMS(100);
        if(LEFT_SENSOR == 0 || RIGHT_SENSOR == 0) {
            return;  // 找到线
        }
    }
    
    // 向右搜索
    for(i = 0; i < 10; i++) {
        Motor_Right();
        DelayMS(100);
        if(LEFT_SENSOR == 0 || RIGHT_SENSOR == 0) {
            return;  // 找到线
        }
    }
    
    // 向后搜索
    Motor_Backward();
    DelayMS(300);
    Motor_Stop();
}

3. PWM调速巡线(更平滑)

// PWM调速巡线控制
void Line_Following_PWM() {
    // PWM参数
    uchar left_speed = 100;   // 左电机速度 0-100
    uchar right_speed = 100;  // 右电机速度 0-100
    uchar pwm_counter = 0;
    
    // 定时器0初始化(PWM生成)
    TMOD &= 0xF0;
    TMOD |= 0x01;  // 定时器0模式1
    TH0 = 0xFC;    // 1ms定时
    TL0 = 0x67;
    ET0 = 1;
    TR0 = 1;
    EA = 1;
    
    while(1) {
        // 读取传感器
        bit left_state = LEFT_SENSOR;
        bit right_state = RIGHT_SENSOR;
        
        // 根据传感器状态调整速度
        if(left_state == 0 && right_state == 0) {
            // 直行
            left_speed = 80;
            right_speed = 80;
        }
        else if(left_state == 0 && right_state == 1) {
            // 左转:左轮慢,右轮快
            left_speed = 40;
            right_speed = 100;
        }
        else if(left_state == 1 && right_state == 0) {
            // 右转:左轮快,右轮慢
            left_speed = 100;
            right_speed = 40;
        }
        else {
            // 都离线:慢速前进
            left_speed = 60;
            right_speed = 60;
        }
        
        DelayMS(20);  // 控制更新频率
    }
}

// 定时器0中断服务函数(PWM生成)
void Timer0_ISR() interrupt 1 {
    static uchar pwm_counter = 0;
    
    TH0 = 0xFC;
    TL0 = 0x67;
    
    pwm_counter++;
    if(pwm_counter >= 100) {
        pwm_counter = 0;
    }
    
    // 左电机PWM控制
    if(pwm_counter < left_speed) {
        LEFT_MOTOR_F = 1;
        LEFT_MOTOR_B = 0;
    } else {
        LEFT_MOTOR_F = 0;
        LEFT_MOTOR_B = 0;
    }
    
    // 右电机PWM控制
    if(pwm_counter < right_speed) {
        RIGHT_MOTOR_F = 1;
        RIGHT_MOTOR_B = 0;
    } else {
        RIGHT_MOTOR_F = 0;
        RIGHT_MOTOR_B = 0;
    }
}

参考代码 双红外反射式红外巡线传感器 www.youwenfan.com/contentcnt/134013.html

五、传感器校准与调试

1. 硬件校准步骤

  1. 安装高度调整

    • 最佳高度:传感器距地面5-15mm
    • 使用支架固定,确保两个传感器高度一致
    • 高度影响:太高→灵敏度低,太低→易受地面不平影响
  2. 电位器调节

    步骤:
    1. 将传感器置于白色区域
    2. 调节电位器使LED刚好熄灭(或输出高电平)
    3. 将传感器移至黑色线路
    4. 确认LED亮起(或输出低电平)
    5. 重复微调至最佳状态
    
  3. 间距设置

    • 标准间距:略大于线路宽度
    • 例如:线路宽2cm,传感器间距2.5-3cm
    • 可调间距设计便于适应不同线路

2. 软件校准程序

// 自动阈值校准程序
void Sensor_Calibration() {
    uchar i;
    uint left_sum = 0, right_sum = 0;
    uint left_white, left_black, right_white, right_black;
    
    // 白色区域采样
    UART_SendString("请将传感器放在白色区域,按任意键开始...\r\n");
    while(!KEY);  // 等待按键
    
    for(i = 0; i < 100; i++) {
        left_sum += LEFT_SENSOR;
        right_sum += RIGHT_SENSOR;
        DelayMS(10);
    }
    left_white = left_sum / 100;
    right_white = right_sum / 100;
    
    UART_SendString("白色区域采样完成\r\n");
    
    // 黑色线路采样
    UART_SendString("请将传感器放在黑色线路,按任意键开始...\r\n");
    while(!KEY);
    
    left_sum = right_sum = 0;
    for(i = 0; i < 100; i++) {
        left_sum += LEFT_SENSOR;
        right_sum += RIGHT_SENSOR;
        DelayMS(10);
    }
    left_black = left_sum / 100;
    right_black = right_sum / 100;
    
    // 计算阈值(中间值)
    left_threshold = (left_white + left_black) / 2;
    right_threshold = (right_white + right_black) / 2;
    
    // 输出结果
    UART_SendString("校准完成:\r\n");
    UART_SendString("左传感器阈值:");
    UART_SendNum(left_threshold);
    UART_SendString("\r\n右传感器阈值:");
    UART_SendNum(right_threshold);
    UART_SendString("\r\n");
}

// 带阈值的传感器读取函数
bit Read_Left_Sensor() {
    return (LEFT_SENSOR > left_threshold) ? 1 : 0;
}

bit Read_Right_Sensor() {
    return (RIGHT_SENSOR > right_threshold) ? 1 : 0;
}

3. 调试技巧

  1. LED指示:为每个传感器添加状态LED,直观显示检测状态
  2. 串口输出:通过串口实时输出传感器数值,便于调试
  3. 可变电阻:使用多圈电位器,调节更精细
  4. 屏蔽罩:添加遮光罩,减少环境光干扰

六、高级应用:PID巡线算法

1. PID控制原理

误差 = 传感器位置偏差
输出 = Kp×误差 + Ki×积分 + Kd×微分

2. PID巡线实现

// PID巡线控制器
typedef struct {
    float Kp, Ki, Kd;      // PID参数
    float integral;         // 积分项
    float last_error;       // 上次误差
    float output;           // 输出值
} PID_Controller;

PID_Controller pid;

// PID初始化
void PID_Init(float kp, float ki, float kd) {
    pid.Kp = kp;
    pid.Ki = ki;
    pid.Kd = kd;
    pid.integral = 0;
    pid.last_error = 0;
    pid.output = 0;
}

// PID计算
float PID_Calculate(float error, float dt) {
    float derivative;
    
    // 积分项(带抗饱和)
    pid.integral += error * dt;
    if(pid.integral > 100) pid.integral = 100;
    if(pid.integral < -100) pid.integral = -100;
    
    // 微分项
    derivative = (error - pid.last_error) / dt;
    
    // PID输出
    pid.output = pid.Kp * error + 
                 pid.Ki * pid.integral + 
                 pid.Kd * derivative;
    
    // 限幅
    if(pid.output > 100) pid.output = 100;
    if(pid.output < -100) pid.output = -100;
    
    pid.last_error = error;
    return pid.output;
}

// 基于PID的巡线控制
void Line_Following_PID() {
    float error;
    float pid_output;
    uchar base_speed = 70;  // 基础速度
    uchar left_speed, right_speed;
    
    // 初始化PID参数
    PID_Init(30.0, 0.1, 5.0);  // 需要根据实际调整
    
    while(1) {
        // 计算位置误差(-1到+1)
        if(LEFT_SENSOR == 0 && RIGHT_SENSOR == 0) {
            error = 0;  // 在线中间
        }
        else if(LEFT_SENSOR == 0 && RIGHT_SENSOR == 1) {
            error = -0.5;  // 偏左
        }
        else if(LEFT_SENSOR == 1 && RIGHT_SENSOR == 0) {
            error = 0.5;   // 偏右
        }
        else {
            // 都离线,使用上次误差
            // 或执行搜索程序
        }
        
        // PID计算
        pid_output = PID_Calculate(error, 0.01);  // dt=10ms
        
        // 转换为电机速度
        left_speed = base_speed + pid_output;
        right_speed = base_speed - pid_output;
        
        // 限幅
        if(left_speed > 100) left_speed = 100;
        if(left_speed < 0) left_speed = 0;
        if(right_speed > 100) right_speed = 100;
        if(right_speed < 0) right_speed = 0;
        
        // 设置电机速度(通过PWM)
        Set_Motor_Speed(left_speed, right_speed);
        
        DelayMS(10);  // 控制周期10ms
    }
}

七、常见问题与解决方案

1. 传感器问题排查表

问题现象 可能原因 解决方案
传感器无反应 1. 电源接反
2. 发射管损坏
3. 接收管损坏
1. 检查电源极性
2. 更换发射管
3. 更换接收管
灵敏度太低 1. 安装高度过高
2. 发射电流太小
3. 负载电阻太大
1. 降低安装高度
2. 减小限流电阻
3. 减小负载电阻
误触发频繁 1. 环境光干扰
2. 阈值设置不当
3. 地面反光
1. 添加遮光罩
2. 重新校准
3. 调整传感器角度
两传感器不一致 1. 高度不一致
2. 元件参数差异
3. 电路不对称
1. 调整安装高度
2. 分别校准
3. 检查电路连接

2. 抗干扰设计

  1. 调制解调技术:使用38kHz载波调制,避免环境光干扰
  2. 软件滤波:多次采样取平均,消除偶然误差
  3. 硬件滤波:添加RC低通滤波器,平滑信号
  4. 时序控制:分时点亮传感器,避免相互干扰

3. 性能优化建议

  1. 动态阈值:根据环境光自动调整阈值
  2. 自适应速度:根据线路曲率调整巡线速度
  3. 预测算法:根据历史数据预测线路走向
  4. 多传感器融合:增加更多传感器提高可靠性

八、项目实例:智能巡线小车

1. 完整系统框图

电源模块(5V)
    │
    ├─ STC15F104E主控
    │     ├─ 左红外传感器 → P3.2
    │     ├─ 右红外传感器 → P3.3
    │     ├─ 左电机驱动 → P3.4/P3.5
    │     └─ 右电机驱动 → P3.0/P3.1
    │
    ├─ L298N电机驱动
    │     ├─ 左直流电机
    │     └─ 右直流电机
    │
    └─ 调试接口
          ├─ 状态指示灯
          └─ 串口通信

2. 完整程序框架

#include <STC15F104E.H>

// 系统状态定义
typedef enum {
    STATE_IDLE,      // 空闲
    STATE_CALIB,     // 校准
    STATE_FOLLOW,    // 巡线
    STATE_SEARCH,    // 寻线
    STATE_ERROR      // 错误
} SystemState;

SystemState current_state = STATE_IDLE;

// 主程序
void main() {
    System_Init();      // 系统初始化
    Sensor_Calibration(); // 传感器校准
    
    while(1) {
        switch(current_state) {
            case STATE_IDLE:
                if(Start_Button_Pressed()) {
                    current_state = STATE_FOLLOW;
                }
                break;
                
            case STATE_FOLLOW:
                Line_Following_PID();  // PID巡线
                
                if(Both_Sensors_Offline() > 2) {
                    current_state = STATE_SEARCH;
                }
                break;
                
            case STATE_SEARCH:
                Search_Line();
                if(Line_Found()) {
                    current_state = STATE_FOLLOW;
                } else if(Search_Timeout()) {
                    current_state = STATE_ERROR;
                }
                break;
                
            case STATE_ERROR:
                Motor_Stop();
                Error_Indicator();
                break;
        }
        
        // 状态指示灯
        Update_Status_LED();
        
        // 看门狗喂狗
        WDT_CONTR = 0x35;
    }
}

3. 扩展功能建议

  1. 速度显示:添加OLED显示当前速度
  2. 路径记忆:记录行驶路径,实现自动学习
  3. 无线控制:添加蓝牙/WiFi模块,手机控制
  4. 避障功能:增加超声波传感器,避让障碍
  5. 数据记录:记录巡线数据,分析优化

九、总结与进阶

双红外反射式巡线传感器是机器人巡线应用中最经典、最可靠的解决方案之一。通过合理的设计和编程,可以实现从基础巡线到高级PID控制的多种功能。STC15F104E虽然资源有限,但完全能够胜任基本的巡线任务。

posted @ 2026-04-13 09:47  chen_yig  阅读(8)  评论(0)    收藏  举报