前言
前面幾章學會了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