智能小車(F103C8T6)RT-THREAD版

前言
前面幾章學會了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;目前的項目基本都是采…