单片机实现寻迹小车功能详解(附源码解析)

1. 硬件组成

实现一个基本的寻迹小车系统,需要以下硬件组件:

  • 单片机(MCU):如 STM32、51 系列或 Arduino,用来处理传感器数据并控制小车运动。
  • 红外传感器(IR):用于感知地面上的黑线和白地。常见的传感器有 TCS3200、QRE1113 或 TCS230 等。
  • 电机驱动模块:如 L298N、L293D 等,用于驱动小车的电机。
  • 直流电机:控制小车前进、后退、转向等运动。
  • 电池和电源管理模块:为电路和电机提供电力。
  • 小车底盘:用于搭载上述电子组件。
  • 2. 硬件连接

  • 红外传感器:假设有两个传感器,用于检测黑线。传感器输出数字信号(高或低),表示是否在线上。
  • 电机控制:使用 L298N 驱动模块控制小车的两个直流电机的转动。
  • 电机的两个引脚连接到 L298N 的输出端口。
  • L298N 的控制引脚连接到单片机的 GPIO 引脚,通过控制这些引脚的电平来控制电机的旋转方向和速度。
  • 3. 基本控制逻辑

    寻迹小车的工作原理通常是通过传感器检测到的黑白轨迹来判断方向。如果传感器在黑线上,表示小车需要向该方向移动,否则小车需要调整行驶方向。具体控制逻辑如下:

    1. 前进:如果两个传感器都检测到黑线,表示小车在轨道上,需要前进。
    2. 左转:如果左侧传感器检测到黑线,而右侧传感器检测到白线,表示小车偏离了轨道,需要左转。
    3. 右转:如果右侧传感器检测到黑线,而左侧传感器检测到白线,表示小车偏离了轨道,需要右转。
    4. 停止:如果两个传感器都检测到白线,表示小车脱离轨道,需要停下来进行修正。

    4. 软件设计

    假设使用 STM32 单片机,下面是一个简单的代码实现方案。

    #include "stm32f4xx_hal.h"
    
    // 电机控制引脚定义
    #define MOTOR1_IN1  GPIO_PIN_0
    #define MOTOR1_IN2  GPIO_PIN_1
    #define MOTOR2_IN1  GPIO_PIN_2
    #define MOTOR2_IN2  GPIO_PIN_3
    #define MOTOR_GPIO_PORT GPIOB  // 假设电机控制引脚连接到 GPIOB
    
    // 红外传感器引脚定义
    #define LEFT_SENSOR_PIN  GPIO_PIN_4  // 左侧传感器
    #define RIGHT_SENSOR_PIN GPIO_PIN_5  // 右侧传感器
    #define SENSOR_GPIO_PORT GPIOA
    
    void GPIO_Init(void) {
        GPIO_InitTypeDef GPIO_InitStruct = {0};
    
        // 初始化电机控制引脚
        __HAL_RCC_GPIOB_CLK_ENABLE();
        GPIO_InitStruct.Pin = MOTOR1_IN1 | MOTOR1_IN2 | MOTOR2_IN1 | MOTOR2_IN2;
        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
        HAL_GPIO_Init(MOTOR_GPIO_PORT, &GPIO_InitStruct);
    
        // 初始化传感器引脚
        __HAL_RCC_GPIOA_CLK_ENABLE();
        GPIO_InitStruct.Pin = LEFT_SENSOR_PIN | RIGHT_SENSOR_PIN;
        GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        HAL_GPIO_Init(SENSOR_GPIO_PORT, &GPIO_InitStruct);
    }
    
    // 电机控制函数
    void move_forward(void) {
        HAL_GPIO_WritePin(MOTOR_GPIO_PORT, MOTOR1_IN1, GPIO_PIN_SET);
        HAL_GPIO_WritePin(MOTOR_GPIO_PORT, MOTOR1_IN2, GPIO_PIN_RESET);
        HAL_GPIO_WritePin(MOTOR_GPIO_PORT, MOTOR2_IN1, GPIO_PIN_SET);
        HAL_GPIO_WritePin(MOTOR_GPIO_PORT, MOTOR2_IN2, GPIO_PIN_RESET);
    }
    
    void move_backward(void) {
        HAL_GPIO_WritePin(MOTOR_GPIO_PORT, MOTOR1_IN1, GPIO_PIN_RESET);
        HAL_GPIO_WritePin(MOTOR_GPIO_PORT, MOTOR1_IN2, GPIO_PIN_SET);
        HAL_GPIO_WritePin(MOTOR_GPIO_PORT, MOTOR2_IN1, GPIO_PIN_RESET);
        HAL_GPIO_WritePin(MOTOR_GPIO_PORT, MOTOR2_IN2, GPIO_PIN_SET);
    }
    
    void turn_left(void) {
        HAL_GPIO_WritePin(MOTOR_GPIO_PORT, MOTOR1_IN1, GPIO_PIN_RESET);
        HAL_GPIO_WritePin(MOTOR_GPIO_PORT, MOTOR1_IN2, GPIO_PIN_SET);
        HAL_GPIO_WritePin(MOTOR_GPIO_PORT, MOTOR2_IN1, GPIO_PIN_SET);
        HAL_GPIO_WritePin(MOTOR_GPIO_PORT, MOTOR2_IN2, GPIO_PIN_RESET);
    }
    
    void turn_right(void) {
        HAL_GPIO_WritePin(MOTOR_GPIO_PORT, MOTOR1_IN1, GPIO_PIN_SET);
        HAL_GPIO_WritePin(MOTOR_GPIO_PORT, MOTOR1_IN2, GPIO_PIN_RESET);
        HAL_GPIO_WritePin(MOTOR_GPIO_PORT, MOTOR2_IN1, GPIO_PIN_RESET);
        HAL_GPIO_WritePin(MOTOR_GPIO_PORT, MOTOR2_IN2, GPIO_PIN_SET);
    }
    
    void stop_car(void) {
        HAL_GPIO_WritePin(MOTOR_GPIO_PORT, MOTOR1_IN1, GPIO_PIN_RESET);
        HAL_GPIO_WritePin(MOTOR_GPIO_PORT, MOTOR1_IN2, GPIO_PIN_RESET);
        HAL_GPIO_WritePin(MOTOR_GPIO_PORT, MOTOR2_IN1, GPIO_PIN_RESET);
        HAL_GPIO_WritePin(MOTOR_GPIO_PORT, MOTOR2_IN2, GPIO_PIN_RESET);
    }
    
    // 传感器读取与决策逻辑
    void track_car(void) {
        int left_sensor = HAL_GPIO_ReadPin(SENSOR_GPIO_PORT, LEFT_SENSOR_PIN);  // 读取左侧传感器状态
        int right_sensor = HAL_GPIO_ReadPin(SENSOR_GPIO_PORT, RIGHT_SENSOR_PIN);  // 读取右侧传感器状态
    
        if (left_sensor == GPIO_PIN_SET && right_sensor == GPIO_PIN_SET) {
            move_forward();  // 两个传感器都在黑线上,前进
        } 
        else if (left_sensor == GPIO_PIN_RESET && right_sensor == GPIO_PIN_SET) {
            turn_left();  // 只有右侧在黑线,左转
        } 
        else if (left_sensor == GPIO_PIN_SET && right_sensor == GPIO_PIN_RESET) {
            turn_right();  // 只有左侧在黑线,右转
        } 
        else {
            stop_car();  // 两个传感器都不在黑线上,停止
        }
    }
    
    int main(void) {
        HAL_Init();  // 初始化 HAL 库
    
        GPIO_Init();  // 初始化 GPIO 引脚
    
        while (1) {
            track_car();  // 根据传感器输入,控制小车运动
        }
    }
    

    代码解释

    1. GPIO 初始化

    GPIO_Init() 函数中,我们初始化了两个主要的硬件部分:

  • 电机控制引脚:用于控制电机的旋转方向,包括前进、后退、左转和右转。我们假设电机控制引脚连接到 GPIOB
  • 传感器引脚:用于读取两个红外传感器的状态,检测是否有黑线。我们假设传感器连接到 GPIOA
  • 2. 电机控制函数
  • move_forward():控制电机前进。通过设置适当的电机驱动引脚状态来使电机旋转。
  • move_backward():控制电机后退,反转电机的旋转方向。
  • turn_left():控制小车左转。左转时,左电机反向转动,右电机正向转动。
  • turn_right():控制小车右转,原理与左转相反。
  • stop_car():停止小车运动,将电机的所有控制引脚置为低电平。
  • 3. 传感器读取与决策逻辑
  • track_car():读取左右传感器的值并作出决策。
  • 如果两个传感器都检测到黑线,小车向前移动。
  • 如果左传感器检测到黑线而右传感器没有,小车向左转。
  • 如果右传感器检测到黑线而左传感器没有,小车向右转。
  • 如果两个传感器都未检测到黑线,则停止小车。
  • 4. 主循环

    main() 函数中,程序进入无限循环,不断读取传感器数据并根据判断结果控制小车的运动。每次通过 track_car() 来判断小车的动作。

    5. 总结

  • 该代码实现了一个基于 STM32 单片机的寻迹小车,通过两个红外传感器来检测轨迹并控制电机的运动。
  • 电机控制通过 GPIO 引脚实现,通过设置电机引脚的高低电平来改变电机的转动方向。
  • 传感器读取和决策逻辑是程序的核心,根据传感器的状态来判断小车是否偏离轨道,并调整行驶方向。
  • 作者:Katie。

    物联沃分享整理
    物联沃-IOTWORD物联网 » 单片机实现寻迹小车功能详解(附源码解析)

    发表回复