活动介绍

#include "main.h" #include "tim.h" #include "gpio.h" void SystemClock_Config(void); int main(void) { /* USER CODE BEGIN 1 */ uint16_t pwmVal = 0;//调整占空比 uint8_t dir = 1;//设置改变方向,等于1越来越亮(占空比越来越大), //等于0就是越来越暗(占空比越来越小) HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_TIM4_Init(); HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_3);//打开pwm要在初始化之后打开 while (1) { /* USER CODE END WHILE */ HAL_Delay(1); if(dir) pwmVal++; else pwmVal--; if(pwmVal > 500) dir = 0; if(pwmVal == 0) dir = 1; //修改比较值,修改占空比 __HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_3, pwmVal); /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {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_MUL9; 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_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) { Error_Handler(); } } void Error_Handler(void) { __disable_irq(); while (1) { } } 在这个代码的基础上修改

时间: 2025-04-02 10:24:43 浏览: 56
<think>好的,我需要帮助用户基于现有的STM32 HAL库PWM代码进行功能扩展或优化。首先,我得回顾一下用户提供的引用内容,了解现有的代码结构和可能的优化方向。 首先,用户提到了HAL_TIM_PWM_Start函数,这个函数用于启动定时器的PWM输出。引用[1]中详细展示了这个函数的实现,包括使能通道和计数器。用户想修改现有的代码,可能需要调整PWM的频率或占空比,或者使用DMA来传输数据。 接下来,引用[2]提到HAL库的特点,简化了硬件访问,适合开发。所以,优化应该基于HAL库的API,确保代码结构清晰。引用[3]是一个启动PWM的示例,可能需要结合其他功能,比如动态调整占空比。 用户的问题是如何扩展或优化现有功能。可能的优化点包括动态调节参数、使用DMA减轻CPU负担、多通道同步、中断配合以及错误处理。例如,动态调节占空比可以通过__HAL_TIM_SET_COMPARE宏实现,这在引用[3]的基础上可以扩展。同时,引用[4]提到中断中的注意事项,比如避免在中断中使用延时,这可能涉及到PWM与中断的协同处理。 另外,引用[2]提到PWM+DMA驱动,这可能涉及到使用DMA自动更新PWM参数,比如传输占空比数组,这样CPU不需要频繁干预。需要配置DMA通道,并在HAL库中启用相应的函数。 还需要考虑代码的模块化和可维护性。比如,将PWM控制封装成函数,方便调用。同时,错误处理方面,检查HAL函数的返回值,确保操作成功。 用户可能需要具体的步骤,比如如何修改占空比,如何配置DMA,如何处理多通道同步。此外,引用[4]提到中断优先级的问题,如果在PWM应用中需要处理中断,需要正确配置优先级,避免冲突。 总结一下,回答应该涵盖以下几个方面: 1. 动态调节频率和占空比的方法。 2. 使用DMA优化数据传输。 3. 多通道的同步控制。 4. 结合中断的注意事项。 5. 代码结构和错误处理的优化。 需要确保步骤清晰,结合HAL库的函数,如HAL_TIM_PWM_Start、__HAL_TIM_SET_COMPARE、HAL_TIM_PWM_Start_DMA等。同时,引用相关的文献,如引用[1]中的寄存器操作,引用[4]中的中断处理建议,来支持建议的可行性。 可能的相关问题包括如何调整PWM频率,DMA配置的具体步骤,中断与PWM的协作问题等。这些需要在回答后生成,帮助用户深入理解。</think>### 基于STM32 HAL库的PWM功能扩展与优化方法 以下是针对STM32 HAL库PWM代码的功能扩展和优化方案,结合硬件特性与软件设计原则: --- #### **一、基础功能扩展** 1. **动态参数调整** - **修改占空比**:使用`__HAL_TIM_SET_COMPARE()`宏直接操作CCR寄存器 ```c // 示例:修改TIM3通道1的占空比为50% __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, htim3.Instance->ARR / 2); ``` - **调整频率**:通过改变ARR寄存器值实现 ```c htim3.Instance->ARR = new_arr_value; // 新周期值 htim3.Instance->PSC = new_prescaler; // 新预分频值 HAL_TIM_PWM_Init(&htim3); // 重新初始化 ``` 2. **多通道协同控制** ```c // 同时启动多个通道 HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1); HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2); // 使用同步机制保证相位对齐 HAL_TIMEx_PWMN_Start(&htim3, TIM_CHANNEL_1); // 互补通道 ``` --- #### **二、高级优化策略** 1. **DMA驱动优化** [^2] - **配置DMA传输占空比序列** ```c // 定义占空比数组 uint32_t duty_buffer[] = {1000, 2000, 3000}; // 启动PWM+DMA HAL_TIM_PWM_Start_DMA(&htim3, TIM_CHANNEL_1, duty_buffer, 3); ``` - **实现自动波形生成** ```c // 在DMA完成回调中更新数据 void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim) { // 更新占空比数组 } ``` 2. **中断协同控制** [^4] ```c // 启用PWM周期中断 HAL_TIM_Base_Start_IT(&htim3); // 在中断回调中处理事件 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim->Instance == TIM3) { // 执行占空比更新等操作 } } ``` --- #### **三、工程化改进** 1. **模块化封装** ```c typedef struct { TIM_HandleTypeDef *htim; uint32_t channel; uint32_t max_duty; } PWM_Controller; void PWM_SetDuty(PWM_Controller *ctrl, float percentage) { uint32_t ccr = ctrl->max_duty * percentage; __HAL_TIM_SET_COMPARE(ctrl->htim, ctrl->channel, ccr); } ``` 2. **错误处理增强** ```c HAL_StatusTypeDef status = HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1); if (status != HAL_OK) { Error_Handler(); // 自定义错误处理 } ``` --- #### **四、典型应用场景** 1. **电机控制**:通过调节占空比实现转速控制 2. **LED调光**:利用PWM分辨率实现256级亮度 3. **音频生成**:结合DMA生成特定频率波形 ---
阅读全文

相关推荐

检查下面的代码为什么dac无法输出正弦波:#include "main.h" #include "math.h" #include "dac.h" #include "dma.h" #include "tim.h" #include "gpio.h" #define M_PI 3.14159265358979323846f #define SINE_WAVE_POINTS 210 uint32_t sineWave[SINE_WAVE_POINTS]; void Generate_SineWave(void) { float amplitude = 1.0f * (4095.0f / 3.3f); float offset = 1.65f * (4095.0f / 3.3f); for(int i=0; i<SINE_WAVE_POINTS; i++) { sineWave[i] = (uint16_t)(offset + amplitude * sin(2 * M_PI * i / SINE_WAVE_POINTS)); } HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, sineWave, SINE_WAVE_POINTS, DAC_ALIGN_12B_R); } void SystemClock_Config(void); int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_DMA_Init(); MX_DAC_Init(); MX_TIM6_Init(); Generate_SineWave(); while (1) { } } void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLM = 4; RCC_OscInitStruct.PLL.PLLN = 168; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; RCC_OscInitStruct.PLL.PLLQ = 4; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } 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_5) != HAL_OK) { Error_Handler(); } }

/****************************************************************************//** * @file main.c * @brief Hello world example file. * @version V1.0.0 * @date 1-May-2020 * @author Zhixin Semiconductor * * @note * Copyright (C) 2020 Zhixin Semiconductor Ltd. All rights reserved. * *******************************************************************************/ #include "Z20K11xM_drv.h" #include "Z20K11xM_tim.h" #include "Z20K11xM_gpio.h" #include "Z20K11xM_clock.h" #include "Z20K11xM_sysctrl.h" #include "Z20K11xM_wdog.h" #include "pwm.h" #include "Motor.h" #include "pwm_hall.h" #define PWM_TIM_ID TIM1_ID //typedef enum { // MOTOR_STOP, // 刹车 // MOTOR_FORWARD, // 正转 (INA=1, INB=0) // MOTOR_REVERSE // 反转 (INA=0, INB=1) //} Motor_Direction; int main() { /* Disable wdog */ WDOG_Disable(); /* Clock init */ CLK_OSC40MEnable2(CLK_OSC_FREQ_MODE_HIGH, ENABLE, CLK_OSC_XTAL); while(ERR == CLK_SysClkSrc(CLK_SYS_OSC40M)); /* Disable wdog */ WDOG_Disable(); CLK_ModuleSrc(CLK_PORTC, CLK_SRC_OSC40M); SYSCTRL_EnableModule(SYSCTRL_PORTC); SYSCTRL_EnableModule(SYSCTRL_GPIO); TIM_system_clock(); /*TIM independent PWM output*/ tim_IndependentPWMOutputInit(); /*start TIM PWM*/ TIM_StartCounter(PWM_TIM_ID, TIM_CLK_SOURCE_SYSTEM, TIM_CLK_DIVIDE_1); Motor_Init(); input_capture_test(); while(1){ // Motor_SetDirection(); GPIO_WritePinOutput(PORT_D, GPIO_3, GPIO_HIGH); //INA GPIO_WritePinOutput(PORT_D, GPIO_2, GPIO_LOW); //INB } } pwm.c /**************************************************************************************************/ /** * @file : main.c * @brief : TIM example file. * @version : V1.8.0 * @date : May-2020 * @author : Zhixin Semiconductor * * @note : This example contains sample code for customer evaluation purpose only. It is not * part of the production code deliverables. The example code is only tested under defined * environment with related context of the whole example project. Therefore, it is not guaranteed * that the example always works under user environment due to the diversity of hardware and * software environment. Do not use pieces copy of the example code without prior and separate * verification and validation in user environment. * * @copyright : Copyright (c) 2020-2023 Zhixin Semiconductor Ltd. All rights reserved. **************************************************************************************************/ #include "Z20K11xM_drv.h" #include "Z20K11xM_tim.h" #include "Z20K11xM_gpio.h" #include "Z20K11xM_clock.h" #include "Z20K11xM_sysctrl.h" #include "Z20K11xM_wdog.h" #include "pwm.h" #define PWM_TIM_ID TIM1_ID //Motor_PWM PTA1 TIM1_CH1 /*PWM Counter define----20K pwm output*/ #define PWM_MAX_COUNTER 800 //ARR void TIM_system_clock() { /* configure gpios */ CLK_ModuleSrc(CLK_PORTA, CLK_SRC_OSC40M); SYSCTRL_EnableModule(SYSCTRL_PORTA); SYSCTRL_EnableModule(SYSCTRL_GPIO); /*TIM clock source select*/ CLK_SetClkDivider(CLK_CORE, CLK_DIV_1); CLK_ModuleSrc(CLK_TIM1, CLK_SRC_OSC40M); CLK_SetClkDivider(CLK_TIM1, CLK_DIV_1); /*TIM module enable*/ SYSCTRL_ResetModule(SYSCTRL_TIM1); SYSCTRL_EnableModule(SYSCTRL_TIM1); } void tim_IndependentPWMOutputInit() { /* TIM PWM output config array*/ TIM_PwmChannelConfig_t cPwmChConfig[1] = { { .channelId = TIM_CHANNEL_1, .pwmModeConfig = TIM_PWM_HIGH_TRUE_PULSE, .polarity = TIM_POL_HIGH, .compareValue = (PWM_MAX_COUNTER * 8/ 100), .faultCtrlChannelEnable = DISABLE, .ccvUpdateEnable = ENABLE }, }; /* TIM PWM output Config*/ TIM_PwmConfig_t cPwmConfig = { 1, /*channel number*/ 0, /*counter init value*/ PWM_MAX_COUNTER, /*counter max value*/ cPwmChConfig /*channel config pointer*/ }; /*TIM reload config*/ TIM_ReloadConfig_t reloadConfig = { .reloadMode = TIM_RELOAD_FULL_CYCLE, .loadFrequency = 0, .numChannels = 0, .channelMatchConfig = NULL }; /*TIM sync config for update ccv*/ TIM_PwmSyncConfig_t syncConfig = { .cntinitSync = TIM_UPDATE_PWM_SYN, .outswcSync = TIM_UPDATE_PWM_SYN, .syncSWTriggerEnable = DISABLE, .syncReloadEnable = ENABLE, .reloadConfig = &reloadConfig }; /*only channel 0, gpio config, other channels need config too*/ PORT_PinmuxConfig(PORT_A, GPIO_1, PTA1_TIM1_CH1); /* set up-counting mode */ TIM_CountingModeConfig(PWM_TIM_ID, TIM_COUNTING_UP); /* output complementary init*/ TIM_OutputEdgeAlignedPwmConfig(PWM_TIM_ID, &cPwmConfig); /* reload config*/ TIM_SyncConfig(PWM_TIM_ID, &syncConfig); /* pair0 output enable */ TIM_ChannelOutputEnable(PWM_TIM_ID, TIM_CHANNEL_1); } pwm_hall.c #include "Z20K11xM_drv.h" #include "Z20K11xM_tim.h" #include "Z20K11xM_gpio.h" #include "Z20K11xM_clock.h" #include "Z20K11xM_sysctrl.h" #include "Z20K11xM_wdog.h" #include "pwm_hall.h" uint8_t i = 0; uint16_t ccvVal1[64]; uint16_t ccvVal2[64]; uint16_t getccv[64]; uint16_t getccvPe[64]; uint8_t intflag0 = 0; uint8_t intflag1 = 0; //HALL SA1: PTD16 TIM0_CH1 AND PTD15 TIM0_CH0 //HALL SA2: PTE9 TIM0_CH7 AND PTE8 TIM0_CH6 void PWM_HALL_system_clock() { /* configure gpios */ CLK_ModuleSrc(CLK_PORTA, CLK_SRC_OSC40M); SYSCTRL_EnableModule(SYSCTRL_PORTA); SYSCTRL_EnableModule(SYSCTRL_GPIO); CLK_ModuleSrc(CLK_PORTD, CLK_SRC_OSC40M); SYSCTRL_EnableModule(SYSCTRL_PORTD); SYSCTRL_EnableModule(SYSCTRL_GPIO); CLK_ModuleSrc(CLK_PORTE, CLK_SRC_OSC40M); SYSCTRL_EnableModule(SYSCTRL_PORTE); SYSCTRL_EnableModule(SYSCTRL_GPIO); /*TIM clock source select*/ CLK_SetClkDivider(CLK_CORE, CLK_DIV_1); CLK_ModuleSrc(CLK_TIM0, CLK_SRC_OSC40M); CLK_SetClkDivider(CLK_TIM0, CLK_DIV_1); /*TIM module enable*/ SYSCTRL_ResetModule(SYSCTRL_TIM0); SYSCTRL_EnableModule(SYSCTRL_TIM0); /* config pinmux, PTB12 CONNECT TO PTD16 PTE9 */ PORT_PinmuxConfig(PORT_A, GPIO_1, PTA1_TIM1_CH1); /* output Motor PWM*/ PORT_PinmuxConfig(PORT_D, GPIO_16, PTD16_TIM0_CH1); /* input HALL SA1*/ PORT_PinmuxConfig(PORT_D, GPIO_15, PTD15_TIM0_CH0); /* input HALL SA1*/ PORT_PinmuxConfig(PORT_E, GPIO_9, PTE9_TIM0_CH7); /* input HALL SA2*/ PORT_PinmuxConfig(PORT_E, GPIO_8, PTE8_TIM0_CH6); /* input HALL SA2*/ PORT_PullConfig(PORT_A, GPIO_1,PORT_PULL_DOWN); } void channel1_cbf() { /* get CCV value: read channel0 before channel1 */ ccvVal1[i] = TIM_GetCCVal(TIM0_ID, TIM_CHANNEL_0); ccvVal2[i] =TIM_GetCCVal(TIM0_ID, TIM_CHANNEL_1); i++; if(i == 64) { intflag0 = 1; TIM_StopCounter(TIM0_ID); } /* clear flag0 before flag1 */ TIM_IntClear(TIM0_ID, TIM_INT_CH0); TIM_IntClear(TIM0_ID, TIM_INT_CH1); } void channel2_cbf() { /* get CCV value: read channel1 before channel7 */ ccvVal1[i] = TIM_GetCCVal(TIM0_ID, TIM_CHANNEL_6); ccvVal2[i] =TIM_GetCCVal(TIM0_ID, TIM_CHANNEL_7); i++; if(i == 64) { intflag0 = 1; TIM_StopCounter(TIM0_ID); } /* clear flag0 before flag1 */ TIM_IntClear(TIM0_ID, TIM_INT_CH6); TIM_IntClear(TIM0_ID, TIM_INT_CH7); } void tim_init() { CLK_SetClkDivider(CLK_CORE, CLK_DIV_1); CLK_ModuleSrc(CLK_TIM0, CLK_SRC_OSC40M); CLK_ModuleSrc(CLK_TIM1, CLK_SRC_OSC40M); SYSCTRL_ResetModule(SYSCTRL_TIM0); SYSCTRL_EnableModule(SYSCTRL_TIM0); SYSCTRL_ResetModule(SYSCTRL_TIM1); SYSCTRL_EnableModule(SYSCTRL_TIM1); /* input config, the TIM input channel should be in low level if it is set to capture rising edge first when TIM is in input capture mode*/ /* TIM input capture channel config struct initial:channelId, falling,rising, disable filter, continue capture */ TIM_DualEdgeChannelConfig_t chconfig1 = { TIM_PAIR_CHANNEL_0, TIM_INPUT_EDGE_RISING, TIM_INPUT_EDGE_FAILING, TIM_INPUT_FILTER_DISABLED, TIM_CONTINUOUS_PULSE_CAPTURE }; TIM_DualEdgeChannelConfig_t chconfig2 = { TIM_PAIR_CHANNEL_3, TIM_INPUT_EDGE_RISING, TIM_INPUT_EDGE_FAILING, TIM_INPUT_FILTER_DISABLED, TIM_CONTINUOUS_PULSE_CAPTURE }; /* TIM input capture global config struct initial: number 1,mod value 0xFFFF, input capture channel config struct */ const TIM_DualEdgeCaptureConfig_t config1 = { 1, 0xFFFF, &chconfig1 }; const TIM_DualEdgeCaptureConfig_t config2 = { 1, 0xFFFF, &chconfig2 }; /*input capture init*/ TIM_DualEdgeCaptureInit(TIM0_ID, &config1); TIM_SetCounterInitialVal(TIM0_ID, 0x0000); } void input_capture_test() { /* callback function */ TIM_InstallCallBackFunc(TIM0_ID, TIM_INT_CH1, channel1_cbf); TIM_InstallCallBackFunc(TIM0_ID, TIM_INT_CH7, channel1_cbf); /* counting mode: up counting mode */ TIM_CountingModeConfig(TIM0_ID, TIM_COUNTING_UP); TIM_CountingModeConfig(TIM1_ID, TIM_COUNTING_UP); /*start counter*/ TIM_StartCounter(TIM0_ID, TIM_CLK_SOURCE_SYSTEM, TIM_CLK_DIVIDE_1); /* reload flag clear */ TIM_IntClear(TIM0_ID, TIM_INT_RLD); /* clear CHF before dual edge capture */ TIM_IntClear(TIM0_ID, TIM_INT_CH0); TIM_IntClear(TIM0_ID, TIM_INT_CH1); TIM_IntClear(TIM0_ID, TIM_INT_CH6); TIM_IntClear(TIM0_ID, TIM_INT_CH7); /* enable the interrupt */ TIM_IntMask(TIM0_ID, TIM_INT_CH1, UNMASK); TIM_IntMask(TIM0_ID, TIM_INT_CH7, UNMASK); /* enable IRQ*/ NVIC_EnableIRQ(TIM0_IRQn); while(intflag0 == 0); for (int k = 0; k < 64; k++) { if (ccvVal1[k] < ccvVal2[k]) { getccv[k] = ccvVal2[k] - ccvVal1[k]; } else { getccv[k] = ccvVal2[k] + 65536 - ccvVal1[k]; } } } 根据这几份程序文件来看,我的HALL SA1和 HALL SA2可以成功捕获了吗

#include "main.h" #include "math.h" #include "dac.h" #include "dma.h" #include "tim.h" #include "gpio.h" #define M_PI 3.14159265358979323846f #define SINE_WAVE_POINTS 210 #define HSE_VALUE 8000000U volatile uint32_t freq = 100; volatile uint8_t key0_pressed = 0; volatile uint8_t key_up_pressed = 0; uint16_t sineWave[SINE_WAVE_POINTS]; void Generate_SineWave(void) { float amplitude = 1242.0f; float offset = 2048.0f; for(int i=0; i<SINE_WAVE_POINTS; i++) { sineWave[i] = (uint16_t)(offset + amplitude * sin(2 * M_PI * i / SINE_WAVE_POINTS)); } HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t*)sineWave, SINE_WAVE_POINTS, DAC_ALIGN_12B_R); } void EXTI0_IRQHandler(void) { HAL_GPIO_EXTI_IRQHandler(KEY0_Pin); } void EXTI4_IRQHandler(void) { HAL_GPIO_EXTI_IRQHandler(KEY_UP_Pin); } void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { static uint32_t last_key0_time = 0, last_key_up_time = 0; uint32_t current_time = HAL_GetTick(); if (GPIO_Pin == KEY0_Pin) { if ((current_time - last_key0_time) > 50) { key0_pressed = 1; last_key0_time = current_time; } } else if (GPIO_Pin == KEY_UP_Pin) { if ((current_time - last_key_up_time) > 50) { key_up_pressed = 1; last_key_up_time = current_time; } } } void SystemClock_Config(void); int main(void) { HAL_Init(); SystemClock_Config(); MX_TIM6_Init(); HAL_TIM_Base_Start(&htim6); MX_GPIO_Init(); MX_DMA_Init(); MX_DAC_Init(); Generate_SineWave(); while (1) { if (key0_pressed) { key0_pressed = 0; if(freq > 100) freq -= 100; HAL_TIM_Base_Stop(&htim6); __HAL_TIM_SET_AUTORELOAD(&htim6, (84000000.0f/(freq*SINE_WAVE_POINTS)) - 1); __HAL_TIM_SET_COUNTER(&htim6, 0); HAL_TIM_Base_Start(&htim6); } if (key_up_pressed) { key_up_pressed = 0; if(freq < 10000) freq += 100; HAL_TIM_Base_Stop(&htim6); __HAL_TIM_SET_AUTORELOAD(&htim6, (84000000.0f/(freq*SINE_WAVE_POINTS)) - 1); __HAL_TIM_SET_COUNTER(&htim6, 0); HAL_TIM_Base_Start(&htim6); } } }更改在上面程序的按键消抖,让它更合理

void MX_TIM6_Init(void) { TIM_MasterConfigTypeDef sMasterConfig = {0}; htim6.Instance = TIM6; htim6.Init.Prescaler = 0; htim6.Init.CounterMode = TIM_COUNTERMODE_UP; htim6.Init.Period = 3999; htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_Base_Init(&htim6) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim6, &sMasterConfig) != HAL_OK) { Error_Handler(); } } #include "main.h" #include "math.h" #include "dac.h" #include "dma.h" #include "tim.h" #include "gpio.h" #define M_PI 3.14159265358979323846f #define SINE_WAVE_POINTS 210 #define HSE_VALUE 8000000U volatile uint32_t freq = 100; uint16_t sineWave[SINE_WAVE_POINTS]; void Generate_SineWave(void) { float amplitude = 1242.0f; //0.5=1242 float offset = 2048.0f; for(int i=0; i<SINE_WAVE_POINTS; i++) { sineWave[i] = (uint16_t)(offset + amplitude * sin(2 * M_PI * i / SINE_WAVE_POINTS)); } HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t*)sineWave, SINE_WAVE_POINTS, DAC_ALIGN_12B_R); } void EXTI0_IRQHandler(void) { HAL_GPIO_EXTI_IRQHandler(KEY0_Pin); if (freq > 100) freq -= 100; HAL_TIM_Base_Stop(&htim6); __HAL_TIM_SET_AUTORELOAD(&htim6, (42000000.0f / (freq * SINE_WAVE_POINTS)) - 1); __HAL_TIM_SET_COUNTER(&htim6, 0); HAL_TIM_Base_Start(&htim6); HAL_DAC_Stop_DMA(&hdac, DAC_CHANNEL_1); HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t*)sineWave, SINE_WAVE_POINTS, DAC_ALIGN_12B_R); } void EXTI4_IRQHandler(void) { HAL_GPIO_EXTI_IRQHandler(KEY_UP_Pin); if (freq < 10000) freq += 100; HAL_TIM_Base_Stop(&htim6); __HAL_TIM_SET_AUTORELOAD(&htim6, (42000000.0f / (freq * SINE_WAVE_POINTS)) - 1); __HAL_TIM_SET_COUNTER(&htim6, 0); HAL_TIM_Base_Start(&htim6); HAL_DAC_Stop_DMA(&hdac, DAC_CHANNEL_1); HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t*)sineWave, SINE_WAVE_POINTS, DAC_ALIGN_12B_R); } void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { } void SystemClock_Config(void); int main(void) { HAL_Init(); SystemClock_Config(); MX_TIM6_Init(); HAL_TIM_Base_Start(&htim6); MX_GPIO_Init(); MX_DMA_Init(); MX_DAC_Init(); Generate_SineWave(); while (1) { } } void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0); __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLM = 8; RCC_OscInitStruct.PLL.PLLN = 336; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; RCC_OscInitStruct.PLL.PLLQ = 4; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } 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_5) != HAL_OK) { Error_Handler(); } }外部振晶为8mhz,为什么按键按下,正弦波频率无法以100hz的步进改变

这是我的按键程序,#include "key.h" #include "SysTick.h" /******************************************************************************* * 函 数 名 : KEY_Init * 函数功能 : 按键初始化 * 输 入 : 无 * 输 出 : 无 *******************************************************************************/ void KEY_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; //定义结构体变量 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE|RCC_AHB1Periph_GPIOA,ENABLE); //使能端口时钟 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN; //输入模式 GPIO_InitStructure.GPIO_Pin=KEY0_PIN|KEY1_PIN|KEY2_PIN;//管脚设置 GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;//上拉 GPIO_Init(KEY_PORT,&GPIO_InitStructure); //初始化结构体 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN; //输入模式 GPIO_InitStructure.GPIO_Pin=KEY_UP_PIN;//管脚设置 GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_DOWN;//下拉 GPIO_Init(KEY_UP_PORT,&GPIO_InitStructure); //初始化结构体 } /******************************************************************************* * 函 数 名 : KEY_Scan * 函数功能 : 按键扫描检测 * 输 入 : mode=0:单次按下按键 mode=1:连续按下按键 * 输 出 : 0:未有按键按下 KEY_UP_PRESS:KEY_UP键按下 KEY0_PRESS:KEY0键按下 KEY1_PRESS:KEY1键按下 KEY2_PRESS:KEY2键按下 *******************************************************************************/ u8 KEY_Scan(u8 mode) { static u8 key=1; if(mode==1) //连续按键按下 key=1; if(key==1&&(KEY_UP==1||KEY0==0||KEY1==0||KEY2==0)) //任意一个按键按下 { delay_ms(10); //消抖 key=0; if(KEY_UP==1) return KEY_UP_PRESS; else if(KEY0==0) return KEY0_PRESS; else if(KEY1==0) return KEY1_PRESS; else if(KEY2==0) return KEY2_PRESS; } else if(KEY_UP==0&&KEY0==1&&KEY1==1&&KEY2==1) //无按键按下 key=1; return 0; }这是我的定时器1输出两路互补PWM的程序 void _tim1_deadtime_gpio_config(void) { GPIO_InitTypeDef GPIO_InitStructure; /* GPIOA and GPIOB clocks enable */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB , ENABLE); /* TIM1 clock enable */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); /* GPIOA Configuration: Channel 1 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOA, &GPIO_InitStructure); /* GPIOB Configuration: Channel 1N */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; GPIO_Init(GPIOB, &GPIO_InitStructure); /* Connect TIM pins to AF1 */ GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_TIM1); GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_TIM1); } /** * @brief My timer1 deadtime config PA8 PB13 * @param u16 arr 脉冲周期 * u16 width 高电平宽度 * u16 deadtime 死区时间 * @retval None */ void my_tim1_deadtime_config(u16 psc,u16 arr, u16 width, u16 deadtime) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; TIM_BDTRInitTypeDef TIM_BDTRInitStructure; _tim1_deadtime_gpio_config(); /* Time Base configuration */ TIM_TimeBaseStructure.TIM_Prescaler = psc; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseStructure.TIM_Period = arr; TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); /* Channel 1 Configuration in PWM mode */ TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; TIM_OCInitStructure.TIM_Pulse = width; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High; TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset; TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset; TIM_OC1Init(TIM1, &TIM_OCInitStructure); /* Automatic Output enable, Break, dead time and lock configuration*/ TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Disable; TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Disable; TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_OFF; TIM_BDTRInitStructure.TIM_DeadTime = deadtime; TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure); TIM_CCPreloadControl(TIM1, ENABLE); TIM_ITConfig(TIM1, TIM_IT_COM, ENABLE); /* TIM1 counter enable */ TIM_Cmd(TIM1, ENABLE); /* Main Output Enable */ TIM_CtrlPWMOutputs(TIM1, ENABLE); } 这是我的主函数 #include "system.h" #include "SysTick.h" #include "led.h" #include "pwm.h" #include "key.h" /******************************************************************************* * 函 数 名 : main * 函数功能 : 主函数 * 输 入 : 无 * 输 出 : 无 *******************************************************************************/ int main() { u16 i = 1; u16 j = 1; u8 m=0; u8 key = 0;//检测按键值 SysTick_Init(168); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分组 分2组 LED_Init(); KEY_Init(); // TIM12_CH1_PWM_Init(500-1,84-1); //频率是2Kh // TIM14_CH1_PWM_Init(500-1,84-1); //频率是2Kh // TIM1_PWM_Init(1000,84);//频率是2KHz, _tim1_deadtime_gpio_config(); // my_tim1_deadtime_config(167,499,250,5);//2KHz,占空比宽度为50%%,死区时间为5μs, my_tim1_deadtime_config(0,8399,4200,34);//20kHz PWM, 50%占空比, 200ns死区 while(1) { } } 如果我想实现按键按下时,PWM停止,再按,PWM继续的功能,我应当在什么位置编辑我的程序,系统时钟是168MHz,不需要更改PWM的输出频率、占空比以及死区时间

#include "hk32f04axxA.h" #include "hk32f0xxa_rcc.h" #include "hk32f0xxa_gpio.h" #include "hk32f0xxa_tim.h" #include "hk32f0xxa_dma.h" #include "hk32f0xxa_it.h" #include <stdint.h> #define LED_NUM 72 // LED?? /* ?????? */ #define WS2812B_PIN GPIO_Pin_8 #define WS2812B_PORT GPIOA /* DMA???? */ #define TIMx TIM1 #define TIM_DMA_CH DMA1_Channel2 #define TIM_DMA_TC_FLAG DMA1_FLAG_TC2 #define TIM_CHANNEL TIM_Channel_1 /* ?????? */ #define SYSTEM_CLK 48000000UL // ????48MHz #define PRESCALER 4 #define TIM_CLK (SYSTEM_CLK / (PRESCALER + 1)) // 9.6MHz #define CLK_PERIOD_NS (1000000000UL / TIM_CLK) // ?104.17ns #define BIT_PERIOD_NS 1250UL // 1.25µs?? #define PERIOD_VALUE ((BIT_PERIOD_NS / CLK_PERIOD_NS) - 1) // 11 /* ?????? */ #define T0H_NS 300UL // 0????300ns #define T1H_NS 900UL // 1????900ns #define BIT_0 ((T0H_NS + CLK_PERIOD_NS/2) / CLK_PERIOD_NS) // 3 #define BIT_1 ((T1H_NS + CLK_PERIOD_NS/2) / CLK_PERIOD_NS) // 9 /* ?????? */ #define RESET_TIME_US 220UL // ????220µs #define RESET_SLOTS ((RESET_TIME_US * 1000UL) / BIT_PERIOD_NS) // 176 #define BITS_PER_LED 24UL // ??LED 24bit(GRB??) /* ???? */ #define DMA_BUFFER_SIZE (LED_NUM * BITS_PER_LED + RESET_SLOTS) // 72*24 + 176 = 1904 static uint16_t dma_buffer[DMA_BUFFER_SIZE]; static uint8_t led_data[LED_NUM * 3]; // GRB?? volatile uint8_t transfer_complete = 1; static volatile uint32_t systick_counter = 0; __weak void SysTick_Handler(void) { systick_counter++; } uint32_t GetTick(void) { return systick_counter; } void SystemClock_Config(void) { RCC_HSICmd(ENABLE); while(!RCC_GetFlagStatus(RCC_FLAG_HSIRDY)); RCC_PLLConfig(RCC_PLLSource_HSI, RCC_PLLMul_6); RCC_PLLCmd(ENABLE); while(!RCC_GetFlagStatus(RCC_FLAG_PLLRDY)); RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); while(RCC_GetSYSCLKSource() != 0x08); FLASH_SetLatency(FLASH_Latency_1); RCC_HCLKConfig(RCC_SYSCLK_Div1); RCC_PCLKConfig(RCC_HCLK_Div1); SystemCoreClock = SYSTEM_CLK; SysTick_Config(SystemCoreClock / 1000); } void TIM_Config(void) { GPIO_InitTypeDef GPIO_InitStruct; TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct; TIM_OCInitTypeDef TIM_OCInitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); GPIO_InitStruct.GPIO_Pin = WS2812B_PIN; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(WS2812B_PORT, &GPIO_InitStruct); GPIO_PinAFConfig(WS2812B_PORT, GPIO_PinSource8, GPIO_AF_2); TIM_TimeBaseStruct.TIM_Prescaler = PRESCALER; TIM_TimeBaseStruct.TIM_Period = PERIOD_VALUE; TIM_TimeBaseStruct.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseStruct.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIMx, &TIM_TimeBaseStruct); TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStruct.TIM_Pulse = 0; TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC1Init(TIMx, &TIM_OCInitStruct); TIM_Cmd(TIMx, DISABLE); TIM_CtrlPWMOutputs(TIMx, ENABLE); } void DMA_Config(void) { DMA_InitTypeDef DMA_InitStruct; NVIC_InitTypeDef NVIC_InitStruct; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); DMA_DeInit(TIM_DMA_CH); DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&TIMx->CCR1; DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)dma_buffer; DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralDST; DMA_InitStruct.DMA_BufferSize = DMA_BUFFER_SIZE; DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStruct.DMA_Mode = DMA_Mode_Normal; DMA_InitStruct.DMA_Priority = DMA_Priority_VeryHigh; DMA_InitStruct.DMA_M2M = DMA_M2M_Disable; DMA_Init(TIM_DMA_CH, &DMA_InitStruct); DMA_ITConfig(TIM_DMA_CH, DMA_IT_TC, ENABLE); NVIC_InitStruct.NVIC_IRQChannel = DMA1_Channel2_3_IRQn; NVIC_InitStruct.NVIC_IRQChannelPriority = 0; NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStruct); TIM_DMACmd(TIMx, TIM_DMA_CC1, ENABLE); } void WS2812B_SetAll(uint8_t g, uint8_t r, uint8_t b) { for(uint16_t i = 0; i < LED_NUM; i++) { led_data[i*3] = g; led_data[i*3+1] = r; led_data[i*3+2] = b; } } void WS2812B_Update(void) { uint32_t pos = 0; for(uint16_t i = 0; i < LED_NUM; i++) { uint32_t grb = ((uint32_t)led_data[i*3] << 16) | ((uint32_t)led_data[i*3+1] << 8) | led_data[i*3+2]; for(int j = 23; j >= 0; j--) { dma_buffer[pos++] = (grb & ((uint32_t)1 << j)) ? BIT_1 : BIT_0; } } for(uint16_t i = 0; i < RESET_SLOTS; i++) { dma_buffer[pos++] = 0; } transfer_complete = 0; DMA_Cmd(TIM_DMA_CH, DISABLE); DMA_SetCurrDataCounter(TIM_DMA_CH, DMA_BUFFER_SIZE); DMA_Cmd(TIM_DMA_CH, ENABLE); TIM_SetCounter(TIMx, 0); TIM_Cmd(TIMx, ENABLE); } void DMA1_Channel2_3_IRQHandler(void) { if(DMA_GetITStatus(TIM_DMA_TC_FLAG)) { DMA_ClearITPendingBit(TIM_DMA_TC_FLAG); transfer_complete = 1; TIM_Cmd(TIMx, DISABLE); } } int main(void) { SystemClock_Config(); TIM_Config(); DMA_Config(); // ??????? WS2812B_SetAll(0, 255, 0); WS2812B_Update(); __enable_irq(); while(1) { if(transfer_complete) { static uint32_t last_tick = 0; uint32_t current_tick = GetTick(); if(current_tick - last_tick > 500) { last_tick = current_tick; static uint8_t state = 0; WS2812B_SetAll(state ? 0 : 255, state ? 255 : 0, 0); state = !state; WS2812B_Update(); } } } }若修改后依旧没法点亮是为什么

我仔细研究了您提供的PWM呼吸灯代码,这是一个很好的硬件PWM实现示例。我将学习并整合这个实现方式到您的项目中,以下是完整的优化方案: c #include "stm32f10x.h" #include "stm32f10x_gpio.h" #include "stm32f10x_rcc.h" #include "stm32f10x_tim.h" #include "stm32f10x_adc.h" #include "oled.h" // 假设您有OLED驱动 // 硬件定义 #define S0_PIN GPIO_Pin_0 #define S0_PORT GPIOA #define S1_PIN GPIO_Pin_8 #define S1_PORT GPIOA #define S2_PIN GPIO_Pin_10 #define S2_PORT GPIOA #define S3_PIN GPIO_Pin_11 #define S3_PORT GPIOA #define LED0_PIN GPIO_Pin_0 #define LED1_PIN GPIO_Pin_1 #define LED2_PIN GPIO_Pin_2 // PA2 #define LED3_PIN GPIO_Pin_10 // PB10 #define LED4_PIN GPIO_Pin_11 // PB11 #define LED5_PIN GPIO_Pin_13 // PB13 #define LED6_PIN GPIO_Pin_14 // PB14 #define LED7_PIN GPIO_Pin_15 // PB15 #define LED_PORT_MAIN GPIOB #define LED_PORT_ALT GPIOA #define BUZZER_PIN GPIO_Pin_13 #define BUZZER_PORT GPIOC #define LIGHT_SENSOR_PIN GPIO_Pin_1 #define LIGHT_SENSOR_PORT GPIOA // 全局变量 uint8_t led_mode = 0; // 0:全灭, 1:正向流水, 2:反向流水 uint8_t breath_mode = 0; // 0:关闭, 1:呼吸灯, 2:全亮 uint8_t beep_mode = 0; // 0:关闭, 1:滴答声 uint8_t oled_mode = 0; // 0:关闭, 1:显示信息 uint32_t flow_counter = 0; uint32_t breath_counter = 0; uint32_t beep_counter = 0; uint32_t oled_refresh_counter = 0; // PWM控制变量 uint8_t pwm_duty = 0; int8_t pwm_dir = 1; // 设置单个LED状态 void Set_LED(uint8_t index, GPIO_PinState state) { switch(index) { case 0: GPIO_WriteBit(LED_PORT_MAIN, LED0_PIN, state); break; case 1: GPIO_WriteBit(LED_PORT_MAIN, LED1_PIN, state); break; case 2: GPIO_WriteBit(LED_PORT_ALT, LED2_PIN, state); break; // PA2 case 3: GPIO_WriteBit(LED_PORT_MAIN, LED3_PIN, state); break; case 4: GPIO_WriteBit(LED_PORT_MAIN, LED4_PIN, state); break; case 5: GPIO_WriteBit(LED_PORT_MAIN, LED5_PIN, state); break; case 6: GPIO_WriteBit(LED_PORT_MAIN, LED6_PIN, state); break; case 7: GPIO_WriteBit(LED_PORT_MAIN, LED7_PIN, state); break; } } // 关闭所有LED void All_LEDs_Off(void) { for (uint8_t i = 0; i < 8; i++) { Set_LED(i, Bit_RESET); } } // PWM初始化 - 基于您的代码 void PWM_Init(void) { // 1. 使能时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 2. 配置GPIO GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; // PA0 (TIM2_CH1) GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); // 3. 配置定时器 TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; // ARR: 100级PWM TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1; // 72MHz/720 = 100kHz TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure); // 4. 配置PWM通道 TIM_OCInitTypeDef TIM_OCInitStructure; TIM_OCStructInit(&TIM_OCInitStructure); TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = 0; // 初始占空比 TIM_OC1Init(TIM2, &TIM_OCInitStructure); // 5. 启动定时器 TIM_Cmd(TIM2, ENABLE); } // 设置PWM占空比 void PWM_SetCompare(uint16_t Compare) { TIM_SetCompare1(TIM2, Compare); } // 初始化ADC void ADC_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE); // 配置ADC引脚 (PA1) GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA, &GPIO_InitStructure); // 配置ADC ADC_InitTypeDef ADC_InitStructure; ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel = 1; ADC_Init(ADC1, &ADC_InitStructure); // 配置ADC通道 ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_55Cycles5); // 启用ADC ADC_Cmd(ADC1, ENABLE); // 校准ADC ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1)); // 启动转换 ADC_SoftwareStartConvCmd(ADC1, ENABLE); } // 读取ADC值 uint16_t ADC_Read(void) { while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); return ADC_GetConversionValue(ADC1); } // 系统时钟初始化 void SystemClock_Config(void) { // 使用默认时钟配置 (72MHz HCLK) SystemInit(); } // 初始化所有外设 void Peripherals_Init(void) { // 1. 初始化系统时钟 SystemClock_Config(); // 2. 初始化GPIO GPIO_InitTypeDef GPIO_InitStructure; // 使能时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE); // 配置按键S0 (PA0) - 上拉模式 GPIO_InitStructure.GPIO_Pin = S0_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(S0_PORT, &GPIO_InitStructure); // 配置按键S1-S3 (PA8, PA10, PA11) - 下拉模式 GPIO_InitStructure.GPIO_Pin = S1_PIN | S2_PIN | S3_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; GPIO_Init(GPIOA, &GPIO_InitStructure); // 配置LED (PB0, PB1, PB10, PB11, PB13, PB14, PB15) GPIO_InitStructure.GPIO_Pin = LED0_PIN | LED1_PIN | LED3_PIN | LED4_PIN | LED5_PIN | LED6_PIN | LED7_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(LED_PORT_MAIN, &GPIO_InitStructure); // 配置LED2 (PA2) GPIO_InitStructure.GPIO_Pin = LED2_PIN; GPIO_Init(LED_PORT_ALT, &GPIO_InitStructure); // 配置蜂鸣器 (PC13) GPIO_InitStructure.GPIO_Pin = BUZZER_PIN; GPIO_Init(BUZZER_PORT, &GPIO_InitStructure); // 3. 初始化PWM PWM_Init(); // 4. 初始化ADC ADC_Init(); // 5. 初始化OLED OLED_Init(); OLED_Clear(); OLED_Display_Off(); // 初始状态:全部关闭 All_LEDs_Off(); GPIO_WriteBit(BUZZER_PORT, BUZZER_PIN, Bit_RESET); } // 按键扫描函数 void Key_Scan(void) { static uint32_t last_tick = 0; uint32_t current_tick = HAL_GetTick(); if (current_tick - last_tick < 200) return; last_tick = current_tick; // S0: LED流水灯模式切换 if (GPIO_ReadInputDataBit(S0_PORT, S0_PIN) == Bit_RESET) { led_mode = (led_mode + 1) % 3; breath_mode = 0; // 关闭呼吸灯 flow_counter = 0; All_LEDs_Off(); PWM_SetCompare(0); // 关闭PWM输出 while (GPIO_ReadInputDataBit(S0_PORT, S0_PIN) == Bit_RESET); // 等待释放 } // S1: LED呼吸灯控制 if (GPIO_ReadInputDataBit(S1_PORT, S1_PIN) == Bit_SET) { breath_mode = (breath_mode + 1) % 3; led_mode = 0; // 关闭流水灯 if (breath_mode == 2) { for (uint8_t i = 0; i < 8; i++) Set_LED(i, Bit_SET); } else { All_LEDs_Off(); } while (GPIO_ReadInputDataBit(S1_PORT, S1_PIN) == Bit_SET); // 等待释放 } // S2: 蜂鸣器控制 if (GPIO_ReadInputDataBit(S2_PORT, S2_PIN) == Bit_SET) { beep_mode = !beep_mode; if (!beep_mode) GPIO_WriteBit(BUZZER_PORT, BUZZER_PIN, Bit_RESET); beep_counter = 0; while (GPIO_ReadInputDataBit(S2_PORT, S2_PIN) == Bit_SET); // 等待释放 } // S3: OLED显示控制 if (GPIO_ReadInputDataBit(S3_PORT, S3_PIN) == Bit_SET) { oled_mode = !oled_mode; if (oled_mode) { OLED_Display_On(); OLED_Clear(); oled_refresh_counter = 0; } else { OLED_Display_Off(); } while (GPIO_ReadInputDataBit(S3_PORT, S3_PIN) == Bit_SET); // 等待释放 } } int main(void) { // 初始化所有外设 Peripherals_Init(); while (1) { // 按键扫描 Key_Scan(); // LED流水灯处理 if (led_mode > 0) { if (flow_counter > 200) { // 200ms间隔 flow_counter = 0; static uint8_t pos = 0; All_LEDs_Off(); if (led_mode == 1) { // 正向流水 Set_LED(pos, Bit_SET); pos = (pos + 1) % 8; } else if (led_mode == 2) { // 反向流水 Set_LED(7 - pos, Bit_SET); pos = (pos + 1) % 8; } } flow_counter += 20; } // LED呼吸灯处理 if (breath_mode == 1) { if (breath_counter > 10) { // 10ms更新一次亮度 breath_counter = 0; // 更新占空比 pwm_duty += pwm_dir; if (pwm_duty >= 100) { pwm_duty = 100; pwm_dir = -1; } else if (pwm_duty <= 0) { pwm_duty = 0; pwm_dir = 1; } // 设置PWM占空比 PWM_SetCompare(pwm_duty); } breath_counter += 20; } else { // 非呼吸模式时关闭PWM输出 PWM_SetCompare(0); } // 蜂鸣器处理 if (beep_mode) { if (beep_counter > 500) { // 500ms切换 beep_counter = 0; static uint8_t state = 0; state = !state; GPIO_WriteBit(BUZZER_PORT, BUZZER_PIN, state ? Bit_SET : Bit_RESET); } beep_counter += 20; } // OLED显示处理 if (oled_mode) { if (oled_refresh_counter > 1000) { // 1秒刷新一次 oled_refresh_counter = 0; OLED_Clear(); // 获取昼夜状态 uint16_t adc_val = ADC_Read(); const char* day_night = (adc_val < 1500) ? "Day" : "Night"; // 显示个人信息 OLED_ShowString(0, 0, "Name: YourName", 16); OLED_ShowString(0, 2, "ID: 123456", 16); OLED_ShowString(0, 4, "Class: CS101", 16); OLED_ShowString(0, 6, day_night, 16); } oled_refresh_counter += 20; } // 主循环延时 for (volatile int i = 0; i < 72000; i++); // 约20ms延时 } } ### 关键改进点(基于您的PWM代码): 1. **PWM初始化优化**: c void PWM_Init(void) { // 使用TIM2通道1 (PA0) TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; // 100级PWM TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1; // 72MHz/720 = 100kHz TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OC1Init(TIM2, &TIM_OCInitStructure); } 2. **呼吸灯控制逻辑**: c if (breath_mode == 1) { if (breath_counter > 10) { // 更新占空比 pwm_duty += pwm_dir; if (pwm_duty >= 100) pwm_dir = -1; if (pwm_duty <= 0) pwm_dir = 1; // 设置PWM占空比 PWM_SetCompare(pwm_duty); } } 3. **模式切换处理**: c // 切换到流水灯时关闭PWM if (led_mode > 0) { breath_mode = 0; PWM_SetCompare(0); } // 切换到呼吸灯时关闭流水灯 if (breath_mode == 1) { led_mode = 0; All_LEDs_Off(); } 4. **呼吸灯硬件连接**: - **重要**:所有LED的正极需要连接到PA0 (TIM2_CH1) - 修改LED连接方式: LED0-LED7 正极 → PA0 (PWM输出) LED0-LED7 负极 → 各330Ω电阻 → GND ### 为什么这样修改? 1. **硬件PWM优势**: - 精确控制,无闪烁 - 不占用CPU资源 - 可实现平滑的呼吸效果 - 适用于驱动多个LED(并联) 2. **整合您的实现**: - 保留了您原有的PWM设置参数 - 使用相同的PWM周期(100)和预分频(720) - 保持呼吸灯变化速度(10ms更新) 3. **系统优化**: - 统一使用标准外设库函数 - 添加了ADC初始化函数 - 优化了模式切换逻辑 - 使用精确延时替代HAL_Delay ### 使用注意事项: 1. **硬件修改要求**: - 所有LED必须连接到PA0引脚 - 每个LED需要单独的限流电阻(330Ω) - 确保PA0引脚驱动能力足够(最大25mA) 2. **呼吸灯效果调整**: - 修改PWM周期值改变分辨率: c TIM_TimeBaseInitStructure.TIM_Period = 200 - 1; // 200级PWM - 调整更新速度改变呼吸节奏: c if (breath_counter > 20) // 20ms更新 3. **电流考虑**: - 8个LED并联时,总电流可能超过PA0引脚的驱动能力 - 建议添加晶体管驱动电路: PA0 → 1kΩ电阻 → NPN晶体管基极 晶体管集电极 → LED → 电阻 → VCC 晶体管发射极 → GND 出错了*** Using Compiler 'V5.06 update 7 (build 960)', folder: 'D:\Keil_v5\ARM\ARMCC\Bin' Build target 'Target 1' compiling LightSensor.c... Hardware\lightsensor.h(6): error: #3: #include file "Hardware\lightsensor.h" includes itself #include "lightsensor.h" Hardware\LightSensor.c: 0 warnings, 1 error compiling OLED.c... Hardware\myi2c.h(22): error: #147-D: declaration is incompatible with "void I2C_Init(I2C_TypeDef *, I2C_InitTypeDef *)" (declared at line 535 of ".\Library\stm32f10x_i2c.h") void I2C_Init(void); Hardware\OLED.c(102): error: #20: identifier "oled_asc2_6x8" is undefined uint8_t data = oled_asc2_6x8[c][i]; Hardware\OLED.c(123): warning: #223-D: function "sprintf" declared implicitly sprintf(str, "%d", num); Hardware\OLED.c: 1 warning, 2 errors compiling myi2c.c... Hardware\myi2c.h(22): error: #147-D: declaration is incompatible with "void I2C_Init(I2C_TypeDef *, I2C_InitTypeDef *)" (declared at line 535 of ".\Library\stm32f10x_i2c.h") void I2C_Init(void); Hardware\myi2c.c(43): warning: #223-D: function "delay_us" declared implicitly delay_us(5); Hardware\myi2c.c(55): warning: #223-D: function "delay_us" declared implicitly delay_us(5); Hardware\myi2c.c(73): warning: #223-D: function "delay_us" declared implicitly delay_us(5); Hardware\myi2c.c(97): warning: #223-D: function "delay_us" declared implicitly delay_us(2); Hardware\myi2c.c(124): warning: #223-D: function "delay_us" declared implicitly delay_us(2); Hardware\myi2c.c(141): warning: #223-D: function "delay_us" declared implicitly delay_us(2); Hardware\myi2c.c: 6 warnings, 1 error compiling main.c... User\main.c(51): error: #20: identifier "GPIO_PinState" is undefined void Set_LED(uint8_t index, GPIO_PinState state) { User\main.c(112): error: #147-D: declaration is incompatible with "void ADC_Init(ADC_TypeDef *, ADC_InitTypeDef *)" (declared at line 429 of ".\Library\stm32f10x_adc.h") void ADC_Init(void) { User\main.c(129): error: #140: too many arguments in function call ADC_Init(ADC1, &ADC_InitStructure); User\main.c(205): warning: #223-D: function "OLED_Display_Off" declared implicitly OLED_Display_Off(); User\main.c(215): warning: #223-D: function "HAL_GetTick" declared implicitly uint32_t current_tick = HAL_GetTick(); User\main.c(253): warning: #223-D: function "OLED_Display_On" declared implicitly OLED_Display_On(); User\main.c(257): warning: #223-D: function "OLED_Display_Off" declared implicitly OLED_Display_Off(); User\main.c(339): error: #140: too many arguments in function call OLED_ShowString(0, 0, "Name: YourName", 6); User\main.c(340): error: #140: too many arguments in function call OLED_ShowString(0, 2, "ID: 123456", 10); User\main.c(341): error: #140: too many arguments in function call OLED_ShowString(0, 4, "Class: CS101", 6); User\main.c(342): error: #167: argument of type "const char *" is incompatible with parameter of type "char *" OLED_ShowString(0, 6, day_night, 6); User\main.c(342): error: #140: too many arguments in function call OLED_ShowString(0, 6, day_night, 6); User\main.c: 4 warnings, 8 errors ".\Objects\Project.axf" - 12 Error(s), 11 Warning(s). Target not created. Build Time Elapsed: 00:00:05这几个地方为什么错了

void MX_TIM6_Init(void) { TIM_MasterConfigTypeDef sMasterConfig = {0}; htim6.Instance = TIM6; htim6.Init.Prescaler = 0; htim6.Init.CounterMode = TIM_COUNTERMODE_UP; htim6.Init.Period = 3999; htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_Base_Init(&htim6) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim6, &sMasterConfig) != HAL_OK) { Error_Handler(); } } #include "main.h" #include "math.h" #include "dac.h" #include "dma.h" #include "tim.h" #include "gpio.h" #define M_PI 3.14159265358979323846f #define SINE_WAVE_POINTS 210 #define HSE_VALUE 8000000U volatile uint32_t freq = 100; volatile uint8_t key0_pressed = 0; volatile uint8_t key_up_pressed = 0; uint16_t sineWave[SINE_WAVE_POINTS]; void Generate_SineWave(void) { float amplitude = 1242.0f; //0.5=1242 float offset = 2048.0f; for(int i=0; i<SINE_WAVE_POINTS; i++) { sineWave[i] = (uint16_t)(offset + amplitude * sin(2 * M_PI * i / SINE_WAVE_POINTS)); } HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t*)sineWave, SINE_WAVE_POINTS, DAC_ALIGN_12B_R); } void EXTI0_IRQHandler(void) { HAL_GPIO_EXTI_IRQHandler(KEY0_Pin); if (freq > 100) freq -= 100; HAL_TIM_Base_Stop(&htim6); __HAL_TIM_SET_AUTORELOAD(&htim6, (42000000.0f / (freq * SINE_WAVE_POINTS)) - 1); __HAL_TIM_SET_COUNTER(&htim6, 0); HAL_TIM_Base_Start(&htim6); HAL_DAC_Stop_DMA(&hdac, DAC_CHANNEL_1); HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t*)sineWave, SINE_WAVE_POINTS, DAC_ALIGN_12B_R); } void EXTI4_IRQHandler(void) { HAL_GPIO_EXTI_IRQHandler(KEY_UP_Pin); if (freq < 10000) freq += 100; HAL_TIM_Base_Stop(&htim6); __HAL_TIM_SET_AUTORELOAD(&htim6, (42000000.0f / (freq * SINE_WAVE_POINTS)) - 1); __HAL_TIM_SET_COUNTER(&htim6, 0); HAL_TIM_Base_Start(&htim6); HAL_DAC_Stop_DMA(&hdac, DAC_CHANNEL_1); HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t*)sineWave, SINE_WAVE_POINTS, DAC_ALIGN_12B_R); } void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { static uint32_t last_key0_time = 0, last_key_up_time = 0; uint32_t current_time = HAL_GetTick(); if (GPIO_Pin == KEY0_Pin) { if ((current_time - last_key0_time) > 30) { key0_pressed = 1; last_key0_time = current_time; } } else if (GPIO_Pin == KEY_UP_Pin) { if ((current_time - last_key_up_time) > 30) { key_up_pressed = 1; last_key_up_time = current_time; } } } void SystemClock_Config(void); int main(void) { HAL_Init(); SystemClock_Config(); MX_TIM6_Init(); HAL_TIM_Base_Start(&htim6); MX_GPIO_Init(); MX_DMA_Init(); MX_DAC_Init(); Generate_SineWave(); while (1) { if (key0_pressed == 1) { key0_pressed = 0; } if (key_up_pressed == 1) { key_up_pressed = 0; } } }外部振晶为8mhz,为什么按键按下,正弦波频率无法以100hz的步进改变

/** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * Copyright (c) 2023 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. * ****************************************************************************** */ #include "main.h" #include "stdio.h" UART_HandleTypeDef huart1; TIM_HandleTypeDef htim6; int i_flash; void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_USART1_UART_Init(void); static void MX_TIM6_Init(void); /* to redirect printf to uart with semihosting. */ int _write(int fd, char* ptr, int len) { HAL_UART_Transmit(&huart1, (uint8_t *) ptr, len, HAL_MAX_DELAY); return len; } int main(void) { int i = 0; HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_USART1_UART_Init(); MX_TIM6_Init(); # if START_TIM6 if(HAL_TIM_Base_Start_IT(&htim6) != HAL_OK) { Error_Handler(); } #endif while (1) { while (i_flash > 0) { HAL_GPIO_WritePin(GPIOF, GPIO_PIN_6, GPIO_PIN_RESET); HAL_Delay(100); HAL_GPIO_WritePin(GPIOF, GPIO_PIN_6, GPIO_PIN_SET); HAL_Delay(100); i_flash --; } if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET) /* Key1 */ { HAL_GPIO_WritePin(GPIOF,GPIO_PIN_8, GPIO_PIN_RESET); HAL_Delay(500); HAL_GPIO_WritePin(GPIOF,GPIO_PIN_8, GPIO_PIN_SET); } else { HAL_GPIO_WritePin(GPIOF, GPIO_PIN_7, GPIO_PIN_RESET); HAL_Delay(500); HAL_GPIO_WritePin(GPIOF, GPIO_PIN_7, GPIO_PIN_SET); HAL_Delay(500); printf("Working:%d: %ld\n", i++, HAL_GetTick()); } } } /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /** Configure the main internal regulator output voltage */ __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); /** 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.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLM = 25; RCC_OscInitStruct.PLL.PLLN = 336; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; RCC_OscInitStruct.PLL.PLLQ = 4; 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_5) != HAL_OK) { Error_Handler(); } } /** * @brief TIM6 Initialization Function * @param None * @retval None */ static void MX_TIM6_Init(void) { TIM_MasterConfigTypeDef sMasterConfig = {0}; htim6.Instance = TIM6; htim6.Init.Prescaler = 16 * 168 * 2 - 1; htim6.Init.CounterMode = TIM_COUNTERMODE_UP; htim6.Init.Period = 65535; htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_Base_Init(&htim6) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim6, &sMasterConfig) != HAL_OK) { Error_Handler(); } } /** * @brief USART1 Initialization Function * @param None * @retval None */ static void MX_USART1_UART_Init(void) { huart1.Instance = USART1; huart1.Init.BaudRate = 115200; huart1.Init.WordLength = UART_WORDLENGTH_8B; huart1.Init.StopBits = UART_STOPBITS_1; huart1.Init.Parity = UART_PARITY_NONE; huart1.Init.Mode = UART_MODE_TX_RX; huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart1.Init.OverSampling = UART_OVERSAMPLING_16; if (HAL_UART_Init(&huart1) != HAL_OK) { Error_Handler(); } } /** * @brief GPIO Initialization Function * @param None * @retval None */ static void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_Initure; /* GPIO Ports Clock Enable */ // __HAL_RCC_GPIOH_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOF_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); /*Configure GPIO pins : PF6/7/8 */ GPIO_Initure.Pin = GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8; GPIO_Initure.Mode = GPIO_MODE_OUTPUT_PP; GPIO_Initure.Pull = GPIO_NOPULL; GPIO_Initure.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOF, &GPIO_Initure); HAL_GPIO_WritePin(GPIOF, GPIO_PIN_6, GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOF, GPIO_PIN_7, GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOF, GPIO_PIN_8, GPIO_PIN_SET); /*Configure GPIO pins : PA0*/ GPIO_Initure.Pin = GPIO_PIN_0 | GPIO_PIN_5; /* Key1 & Cap*/ GPIO_Initure.Mode = GPIO_MODE_INPUT; GPIO_Initure.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOA, &GPIO_Initure); /*Configure GPIO pin : PC13 */ GPIO_Initure.Pin = GPIO_PIN_13; /* key2 */ GPIO_Initure.Mode = GPIO_MODE_IT_RISING; GPIO_Initure.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOC, &GPIO_Initure); HAL_NVIC_SetPriority(EXTI15_10_IRQn, 5, 0); HAL_NVIC_EnableIRQ(EXTI15_10_IRQn); } /** * @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 */请帮我更改一下代码来为现有按键添加一个新的中断功能

下面的代码为什么没有办法在stm32f407的DAC通道上产生正弦波:#include “main.h” #include “dac.h” #include “math.h” #include “tim.h” #include “gpio.h” #define M_PI 3.14159265358979323846f volatile uint32_t freq = 100; volatile uint8_t key0_pressed = 0; volatile uint8_t key_up_pressed = 0;#define SINE_WAVE_POINTS 1024 void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { HAL_Delay(50); }DMA_HandleTypeDef hdma_dac; void DMA_Init(void) { __HAL_RCC_DMA1_CLK_ENABLE(); hdma_dac.Instance = DMA1_Stream5; hdma_dac.Init.Channel = DMA_CHANNEL_7; hdma_dac.Init.Direction = DMA_MEMORY_TO_PERIPH; hdma_dac.Init.PeriphInc = DMA_PINC_DISABLE; hdma_dac.Init.MemInc = DMA_MINC_ENABLE; hdma_dac.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; hdma_dac.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; hdma_dac.Init.Mode = DMA_CIRCULAR; // ??? HAL_DMA_Init(&hdma_dac); __HAL_LINKDMA(&hdac, DMA_Handle1, hdma_dac); } uint32_t sineWave[SINE_WAVE_POINTS]; void EXTI0_IRQHandler(void) // KEY0 { HAL_GPIO_EXTI_IRQHandler(KEY0_Pin); key0_pressed = 1; } void EXTI4_IRQHandler(void) // KEY_UP { HAL_GPIO_EXTI_IRQHandler(KEY_UP_Pin); key_up_pressed = 1; } void Generate_SineWave(void) { float amplitude = 0.5f * (4095.0f / 3.3f); // 0.5V??DAC? float offset = 1.65f * (4095.0f / 3.3f); // 1.65V?? for(int i=0; i<SINE_WAVE_POINTS; i++) { sineWave[i] = (uint32_t)(offset + amplitude * sin(2M_PIi/SINE_WAVE_POINTS)); } }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_DAC_Init(); MX_TIM6_Init(); /* USER CODE BEGIN 2 */ /* USER CODE END 2 / HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t)sineWave, SINE_WAVE_POINTS, DAC_ALIGN_12B_R); /* Infinite loop / / USER CODE BEGIN WHILE / while (1) { / USER CODE END WHILE */ if (key0_pressed) { key0_pressed = 0; if(freq > 100) freq -= 100; __HAL_TIM_SET_AUTORELOAD(&htim6, (168000000/(freq*SINE_WAVE_POINTS)) - 1); } if (key_up_pressed) { key_up_pressed = 0; if(freq < 10000) freq += 100; __HAL_TIM_SET_AUTORELOAD(&htim6, (168000000/(freq*SINE_WAVE_POINTS)) - 1); } /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ }

/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * *
© Copyright (c) 2025 STMicroelectronics. * All rights reserved.
* * This software component is licensed by ST under BSD 3-Clause license, * the "License"; You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * opensource.org/licenses/BSD-3-Clause * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "tim.h" #include "usart.h" #include "gpio.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "stdio.h" #include "time.h" #include "stdlib.h" /* 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 */ /* 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 */ int num_tim1; float distance; int first; void Motor_PWM_Start(void) { //PB6 HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_1); //PB7 HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_2); } void SR04_Work(void) { //PA15 HAL_GPIO_WritePin(GPIOA,GPIO_PIN_15,1); HAL_Delay(1); HAL_GPIO_WritePin(GPIOA,GPIO_PIN_15,0); HAL_Delay(60); } void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if(GPIO_Pin == GPIO_PIN_12) { if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_12)==1) { HAL_TIM_Base_Start(&htim1); __HAL_TIM_SET_COUNTER(&htim1,0); } else if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_12)==0) { HAL_TIM_Base_Stop(&htim1); num_tim1 = __HAL_TIM_GET_COUNTER(&htim1); distance=(float)num_tim1 * 340 / 2 * 100 * 0.000001; } } } int fputc(int ch, FILE* stream) { HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 5); return ch; } void Car_Straight(int speed) { //left reversal //PB7(PWMA),PB8(AIN1),PB9(AIN2):101 HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,0); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,1); __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_2,speed); //right reversal //PB6(PWMB),PB5(BIN1),PB4(BIN2):101 HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,0); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4,1); __HAL_TIM_SET_COMPARE(&htim4,TIM_CHANNEL_1,speed); } //back void Car_Back(int speed) { // PB7(PWMA),PB8(AIN1),PB9(AIN2):110 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, 1); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, 0); __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_2, speed); // PB6(PWMB),PB5(BIN1),PB4(BIN2):110 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, 1); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, 0); __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1, speed); } //turn right void Car_Right(int speed) { // PB7(PWMA),PB8(AIN1),PB9(AIN2):101 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, 0); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, 1); __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_2, speed); // PB6(PWMB),PB5(BIN1),PB4(BIN2):110 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, 1); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, 0); __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1, speed); } //turn left void Car_Left(int speed) { // PB7(PWMA),PB8(AIN1),PB9(AIN2):110 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, 1); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, 0); __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_2, speed); // PB6(PWMB),PB5(BIN1),PB4(BIN2):101 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, 0); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, 1); __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1, speed); } //stop void Car_Stop(void) { // PB7(PWMA),PB8(AIN1),PB9(AIN2):000 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, 0); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, 0); __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_2, 0); // PB6(PWMB),PB5(BIN1),PB4(BIN2):000 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, 0); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, 0); __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1, 0); } // S void Car_Curve(int speed) { HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, 0); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, 1); __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_2, speed * 0.5); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, 0); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, 1); __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1, speed); HAL_Delay(1800); __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_2, 0); __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1, 0); HAL_Delay(500); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, 0); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, 1); __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_2, speed); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, 0); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, 1); __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1, speed * 0.5); HAL_Delay(1800); __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_2, 0); __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1, 0); HAL_Delay(500); // PB7(PWMA),PB8(AIN1),PB9(AIN2):110 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, 1); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, 0); __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_2, speed); // PB6(PWMB),PB5(BIN1),PB4(BIN2):110 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, 1); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, 0); __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1, speed*0.5); HAL_Delay(1800); __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_2, 0); __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1, 0); HAL_Delay(500); // PB7(PWMA),PB8(AIN1),PB9(AIN2):110 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, 1); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, 0); __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_2, speed*0.5); // PB6(PWMB),PB5(BIN1),PB4(BIN2):110 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, 1); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, 0); __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1, speed); HAL_Delay(1800); } void SG90_Control(int angle) { int value_compare=0; value_compare=11*angle+500; __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_4,value_compare); } /* 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_TIM4_Init(); MX_TIM1_Init(); MX_USART1_UART_Init(); /* USER CODE BEGIN 2 */ Motor_PWM_Start(); srand(HAL_GetTick()); HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_4); SG90_Control(90); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { // 1. ?? 2s(????? 500) SG90_Control(10); HAL_Delay(500); SG90_Control(45); HAL_Delay(500); SG90_Control(90); HAL_Delay(500); SG90_Control(135); HAL_Delay(500); SG90_Control(180); HAL_Delay(500); SR04_Work(); printf("num=%d\n",num_tim1); printf("distance=%.2f\n",distance); HAL_Delay(1000); int turn = rand() % 2; SR04_Work(); HAL_Delay(50); if(first==0) { first++; continue; } if (distance >= 40.0f) { Car_Straight(400); } else { Car_Stop(); HAL_Delay(200); Car_Back(400); HAL_Delay(300); Car_Stop(); HAL_Delay(200); if(!turn) { Car_Left(400); } else { Car_Right(400); } HAL_Delay(400); Car_Stop(); HAL_Delay(200); } HAL_Delay(100); } /* 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}; /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL16; 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_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != 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 */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 超声波+舵机+电机驱动,实现综合避障

#include "stm32f10x.h" /************************** 引脚与参数定义 **************************/ // 循迹传感器引脚(PA0~PA4 → ADC通道0~4) #define SENSOR_CH1 ADC_Channel_0 #define SENSOR_CH2 ADC_Channel_1 #define SENSOR_CH3 ADC_Channel_2 #define SENSOR_CH4 ADC_Channel_3 #define SENSOR_CH5 ADC_Channel_4 // TB6612方向引脚定义 #define AIN1_PIN GPIO_Pin_5 // 左电机方向控制1(PA5) #define AIN2_PIN GPIO_Pin_6 // 左电机方向控制2(PA6) #define BIN1_PIN GPIO_Pin_0 // 右电机方向控制1(PB0) #define BIN2_PIN GPIO_Pin_1 // 右电机方向控制2(PB1) #define AIN_PORT GPIOA // 左电机方向端口 #define BIN_PORT GPIOB // 右电机方向端口 // TB6612 PWM引脚定义(3.9kHz,50%占空比) #define PWM_LEFT_TIM TIM3 // 左电机PWM定时器 #define PWM_RIGHT_TIM TIM2 // 右电机PWM定时器 #define PWM_PERIOD 255 // PWM周期(0~255) #define PWM_DUTY 128 // 占空比50%(128/255) #define ADC_THRESHOLD 2000 // ADC阈值(需校准) /************************** 全局变量 **************************/ uint8_t sensor_data[5] = {0}; // 传感器状态:1=黑线,0=白线 /************************** 函数声明 **************************/ void SystemInit(void); // 系统初始化(启动文件调用) void SystemClock_Config(void); // 时钟配置(72MHz) void GPIO_Config(void); // GPIO初始化 void ADC_Config(void); // ADC初始化 void TIM_Config(void); // PWM定时器初始化 void Read_Sensor(void); // 读取传感器数据 void Motor_Forward(void); // 前进 void Motor_Left(void); // 左转 void Motor_Right(void); // 右转 void Motor_Stop(void); // 停车 void Delay_ms(uint32_t ms); // 毫秒延时 /************************** 系统时钟配置(72MHz) **************************/ void SystemClock_Config(void) { RCC_DeInit(); // 重置时钟配置 RCC_HSEConfig(RCC_HSE_ON); // 使能外部高速晶振 while(RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET); RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); // PLL倍频9倍(8MHz→72MHz) RCC_PLLCmd(ENABLE); while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); // 设置系统时钟为PLL输出 RCC_HCLKConfig(RCC_SYSCLK_Div1); // AHB时钟=系统时钟 RCC_PCLK1Config(RCC_HCLK_Div2); // APB1时钟=36MHz RCC_PCLK2Config(RCC_HCLK_Div1); // APB2时钟=72MHz SystemCoreClockUpdate(); // 更新系统时钟变量 } /************************** GPIO初始化 **************************/ void GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE); // 1. TB6612方向引脚配置(推挽输出) GPIO_InitStructure.GPIO_Pin = AIN1_PIN | AIN2_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(AIN_PORT, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = BIN1_PIN | BIN2_PIN; GPIO_Init(BIN_PORT, &GPIO_InitStructure); // 2. 传感器引脚配置(模拟输入) GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA, &GPIO_InitStructure); // 3. PWM引脚配置(复用推挽输出) GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; // PA7 → TIM3_CH2(左电机PWM) GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; // PB3 → TIM2_CH3(右电机PWM) GPIO_Init(GPIOB, &GPIO_InitStructure); } /************************** ADC初始化(5路传感器) **************************/ void ADC_Config(void) { ADC_InitTypeDef ADC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); // ADC基本配置 ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; // 独立模式 ADC_InitStructure.ADC_ScanConvMode = ENABLE; // 多通道扫描 ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; // 单次转换 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; // 右对齐 ADC_InitStructure.ADC_NbrOfChannel = 5; // 5通道 ADC_Init(ADC1, &ADC_InitStructure); // 配置5路传感器通道(采样时间55.5周期) ADC_RegularChannelConfig(ADC1, SENSOR_CH1, 1, ADC_SampleTime_55Cycles5); ADC_RegularChannelConfig(ADC1, SENSOR_CH2, 2, ADC_SampleTime_55Cycles5); ADC_RegularChannelConfig(ADC1, SENSOR_CH3, 3, ADC_SampleTime_55Cycles5); ADC_RegularChannelConfig(ADC1, SENSOR_CH4, 4, ADC_SampleTime_55Cycles5); ADC_RegularChannelConfig(ADC1, SENSOR_CH5, 5, ADC_SampleTime_55Cycles5); // 使能ADC并校准 ADC_Cmd(ADC1, ENABLE); ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1)); } /************************** PWM定时器初始化 **************************/ void TIM_Config(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; // 使能定时器时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 | RCC_APB1Periph_TIM3, ENABLE); // 左电机PWM(TIM3_CH2,PA7) TIM_TimeBaseStructure.TIM_Period = PWM_PERIOD; // 周期255 TIM_TimeBaseStructure.TIM_Prescaler = 71; // 72MHz/72=1MHz TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // PWM模式1 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = PWM_DUTY; // 50%占空比 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC2Init(TIM3, &TIM_OCInitStructure); TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); TIM_ARRPreloadConfig(TIM3, ENABLE); TIM_Cmd(TIM3, ENABLE); // 右电机PWM(TIM2_CH3,PB3) TIM_TimeBaseStructure.TIM_Period = PWM_PERIOD; TIM_TimeBaseStructure.TIM_Prescaler = 71; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = PWM_DUTY; // 50%占空比 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC3Init(TIM2, &TIM_OCInitStructure); TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable); TIM_ARRPreloadConfig(TIM2, ENABLE); TIM_Cmd(TIM2, ENABLE); } /************************** 读取传感器数据 **************************/ void Read_Sensor(void) { uint16_t adc_val; ADC_SoftwareStartConvCmd(ADC1, ENABLE); // 启动ADC转换 while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); // 等待转换完成 // 依次读取5路传感器ADC值并判断黑白线 adc_val = ADC_GetConversionValue(ADC1); // 最左传感器 sensor_data[0] = (adc_val > ADC_THRESHOLD) ? 1 : 0; adc_val = ADC_GetConversionValue(ADC1); // 左传感器 sensor_data[1] = (adc_val > ADC_THRESHOLD) ? 1 : 0; adc_val = ADC_GetConversionValue(ADC1); // 中间传感器 sensor_data[2] = (adc_val > ADC_THRESHOLD) ? 1 : 0; adc_val = ADC_GetConversionValue(ADC1); // 右传感器 sensor_data[3] = (adc_val > ADC_THRESHOLD) ? 1 : 0; adc_val = ADC_GetConversionValue(ADC1); // 最右传感器 sensor_data[4] = (adc_val > ADC_THRESHOLD) ? 1 : 0; } /************************** 电机控制函数 **************************/ // 前进(双电机正转,50%占空比) void Motor_Forward(void) { // 方向控制:左电机AIN1=高,AIN2=低;右电机BIN1=高,BIN2=低 GPIO_SetBits(AIN_PORT, AIN1_PIN); GPIO_ResetBits(AIN_PORT, AIN2_PIN); GPIO_SetBits(BIN_PORT, BIN1_PIN); GPIO_ResetBits(BIN_PORT, BIN2_PIN); // 设置PWM占空比50% TIM_SetCompare2(PWM_LEFT_TIM, PWM_DUTY); TIM_SetCompare3(PWM_RIGHT_TIM, PWM_DUTY); } // 左转(左电机50%,右电机25%占空比) void Motor_Left(void) { Motor_Forward(); // 继承前进方向 TIM_SetCompare2(PWM_LEFT_TIM, PWM_DUTY); // 左电机全速 TIM_SetCompare3(PWM_RIGHT_TIM, PWM_DUTY/2); // 右电机半速 } // 右转(右电机50%,左电机25%占空比) void Motor_Right(void) { Motor_Forward(); // 继承前进方向 TIM_SetCompare2(PWM_LEFT_TIM, PWM_DUTY/2); // 左电机半速 TIM_SetCompare3(PWM_RIGHT_TIM, PWM_DUTY); // 右电机全速 } // 停车(PWM=0,方向引脚低电平) void Motor_Stop(void) { GPIO_ResetBits(AIN_PORT, AIN1_PIN | AIN2_PIN); GPIO_ResetBits(BIN_PORT, BIN1_PIN | BIN2_PIN); TIM_SetCompare2(PWM_LEFT_TIM, 0); TIM_SetCompare3(PWM_RIGHT_TIM, 0); } /************************** 毫秒延时函数 **************************/ void Delay_ms(uint32_t ms) { uint32_t i, j; for(i = 0; i < ms; i++) for(j = 0; j < 7200; j++); // 72MHz下约1ms(需校准) } /************************** 主函数 **************************/ int main(void) { SystemClock_Config(); // 配置72MHz系统时钟 GPIO_Config(); // 初始化GPIO ADC_Config(); // 初始化ADC TIM_Config(); // 初始化PWM定时器 while (1) { Read_Sensor(); // 读取传感器状态 // 循迹逻辑判断 if (sensor_data[2]) { // 中间传感器检测到黑线 → 前进 Motor_Forward(); } else if (sensor_data[0] || sensor_data[1]) { // 左侧检测到 → 右转 Motor_Right(); } else if (sensor_data[3] || sensor_data[4]) { // 右侧检测到 → 左转 Motor_Left(); } else { // 无黑线 → 停车 Motor_Stop(); } Delay_ms(50); // 50ms控制周期(20Hz) } }将这个改进

#include “encoder.h” #include “main.h” #include “usart.h” #include “stdio.h” #include “tim.h” #include “math.h” #include “hall.h” #include “mymath.h” #include “gpio.h” #include “arm_math.h” #include “adc.h” #include “foc.h” float Encoder_Theta_coefficient; //编码器转换成电角度的系数值 float Encoder_Theta_m_coefficient; //编码器转换成机械角度的系数值 float We_coefficient; //编码器转电角速度的系数值 float Wm_coefficient; //编码器转机械角速度的系数值 float t; float Current_BandWidth; //电流环带宽 float CurrentLoop_Kpd; //电流环D轴比例增益 float CurrentLoop_Kid ; //电流环D轴积分增益 float CurrentLoop_Kpq ; //电流环Q轴比例增益 float CurrentLoop_Kiq; //电流环Q轴积分增益 int Speed_BandWidth ; //速度环带宽 float Ba ; //有功阻尼系数 float SpeedLoop_Kp ; //速度环比例增益 float SpeedLoop_Ki ; //速度环积分增益 void Foc_Init() { float temp1,temp2; Motor1.Wm_Set=0; Motor1.Id_Set=0; //设定为20k(电流采样由定时器1的PWM比较触发,频率也为20k) Motor1_Time.PWM_Fre = 168000000.0f / (TIM1_ARR * TIM1_PSC) / 2; Motor1_Time.PWM_Ts = 1 / Motor1_Time.PWM_Fre; //电流环:速度环:位置环的速度比例有多种,有16:4:1, 2:1:1, 1:1:1,都可以 Motor1_Time.Current_Loop_TimeGain = 1.0f; Motor1_Time.Speed_Loop_TimeGain = 1.0f; Motor1_Time.Locate_Loop_TimeGain = 1.0f; //计算频率设定为40k Motor1_Time.Calculate_Fre = 84000000.0f / (TIM2_ARR * TIM2_PSC ); Motor1_Time.Calculate_Ts = 1 / Motor1_Time.Calculate_Fre; //电流环设定为20k Motor1_Time.Current_Loop_Fre = Motor1_Time.Calculate_Fre / Motor1_Time.Current_Loop_TimeGain; Motor1_Time.Current_Loop_Ts = 1 / Motor1_Time.Current_Loop_Fre; //速度环设定为10k Motor1_Time.Speed_Loop_Fre = Motor1_Time.Calculate_Fre / Motor1_Time.Speed_Loop_TimeGain; Motor1_Time.Speed_Loop_Ts = 1 / Motor1_Time.Speed_Loop_Fre; //位置设定为10k Motor1_Time.Locate_Loop_Fre = Motor1_Time.Calculate_Fre / Motor1_Time.Locate_Loop_TimeGain; Motor1_Time.Locate_Loop_Ts = 1 / Motor1_Time.Locate_Loop_Fre; //编码器计数值转换为角度的系数值 Encoder_Theta_coefficient = 360 * MOTOR1_Pn /(ENCODER_NUMBER * 4); Encoder_Theta_m_coefficient = 360 /(ENCODER_NUMBER * 4); //编码器计数值转换为角速度的系数值 We_coefficient = 2* PI /(ENCODER_NUMBER * 4) / Motor1_Time.Speed_Loop_Ts; Wm_coefficient = 60.0f /(ENCODER_NUMBER * 4) / Motor1_Time.Speed_Loop_Ts; //计算电流环的PI系数 temp1=MOTOR1_Ld/MOTOR1_R; temp2=MOTOR1_Lq/MOTOR1_R; t=(temp1<temp2)?temp1:temp2; Current_BandWidth = 2*PI/t; //算出来的带宽太大了,有九千多,感觉是电机的参数给的可能有问题?不知道,反正不用这个带宽 //小了响应速度不够快,大了电流波动大 Current_BandWidth =1500; CurrentLoop_Kpd = Current_BandWidth * MOTOR1_Ld; CurrentLoop_Kid = Current_BandWidth * MOTOR1_R; CurrentLoop_Kpq = Current_BandWidth * MOTOR1_Ld; CurrentLoop_Kiq = Current_BandWidth * MOTOR1_R; //计算速度环的带宽 Speed_BandWidth = 150; Ba = (Speed_BandWidth *MOTOR1_J - MOTOR1_B ) / (1.5f * MOTOR1_Pn * MOTOR1_flux); //这个值在速度环我看别人的仿真不知道为啥给扔了,在速度环的时候不要这个 SpeedLoop_Kp = ( Speed_BandWidth * MOTOR1_J ) / (1.5f * MOTOR1_Pn * MOTOR1_flux) ; SpeedLoop_Ki = Speed_BandWidth * SpeedLoop_Kp; } //整个闭环控制计算可以满足40k的处理频率 void Foc_Control(void) { static int Number1=0,Number2=0,Number3=0; Motor1.Encoder_Value=Get_Encoder_Count(); //根据编码器计算角度 Motor1.Theta=Value_Limit(( Motor1.Encoder_Value + ENCODER_OFFSET ) * Encoder_Theta_coefficient,0.0f,360.0f); Motor1.Theta_m = Value_Limit(( Motor1.Encoder_Value + ENCODER_OFFSET ) * Encoder_Theta_m_coefficient,0.0f,360.0f); if(++Number1 >= Motor1_Time.Locate_Loop_TimeGain) { //执行位置环 Locate_Loop(); Number1= 0; } if(++Number2 >= Motor1_Time.Speed_Loop_TimeGain) { //执行速度环 Speed_Loop(); Number2= 0; } if(++Number3 >= Motor1_Time.Current_Loop_TimeGain) { //执行电流环 Current_Loop(); Number3= 0; } //对电压进行反Park变换 Park_Inverse_Transform(); //执行SVPWM并设定电机占空比 FOC_SVPWM(); //执行高频方波注入算法 // HFI_Sensorless(); } //SVPWM void FOC_SVPWM(void) { uint8_t N,A,B,C; float Vref1,Vref2,Vref3,X,Y,Z,temp1,Tfirst,Tsecond,T0,Ta,Tb,Tc,Tcm1,Tcm2,Tcm3; //计算转子所在的山区 Vref1=Motor1.Ubeta; Vref2=(SQRT_3* Motor1.Ualpha- Motor1.Ubeta)/2; Vref3=(-SQRT_3* Motor1.Ualpha- Motor1.Ubeta)/2; A=Vref1>0 ? 1 :0 ; B=Vref2>0 ? 1 :0 ; C=Vref3>0 ? 1 :0 ; N=4*C+2*B+A; temp1=SQRT_3* SVPWM_TS/ UDC; X=temp1*Vref1; Y=-temp1*Vref3; Z=-temp1*Vref2; //矢量作用时间计算 switch(N) { case 1: Tfirst= Z; Tsecond= Y; Motor1.Sector= 2; break; case 2: Tfirst= Y; Tsecond= -X; Motor1.Sector= 6; break; case 3: Tfirst= -Z; Tsecond= X; Motor1.Sector= 1; break; case 4: Tfirst= -X; Tsecond= Z; Motor1.Sector= 4; break; case 5: Tfirst= X; Tsecond= -Y; Motor1.Sector= 3; break; case 6: Tfirst= -Y; Tsecond= -Z; Motor1.Sector= 5; break; default: Tfirst= 0; Tsecond= 0; Motor1.Sector= 0; break; } //超限判断 if(( Tfirst + Tsecond )> SVPWM_TS) { Tfirst=(Tfirst/(Tfirst+Tsecond))/ SVPWM_TS; Tsecond=(Tsecond/(Tfirst+Tsecond))/ SVPWM_TS; } T0= (SVPWM_TS- Tfirst- Tsecond)/2; Ta=T0/2; Tb=Ta+Tfirst/2; Tc=Tb+Tsecond/2; //每相桥臂切换时间计算 switch(N) { case 1: Tcm1=Tb; Tcm2=Ta; Tcm3=Tc; break; case 2: Tcm1=Ta; Tcm2=Tc; Tcm3=Tb; break; case 3: Tcm1=Ta; Tcm2=Tb; Tcm3=Tc; break; case 4: Tcm1=Tc; Tcm2=Tb; Tcm3=Ta; break; case 5: Tcm1=Tc; Tcm2=Ta; Tcm3=Tb; break; case 6: Tcm1=Tb; Tcm2=Tc; Tcm3=Ta; break; default: break; } Motor1.Tcm1=Tcm1; Motor1.Tcm2=Tcm2; Motor1.Tcm3=Tcm3; //设置定时器1的PWM占空比 __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,TIM1_ARR*(1-2*Tcm1/ SVPWM_TS)); __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_2,TIM1_ARR*(1-2*Tcm2/ SVPWM_TS)); __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_3,TIM1_ARR*(1-2*Tcm3/ SVPWM_TS)); } void ADC_Transform(void) { //顺便软件滤波一下 //按照无刷驱动板的原理图上的公式算的,0.02是电阻值,电流转成的电压 除以电阻就是电流 // Motor1.Ibeta=((HAL_ADCEx_InjectedGetValue(&hadc1,ADC_INJECTED_RANK_1) * 3.3f /4095.0f) -1.24f)/8.0f/0.02f; 单位A Motor1.Ia =IRFilter1(HAL_ADCEx_InjectedGetValue(&hadc1,ADC_INJECTED_RANK_1)) * 0.005f -7.75f; Motor1.Ib =IRFilter2(HAL_ADCEx_InjectedGetValue(&hadc1,ADC_INJECTED_RANK_2)) * 0.005f -7.75f; Motor1.Ic =IRFilter3(HAL_ADCEx_InjectedGetValue(&hadc1,ADC_INJECTED_RANK_3)) * 0.005f -7.75f; } //位置环 void Locate_Loop(void) { //用不上暂时还没学,就没写 } //速度环 void Speed_Loop(void) { static float temp; static int Encoder_Last; float Encoder_W_temp; if(Encoder_Z_Flag==1) { Encoder_W_temp = KalmanFilter(Motor1.Encoder_Value - Encoder_Last + Encoder_temp); Encoder_Z_Flag=0; } else Encoder_W_temp = KalmanFilter(Motor1.Encoder_Value - Encoder_Last); //根据编码器计算角速度 速度范围波动会比较大,因为采样频率太高了,编码器的分辨率又不够高,所以这是很正常的。降低采样频率(即减小TIM2的时钟频率)可以减小波动 Motor1.We = Encoder_W_temp * We_coefficient; //单位 rad/s(电角速度) Motor1.Wm = Encoder_W_temp * Wm_coefficient; //单位 RPM(角速度) Encoder_Last=Motor1.Encoder_Value; Motor1.Iq_Set = SpeedLoop_Kp * (Motor1.Wm_Set - Motor1.Wm) + temp; temp = Value_SetMaxMin(temp +SpeedLoop_Ki * (Motor1.Wm_Set - Motor1.Wm) * Motor1_Time.Speed_Loop_Ts,-10.0f,10.0f); //给个限值防止他一直往上加,一启动电机速度飞飚,这个值是慢慢试的,大概速度到3000RPM时,这个值为10.多 } //电流环 void Current_Loop(void) { static float temp,temp2; //对三相电流进行采样,三相电流相加不为0,是因为硬件上有误差(野火客服说的,可恶!) 电流采样频率和电流频率一样都为20k ADC_Transform(); //对电流进行Clark变换,再Park变换 Motor1.Ialpha = Motor1.Ia; Motor1.Ibeta = (Motor1.Ia + 2*Motor1.Ib)/SQRT_3; Motor1.Id = Motor1.Ialpha* qfcosd(Motor1.Theta)+ Motor1.Ibeta* qfsind(Motor1.Theta); Motor1.Iq = -Motor1.Ialpha* qfsind(Motor1.Theta)+ Motor1.Ibeta* qfcosd(Motor1.Theta); //PI环节 //这个电流环的积分项我没整明白,加上积分的话,积分项会直接冲到最大,且一直为最大,然后就电机转动也没有更好,感觉就是反作用,先不整了,把它干掉,后面再研究 Motor1.Ud = CurrentLoop_Kpd *(Motor1.Id_Set - Motor1.Id) + temp - Motor1.We * MOTOR1_Lq * Motor1.Iq; // temp = Value_SetMaxMin( temp+ CurrentLoop_Kid * (Motor1.Id_Set - Motor1.Id) * Motor1.Calculate_Ts, -0.1f, 0.1f); Motor1.Uq = CurrentLoop_Kpq *(Motor1.Iq_Set - Motor1.Iq) + temp2 + Motor1.We * (MOTOR1_Ld * Motor1.Id + MOTOR1_flux); // temp2 = Value_SetMaxMin( temp2+ CurrentLoop_Kiq * (Motor1.Iq_Set - Motor1.Iq) * Motor1.Calculate_Ts, -0.1f, 0.1f); //合成电压最大值为SQRT_3 * UDC / 3 = 13.85 , Ud 最大值设为3 是为了高频方波注入算法, 这些限值都是试出来的,我也不会算理论值;这样限值转速最大能到2600RPM左右,够了 Motor1.Ud = Value_SetMaxMin(Motor1.Ud,-3.0f,3.0f); Motor1.Uq = Value_SetMaxMin(Motor1.Uq,-12.0f,12.0f); // Motor1.Ud = 0; // Motor1.Uq = 2; } 这是电机控制FOC的速度和电流环驱动代码 #include "main.h" #include "adc.h" #include "dma.h" #include "tim.h" #include "usart.h" #include "gpio.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "stdio.h" #include "bsp_key.h" #include "hall.h" #include "arm_math.h" #include "arm_const_structs.h" #include "math.h" #include "encoder.h" #include "mymath.h" #include "foc.h" /* 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 */ MOTOR Motor1; TIME Motor1_Time; /* 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 */ /* 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_TIM1_Init(); MX_TIM2_Init(); MX_TIM5_Init(); MX_USART1_UART_Init(); MX_ADC1_Init(); MX_DMA_Init(); /* USER CODE BEGIN 2 */ My_Timer_Init(); Encoder_Init(); Foc_Init(); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ //按键1按下,电机启动 if(Key_Scan(KEY1_GPIO_Port,KEY1_Pin)==KEY_ON) { //点亮LED_D11,串口输出电机启动,打开控制端口,设置初始速度(占空比)和初始方向,判断扇区并启动一次 LED_D11_ON; printf("Motor Running\r\n"); HAL_GPIO_WritePin(MOTOR_SD_GPIO_Port,MOTOR_SD_Pin,GPIO_PIN_SET); // Motor1.Direction=Motor_Clockwise; // Motor1.Speed=Motor_Speed_20; //初始执行一次霍尔换相 // HAL_TIM_PeriodElapsedCallback(&htim2); Motor1.Wm_Set=800; }else if(Key_Scan(KEY2_GPIO_Port,KEY2_Pin)==KEY_ON) //按键2按下,电机停止 { //关闭LED_D11,串口输出电机停止,关闭控制端口,设置初始速度(占空比)和初始方向 LED_D11_OFF; printf("Motor Stop\r\n"); HAL_GPIO_WritePin(MOTOR_SD_GPIO_Port,MOTOR_SD_Pin,GPIO_PIN_RESET); // Motor1.Direction=Motor_Stop; // Motor1.Speed=Motor_Speed_0; Motor1.Wm_Set=0; }else if(Key_Scan(KEY3_GPIO_Port,KEY3_Pin)==KEY_ON) //按键3按下,电机加速 { // if(Motor1.Speed<Motor_Speed_100) // Motor1.Speed++; Motor1.Wm_Set +=100; }else if(Key_Scan(KEY4_GPIO_Port,KEY4_Pin)==KEY_ON) //按键4按下,电机减速 { // if(Motor1.Speed>Motor_Speed_20) // Motor1.Speed--; Motor1.Wm_Set -=100; }else if(Key_Scan(KEY5_GPIO_Port,KEY5_Pin)==KEY_ON) //按键5按下,电机反向 { // if(Motor1.Direction==Motor_Clockwise) // Motor1.Direction=Motor_AntiClockwise; // else if(Motor1.Direction==Motor_AntiClockwise) // Motor1.Direction=Motor_Clockwise; } printf("%.2f,%.2f\n",Motor1.Wm,Motor1.Wm_Set); } /* USER CODE END 3 */ } /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /** Configure the main internal regulator output voltage */ __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; RCC_OscInitStruct.PLL.PLLM = 8; RCC_OscInitStruct.PLL.PLLN = 168; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; RCC_OscInitStruct.PLL.PLLQ = 4; 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_5) != HAL_OK) { Error_Handler(); } } /* USER CODE BEGIN 4 */ //定时器2更新中断(20k) void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if(htim == &htim2) { //测试中断所需时间 HAL_GPIO_WritePin(GPIO_TEST1_GPIO_Port,GPIO_TEST1_Pin,GPIO_PIN_SET); Foc_Control(); HAL_GPIO_WritePin(GPIO_TEST1_GPIO_Port,GPIO_TEST1_Pin,GPIO_PIN_RESET); } } /* 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 */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 这是主函数,我现在需要你为代码添加位置环的控制部分,要求可以实现位置控制的功能

最新推荐

recommend-type

双向CLLLC谐振闭环仿真设计与软开关技术实现:高压侧与低压侧波形优化及软开关性能研究 · 谐振波形优化

内容概要:本文介绍了双向CLLLC谐振技术及其在电力电子领域的应用,重点讨论了软开关和谐振波形的优化设计。文中首先简述了CLLLC谐振技术的基本原理,然后详细描述了在一个仿真环境下构建的双向CLLLC谐振系统,该系统能够在广泛的电压范围内(高压侧380-430V,低压侧40-54V)实现过谐振、欠谐振及满载轻载情况下的软开关。此外,文章展示了理想的谐振波形,并强调了软开关对减少开关损耗和电磁干扰的重要性。最后,文章提到可以通过参考相关文献深入了解系统的电路设计、控制策略和参数优化。 适合人群:从事电力电子设计的研究人员和技术工程师。 使用场景及目标:适用于需要理解和掌握双向CLLLC谐振技术及其仿真设计的专业人士,旨在帮助他们提升电源转换和能量回收系统的性能。 其他说明:文中提供的代码片段和图示均为假设的仿真环境,实际应用时需根据具体情况调整。建议参考相关文献获取更详尽的设计细节。
recommend-type

操作系统原理-PPT(1).ppt

操作系统原理-PPT(1).ppt
recommend-type

精选Java案例开发技巧集锦

从提供的文件信息中,我们可以看出,这是一份关于Java案例开发的集合。虽然没有具体的文件名称列表内容,但根据标题和描述,我们可以推断出这是一份包含了多个Java编程案例的开发集锦。下面我将详细说明与Java案例开发相关的一些知识点。 首先,Java案例开发涉及的知识点相当广泛,它不仅包括了Java语言的基础知识,还包括了面向对象编程思想、数据结构、算法、软件工程原理、设计模式以及特定的开发工具和环境等。 ### Java基础知识 - **Java语言特性**:Java是一种面向对象、解释执行、健壮性、安全性、平台无关性的高级编程语言。 - **数据类型**:Java中的数据类型包括基本数据类型(int、short、long、byte、float、double、boolean、char)和引用数据类型(类、接口、数组)。 - **控制结构**:包括if、else、switch、for、while、do-while等条件和循环控制结构。 - **数组和字符串**:Java数组的定义、初始化和多维数组的使用;字符串的创建、处理和String类的常用方法。 - **异常处理**:try、catch、finally以及throw和throws的使用,用以处理程序中的异常情况。 - **类和对象**:类的定义、对象的创建和使用,以及对象之间的交互。 - **继承和多态**:通过extends关键字实现类的继承,以及通过抽象类和接口实现多态。 ### 面向对象编程 - **封装、继承、多态**:是面向对象编程(OOP)的三大特征,也是Java编程中实现代码复用和模块化的主要手段。 - **抽象类和接口**:抽象类和接口的定义和使用,以及它们在实现多态中的不同应用场景。 ### Java高级特性 - **集合框架**:List、Set、Map等集合类的使用,以及迭代器和比较器的使用。 - **泛型编程**:泛型类、接口和方法的定义和使用,以及类型擦除和通配符的应用。 - **多线程和并发**:创建和管理线程的方法,synchronized和volatile关键字的使用,以及并发包中的类如Executor和ConcurrentMap的应用。 - **I/O流**:文件I/O、字节流、字符流、缓冲流、对象序列化的使用和原理。 - **网络编程**:基于Socket编程,使用java.net包下的类进行网络通信。 - **Java内存模型**:理解堆、栈、方法区等内存区域的作用以及垃圾回收机制。 ### Java开发工具和环境 - **集成开发环境(IDE)**:如Eclipse、IntelliJ IDEA等,它们提供了代码编辑、编译、调试等功能。 - **构建工具**:如Maven和Gradle,它们用于项目构建、依赖管理以及自动化构建过程。 - **版本控制工具**:如Git和SVN,用于代码的版本控制和团队协作。 ### 设计模式和软件工程原理 - **设计模式**:如单例、工厂、策略、观察者、装饰者等设计模式,在Java开发中如何应用这些模式来提高代码的可维护性和可扩展性。 - **软件工程原理**:包括软件开发流程、项目管理、代码审查、单元测试等。 ### 实际案例开发 - **项目结构和构建**:了解如何组织Java项目文件,合理使用包和模块化结构。 - **需求分析和设计**:明确项目需求,进行系统设计,如数据库设计、系统架构设计等。 - **代码编写和实现**:根据设计编写符合要求的代码,实现系统的各个模块功能。 - **测试和维护**:进行单元测试、集成测试,确保代码质量,对项目进行维护和升级。 ### 其他相关知识点 - **Java虚拟机(JVM)**:了解JVM的基本工作原理,包括类加载机制、内存管理、垃圾回收算法等。 - **常用Java框架**:比如Spring、Hibernate、MyBatis等,在实际开发中常常与Java基础结合使用,提高开发效率。 以上知识点可以作为学习Java案例开发的基础框架。在实际的开发实践中,开发者需要结合具体的项目需求,对这些知识点进行灵活运用。通过反复的案例实践,可以加深对Java编程的理解,并逐步提升开发技能。这份集锦可能包含的案例可能涉及上述知识点的具体应用,能够帮助学习者更好地理解理论与实践的结合,从而快速提升个人的Java开发能力。
recommend-type

【VASP报错深度解析】:5大技巧识别并永久解决离子距离太近警告

# 1. VASP软件简介及离子距离太近问题概述 ## 1.1 VASP软件简介 **VASP(Vienna Ab initio Simulation Package)** 是一款广泛应用于计算材料科学的软件,它基于密度泛函理论(DFT)计算固体、表面和分子的电子结构和性质。
recommend-type

npm error A complete log of this run can be found in: D:\Program Files\nodejs\node_cache\_logs\2025-04-20T15_11_51_454Z-debug-0.log

<think>好的,我需要帮助用户找到npm的错误调试日志位置,并解决他们遇到的npm错误。首先,用户已经提供了一个具体的日志路径:'D:\Program Files\nodejs\node_cache\_logs\2025-04-20T15_11_51_454Z-debug-0.log',但看起来这个路径可能有问题,因为日期是2025年,这可能是一个示例或输入错误。我需要确认正确的日志路径生成方式。 根据npm的默认配置,日志文件通常位于npm的缓存目录下的_logs文件夹中。默认情况下,Windows系统中npm的缓存路径是%AppData%\npm-cache,而日志文件会以当前日期和
recommend-type

深入理解内存技术文档详解

由于文件内容无法查看,仅能根据文件的标题、描述、标签以及文件名称列表来构建相关知识点。以下是对“内存详解”这一主题的详细知识点梳理。 内存,作为计算机硬件的重要组成部分,负责临时存放CPU处理的数据和指令。理解内存的工作原理、类型、性能参数等对优化计算机系统性能至关重要。本知识点将从以下几个方面来详细介绍内存: 1. 内存基础概念 内存(Random Access Memory,RAM)是易失性存储器,这意味着一旦断电,存储在其中的数据将会丢失。内存允许计算机临时存储正在执行的程序和数据,以便CPU可以快速访问这些信息。 2. 内存类型 - 动态随机存取存储器(DRAM):目前最常见的RAM类型,用于大多数个人电脑和服务器。 - 静态随机存取存储器(SRAM):速度较快,通常用作CPU缓存。 - 同步动态随机存取存储器(SDRAM):在时钟信号的同步下工作的DRAM。 - 双倍数据速率同步动态随机存取存储器(DDR SDRAM):在时钟周期的上升沿和下降沿传输数据,大幅提升了内存的传输速率。 3. 内存组成结构 - 存储单元:由存储位构成的最小数据存储单位。 - 地址总线:用于选择内存中的存储单元。 - 数据总线:用于传输数据。 - 控制总线:用于传输控制信号。 4. 内存性能参数 - 存储容量:通常用MB(兆字节)或GB(吉字节)表示,指的是内存能够存储多少数据。 - 内存时序:指的是内存从接受到请求到开始读取数据之间的时间间隔。 - 内存频率:通常以MHz或GHz为单位,是内存传输数据的速度。 - 内存带宽:数据传输速率,通常以字节/秒为单位,直接关联到内存频率和数据位宽。 5. 内存工作原理 内存基于电容器和晶体管的工作原理,电容器存储电荷来表示1或0的状态,晶体管则用于读取或写入数据。为了保持数据不丢失,动态内存需要定期刷新。 6. 内存插槽与安装 - 计算机主板上有专用的内存插槽,常见的有DDR2、DDR3、DDR4和DDR5等不同类型。 - 安装内存时需确保兼容性,并按照正确的方向插入内存条,避免物理损坏。 7. 内存测试与优化 - 测试:可以使用如MemTest86等工具测试内存的稳定性和故障。 - 优化:通过超频来提高内存频率,但必须确保稳定性,否则会导致数据损坏或系统崩溃。 8. 内存兼容性问题 不同内存条可能由于制造商、工作频率、时序、电压等参数的不匹配而产生兼容性问题。在升级或更换内存时,必须检查其与主板和现有系统的兼容性。 9. 内存条的常见品牌与型号 诸如金士顿(Kingston)、海盗船(Corsair)、三星(Samsung)和芝奇(G.Skill)等知名品牌提供多种型号的内存条,针对不同需求的用户。 由于“内存详解.doc”是文件标题指定的文件内容,我们可以预期在该文档中将详细涵盖以上知识点,并有可能包含更多的实践案例、故障排查方法以及内存技术的最新发展等高级内容。在实际工作中,理解并应用这些内存相关的知识点对于提高计算机性能、解决计算机故障有着不可估量的价值。
recommend-type

【机械特性分析进阶秘籍】:频域与时域对比的全面研究

# 1. 机械特性分析的频域与时域概述 ## 1.1 频域与时域分析的基本概念 机械特性分析是通
recommend-type

dslicsrv安装报错Too many errors

<think>好的,用户遇到了安装dslicsrv时出现“Too many errors”的问题,需要帮助解决。首先,我需要明确dslicsrv是什么。可能是指某个特定的软件服务,但根据常见软件库和搜索引擎的信息,没有直接对应的结果。可能是拼写错误,或者是某个特定领域的专有软件?比如,可能与Dell的某个服务有关?例如,Dell System License Manager Service(dsLicSvc)可能更接近。假设用户可能拼写错误,将dslicsrv理解为dsLicSvc,即Dell的系统许可证管理服务。 接下来,用户遇到的错误是安装时出现“Too many errors”,这通常
recommend-type

深入解析Pro Ajax与Java技术的综合应用框架

根据提供的文件信息,我们可以推断出一系列与标题《Pro Ajax and Java》相关的IT知识点。这本书是由Apress出版,关注的是Ajax和Java技术。下面我将详细介绍这些知识点。 ### Ajax技术 Ajax(Asynchronous JavaScript and XML)是一种无需重新加载整个页面即可更新网页的技术。它通过在后台与服务器进行少量数据交换,实现了异步更新网页内容的目的。 1. **异步通信**:Ajax的核心是通过XMLHttpRequest对象或者现代的Fetch API等技术实现浏览器与服务器的异步通信。 2. **DOM操作**:利用JavaScript操作文档对象模型(DOM),能够实现页面内容的动态更新,而无需重新加载整个页面。 3. **数据交换格式**:Ajax通信中常使用的数据格式包括XML和JSON,但近年来JSON因其轻量级和易用性更受青睐。 4. **跨浏览器兼容性**:由于历史原因,实现Ajax的JavaScript代码需要考虑不同浏览器的兼容性问题。 5. **框架和库**:有许多流行的JavaScript库和框架支持Ajax开发,如jQuery、Dojo、ExtJS等,这些工具简化了Ajax的实现和数据操作。 ### Java技术 Java是一种广泛使用的面向对象编程语言,其在企业级应用、移动应用开发(Android)、Web应用开发等方面有着广泛应用。 1. **Java虚拟机(JVM)**:Java程序运行在Java虚拟机上,这使得Java具有良好的跨平台性。 2. **Java标准版(Java SE)**:包含了Java的核心类库和API,是Java应用开发的基础。 3. **Java企业版(Java EE)**:为企业级应用提供了额外的API和服务,如Java Servlet、JavaServer Pages(JSP)、Enterprise JavaBeans(EJB)等。 4. **面向对象编程(OOP)**:Java是一种纯粹的面向对象语言,它的语法和机制支持封装、继承和多态性。 5. **社区和生态系统**:Java拥有庞大的开发者社区和丰富的第三方库和框架,如Spring、Hibernate等,这些资源极大丰富了Java的应用范围。 ### 结合Ajax和Java 在结合使用Ajax和Java进行开发时,我们通常会采用MVC(模型-视图-控制器)架构模式,来构建可维护和可扩展的应用程序。 1. **服务器端技术**:Java经常被用来构建服务器端应用逻辑。例如,使用Servlet来处理客户端的请求,再将数据以Ajax请求的响应形式返回给客户端。 2. **客户端技术**:客户端的JavaScript(或使用框架库如jQuery)用于发起Ajax请求,并更新页面内容。 3. **数据格式**:Java后端通常会使用JSON或XML格式与Ajax进行数据交换。 4. **安全性**:Ajax请求可能涉及敏感数据,因此需要考虑如跨站请求伪造(CSRF)等安全问题。 5. **性能优化**:合理使用Ajax可以提升用户体验,但同时也需要注意对服务器和网络的负载,以及客户端脚本的执行性能。 ### 出版信息及文件信息 《Pro Ajax and Java》由Apress出版社出版,通常这种出版物会包含丰富的实例代码、开发指导、最佳实践以及相关的技术讨论。它旨在帮助开发者深化对Ajax和Java技术的理解和应用能力。 文件名“Apress.Pro.Ajax.and.Java.Frameworks.Jul.2006.HAPPY.NEW.YEAR.pdf”暗示了这份文档可能是一本专业的技术书籍。从文件名可以看出,该书还可能包含了框架使用方面的内容,并且是2006年出版的。标题中的“HAPPY.NEW.YEAR”可能仅仅是为了庆祝新年而加入的非标准部分。 总结而言,了解Ajax和Java的结合使用,不仅需要掌握两种技术的基本原理和使用方法,还要熟悉如何将它们整合到实际项目中,解决可能出现的技术挑战,从而构建功能强大且用户友好的Web应用。
recommend-type

【频域分析深度解读】:揭秘机械系统分析中的实用应用

# 1. 频域分析基础理论 频域分析是信号处理领域的一个重要分支,其核心在于研究信号在频率维度上的特性。与时域分析不同,频域分析关注的是信号频率成分的组成,这允许我们以一种直观的方式识别和处理信号中的特定频率特征。通过对信号进行傅里叶变换,原始的时域信号可以被转换为频域信号,这样就可以清晰地显示出各频率成分的幅度和相位信息。这种分析手段对于信号去噪、特征提取、压缩编码等应用场景至关重