前言
前面几章学会了PWM,超声波等,现在刚好结合起来控制智能小车
1:环境
KEIL5.38
RT-THREAD 3.1.3
STM32F103C8T6
2:硬件配件(原来网上买的一套)
STM32F103C8T6 一个
MCU底板 一个
SG90 舵机 一个
红外避障 2个
hc-sr04 超声波 一个
降压模块 一个
电池盒及 2节14500电池
小车 亚克力 地板 一个
TTL 电机级 轮子 2个
万向轮 一个
其他 配件线 材料 若干
3:GPIO 配置
超声波 HC-SR04
PB15 TRIG 发送
PB14 ECHO 接收 中断
TIM2 计时器 配合超声波 测距
TIM4 PWM 已经用盖帽使能,值需要4CH PB6 PB7 PB8 PB9 控制 输出到L298N 控制电机 2个TTL电机
USART PA9 PA10 异步串口 用来打印日志,只写模式,
陀机 SG90 TIM3 PWM CH2 PB5 转角度
2个红外 避障 PA11 PA12 检测障碍物
按键 一个独立的 PA15 小车一开始是等待按键按一次 启动 巡航,如果再按一次,停止寻路巡航
4:上主要代码
先用MX 配置下,再手动修改下
gpio.c
/* USER CODE BEGIN Header */
/********************************************************************************* @file gpio.c* @brief This file provides code for the configuration* of all used GPIO pins.******************************************************************************* @attention** Copyright (c) 2025 STMicroelectronics.* All rights reserved.** This software is licensed under terms that can be found in the LICENSE file* in the root directory of this software component.* If no LICENSE file comes with this software, it is provided AS-IS.********************************************************************************/
/* USER CODE END Header *//* Includes ------------------------------------------------------------------*/
#include "gpio.h"
#include "main.h"
#include "tim.h"
/* USER CODE BEGIN 0 *//* USER CODE END 0 *//*----------------------------------------------------------------------------*/
/* Configure GPIO */
/*----------------------------------------------------------------------------*/
/* USER CODE BEGIN 1 */
#define TRIG_PORT GPIOB //TRIG
#define ECHO_PORT GPIOB //ECHO
#define TRIG_PIN GPIO_PIN_15 //TRIG
#define ECHO_PIN GPIO_PIN_14 //ECHO #define Ultrasonic_TimeOut 80 //80*1.7 =135 cmuint32_t g_echo_time = 0;uint32_t g_distance_ready = 0;
/* USER CODE END 1 *//** Configure pins as* Analog* Input* Output* EVENT_OUT* EXTI
*/
void MX_GPIO_Init(void)
{GPIO_InitTypeDef GPIO_InitStruct = {0};/* GPIO Ports Clock Enable */__HAL_RCC_GPIOC_CLK_ENABLE();__HAL_RCC_GPIOD_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_GPIOB_CLK_ENABLE();/*Configure GPIO pin Output Level */HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);//灭/*Configure GPIO pin : PC13 */GPIO_InitStruct.Pin = GPIO_PIN_13;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_PULLDOWN;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);/*Configure GPIO pin : PA15 */GPIO_InitStruct.Pin = GPIO_PIN_15;GPIO_InitStruct.Mode = GPIO_MODE_INPUT;GPIO_InitStruct.Pull = GPIO_PULLUP;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);//红外避障/*Configure GPIO pin : PA11 PA12 */GPIO_InitStruct.Pin = GPIO_PIN_11 |GPIO_PIN_12;GPIO_InitStruct.Mode = GPIO_MODE_INPUT;GPIO_InitStruct.Pull = GPIO_PULLUP;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);//dh addUltrasonic_Init();}/* USER CODE BEGIN 2 */
void Ultrasonic_Init(void)
{GPIO_InitTypeDef GPIO_InitStruct = {0};//HAL_NVIC_InitTypeDef NVIC_InitStruct = {0};/* 使能 GPIO 和 AFIO 时钟 */// __HAL_RCC_GPIOB_CLK_ENABLE();__HAL_RCC_AFIO_CLK_ENABLE(); // STM32F1 系列需要使能 AFIO/* 配置 TRIG 引脚 (PB15) - 推挽输出 */GPIO_InitStruct.Pin = GPIO_PIN_15;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);/* 配置 ECHO 引脚 (PB14) - 下拉输入 */GPIO_InitStruct.Pin = GPIO_PIN_14;GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING; // 上升和下降沿触发中断GPIO_InitStruct.Pull = GPIO_PULLDOWN;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);/* 配置 EXTI 中断 (PB14 对应 EXTI14) */HAL_NVIC_SetPriority(EXTI15_10_IRQn, 2, 0); // 抢占优先级2,子优先级2HAL_NVIC_EnableIRQ(EXTI15_10_IRQn); // 使能中断
}/* EXTI 中断处理函数 */
void EXTI15_10_IRQHandler(void)
{HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_14); // 调用 HAL 库中断处理函数
}/* 回调函数:在 HAL_GPIO_EXTI_IRQHandler 中被调用 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{if (GPIO_Pin == GPIO_PIN_14){/* 处理超声波 ECHO 信号 */if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_14) == GPIO_PIN_SET){/* 上升沿:启动计时器 */__HAL_TIM_SET_COUNTER(&htim2, 0); // 重置计数器HAL_TIM_Base_Start(&htim2); // 启动计时器}else{/* 下降沿:停止计时器并计算时间 */HAL_TIM_Base_Stop(&htim2); // 停止计时器g_echo_time = __HAL_TIM_GET_COUNTER(&htim2); // 获取计数值g_distance_ready = RT_TRUE; // 标记距离测量完成}}
}/* 测量超声波距离 */
uint16_t Ultrasonic_measure_distance(void)
{// float distance = -1;g_distance_ready = RT_FALSE;/* 发送触发信号 (至少10us高电平) */HAL_GPIO_WritePin(TRIG_PORT, GPIO_PIN_15, GPIO_PIN_SET);// HAL_Delay(1); // 延时1ms,确保足够长rt_hw_us_delay(20); // 持续20us确保触发成功HAL_GPIO_WritePin(TRIG_PORT, GPIO_PIN_15, GPIO_PIN_RESET);/* 等待测量完成 (超时时间50ms) */uint32_t start_time = rt_tick_get();//HAL_GetTick();while (!g_distance_ready && (rt_tick_get() - start_time) < Ultrasonic_TimeOut) //HAL_GetTick(){rt_thread_mdelay(1); // RT-Thread 延时,释放 CPU}if (g_distance_ready){/* 计算距离 (单位: cm) */// distance = (float)g_echo_time * 0.034 / 2;g_distance_ready = RT_FALSE; // 清除标志return (uint16_t)(g_echo_time*1.7f);}else{return (uint16_t)(50*1.7f); //不返回默认距离}// return 0;
}uint8_t Left_Irobstacle_Get(void)
{return (uint8_t)HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_11);
}uint8_t Right_Irobstacle_Get(void)
{return (uint8_t)HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_12);
}/* USER CODE END 2 */
tim.c
/* USER CODE BEGIN Header */
/********************************************************************************* @file tim.c* @brief This file provides code for the configuration* of the TIM instances.******************************************************************************* @attention** Copyright (c) 2025 STMicroelectronics.* All rights reserved.** This software is licensed under terms that can be found in the LICENSE file* in the root directory of this software component.* If no LICENSE file comes with this software, it is provided AS-IS.********************************************************************************/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "tim.h"/* USER CODE BEGIN 0 *//* USER CODE END 0 */TIM_HandleTypeDef htim2;
TIM_HandleTypeDef htim3;
TIM_HandleTypeDef htim4;#define SERVO_TIM_PERIOD 19999 // 定时器周期 (20000-1 = 20ms = 50Hz) TIM3
#define SERVO_TIM_PRESCALER 71 // 预分频器 (72MHz/72=1MHz → 1计数=1us) TIM3/* TIM2 init function */
void MX_TIM2_Init(void)
{/* USER CODE BEGIN TIM2_Init 0 *//* USER CODE END TIM2_Init 0 */TIM_ClockConfigTypeDef sClockSourceConfig = {0};TIM_MasterConfigTypeDef sMasterConfig = {0};/* USER CODE BEGIN TIM2_Init 1 *//* USER CODE END TIM2_Init 1 */ // 72MHz/7200 = 1/100 * 1000*1000 = 10*1000 HZ//1/(10*1000)Hz = 1 ms *0.1 = 100us = 0.1ms// 5000 *100us = 500ms //Period 一个单位 =100us =0.1mshtim2.Instance = TIM2;htim2.Init.Prescaler = 7200-1;htim2.Init.CounterMode = TIM_COUNTERMODE_UP;htim2.Init.Period = 5000;htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;if (HAL_TIM_Base_Init(&htim2) != HAL_OK){Error_Handler();}sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK){Error_Handler();}sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK){Error_Handler();}/* USER CODE BEGIN TIM2_Init 2 *//* USER CODE END TIM2_Init 2 */}void MX_TIM3_Init(void){/* USER CODE BEGIN TIM33_Init 0 *//* USER CODE END TIM3_Init 0 */TIM_MasterConfigTypeDef sMasterConfig = {0};TIM_OC_InitTypeDef sConfigOC = {0};/* USER CODE BEGIN TIM3_Init 1 *//* USER CODE END TIM3_Init 1 */htim3.Instance = TIM3;htim3.Init.Prescaler = SERVO_TIM_PRESCALER;//36-1;//psc; //时钟预分频数htim3.Init.CounterMode = TIM_COUNTERMODE_UP;htim3.Init.Period = SERVO_TIM_PERIOD ;//100 - 1;//arr;//自动重装值htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;if (HAL_TIM_PWM_Init(&htim3) != HAL_OK){Error_Handler();}sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK){Error_Handler();}////////////////////////////////////////////////////
// sConfigOC.OCMode = TIM_OCMODE_PWM2;
// sConfigOC.Pulse = 0; // 初始占空比:0%
// sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; //有些SG90是高的,可能内部有反转电路,有点用低的,不转时可以 都试下
// sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;sConfigOC.OCMode = TIM_OCMODE_PWM2;sConfigOC.Pulse = 18500; // 90度初始值(20000 - 1500)sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW;sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; // 启用CCR2预装载(等效于标准库的TIM_OCPreload_Enable)// sConfigOC.OutputState = TIM_OUTPUTSTATE_ENABLE;/////////////////////////////////////////////////////if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_2) != HAL_OK){Error_Handler();}/* USER CODE BEGIN TIM3_Init 2 */// 使能比较值预装载(与标准库的TIM_OC2PreloadConfig一致)
// TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);/* USER CODE END TIM3_Init 2 */HAL_TIM_MspPostInit(&htim3);
}
/* TIM4 init function */
void MX_TIM4_Init(void)
{/* USER CODE BEGIN TIM4_Init 0 *//* USER CODE END TIM4_Init 0 */TIM_MasterConfigTypeDef sMasterConfig = {0};TIM_OC_InitTypeDef sConfigOC = {0};/* USER CODE BEGIN TIM4_Init 1 *//* USER CODE END TIM4_Init 1 */htim4.Instance = TIM4;htim4.Init.Prescaler = 36-1;//psc; //时钟预分频数htim4.Init.CounterMode = TIM_COUNTERMODE_UP;htim4.Init.Period = 100 - 1;//arr;//自动重装值htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;if (HAL_TIM_PWM_Init(&htim4) != HAL_OK){Error_Handler();}sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK){Error_Handler();}sConfigOC.OCMode = TIM_OCMODE_PWM1;sConfigOC.Pulse = 0; // 初始占空比:0%sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;if (HAL_TIM_PWM_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_1) != HAL_OK){Error_Handler();}if (HAL_TIM_PWM_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_2) != HAL_OK){Error_Handler();}if (HAL_TIM_PWM_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_3) != HAL_OK){Error_Handler();}if (HAL_TIM_PWM_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_4) != HAL_OK){Error_Handler();}/* USER CODE BEGIN TIM4_Init 2 *//* USER CODE END TIM4_Init 2 */HAL_TIM_MspPostInit(&htim4);}void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{if(tim_baseHandle->Instance==TIM2){/* USER CODE BEGIN TIM2_MspInit 0 *//* USER CODE END TIM2_MspInit 0 *//* TIM2 clock enable */__HAL_RCC_TIM2_CLK_ENABLE();/* USER CODE BEGIN TIM2_MspInit 1 *//* USER CODE END TIM2_MspInit 1 */}
}void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef* tim_pwmHandle)
{if(tim_pwmHandle->Instance==TIM4){/* USER CODE BEGIN TIM4_MspInit 0 *//* USER CODE END TIM4_MspInit 0 *//* TIM4 clock enable */__HAL_RCC_TIM4_CLK_ENABLE();/* USER CODE BEGIN TIM4_MspInit 1 *//* USER CODE END TIM4_MspInit 1 */}else if(tim_pwmHandle->Instance==TIM3){/* USER CODE BEGIN TIM4_MspInit 0 *//* USER CODE END TIM4_MspInit 0 *//* TIM4 clock enable */__HAL_RCC_TIM3_CLK_ENABLE();/* USER CODE BEGIN TIM4_MspInit 1 *//* USER CODE END TIM4_MspInit 1 */}}
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle)
{GPIO_InitTypeDef GPIO_InitStruct = {0};if(timHandle->Instance==TIM4){/* USER CODE BEGIN TIM4_MspPostInit 0 *//* USER CODE END TIM4_MspPostInit 0 */__HAL_RCC_GPIOB_CLK_ENABLE();/**TIM4 GPIO ConfigurationPB6 ------> TIM4_CH1PB7 ------> TIM4_CH2PB8 ------> TIM4_CH3PB9 ------> TIM4_CH4*/GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);/* USER CODE BEGIN TIM4_MspPostInit 1 */// 启动TIM4的PWM输出HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_1);HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_2);HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_3);HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_4);/* USER CODE END TIM4_MspPostInit 1 */}else if(timHandle->Instance==TIM3){__HAL_RCC_GPIOB_CLK_ENABLE();__HAL_RCC_AFIO_CLK_ENABLE();// 配置TIM3部分重映射 (TIM3_CH2 -> PB5)__HAL_AFIO_REMAP_TIM3_PARTIAL();GPIO_InitStruct.Pin = GPIO_PIN_5;// PB5GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);/* USER CODE BEGIN TIM3_MspPostInit 1 */// 启动TIM3的PWM输出
// HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2);if(HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2) != HAL_OK){Error_Handler(); // 若启动失败,在此处调试}/* USER CODE END TIM3_MspPostInit 1 */}}void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle)
{if(tim_baseHandle->Instance==TIM2){/* USER CODE BEGIN TIM2_MspDeInit 0 *//* USER CODE END TIM2_MspDeInit 0 *//* Peripheral clock disable */__HAL_RCC_TIM2_CLK_DISABLE();/* USER CODE BEGIN TIM2_MspDeInit 1 *//* USER CODE END TIM2_MspDeInit 1 */}
}void HAL_TIM_PWM_MspDeInit(TIM_HandleTypeDef* tim_pwmHandle)
{if(tim_pwmHandle->Instance==TIM4){/* USER CODE BEGIN TIM4_MspDeInit 0 *//* USER CODE END TIM4_MspDeInit 0 *//* Peripheral clock disable */__HAL_RCC_TIM4_CLK_DISABLE();/* USER CODE BEGIN TIM4_MspDeInit 1 *//* USER CODE END TIM4_MspDeInit 1 */}else if(tim_pwmHandle->Instance==TIM3){/* USER CODE BEGIN TIM4_MspDeInit 0 *//* USER CODE END TIM4_MspDeInit 0 *//* Peripheral clock disable */__HAL_RCC_TIM3_CLK_DISABLE();/* USER CODE BEGIN TIM4_MspDeInit 1 *//* USER CODE END TIM4_MspDeInit 1 */}
}/* USER CODE BEGIN 1 *//* USER CODE END 1 */
my_thread.c
#include "my_thread.h"
#include "gpio.h"
#include "tim.h"
volatile bool g_bRun = false; //是否运行//舵机
#define SERVO_INIT_ANGLE 90 //初始化90度
// 当前角度存储
static uint16_t currentAngle = SERVO_INIT_ANGLE; //当前90都
// 舵机转动速度(秒/60度)
#define SERVO_SPEED 150 //150ms 150毫秒转60度#define SERVO_TURN_LEFT 171 //左边
#define SERVO_TURN_STRAIGHT 90 //真的 正面
#define SERVO_TURN_RIGHT 9 //右边static rt_thread_t dis_thread = RT_NULL;
static void dis_thread_entry(void* parameter){// HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);//亮// rt_thread_delay(500);
// uint32_t dis_count =0;while(1){uint16_t dis = Ultrasonic_measure_distance();rt_thread_delay(100);rt_kprintf("[dis] running on[%d][%d]==>\n",rt_tick_get(),dis);rt_thread_delay(1013); }
}//按键 GPIO 设置
#define KEY_PORT GPIOA
#define KEY_PIN GPIO_PIN_15static rt_thread_t key_thread = RT_NULL;
static void key_thread_entry(void* parameter){rt_kprintf("[key] ready loop\n ");
// uint32_t key_count =0;while(1){if (HAL_GPIO_ReadPin(KEY_PORT, KEY_PIN) == 0){rt_thread_delay(20);while (HAL_GPIO_ReadPin(KEY_PORT, KEY_PIN) == 0){rt_thread_delay(1);}bool bflag = g_bRun;g_bRun =!bflag;// ++key_count; // g_bRun = (key_count&1)>0?true:false;rt_kprintf("[key] KEY1 DOWN=>UP[%d][%d]\n ",rt_tick_get(),(int)bflag);}else{rt_thread_delay(2);}}
}int my_rt_thread_init(void){
// dis_thread = /* 线程控制块指针 */
// rt_thread_create( "dis", /* 线程名字 */
// dis_thread_entry, /* 线程入口函数 */
// RT_NULL, /* 线程入口函数参数 */
// 512*2, /* 线程栈大小 */
// 3, /* 线程的优先级 */
// 40); /* 线程时间片 */
// /* 启动线程,开启调度 */
// if (dis_thread != RT_NULL){
// if(RT_EOK != rt_thread_startup(dis_thread)){
// rt_kprintf("[fail]dis_thread create \n");
// return -1;
// }
// }
// else
// return -1;key_thread = /* 线程控制块指针 */rt_thread_create( "key", /* 线程名字 */key_thread_entry, /* 线程入口函数 */RT_NULL, /* 线程入口函数参数 */512, /* 线程栈大小 */3, /* 线程的优先级 */20); /* 线程时间片 *//* 启动线程,开启调度 */if (key_thread != RT_NULL){if(RT_EOK != rt_thread_startup(key_thread)){rt_kprintf("[fail]key_thread create \n");return -1;}}elsereturn -1;return RT_EOK;
}#define VAILD_DIS_CM 18 //15 厘米
#define CAR_BRAKE_TIME 800 //ms 毫秒 //小车刹车时间 毫秒#define CAR_BRAKE(X) makerobo_brake(CAR_BRAKE_TIME);X=false;#define CAR_RUN(X) X=true;static bool b_car_cur_state = false; //false 停止 true 运动
uint32_t g_log_flag =0;
uint32_t tmpflag =0;
void control_run( uint16_t dis_cm){g_log_flag |=1<<5;if(b_car_cur_state){CAR_BRAKE(b_car_cur_state) //makerobo_brake(CAR_BRAKE_TIME); //刹车}makerobo_back(70,500); //后退CAR_BRAKE(b_car_cur_state) //makerobo_brake(CAR_BRAKE_TIME); //刹车g_log_flag |=1<<9;//超声波查看左边Servo_SetAngle(SERVO_TURN_LEFT,true); //转到左边uint16_t left_dis_cm = Ultrasonic_measure_distance(); //厘米rt_thread_delay(100);Servo_SetAngle(SERVO_TURN_RIGHT,true); //转到右边uint16_t right_dis_cm = Ultrasonic_measure_distance(); //厘米if(left_dis_cm > VAILD_DIS_CM && right_dis_cm > VAILD_DIS_CM){ //(left_dis_cm == 0 && right_dis_cm ==0) || (//左边 右边没障碍物 50毫秒内没反应 80*1.7 =135cm内没右if(dis_cm&1) {makerobo_Left(70,500); //左转}else{makerobo_Right(70,500);//右转}CAR_BRAKE(b_car_cur_state)//makerobo_brake(CAR_BRAKE_TIME); }else if(left_dis_cm > VAILD_DIS_CM ){ //|| left_dis_cm== 0if(b_car_cur_state){CAR_BRAKE(b_car_cur_state) //makerobo_brake(CAR_BRAKE_TIME); //刹车}makerobo_back(70,500); //后退CAR_BRAKE(b_car_cur_state) //makerobo_brake(CAR_BRAKE_TIME); //刹车makerobo_Left(70,700);CAR_BRAKE(b_car_cur_state)//makerobo_brake(CAR_BRAKE_TIME);}else if(right_dis_cm > VAILD_DIS_CM ){ //|| right_dis_cm ==0if(b_car_cur_state){CAR_BRAKE(b_car_cur_state) //makerobo_brake(CAR_BRAKE_TIME); //刹车}makerobo_back(70,500); //后退CAR_BRAKE(b_car_cur_state) //makerobo_brake(CAR_BRAKE_TIME); //刹车makerobo_Right(70,700);CAR_BRAKE(b_car_cur_state)//makerobo_brake(CAR_BRAKE_TIME); }g_log_flag |=1<<10;
}//红外避障
void control_turn_by_ir(bool bLeft){g_log_flag |=1<<6;Servo_SetAngle(bLeft?SERVO_TURN_LEFT:SERVO_TURN_RIGHT,true); //转到左边uint16_t left_dis_cm = Ultrasonic_measure_distance(); //厘米rt_thread_delay(100);g_log_flag |=1<<9;if(left_dis_cm > VAILD_DIS_CM ){ //|| left_dis_cm == 0if(bLeft) makerobo_Left(70,700);else makerobo_Right(70,700);CAR_BRAKE(b_car_cur_state)//makerobo_brake(CAR_BRAKE_TIME);}else if(left_dis_cm >= VAILD_DIS_CM/2){//急转if(bLeft){ makerobo_Spin_Left(60,500);}else{makerobo_Spin_Right(60,500);}CAR_BRAKE(b_car_cur_state)}else{//后退if(b_car_cur_state){CAR_BRAKE(b_car_cur_state) //makerobo_brake(CAR_BRAKE_TIME); //刹车}makerobo_back(70,500); //后退CAR_BRAKE(b_car_cur_state) //makerobo_brake(CAR_BRAKE_TIME); //刹车}g_log_flag |=1<<10;
}//void control_turn_right(){
// Servo_SetAngle(SERVO_TURN_RIGHT,true); //转到左边
// uint16_t right_dis_cm = Ultrasonic_measure_distance(); //厘米
// rt_thread_delay(100);
// if(right_dis_cm > VAILD_DIS_CM || right_dis_cm == 0){
// makerobo_Right(70,700);
// CAR_BRAKE(b_car_cur_state)//makerobo_brake(CAR_BRAKE_TIME);
// }else{
// //后退
// if(b_car_cur_state){
// CAR_BRAKE(b_car_cur_state) //makerobo_brake(CAR_BRAKE_TIME); //刹车
// }
// makerobo_back(70,500); //后退
// CAR_BRAKE(b_car_cur_state) //makerobo_brake(CAR_BRAKE_TIME); //刹车
// }
//}void my_main_fun_test(void){while(1){// 循环测试0°→90°→180°→90°Servo_SetAngle(SERVO_TURN_RIGHT,true); //9rt_thread_mdelay(1000); // 延时1秒(RT-Thread 线程安全延时)Servo_SetAngle(SERVO_TURN_STRAIGHT,true); //转到90度 rt_thread_mdelay(1000);Servo_SetAngle(SERVO_TURN_LEFT,true);rt_thread_mdelay(1000);Servo_SetAngle(SERVO_TURN_STRAIGHT,true); //转到90度 rt_thread_mdelay(1000);}
}void my_main_fun(void){
// HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);//亮
// rt_thread_delay(500);
// /// uint16_t dis = Ultrasonic_measure_distance();
//// rt_thread_delay(100);
// HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET); ////灭
// rt_kprintf("[mian] on[%d]==>\n",rt_tick_get());
// rt_thread_delay(1679); rt_kprintf("my_main_fun [0]\n");Servo_InitAngle_90();rt_kprintf("my_main_fun [1]\n");rt_thread_delay(300);
// Servo_SetAngle(SERVO_TURN_LEFT,true); //转到左边
// rt_thread_delay(1500);
// Servo_InitAngle_90();
// rt_thread_delay(500);
// rt_kprintf("my_main_fun [2]\n");uint32_t tmpcount =0;bool b_laststate = false;rt_kprintf("my_main_fun [3]\n");while(1){// bool bStopToRun = false;tmpflag =0;g_log_flag=0;bool b_Run = g_bRun;if(b_laststate != b_Run){b_laststate= b_Run;if(!b_Run){//车子停止 从动到停// rt_kprintf("my_main_fun stop->run[1]\n");CAR_BRAKE(b_car_cur_state)//makerobo_brake(CAR_BRAKE_TIME); continue;}else{ //停止到运行// bStopToRun = true ;}}tmpflag |=1;if(!b_Run){rt_thread_delay(7); //停止 就休眠7毫秒}else {//runtmpflag |=2;//超声波检测Servo_SetAngle(SERVO_TURN_STRAIGHT,true); //转到90度 tmpflag |=4;uint16_t dis_cm = Ultrasonic_measure_distance(); //厘米tmpflag |=8;uint8_t stace_left = Left_Irobstacle_Get();//hongwai left //红外左边tmpflag |=16;uint8_t stace_right = Right_Irobstacle_Get();//hongwai right//红外右边if(dis_cm < VAILD_DIS_CM ){ //超声波 检测前面有障碍物 //dis_cm > 0 && tmpflag |=(1<<5);g_log_flag =1;control_run(dis_cm);tmpflag |=(1<<6);//左右都有障碍物 继续退}else if(stace_left >0 & stace_right > 0 ){ //没有障碍物g_log_flag =2;tmpflag |=(1<<7);makerobo_run(70,10);CAR_RUN(b_car_cur_state)tmpflag |=(1<<8);}else if(stace_left >0){ //往左边转//control_run(dis_cm);g_log_flag =3;tmpflag |=(1<<9);control_turn_by_ir(true);tmpflag |=(1<<10);}else{//g_log_flag =4;tmpflag |=(1<<11);control_turn_by_ir(false); //往右边转tmpflag |=(1<<12);}// rt_kprintf("my_main_fun[%d][%d][%d]\n",++tmpcount,tmpflag,g_log_flag);// rt_thread_delay(300); //停止 就休眠7毫秒}}//end while}void Servo_InitAngle_90(void)
{//TIM_SetCompare2(TIM3,90 / 180 * 2000 +500);//__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, SERVO_INIT_ANGLE / 180 * 2000 +500);//__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, SERVO_INIT_ANGLE * 2000/ 180 +500);__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, SERVO_INIT_ANGLE * 100/ 9 +500); //公式简化
}
//
/*** 设置舵机角度并等待转动完成* @param angle 目标角度 (0-180度)* @param wait 是否等待转动完成*/
void Servo_SetAngle(uint16_t angle, bool wait)
{ // 角度范围限制// if (angle < 0) angle = 0;if (angle > 180) angle = 180;// 计算角度差uint16_t deltaAngle = abs(angle - currentAngle);// 仅在角度变化时更新PWM输出if (deltaAngle > 0) { // 添加一个小阈值避免浮点数精度问题// uint16_t pulseWidth = (uint16_t)((float)angle / 180.0f * 2000.0f + 500.0f);//uint16_t pulseWidth = (uint16_t)(angle*100.0f/9.0f + 500.0f);uint16_t pulseWidth = (uint16_t)(angle*100/9 + 500);// HAL_TIM_SetCompare2(TIM3, pulseWidth);__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, pulseWidth);currentAngle = angle;// 如果需要等待转动完成if (wait) {// 计算转动时间(毫秒)// uint32_t delayTime = (uint32_t)((deltaAngle / 60.0f) * SERVO_SPEED );//* 1000//uint32_t delayTime = (uint32_t)((deltaAngle / 60.0f) * SERVO_SPEED )//uint32_t delayTime = (uint32_t)(deltaAngle*SERVO_SPEED / 60)+50+(deltaAngle>90?50:0); //增加50毫秒 //角度大再增加50毫秒uint32_t delayTime = deltaAngle*3+ (deltaAngle/40)*25+30; //优化版rt_thread_delay(delayTime); // 等待舵机转动完成 //return (rt_tick_t)(ms * RT_TICK_PER_SECOND / 1000);}}
}// (uint16_t)(angle / 180.0f * 2000.0f + 500.0f);
//即脉冲宽度范围为 500μs ~ 2500μs,对应角度范围 0° ~ 180°
//500.0f 是 0 度对应的脉冲宽度(基础值)
//将角度值(0-180 度)转换为 0-1 之间的比例系数
//2000.0f 是脉冲宽度的总变化范围(2500μs - 500μs = 2000μs)。
//例如:90 度 → 0.5 × 2000 = 1000μs(相对于 0 度的偏移) //
//0° (0 / 180) × 2000 + 500 = 0 + 500 500 0 度脉冲宽度
//45° (45 / 180) × 2000 + 500 = 500 + 500 1000 45 度脉冲宽度
//90° (90 / 180) × 2000 + 500 = 1000 + 500 1500 90 度脉冲宽度
//180° (180 / 180) × 2000 + 500 = 2000 + 500 2500 180 度脉冲宽度
////>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#define CAR_MAX_SPEED 100
//小车控制
/*** 设置四路电机PWM输出* @param left1_speed 左电机1速度 (0-100)* @param left2_speed 左电机2速度 (0-100)* @param right1_speed 右电机1速度 (0-100)* @param right2_speed 右电机2速度 (0-100)*/
void robot_speed(uint8_t left1_speed, uint8_t left2_speed, uint8_t right1_speed, uint8_t right2_speed)
{//left1_speed =left2_speed=right1_speed=right2_speed =0;__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1, left1_speed);__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_2, left2_speed);__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_3, right1_speed);__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_4, right2_speed);// 将0-100的速度值映射到TIM4的PWM范围
// uint16_t max_pulse = __HAL_TIM_GET_AUTORELOAD(&htim4);
// uint16_t pulse1 = (uint16_t)(left1_speed * max_pulse / 100);
// uint16_t pulse2 = (uint16_t)(left2_speed * max_pulse / 100);
// uint16_t pulse3 = (uint16_t)(right1_speed * max_pulse / 100);
// uint16_t pulse4 = (uint16_t)(right2_speed * max_pulse / 100);// 设置TIM4四个通道的PWM占空比
// __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1, pulse1);
// __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_2, pulse2);
// __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_3, pulse3);
// __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_4, pulse4);
}/*** 机器人前进* @param speed 速度值 (0-100)* @param time 运行时间 (毫秒)*/
void makerobo_run(uint8_t speed, uint16_t time)
{// 限制速度范围if (speed > CAR_MAX_SPEED) speed = CAR_MAX_SPEED;// if (speed < 0) speed = 0;robot_speed(speed, 0, speed, 0);rt_thread_mdelay(time); // 使用RT-Thread延时// robot_speed(0, 0, 0, 0); // 取消注释可自动停止
}/*** 机器人刹车* @param time 刹车时间 (毫秒)*/
void makerobo_brake(uint16_t time)
{robot_speed(0, 0, 0, 0);rt_thread_mdelay(time);
}/*** 机器人左转 (差速)* @param speed 速度值 (0-100)* @param time 运行时间 (毫秒)*/
void makerobo_Left(uint8_t speed, uint16_t time)
{if (speed > CAR_MAX_SPEED) speed = CAR_MAX_SPEED;// if (speed < 0) speed = 0;robot_speed(0, 0, speed, 0);rt_thread_mdelay(time);// robot_speed(0, 0, 0, 0);
}/*** 机器人左旋转 (原地)* @param speed 速度值 (0-100)* @param time 运行时间 (毫秒)*/
void makerobo_Spin_Left(uint8_t speed, uint16_t time)
{if (speed > CAR_MAX_SPEED) speed = CAR_MAX_SPEED;// if (speed < 0) speed = 0;robot_speed(0, speed, speed, 0);rt_thread_mdelay(time);// robot_speed(0, 0, 0, 0);
}/*** 机器人右转 (差速)* @param speed 速度值 (0-100)* @param time 运行时间 (毫秒)*/
void makerobo_Right(uint8_t speed, uint16_t time)
{if (speed > CAR_MAX_SPEED) speed = CAR_MAX_SPEED;// if (speed < 0) speed = 0;robot_speed(speed, 0, 0, 0);rt_thread_mdelay(time);// robot_speed(0, 0, 0, 0);
}/*** 机器人右旋转 (原地)* @param speed 速度值 (0-100)* @param time 运行时间 (毫秒)*/
void makerobo_Spin_Right(uint8_t speed, uint16_t time)
{if (speed > CAR_MAX_SPEED) speed = CAR_MAX_SPEED;// if (speed < 0) speed = 0;robot_speed(speed, 0, 0, speed);rt_thread_mdelay(time);// robot_speed(0, 0, 0, 0);
}/*** 机器人后退* @param speed 速度值 (0-100)* @param time 运行时间 (毫秒)*/
void makerobo_back(uint8_t speed, uint16_t time)
{if (speed > CAR_MAX_SPEED) speed = CAR_MAX_SPEED;// if (speed < 0) speed = 0;robot_speed(0, speed, 0, speed);rt_thread_mdelay(time);// robot_speed(0, 0, 0, 0);
}
main函数
int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit */HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2); // 设置中断优先级组为2 2bit 2bit //4 级抢占优先级(0-3),4 级子优先级/* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_TIM2_Init();MX_TIM3_Init();MX_TIM4_Init();MX_USART1_UART_Init();/* USER CODE BEGIN 2 */rt_kprintf("main runining [1]\n");// uint32_t led_count =0;rt_thread_delay(10);my_rt_thread_init();rt_thread_delay(10);rt_kprintf("main runining [2]\n");/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */// while (1){/* USER CODE END WHILE */my_main_fun();// my_main_fun_test();/* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}
总结下:有问题
可以对比.map的地址 ,快速定位问题坐在代码的位置
解析工具 GO 些的 (只针对是F103C8T6,其他不保证有效,地址不一样)
package mainimport ("bytes""flag""fmt""os""regexp""strings"
)// 错误类型常量
const (ERROR_NONE = iotaERROR_MEMORY_MANAGEMENT = iotaERROR_BUS_FAULT = iotaERROR_USAGE_FAULT = iotaERROR_HARD_FAULT = iotaERROR_DEBUG = iota
)// 错误信息结构体
type FaultInfo struct {ErrorType intPSR uint32PC uint32LR uint32FaultAddress uint32CFSR uint32HFSR uint32DFSR uint32MMFAR uint32BFAR uint32AFSR uint32R0 uint32R1 uint32R2 uint32R3 uint32R12 uint32
}// 从文件读取错误信息(处理特殊分隔符)
func readFaultInfoFromFile(filePath string) (*FaultInfo, error) {file, err := os.Open(filePath)if err != nil {return nil, err}defer file.Close()fault := &FaultInfo{}// 读取整个文件内容data, err := os.ReadFile(filePath)if err != nil {return nil, err}// 使用特殊字符分割数据lines := bytes.Split(data, []byte{0x01}) // 分割字符为 0x01 (SOH)// 定义正则表达式模式,用于匹配寄存器值psrRegex := regexp.MustCompile(`psr:\s*0x([0-9A-Fa-f]+)`)pcRegex := regexp.MustCompile(`pc:\s*0x([0-9A-Fa-f]+)`)lrRegex := regexp.MustCompile(`lr:\s*0x([0-9A-Fa-f]+)`)cfsrRegex := regexp.MustCompile(`cfsr:\s*0x([0-9A-Fa-f]+)`)hfsrRegex := regexp.MustCompile(`hfsr:\s*0x([0-9A-Fa-f]+)`)dfsrRegex := regexp.MustCompile(`dfsr:\s*0x([0-9A-Fa-f]+)`)mmfarRegex := regexp.MustCompile(`mmfar:\s*0x([0-9A-Fa-f]+)`)bfarRegex := regexp.MustCompile(`bfar:\s*0x([0-9A-Fa-f]+)`)afsrRegex := regexp.MustCompile(`afsr:\s*0x([0-9A-Fa-f]+)`)r0Regex := regexp.MustCompile(`r00?:\s*0x([0-9A-Fa-f]+)`)r1Regex := regexp.MustCompile(`r0?1:\s*0x([0-9A-Fa-f]+)`)r2Regex := regexp.MustCompile(`r0?2:\s*0x([0-9A-Fa-f]+)`)r3Regex := regexp.MustCompile(`r0?3:\s*0x([0-9A-Fa-f]+)`)r12Regex := regexp.MustCompile(`r12:\s*0x([0-9A-Fa-f]+)`)// 处理每一行for _, line := range lines {strLine := strings.TrimSpace(string(line))if strLine == "" {continue}if matches := psrRegex.FindStringSubmatch(strLine); len(matches) > 1 {fmt.Sscanf(matches[1], "%x", &fault.PSR)} else if matches := pcRegex.FindStringSubmatch(strLine); len(matches) > 1 {fmt.Sscanf(matches[1], "%x", &fault.PC)} else if matches := lrRegex.FindStringSubmatch(strLine); len(matches) > 1 {fmt.Sscanf(matches[1], "%x", &fault.LR)} else if matches := cfsrRegex.FindStringSubmatch(strLine); len(matches) > 1 {fmt.Sscanf(matches[1], "%x", &fault.CFSR)} else if matches := hfsrRegex.FindStringSubmatch(strLine); len(matches) > 1 {fmt.Sscanf(matches[1], "%x", &fault.HFSR)} else if matches := dfsrRegex.FindStringSubmatch(strLine); len(matches) > 1 {fmt.Sscanf(matches[1], "%x", &fault.DFSR)} else if matches := mmfarRegex.FindStringSubmatch(strLine); len(matches) > 1 {fmt.Sscanf(matches[1], "%x", &fault.MMFAR)} else if matches := bfarRegex.FindStringSubmatch(strLine); len(matches) > 1 {fmt.Sscanf(matches[1], "%x", &fault.BFAR)} else if matches := afsrRegex.FindStringSubmatch(strLine); len(matches) > 1 {fmt.Sscanf(matches[1], "%x", &fault.AFSR)} else if matches := r0Regex.FindStringSubmatch(strLine); len(matches) > 1 {fmt.Sscanf(matches[1], "%x", &fault.R0)} else if matches := r1Regex.FindStringSubmatch(strLine); len(matches) > 1 {fmt.Sscanf(matches[1], "%x", &fault.R1)} else if matches := r2Regex.FindStringSubmatch(strLine); len(matches) > 1 {fmt.Sscanf(matches[1], "%x", &fault.R2)} else if matches := r3Regex.FindStringSubmatch(strLine); len(matches) > 1 {fmt.Sscanf(matches[1], "%x", &fault.R3)} else if matches := r12Regex.FindStringSubmatch(strLine); len(matches) > 1 {fmt.Sscanf(matches[1], "%x", &fault.R12)}}return fault, nil
}// 解析CFSR寄存器并返回详细信息
func parseCFSR(cfsr uint32) []string {var details []stringif cfsr&0x00000001 != 0 {details = append(details, "MMFARVALID: Memory Management Fault Address Valid")}if cfsr&0x00000002 != 0 {details = append(details, "IACCVIOL: Instruction Access Violation")}if cfsr&0x00000004 != 0 {details = append(details, "DACCVIOL: Data Access Violation")}if cfsr&0x00000080 != 0 {details = append(details, "MUNSTKERR: Unstacking Error")}if cfsr&0x00000100 != 0 {details = append(details, "MSTKERR: Stacking Error")}if cfsr&0x00010000 != 0 {details = append(details, "IBUSERR: Instruction Bus Error")}if cfsr&0x00020000 != 0 {details = append(details, "PRECISERR: Precise Data Bus Error")}if cfsr&0x00040000 != 0 {details = append(details, "IMPRECISERR: Imprecise Data Bus Error")}if cfsr&0x00080000 != 0 {details = append(details, "UNSTKERR: Bus Fault on Unstacking")}if cfsr&0x00100000 != 0 {details = append(details, "STKERR: Bus Fault on Stacking")}if cfsr&0x01000000 != 0 {details = append(details, "UNDEFINSTR: Undefined Instruction")}if cfsr&0x02000000 != 0 {details = append(details, "INVSTATE: Invalid Execution State")}if cfsr&0x04000000 != 0 {details = append(details, "INVPC: Invalid PC Load")}if cfsr&0x08000000 != 0 {details = append(details, "NOCP: No Coprocessor")}if cfsr&0x10000000 != 0 {details = append(details, "UNALIGNED: Unaligned Access")}if cfsr&0x20000000 != 0 {details = append(details, "DIVBYZERO: Divide by Zero")}return details
}// 解析HFSR寄存器并返回详细信息
func parseHFSR(hfsr uint32) []string {var details []stringif hfsr&0x00000001 != 0 {details = append(details, "VECTTBL: Vector Table Hard Fault")}if hfsr&0x40000000 != 0 {details = append(details, "FORCED: Forced Hard Fault (due to configurable fault)")}if hfsr&0x80000000 != 0 {details = append(details, "DEBUGEVT: Debug Event")}return details
}// 解析DFSR寄存器并返回详细信息
func parseDFSR(dfsr uint32) []string {var details []stringif dfsr&0x00000001 != 0 {details = append(details, "HALTED: Core Halted")}if dfsr&0x00000002 != 0 {details = append(details, "BKPT: Breakpoint")}if dfsr&0x00000004 != 0 {details = append(details, "DWTTRAP: DWT Match")}if dfsr&0x00000008 != 0 {details = append(details, "VCATCH: Vector Catch")}if dfsr&0x00000010 != 0 {details = append(details, "EXTERNAL: External Debug Request")}return details
}// 分析错误类型
func analyzeFaultType(fault *FaultInfo) int {if fault.HFSR&0x40000000 != 0 {return ERROR_HARD_FAULT} else if fault.CFSR&0x0000FFFF != 0 {return ERROR_MEMORY_MANAGEMENT} else if fault.CFSR&0x00FF0000 != 0 {return ERROR_BUS_FAULT} else if fault.CFSR&0xFF000000 != 0 {return ERROR_USAGE_FAULT} else if fault.DFSR != 0 {return ERROR_DEBUG} else {return ERROR_NONE}
}// 获取错误类型名称
func getFaultTypeName(faultType int) string {switch faultType {case ERROR_MEMORY_MANAGEMENT:return "Memory Management Fault"case ERROR_BUS_FAULT:return "Bus Fault"case ERROR_USAGE_FAULT:return "Usage Fault"case ERROR_HARD_FAULT:return "Hard Fault"case ERROR_DEBUG:return "Debug Fault"default:return "Unknown Fault"}
}// 获取错误修复建议
func getFixSuggestions(faultType int) []string {var suggestions []stringswitch faultType {case ERROR_MEMORY_MANAGEMENT:suggestions = append(suggestions, "Possible causes:")suggestions = append(suggestions, " 1. Accessing invalid memory address")suggestions = append(suggestions, " 2. Stack overflow or underflow")suggestions = append(suggestions, " 3. Using uninitialized pointers")suggestions = append(suggestions, "Suggestions:")suggestions = append(suggestions, " - Check array bounds and pointer initialization")suggestions = append(suggestions, " - Increase stack size in linker script")case ERROR_BUS_FAULT:suggestions = append(suggestions, "Possible causes:")suggestions = append(suggestions, " 1. Memory alignment issues")suggestions = append(suggestions, " 2. Accessing hardware that is not ready")suggestions = append(suggestions, " 3. Incorrect peripheral configuration")suggestions = append(suggestions, "Suggestions:")suggestions = append(suggestions, " - Ensure all memory accesses are aligned")suggestions = append(suggestions, " - Add delays or wait for hardware ready flags")case ERROR_USAGE_FAULT:suggestions = append(suggestions, "Possible causes:")suggestions = append(suggestions, " 1. Undefined instruction execution")suggestions = append(suggestions, " 2. Invalid state transition")suggestions = append(suggestions, " 3. Divide by zero")suggestions = append(suggestions, " 4. Unaligned memory access")suggestions = append(suggestions, "Suggestions:")suggestions = append(suggestions, " - Check for division operations without zero checks")suggestions = append(suggestions, " - Ensure all functions are properly linked")case ERROR_HARD_FAULT:suggestions = append(suggestions, "Possible causes:")suggestions = append(suggestions, " 1. Nested fault (fault occurred during exception handling)")suggestions = append(suggestions, " 2. Stack overflow or corruption")suggestions = append(suggestions, " 3. Invalid interrupt handler address")suggestions = append(suggestions, "Suggestions:")suggestions = append(suggestions, " - Check interrupt vector table")suggestions = append(suggestions, " - Increase stack size and check for stack corruption")case ERROR_DEBUG:suggestions = append(suggestions, "Possible causes:")suggestions = append(suggestions, " 1. Debugger breakpoint hit")suggestions = append(suggestions, " 2. DWT watchpoint triggered")suggestions = append(suggestions, " 3. External debug request")suggestions = append(suggestions, "Suggestions:")suggestions = append(suggestions, " - Check debugger configuration")suggestions = append(suggestions, " - Review DWT/watchpoint settings")}return suggestions
}// 打印PSR分析信息
func printPSRInfo(psr uint32) {fmt.Printf("PSR (Program Status Register) = 0x%08X\n", psr)if psr&0x01000000 != 0 {fmt.Println(" Thumb state (T bit set)")}exceptionNumber := psr & 0x000000FFif exceptionNumber > 0 {fmt.Printf(" Exception number: %d\n", exceptionNumber)}
}// 打印错误分析报告
func printFaultReport(fault *FaultInfo) {// 确定错误类型fault.ErrorType = analyzeFaultType(fault)// 打印基本信息fmt.Println("\n=== STM32F103C8T6 硬件错误分析报告 ===")fmt.Printf("错误类型: %s\n", getFaultTypeName(fault.ErrorType))fmt.Printf("错误发生地址: 0x%08X\n", fault.PC)// 打印PSR分析printPSRInfo(fault.PSR)// 打印调用栈信息fmt.Println("\n调用栈信息:")fmt.Printf(" LR (链接寄存器) = 0x%08X\n", fault.LR)fmt.Printf(" R0 = 0x%08X\n", fault.R0)fmt.Printf(" R1 = 0x%08X\n", fault.R1)fmt.Printf(" R2 = 0x%08X\n", fault.R2)fmt.Printf(" R3 = 0x%08X\n", fault.R3)fmt.Printf(" R12 = 0x%08X\n", fault.R12)// 打印错误状态寄存器分析fmt.Println("\n=== 错误状态寄存器分析 ===")fmt.Println("\nCFSR (配置错误状态寄存器):")cfsrDetails := parseCFSR(fault.CFSR)if len(cfsrDetails) > 0 {for _, detail := range cfsrDetails {fmt.Println(" " + detail)}} else {fmt.Println(" 无错误标志")}fmt.Println("\nHFSR (硬件错误状态寄存器):")hfsrDetails := parseHFSR(fault.HFSR)if len(hfsrDetails) > 0 {for _, detail := range hfsrDetails {fmt.Println(" " + detail)}} else {fmt.Println(" 无错误标志")}fmt.Println("\nDFSR (调试错误状态寄存器):")dfsrDetails := parseDFSR(fault.DFSR)if len(dfsrDetails) > 0 {for _, detail := range dfsrDetails {fmt.Println(" " + detail)}} else {fmt.Println(" 无错误标志")}// 打印修复建议fmt.Println("\n=== 修复建议 ===")suggestions := getFixSuggestions(fault.ErrorType)for _, suggestion := range suggestions {fmt.Println(suggestion)}
}func main() {// 解析命令行参数filePath := flag.String("file", "", "包含错误信息的文件路径")flag.Parse()// 检查是否提供了文件路径if *filePath == "" {fmt.Println("错误: 请提供包含错误信息的文件路径")fmt.Println("使用方法: go run fault_analyzer.go -file error_log.txt")return}// 从文件读取错误信息fault, err := readFaultInfoFromFile(*filePath)if err != nil {fmt.Printf("读取文件错误: %v\n", err)return}// 检查是否读取到有效数据if fault.PC == 0 && fault.PSR == 0 {fmt.Println("错误: 文件中未找到有效的错误信息")return}// 打印错误分析报告printFaultReport(fault)
}
6:测试结果 如果对你又帮助,麻烦点个赞,加个关注
总结:传感器 还是少了,低的障碍物检测不到,想做PID,编码器价格偏贵,红外避障模块在对着光,一直亮,感觉是鸡肋 ,超声波比较准,可以多搞几个,上面用舵机,下面固定,不然矮得障碍物 检测不到
后续准备增加已个摄像头检测的,成本不能太贵,MCU也得换了 F103C8T6 性能还是差了点
1:存储在 FLASH 中的只读数据(代码、常量、字符串等)
2:运行时占用 RAM 的部分:- RW Data:已初始化的全局变量(从 FLASH 加载到 RAM)- ZI Data:未初始化的全局变量(BSS 段,运行时清零)
3:实际占用的 FLASH 总大小(包含需要加载到 RAM 的初始化数据)
DEBUG信息等都包含进去了,还开启了动态堆等,不然还能少2-3K吧
FLASH 比RAM 空余比 富有点,都够用,线程附带大点HEAP,就要省着点了
测试视频
智能小车
代码工程自行下载
MD5:ed7c72e58fefd17f3fb66ca688928ddc