前言
前面几章学会了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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/916621.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/916621.shtml
英文地址,请注明出处:http://en.pswp.cn/news/916621.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux 远程连接与文件传输:从基础到高级配置

Linux 远程连接与文件传输&#xff1a;从基础到高级配置 在 Linux 系统管理中&#xff0c;远程连接和文件传输是核心技能。SSH 协议提供了安全的远程访问方式&#xff0c;而基于 SSH 的 SFTP 和 SCP 则解决了跨服务器文件传输的需求。下面将详细解析 SSH 服务配置、三种远程操作…

17. 如何修改 flex 主轴方向

总结 flex-direction: row | row-reverse | column | column-reverse;一、作用说明 在 Flex 布局中&#xff0c;默认的主轴&#xff08;main axis&#xff09;方向是 水平向右&#xff08;即 row&#xff09;。 通过设置 flex-direction 属性&#xff0c;可以灵活改变主轴的方向…

【Linux】重生之从零开始学习运维之mysql用户管理

mariadb用户管理创建用户create user test210.0.0.% identified by 123456;用户改名rename user test210.0.0.% to test310.0.0.%;用户删除 drop user test310.0.0.%;mysql用户管理创建用户create user test210.0.0.% identified by 123456;用户改名rename user test210.0.0.% …

matlab小计

3.变量命名_哔哩哔哩_bilibili clc 清空页面 文件名&#xff1a;字母开头 clc:清除命令行窗口 clear all&#xff1a;清除工作区变量 编译器里面 %%注释 24 2-4 2*4 4/2 cumsum累计和 312 6123 movsum:滑窗计算数值 eg步长是3 1236 2349 6 9 ... 按列求最大值 先列…

getdents64系统调用及示例

getdents64 函数详解 1. 函数介绍 getdents64 是 Linux 系统中用于读取目录内容的底层系统调用。可以把这个函数想象成一个"目录内容扫描仪"——它能够高效地扫描目录中的所有文件和子目录,就像超市的扫描枪快速读取商品条码一样。 与高级的目录操作函数(如 rea…

HBuilder X打包发布微信小程序

一、获取AppId 二、获取微信小程序AppId 三、发行->微信小程序&#xff0c;调起微信开发者工具 四、点击上传,上传至微信公众平台 五、微信公众平台查看版本管理 完结&#xff01;&#xff01;&#xff01;

docker排查OOM

思路&#xff1a; 1.先从代码程序上排查&#xff0c;线程池创建是否使用ThreadPoolExecutor&#xff0c;线程池各项设置是否合理。 任务对象是否释放&#xff0c;网关是否需要限流。 2.服务器内存大小&#xff0c;cpu使用率&#xff0c;存储空间大小&#xff0c;java程序启动…

Web后端进阶:springboot原理(面试多问)

1.配置优先级 3种配置文件: application.properties server.port8081application.yml server:port: 8082application.yaml server:port: 80822种外部属性的配置(Java系统属性、命令行参数): Java系统属性配置 &#xff08;格式&#xff1a; -Dkeyvalue&#xff09; -Dserver.po…

第十天:字符菱形

每日一道C题&#xff1a;字符菱形 问题&#xff1a;给定一个字符&#xff0c;用它构造一个对角线长5个字符&#xff0c;倾斜放置的菱形。 要求&#xff1a;输入只有一行&#xff0c; 包含一个字符&#xff1b;输出该字符构成的菱形。 最基础的做法&#xff1a; #include <io…

Qt 多线程编程最佳实践

在现代软件开发中&#xff0c;多线程编程是提升应用性能和响应性的关键技术。Qt 作为一个强大的跨平台框架&#xff0c;提供了丰富的多线程支持&#xff0c;包括 QThread、QtConcurrent、信号槽机制等。本文将深入探讨 Qt 多线程编程的最佳实践&#xff0c;帮助开发者避免常见陷…

Photo Studio PRO 安卓版:专业级照片编辑的移动解决方案

Photo Studio PRO 安卓版是一款功能强大的专业级照片编辑应用&#xff0c;旨在为用户提供丰富而强大的编辑工具和特效&#xff0c;帮助用户轻松地对照片进行美化和修饰。无论是摄影爱好者还是专业摄影师&#xff0c;都能通过这款应用实现从基础调整到高级合成的全流程编辑。 核…

2025高考志愿怎么填?张雪峰最新“保底”推荐来了!这4个专业专科也能拿高薪,毕业不愁!

专业选得好&#xff0c;就业跑不了&#xff01;2025年高考落幕&#xff0c;现在是决战未来的关键时刻&#xff0c;选专业比选学校更重要&#xff01; 今天&#xff0c;学长就根据张雪峰老师多次力荐、再结合2024年就业大数据&#xff0c;给大家盘点4个紧缺人才专业&#xff0c…

C++初学者4——标准数据类型

先导&#xff1a; 目录 一、整形 二、浮点型 &#xff01;保留指定小数位数 三、布尔类型 关系运算 逻辑运算 ​C逻辑运算四句口诀​ 四、字符型 ASCll码 C中的字符表示 字符比较 ASCII中的常用转换 大小写转换 转换成0~25 五、数据类型隐式转换 ​1. 隐式转…

HCIP的MGRE综合实验1

拓扑图&#xff1a;二、实验要求 1、R5为ISP&#xff0c;只能进行IP地址配置&#xff0c;其所有地址均配为公有Ip地址;2、R1和R5间使用PPP的PAP认证&#xff0c;R5为主认证方&#xff1b;R2与R5之间使用PPP的CHAP认证&#xff0c;R5为主认证方;R3与R5之间使用HDLC封装;3、R2、R…

Go语言实战案例-链表的实现与遍历

在数据结构的世界中&#xff0c;链表&#xff08;Linked List&#xff09; 是一种经典的线性结构&#xff0c;它以灵活的插入与删除能力著称。链表不像数组那样需要连续的内存空间&#xff0c;而是通过节点指针连接形成一条“链”。本篇我们将使用 Go 语言实现一个单向链表&…

C++常见的仿函数,预定义函数,functor,二元操作函数(对vector操作,加减乘除取余位运算等 )

C 标准库在 <functional> 头文件中为我们提供了一套非常方便的预定义函数对象&#xff08;也称为“仿函数”或 “functor”&#xff09;&#xff0c;它们可以像变量一样直接传递给 std::reduce 和其他标准算法。 你提到的 std::bit_or 和 std::multiplies 就是其中的成员…

【RH134 问答题】第 6 章 管理 SELinux 安全性

目录SELinux 是如何保护资源的&#xff1f;什么是自由决定的访问控制(DAC)&#xff1f;它有什么特点&#xff1f;什么是强制访问控制(MAC)&#xff1f;它有什么特点&#xff1f;什么是 SELinux 上下文&#xff1f;setenforce 0 命令的作用是什么&#xff1f;定义一条 SELinux 文…

【MacOS】发展历程

很高兴为您详细介绍 macOS 的详细发展历程。macOS 是苹果公司开发的操作系统&#xff0c;用于 Mac 电脑、iPad 和 Apple TV 等设备。以下是 macos 的主要版本和发展历程&#xff1a;1. System 7 (1991)发布日期&#xff1a;1991年特点&#xff1a;引入多任务处理功能。改进了拖…

智慧社区项目开发(二)——基于 JWT 的登录验证功能实现详解

在 Web 应用中&#xff0c;登录验证是保障系统安全的核心环节。本文将结合具体接口文档&#xff0c;详细讲解如何基于 JWT&#xff08;JSON Web Token&#xff09;实现登录验证功能&#xff0c;包括 JWT 配置、工具类封装、登录流程处理等关键步骤&#xff0c;帮助开发者快速理…

Jmeter的元件使用介绍:(七)后置处理器详解

Jmeter的后置处理器主要用于取样器执行后的提取数据操作。 Jmeter常用的后置处理器有:Json提取器、正则表达式提取器、边界提取器、Beanshell后置处理器。此外还有Xpath提取器、CSS选择器提取器等&#xff0c;由于这两项多用前端页面提取元素&#xff0c;目前的项目基本都是采…