用STM32CubeIDE和L298N,从零搭建一个蓝牙遥控+红外循迹的智能小车(附完整代码)

张开发
2026/4/21 11:25:23 15 分钟阅读

分享文章

用STM32CubeIDE和L298N,从零搭建一个蓝牙遥控+红外循迹的智能小车(附完整代码)
用STM32CubeIDE和L298N从零构建蓝牙遥控红外循迹智能小车实战指南第一次拿到STM32开发板时看着密密麻麻的引脚和陌生的开发环境我完全不知道如何让它控制一个小车跑起来。经过三个月的摸索和五次硬件烧毁的教训终于总结出这套保姆级教程。本文将带你从零开始用最基础的硬件STM32F103C8T6核心板、L298N电机驱动、HC-05蓝牙模块和五路红外传感器搭建一个既能蓝牙遥控又能自动循迹的智能小车。1. 硬件准备与电路设计1.1 物料清单与选型建议在开始前请准备好以下硬件总成本约150元主控模块STM32F103C8T6最小系统板蓝色药丸板推荐理由性价比高社区资源丰富64KB Flash完全够用运动系统L298N电机驱动模块带散热片版本TT减速电机6V/200RPM 车轮套件18650电池盒两节串联感知系统五路红外循迹传感器TCRT5000注意选择带数字量输出的版本避免额外设计比较器电路通信模块HC-05蓝牙模块建议买已刷好AT固件的版本注意区分主从模式我们这里使用从机模式其他万用板铜柱车架杜邦线建议用20cm公对公公对母组合开关、扎带等辅助材料1.2 电路连接详解电路连接是初学者最容易出错的部分这里给出经过验证的可靠接法模块引脚连接注意事项L298NENA→PA0, IN1→PA1, IN2→PA2左侧电机控制线ENB→PA3, IN3→PA4, IN4→PA5右侧电机控制线HC-05蓝牙RX→PB10, TX→PB11需接3.3V5V会烧毁模块红外传感器左1→PC4, 左2→PC5数字输出直接接GPIO中→PB0, 右1→PB1, 右2→PB2建议加上10K上拉电阻关键提示电机驱动电源与单片机电源必须共地这是导致80%控制失效问题的根源。建议先用USB供电调试待基本功能验证后再切换为电池供电。2. STM32CubeIDE工程配置2.1 基础工程创建打开STM32CubeIDE选择Start new STM32 project在MCU选择器中输入STM32F103C8选择Tx系列配置时钟树HSE选择Crystal/Ceramic Resonator将HCLK设置为72MHz最大值系统核心中启用Serial Wire调试接口2.2 关键外设配置定时器PWM配置电机控制// TIM2 Channel1→PA0 (左电机PWM) // TIM2 Channel2→PA1 (右电机PWM) htim2.Instance TIM2; htim2.Init.Prescaler 71; // 1MHz计数频率 htim2.Init.CounterMode TIM_COUNTERMODE_UP; htim2.Init.Period 999; // 1kHz PWM频率 htim2.Init.ClockDivision TIM_CLOCKDIVISION_DIV1;串口配置蓝牙通信// USART3 PB10/PB11 huart3.Instance USART3; huart3.Init.BaudRate 9600; huart3.Init.WordLength UART_WORDLENGTH_8B; huart3.Init.StopBits UART_STOPBITS_1; huart3.Init.Parity UART_PARITY_NONE; huart3.Init.Mode UART_MODE_TX_RX; huart3.Init.HwFlowCtl UART_HWCONTROL_NONE;GPIO配置红外传感器将PC4、PC5、PB0-PB2设置为输入模式建议启用内部上拉GPIO_PULLUP3. 核心代码实现3.1 电机驱动模块化编程在Core/Src创建motor.c文件实现以下关键函数// 电机初始化 void Motor_Init(void) { HAL_TIM_PWM_Start(htim2, TIM_CHANNEL_1); // 左电机PWM HAL_TIM_PWM_Start(htim2, TIM_CHANNEL_2); // 右电机PWM } // 通用电机控制函数 void Motor_Control(uint8_t motor, int16_t speed) { speed (speed 100) ? 100 : ((speed -100) ? -100 : speed); if(motor LEFT_MOTOR) { __HAL_TIM_SET_COMPARE(htim2, TIM_CHANNEL_1, abs(speed)*10); HAL_GPIO_WritePin(IN1_GPIO_Port, IN1_Pin, (speed 0) ? GPIO_PIN_SET : GPIO_PIN_RESET); HAL_GPIO_WritePin(IN2_GPIO_Port, IN2_Pin, (speed 0) ? GPIO_PIN_RESET : GPIO_PIN_SET); } else { __HAL_TIM_SET_COMPARE(htim2, TIM_CHANNEL_2, abs(speed)*10); HAL_GPIO_WritePin(IN3_GPIO_Port, IN3_Pin, (speed 0) ? GPIO_PIN_SET : GPIO_PIN_RESET); HAL_GPIO_WritePin(IN4_GPIO_Port, IN4_Pin, (speed 0) ? GPIO_PIN_RESET : GPIO_PIN_SET); } }3.2 蓝牙指令解析在main.c中添加蓝牙回调处理uint8_t bluetooth_rx_data[1]; void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart huart3) { switch(bluetooth_rx_data[0]) { case F: // 前进 Motor_Control(LEFT_MOTOR, 70); Motor_Control(RIGHT_MOTOR, 70); break; case L: // 左转 Motor_Control(LEFT_MOTOR, -40); Motor_Control(RIGHT_MOTOR, 70); break; case S: // 停止 Motor_Control(LEFT_MOTOR, 0); Motor_Control(RIGHT_MOTOR, 0); break; // 其他指令... } HAL_UART_Receive_IT(huart3, bluetooth_rx_data, 1); } }3.3 红外循迹算法优化传统if-else判断方式在复杂路径下效果不佳建议采用状态机实现typedef enum { TRACK_LOST, // 丢失路径 TRACK_STRAIGHT, // 直行 TRACK_LEFT_CURVE, // 左弯道 TRACK_RIGHT_CURVE // 右弯道 } TrackState; TrackState track_detect(void) { uint8_t sensor_val 0; sensor_val | (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_4) 4); sensor_val | (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_5) 3); sensor_val | (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) 2); sensor_val | (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) 1); sensor_val | HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2); switch(sensor_val) { case 0b11100: return TRACK_LEFT_CURVE; case 0b11000: return TRACK_LEFT_CURVE; case 0b00111: return TRACK_RIGHT_CURVE; case 0b00011: return TRACK_RIGHT_CURVE; case 0b00100: return TRACK_STRAIGHT; default: return TRACK_LOST; } }4. 系统整合与调试技巧4.1 多模式切换实现在main.h中定义工作模式枚举typedef enum { MODE_MANUAL, // 蓝牙遥控模式 MODE_AUTO_TRACK, // 自动循迹模式 MODE_IDLE // 空闲模式 } WorkMode; extern WorkMode current_mode;在main.c的while循环中实现模式调度while (1) { switch(current_mode) { case MODE_MANUAL: // 蓝牙指令已在中断处理 break; case MODE_AUTO_TRACK: switch(track_detect()) { case TRACK_STRAIGHT: Motor_Control(LEFT_MOTOR, 60); Motor_Control(RIGHT_MOTOR, 60); break; case TRACK_LEFT_CURVE: Motor_Control(LEFT_MOTOR, 30); Motor_Control(RIGHT_MOTOR, 70); break; // 其他状态处理... } break; } HAL_Delay(50); // 控制循环频率 }4.2 常见问题排查指南电机不转检查L298N使能跳线帽是否接好用万用表测量电机端口是否有电压输出尝试直接给电机供电排除电机本身故障蓝牙无法连接确认模块已进入配对模式LED快闪手机端尝试使用蓝牙串口APP检查TX/RX是否接反循迹不准确调节传感器上的电位器改变灵敏度在白色背景上用黑色胶带测试传感器输出检查供电电压是否稳定建议5V单独供电4.3 性能优化建议PID控制算法在motor.c中实现简单的PID控制器让小车运动更平滑typedef struct { float Kp, Ki, Kd; float integral; float prev_error; } PID_Controller; float PID_Update(PID_Controller* pid, float error) { pid-integral error; float derivative error - pid-prev_error; pid-prev_error error; return pid-Kp*error pid-Ki*pid-integral pid-Kd*derivative; }电池管理添加电压检测功能当电压低于6.5V时自动减速void Battery_Check(void) { HAL_ADC_Start(hadc1); if(HAL_ADC_GetValue(hadc1) BATTERY_LOW) { Motor_Control(LEFT_MOTOR, 0); Motor_Control(RIGHT_MOTOR, 0); } }无线升级通过蓝牙实现固件更新需配合Bootloader完成基础功能后可以尝试添加超声波避障、OLED状态显示等扩展功能。这个项目的真正价值不在于小车本身而在于掌握如何将多个功能模块有机整合成一个完整系统的方法论。

更多文章