/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @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 "main.h" #include "adc.h" #include "tim.h" #include "gpio.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ int Turn_Pwm = 0; uint8_t stop_flag = 0; // 停止标志位 uint8_t void_flag = 0; // 停止标志位 float feature_time = 0; // 特征区域经过时间 // 存放测距距离 /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); void TIM4_Dealy_us(uint16_t n_us); double get_distance(); /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ 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 */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_ADC1_Init(); MX_TIM3_Init(); MX_TIM4_Init(); /* USER CODE BEGIN 2 */ HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_4); HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2); // HAL_Delay(3000); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) {float dis = 0; dis = get_distance(); HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_SET); //if(dis < 20.0) // 距离小于20cm亮灯 // HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_RESET); //else //HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_SET); //HAL_Delay(100); // 0.1s测量一次} /* int pwmVal_R = 200; int pwmVal_L = 200; RD_TSL(); Find_CCD_Zhongzhi(); // 计算特征区域经过时间(假设采样频率为100Hz) feature_time = ccd_data_process(ADV, 50.0f); // 检查是否达到积分阈值 if (feature_time >= INTEGRATION_THRESHOLD) { stop_flag = 1; } if (!stop_flag) { Turn_Pwm = turn(CCD_Zhongzhi, 0); // 右侧电机控制 if (pwmVal_R - Turn_Pwm > 0) { HAL_GPIO_WritePin(GPIOA, R1_Pin, 1); HAL_GPIO_WritePin(GPIOA, R2_Pin, 0); __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_2, pwmVal_R - Turn_Pwm); } else if (pwmVal_R - Turn_Pwm < 0) { HAL_GPIO_WritePin(GPIOA, R1_Pin, 0); HAL_GPIO_WritePin(GPIOA, R2_Pin, 1); __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_2, -pwmVal_R + Turn_Pwm); } else { HAL_GPIO_WritePin(GPIOA, R1_Pin, 0); HAL_GPIO_WritePin(GPIOA, R2_Pin, 0); } // 左侧电机控制 if (pwmVal_L + Turn_Pwm > 0) { HAL_GPIO_WritePin(GPIOA, L1_Pin, 1); HAL_GPIO_WritePin(GPIOA, L2_Pin, 0); __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_4, pwmVal_L + Turn_Pwm); } else if (pwmVal_L + Turn_Pwm < 0) { HAL_GPIO_WritePin(GPIOA, L1_Pin, 0); HAL_GPIO_WritePin(GPIOA, L2_Pin, 1); __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_4, -pwmVal_L - Turn_Pwm); } else { HAL_GPIO_WritePin(GPIOA, L1_Pin, 0); HAL_GPIO_WritePin(GPIOA, L2_Pin, 0); } } else if(void_flag==1){ HAL_GPIO_WritePin(GPIOA, R1_Pin, 1); HAL_GPIO_WritePin(GPIOA, R2_Pin, 0); HAL_GPIO_WritePin(GPIOA, L1_Pin, 1); HAL_GPIO_WritePin(GPIOA, L2_Pin, 0); __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_4, 350); __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_2,100);//右边 HAL_Delay(300); __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_2, 350);//右边 __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_4,100); HAL_Delay(300); __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_2, 220);//右边 __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_4,200); HAL_Delay(100); __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_2, 350);//右边 __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_4,100); HAL_Delay(300); __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_4, 350); __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_2,100);//右边 HAL_Delay(300); stop_flag = 0; // __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_2, -pwmVal_R); // __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_4, pwmVal_L); } else { // 停止小车 HAL_GPIO_WritePin(GPIOA, R1_Pin, 1); HAL_GPIO_WritePin(GPIOA, R2_Pin, 1); HAL_GPIO_WritePin(GPIOA, L1_Pin, 1); HAL_GPIO_WritePin(GPIOA, L2_Pin, 1); __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_4, 0); __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_2, 0); HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_RESET); } Dly_us(); */ /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } /** * @brief System Clock Configuration * @retval None */ void TIM4_Dealy_us(uint16_t n_us) { __HAL_TIM_ENABLE(&htim4); __HAL_TIM_SetCounter(&htim4,0); uint32_t timeout = 0; while(__HAL_TIM_GetCounter(&htim4) < ((1 * n_us)-1)) { if(timeout++ > n_us * 2) break; // 超时保护,避免死循环 } __HAL_TIM_DISABLE(&htim4); } double get_distance() { int cnt = 0; // 存放定时器计次次数 // 1.给Trig端口20us(至少10us)高电平 HAL_GPIO_WritePin(Trig_GPIO_Port,Trig_Pin,GPIO_PIN_SET); TIM4_Dealy_us(20); HAL_GPIO_WritePin(Trig_GPIO_Port,Trig_Pin,GPIO_PIN_RESET); // 2.波发出去时启动定时器 while(HAL_GPIO_ReadPin(Echo_GPIO_Port,Echo_Pin)==GPIO_PIN_RESET); HAL_TIM_Base_Start(&htim4); __HAL_TIM_SetCounter(&htim4,0); // 将Timer4的值重置为指定值0 // 3.由高电平到低电平表示波已返回,关闭定时器 while(HAL_GPIO_ReadPin(Echo_GPIO_Port,Echo_Pin)==GPIO_PIN_SET); HAL_TIM_Base_Stop(&htim4); cnt = __HAL_TIM_GetCounter(&htim4); // 获取Timer4当前计数值 // 4.计算时间和距离 // cnt为计数次数,1次1us,cnt次即cntus,×0.000001转换为s,×340÷2得到距离,单位为m,×100转换为cm return (cnt*340/2*0.000001*100); // 单位为cm } void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; RCC_PeriphCLKInitTypeDef PeriphClkInit = {0}; /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL2; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB buses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) { Error_Handler(); } PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC; PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV2; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) { Error_Handler(); } } /* USER CODE BEGIN 4 */ /* USER CODE END 4 */ /** * @brief This function is executed in case of error occurrence. * @retval None */ void Error_Handler(void) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ __disable_irq(); while (1) { } /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t *file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */ 逻辑合理码
时间: 2025-05-28 17:45:16 浏览: 31
### STM32代码逻辑合理性分析
以下是对STM32在超声波测距中的代码逻辑进行的全面分析,涵盖了定时器、PWM、GPIO以及信号处理等方面的内容。
---
#### 1. 定时器配置与中断回调
在超声波测距系统中,定时器通常被用来测量回波信号的时间差。以下是合理的实现方法:
```c
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM2) { // 判断是否为TIM2溢出中断
overflow_count++; // 更新溢出计数值
}
}
```
- **功能说明**:此函数作为定时器周期中断的回调函数,每当发生一次溢出事件时更新全局变量 `overflow_count`[^2]。
- **重要性**:通过记录定时器的溢出次数和捕获单元获取的具体值,可以计算总时间延迟 \( \text{Total Time} = (\text{Overflow Count} \times \text{Auto Reload Register}) + \text{Captured Value} \)[^2]。
---
#### 2. PWM信号生成与控制
PWM信号用于驱动超声波模块发射端的工作状态。以下是典型的PWM配置过程:
```c
TIM_OC_InitTypeDef sConfigOC;
__HAL_RCC_TIM1_CLK_ENABLE(); // 启用TIM1时钟
hTim.Instance = TIM1; // 设置定时器实例
...
sConfigOC.OCMode = TIM_OCMODE_PWM1; // 配置为PWM模式1
sConfigOC.Pulse = CCR_VALUE; // 设定占空比初值
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; // 输出极性为高有效
HAL_TIM_PWM_ConfigChannel(&hTim, &sConfigOC, TIM_CHANNEL_1); // 配置通道1
HAL_TIM_PWM_Start(&hTim, TIM_CHANNEL_1); // 启动PWM输出
```
- **功能说明**:上述代码片段展示了如何利用STM32的高级定时器(如TIM1)生成精确的PWM信号[^1]。
- **注意事项**:确保PWM频率适配于所使用的超声波传感器规格书的要求,一般范围为40kHz左右。
---
#### 3. GPIO配置与触发机制
GPIO主要用于控制超声波模块的启动脉冲发送以及接收回波信号的变化通知。
```c
GPIO_InitTypeDef GPIO_InitStruct = {0};
// 发送端配置
GPIO_InitStruct.Pin = TRIG_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(TRIG_PORT, &GPIO_InitStruct);
// 接收端配置
GPIO_InitStruct.Pin = ECHO_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT; // 输入模式
GPIO_InitStruct.Pull = GPIO_PULLDOWN; // 下拉输入
HAL_GPIO_Init(ECHO_PORT, &GPIO_InitStruct);
```
- **功能说明**:TRIG引脚负责向超声波模块发出短促的正脉冲以激活其发射功能;ECHO引脚则监控返回信号的到来时刻[^1]。
- **优化建议**:考虑加入外部滤波电路减少噪声干扰对检测精度的影响[^2]。
---
#### 4. 超声波测距核心算法
基于以上硬件资源的支持下,最终形成距离测算的核心部分如下所示:
```c
float CalculateDistance(uint32_t time_us)
{
const float sound_speed_m_per_s = 340.0f; // 声音传播速度(m/s),标准条件下约为340m/s
return ((time_us / 1e6) * sound_speed_m_per_s) / 2.0f; // 单位转换并折半得到单程路程
}
```
- **原理解释**:声音在空气中每秒钟大约能前进340米的距离。因此只要知道来回所需时间就可以求得目标物体离探头的实际间距[^1]。
- **误差校准**:考虑到温度变化会对声速造成影响,在精密场合可能还需要引入补偿措施进一步提升准确性。
---
#### 5. 整体流程总结
综合来看,整个程序遵循了清晰的设计思路——先由软件产生特定宽度的方波激励超声器件工作,再捕捉反射回来的第一条前沿位置从而得知飞行耗时时长最后依据物理公式得出结论。这种分步实施的方式不仅便于调试而且利于后期维护升级。
---
阅读全文
相关推荐
















