| @@ -738,89 +738,108 @@ void PLSR_PWM_Stop(void) | |||
| */ | |||
| static void PLSR_CalculateTimerParams(uint32_t frequency, uint16_t* prescaler, uint32_t* period) | |||
| { | |||
| // STM32F4系列定时器时钟频率(APB1定时器通常为84MHz,APB2定时器为168MHz) | |||
| // 这里使用168MHz,适用于APB2上的高速定时器(如TIM1、TIM8等) | |||
| if (frequency < PLSR_PWM_FREQ_MIN) frequency = PLSR_PWM_FREQ_MIN; | |||
| if (frequency > PLSR_PWM_FREQ_MAX) frequency = PLSR_PWM_FREQ_MAX; | |||
| uint32_t psc; | |||
| uint32_t arr; | |||
| uint32_t f = (uint32_t)(frequency + 0.5f); | |||
| // PLSR_Calc_TimerParams((uint32_t)(f_hz + 0.5f), &psc, &arr); | |||
| uint32_t timer_clock = 168000000; | |||
| // 定时器频率计算原理: | |||
| // 输出频率 = 定时器时钟频率 / ((预分频器 + 1) * (自动重装载值 + 1)) | |||
| // 因此:(预分频器 + 1) * (自动重装载值 + 1) = 定时器时钟频率 / 目标频率 | |||
| // 频率为0时的异常处理 | |||
| if (frequency == 0) { | |||
| *prescaler = 65535; // 最大预分频器 | |||
| *period = 65535; // 最大周期,输出最低频率 | |||
| return; | |||
| } | |||
| // 频率过高时的处理(超过定时器时钟频率) | |||
| if (frequency > timer_clock) { | |||
| *prescaler = 0; // 最小预分频器 | |||
| *period = 0; // 最小周期,输出最高频率 | |||
| return; | |||
| psc = 1; | |||
| while (timer_clock / (psc + 1) / f > 65535) { | |||
| psc++; | |||
| if (psc > 0XFFFF) psc = 0XFFFF; | |||
| } | |||
| // 计算总的计数值:定时器时钟频率除以目标频率 | |||
| uint64_t total_count = (uint64_t)timer_clock / frequency; | |||
| // 如果总计数值超出范围,直接设置为最低频率 | |||
| if (total_count > (uint64_t)65536 * 65536) { | |||
| *prescaler = 65535; | |||
| *period = 65535; | |||
| return; | |||
| } | |||
| // 优化搜索策略:寻找最佳的预分频器和自动重装载值组合 | |||
| // 目标:找到误差最小且分辨率最高的组合 | |||
| uint32_t best_prescaler = 65535; | |||
| uint32_t best_period = 65535; | |||
| uint32_t min_error = UINT32_MAX; | |||
| // 计算合理的搜索范围,避免无效遍历 | |||
| uint32_t max_psc = (total_count > 65535) ? 65535 : (uint32_t)total_count; | |||
| uint32_t min_psc = (total_count + 65535) / 65536; // 确保ARR不超过65535 | |||
| if (min_psc == 0) min_psc = 1; | |||
| // 遍历预分频器值,寻找最佳组合 | |||
| for (uint32_t psc = min_psc; psc <= max_psc; psc++) { | |||
| // 计算对应的自动重装载值(四舍五入) | |||
| uint32_t arr = (uint32_t)((total_count + psc/2) / psc); | |||
| arr = (timer_clock / (psc + 1)) / f - 1; | |||
| if (arr < 2) arr = 2; | |||
| *prescaler = psc; | |||
| *period = arr; | |||
| // // STM32F4系列定时器时钟频率(APB1定时器通常为84MHz,APB2定时器为168MHz) | |||
| // // 这里使用168MHz,适用于APB2上的高速定时器(如TIM1、TIM8等) | |||
| // uint32_t timer_clock = 168000000; | |||
| // // 定时器频率计算原理: | |||
| // // 输出频率 = 定时器时钟频率 / ((预分频器 + 1) * (自动重装载值 + 1)) | |||
| // // 因此:(预分频器 + 1) * (自动重装载值 + 1) = 定时器时钟频率 / 目标频率 | |||
| // // 频率为0时的异常处理 | |||
| // if (frequency == 0) { | |||
| // *prescaler = 65535; // 最大预分频器 | |||
| // *period = 65535; // 最大周期,输出最低频率 | |||
| // return; | |||
| // } | |||
| // // 频率过高时的处理(超过定时器时钟频率) | |||
| // if (frequency > timer_clock) { | |||
| // *prescaler = 0; // 最小预分频器 | |||
| // *period = 0; // 最小周期,输出最高频率 | |||
| // return; | |||
| // } | |||
| // // 计算总的计数值:定时器时钟频率除以目标频率 | |||
| // uint64_t total_count = (uint64_t)timer_clock / frequency; | |||
| // // 如果总计数值超出范围,直接设置为最低频率 | |||
| // if (total_count > (uint64_t)65536 * 65536) { | |||
| // *prescaler = 65535; | |||
| // *period = 65535; | |||
| // return; | |||
| // } | |||
| // // 优化搜索策略:寻找最佳的预分频器和自动重装载值组合 | |||
| // // 目标:找到误差最小且分辨率最高的组合 | |||
| // uint32_t best_prescaler = 65535; | |||
| // uint32_t best_period = 65535; | |||
| // uint32_t min_error = UINT32_MAX; | |||
| // // 计算合理的搜索范围,避免无效遍历 | |||
| // uint32_t max_psc = (total_count > 65535) ? 65535 : (uint32_t)total_count; | |||
| // uint32_t min_psc = (total_count + 65535) / 65536; // 确保ARR不超过65535 | |||
| // if (min_psc == 0) min_psc = 1; | |||
| // // 遍历预分频器值,寻找最佳组合 | |||
| // for (uint32_t psc = min_psc; psc <= max_psc; psc++) { | |||
| // // 计算对应的自动重装载值(四舍五入) | |||
| // uint32_t arr = (uint32_t)((total_count + psc/2) / psc); | |||
| // 检查自动重装载值是否在有效范围内 | |||
| if (arr >= 1 && arr <= 65536) { | |||
| // 计算实际输出频率和误差 | |||
| uint32_t actual_total = psc * arr; | |||
| uint32_t actual_freq = timer_clock / actual_total; | |||
| uint32_t error = (actual_freq > frequency) ? | |||
| (actual_freq - frequency) : (frequency - actual_freq); | |||
| // // 检查自动重装载值是否在有效范围内 | |||
| // if (arr >= 1 && arr <= 65536) { | |||
| // // 计算实际输出频率和误差 | |||
| // uint32_t actual_total = psc * arr; | |||
| // uint32_t actual_freq = timer_clock / actual_total; | |||
| // uint32_t error = (actual_freq > frequency) ? | |||
| // (actual_freq - frequency) : (frequency - actual_freq); | |||
| // 选择误差最小的组合,误差相同时选择分辨率更高的(ARR更大) | |||
| if (error < min_error || (error == min_error && arr > best_period + 1)) { | |||
| min_error = error; | |||
| best_prescaler = psc - 1; // 转换为寄存器值 | |||
| best_period = arr - 1; // 转换为寄存器值 | |||
| // // 选择误差最小的组合,误差相同时选择分辨率更高的(ARR更大) | |||
| // if (error < min_error || (error == min_error && arr > best_period + 1)) { | |||
| // min_error = error; | |||
| // best_prescaler = psc - 1; // 转换为寄存器值 | |||
| // best_period = arr - 1; // 转换为寄存器值 | |||
| // 如果找到精确匹配,直接返回 | |||
| if (error == 0) { | |||
| *prescaler = best_prescaler; | |||
| *period = best_period; | |||
| return; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| // 返回找到的最佳组合 | |||
| *prescaler = best_prescaler; | |||
| *period = best_period; | |||
| // 如果没有找到合理的组合,使用默认的1kHz配置 | |||
| if (min_error == UINT32_MAX) { | |||
| // 预分频器 = 167 (实际分频168),自动重装载 = 999 (实际计数1000) | |||
| // 输出频率 = 168MHz / (168 * 1000) = 1kHz | |||
| *prescaler = 167; // 168MHz / 168 = 1MHz | |||
| *period = 999; // 1MHz / 1000 = 1kHz | |||
| } | |||
| // // 如果找到精确匹配,直接返回 | |||
| // if (error == 0) { | |||
| // *prescaler = best_prescaler; | |||
| // *period = best_period; | |||
| // return; | |||
| // } | |||
| // } | |||
| // } | |||
| // } | |||
| // // 返回找到的最佳组合 | |||
| // *prescaler = best_prescaler; | |||
| // *period = best_period; | |||
| // // 如果没有找到合理的组合,使用默认的1kHz配置 | |||
| // if (min_error == UINT32_MAX) { | |||
| // // 预分频器 = 167 (实际分频168),自动重装载 = 999 (实际计数1000) | |||
| // // 输出频率 = 168MHz / (168 * 1000) = 1kHz | |||
| // *prescaler = 167; // 168MHz / 168 = 1MHz | |||
| // *period = 999; // 1MHz / 1000 = 1kHz | |||
| // } | |||
| } | |||
| @@ -1044,6 +1063,9 @@ uint32_t integer_sqrt_64(uint64_t x) | |||
| return (uint32_t)result; | |||
| } | |||
| // ==================== PLSR 路径计算函数实现 ==================== | |||
| //在加速度较小时,可能会出现计算脉冲数为0的情况,此时会导致无法进入加速状态 | |||
| void Calculate_PluseNum_Simplified(PLSR_RouteConfig_t *route) | |||
| { | |||
| int32_t accel_pulse_num = 0; // 加速过程脉冲数 | |||
| @@ -1762,8 +1784,15 @@ static uint8_t PLSR_SetDirectionPin(PLSR_RouteConfig_t* route, PLSR_SectionConfi | |||
| GPIO_PinState dir_pin_state; | |||
| // 根据计算后的实际可发脉冲数确定方向(正值为正向,负值为反向) | |||
| // 在绝对模式下,actual_pulse已经计算为目标位置与当前位置的差值 | |||
| uint8_t is_forward = (current_section->actual_pulse >= 0); | |||
| uint8_t is_forward; | |||
| if(route->mode == PLSR_MODE_ABSOLUTE) | |||
| { | |||
| is_forward = (current_section->actual_pulse >= 0); | |||
| } | |||
| else | |||
| { | |||
| is_forward = (current_section->target_pulse >= 0); | |||
| } | |||
| // 检测方向是否发生变化 | |||
| uint8_t direction_changed = (s_last_direction != 0xFF && s_last_direction != is_forward); | |||
| @@ -1807,8 +1836,16 @@ static uint8_t PLSR_SetDirectionPin(PLSR_RouteConfig_t* route, PLSR_SectionConfi | |||
| // 如果设置了方向延时时间,则等待指定时间 | |||
| if (route->dir_delay > 0 && direction_changed) | |||
| { | |||
| // 使用HAL库延时函数,单位为毫秒 | |||
| HAL_Delay(route->dir_delay); | |||
| if(route->dir_delay > 10) | |||
| { | |||
| // 使用HAL库延时函数,单位为毫秒 | |||
| HAL_Delay(route->dir_delay-1); | |||
| } | |||
| else | |||
| { | |||
| HAL_Delay(route->dir_delay); | |||
| } | |||
| } | |||
| // 返回方向变化状态 | |||
| @@ -2143,7 +2180,12 @@ uint32_t PLSR_Calculate_FreqByPosition(PLSR_RouteConfig_t* route, uint8_t is_acc | |||
| { | |||
| if (route == NULL) return 0; | |||
| // 使用全局变量g_last_freq替代static变量 | |||
| // 静态变量用于缓存上次计算的结果,避免重复计算 | |||
| static uint32_t s_last_executed_pulses = 0xFFFFFFFF; // 初始化为无效值 | |||
| static uint32_t s_last_calculated_freq = 0; | |||
| static uint8_t s_last_is_accel = 0xFF; // 初始化为无效值 | |||
| static uint8_t s_last_section_num = 0xFF; // 初始化为无效值 | |||
| // 获取当前段配置 | |||
| PLSR_SectionConfig_t* current_section = &route->section[route->current_section_num - 1]; | |||
| @@ -2167,6 +2209,15 @@ uint32_t PLSR_Calculate_FreqByPosition(PLSR_RouteConfig_t* route, uint8_t is_acc | |||
| next_executed_pulses = 0; | |||
| } | |||
| } | |||
| // 检查是否需要重新计算:脉冲步数、加减速状态或段号发生变化时才重新计算 | |||
| if (executed_pulses == s_last_executed_pulses && | |||
| is_accel == s_last_is_accel && | |||
| route->current_section_num == s_last_section_num) | |||
| { | |||
| // 脉冲步数、状态和段号都没有变化,直接返回上次计算的结果 | |||
| return s_last_calculated_freq; | |||
| } | |||
| // 使用速度位移公式 vt^2 = v0^2 + 2ax 计算当前频率,其中v0使用initial_freq作为初始速度 | |||
| @@ -2202,16 +2253,9 @@ uint32_t PLSR_Calculate_FreqByPosition(PLSR_RouteConfig_t* route, uint8_t is_acc | |||
| } | |||
| else | |||
| { | |||
| uint64_t v0_squared = (uint64_t)v0 * v0; | |||
| if (v0_squared >= 2 * a * executed_pulses) | |||
| { | |||
| uint64_t freq_squared_start = 2 * a * executed_pulses; | |||
| freq_start = integer_sqrt_64(freq_squared_start); | |||
| } | |||
| else | |||
| { | |||
| freq_start = 0; | |||
| } | |||
| uint64_t freq_squared_start = 2 * a * executed_pulses; | |||
| freq_start = integer_sqrt_64(freq_squared_start); | |||
| } | |||
| } | |||
| @@ -2226,15 +2270,8 @@ uint32_t PLSR_Calculate_FreqByPosition(PLSR_RouteConfig_t* route, uint8_t is_acc | |||
| else | |||
| { | |||
| uint64_t v0_squared = (uint64_t)v0 * v0; | |||
| if (v0_squared >= 2 * a * next_executed_pulses) | |||
| { | |||
| uint64_t freq_squared_end = 2 * a * next_executed_pulses; | |||
| freq_end = integer_sqrt_64(freq_squared_end); | |||
| } | |||
| else | |||
| { | |||
| freq_end = 0; | |||
| } | |||
| uint64_t freq_squared_end = 2 * a * next_executed_pulses; | |||
| freq_end = integer_sqrt_64(freq_squared_end); | |||
| } | |||
| // 计算当前脉冲的平均频率 | |||
| @@ -2242,6 +2279,10 @@ uint32_t PLSR_Calculate_FreqByPosition(PLSR_RouteConfig_t* route, uint8_t is_acc | |||
| // 更新全局变量(保存当前脉冲结束时的频率,供下次使用) | |||
| g_last_freq = freq_end; | |||
| // if(executed_pulses > 61) | |||
| // { | |||
| // printf("freq_start: %lu, freq_end: %lu, calculated_freq: %lu\r\n", freq_start, freq_end, calculated_freq); | |||
| // } | |||
| // 限制频率范围 | |||
| if (calculated_freq < PLSR_PWM_FREQ_MIN) | |||
| @@ -2253,6 +2294,12 @@ uint32_t PLSR_Calculate_FreqByPosition(PLSR_RouteConfig_t* route, uint8_t is_acc | |||
| calculated_freq = PLSR_PWM_FREQ_MAX; | |||
| } | |||
| // 缓存本次计算结果,供下次比较使用 | |||
| s_last_executed_pulses = executed_pulses; | |||
| s_last_calculated_freq = calculated_freq; | |||
| s_last_is_accel = is_accel; | |||
| s_last_section_num = route->current_section_num; | |||
| return calculated_freq; | |||
| } | |||
| @@ -2303,16 +2350,16 @@ void PLSR_Accel_Process(PLSR_RouteConfig_t* route) | |||
| // 根据当前脉冲位置计算频率(传入1表示加速过程) | |||
| uint32_t calculated_freq = PLSR_Calculate_FreqByPosition(route, 1); | |||
| // 更新当前频率 | |||
| route->current_freq = calculated_freq; | |||
| // 检查是否达到目标频率 | |||
| if (route->current_freq >= route->target_freq) { | |||
| route->current_freq = route->target_freq; // 限制到目标频率 | |||
| if (calculated_freq >= route->target_freq) { | |||
| calculated_freq = route->target_freq; // 限制到目标频率 | |||
| } | |||
| // 更新PWM频率 | |||
| PLSR_PWM_SetFrequency(route->current_freq); | |||
| // 只有当计算出的频率与当前频率不同时才更新 | |||
| if (calculated_freq != route->current_freq) { | |||
| route->current_freq = calculated_freq; | |||
| PLSR_PWM_SetFrequency(route->current_freq); | |||
| } | |||
| // 如果是第一次设置非零频率,启动PWM输出 | |||
| if(first_flag == 1 && route->current_freq != 0) | |||
| @@ -2327,12 +2374,9 @@ void PLSR_Accel_Process(PLSR_RouteConfig_t* route) | |||
| // 使用速度位移公式 vt^2 = v0^2 - 2ax 计算当前脉冲的下一个脉冲频率 | |||
| uint32_t calculated_freq = PLSR_Calculate_FreqByPosition(route, 0); | |||
| // 更新当前频率 | |||
| route->current_freq = calculated_freq; | |||
| // 检查是否达到目标频率 | |||
| if (route->current_freq <= route->target_freq) { | |||
| route->current_freq = route->target_freq; // 限制到目标频率 | |||
| if (calculated_freq <= route->target_freq) { | |||
| calculated_freq = route->target_freq; // 限制到目标频率 | |||
| // 如果目标频率为0,说明减速到停止 | |||
| if (route->target_freq == 0) | |||
| @@ -2343,15 +2387,14 @@ void PLSR_Accel_Process(PLSR_RouteConfig_t* route) | |||
| } | |||
| } | |||
| // 更新PWM频率或停止PWM | |||
| if (route->current_freq > 0) | |||
| { | |||
| PLSR_PWM_SetFrequency(route->current_freq); | |||
| } else | |||
| { | |||
| // 频率减速到0,停止PWM输出 | |||
| route->run_state = PLSR_STATE_IDLE; | |||
| PLSR_PWM_Stop(); | |||
| // 只有当计算出的频率与当前频率不同时才更新PWM频率 | |||
| if (calculated_freq != route->current_freq) { | |||
| route->current_freq = calculated_freq; | |||
| if (route->current_freq > 0) | |||
| { | |||
| PLSR_PWM_SetFrequency(route->current_freq); | |||
| } | |||
| } | |||
| } | |||
| } | |||