#include "stm32f10x.h" // Device header #include "delay.h" #include "OLED.h" #include "wheel.h" #include "PWM.h" #include "Timer.h" #include "track.h" #include "drive.h" #include "Buzzer.h" #include "Encoder.h" #include "PID将这个改成可以循迹虚线的代码
时间: 2025-06-19 15:13:14 浏览: 26
### 实现循迹虚线功能的代码示例
基于STM32F10x实现循迹虚线功能,需要结合PWM、Timer、Encoder和PID算法。以下是一个完整的解决方案,包括硬件初始化、PID控制逻辑以及如何通过编码器反馈调整电机速度以实现循迹。
#### 硬件初始化
首先,初始化系统时钟、GPIO、定时器(用于生成PWM信号)和编码器(用于反馈电机位置)。以下是初始化代码示例:
```c
#include "stm32f10x.h"
// 初始化系统时钟
void SystemClock_Config(void) {
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
// 配置系统时钟为72MHz
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
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) {
while (1); // 错误处理
}
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) {
while (1); // 错误处理
}
}
// 初始化GPIO
void GPIO_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE(); // 启用GPIOA时钟
__HAL_RCC_GPIOB_CLK_ENABLE(); // 启用GPIOB时钟
// 配置PA8为TIM1_CH1输出PWM
GPIO_InitStruct.Pin = GPIO_PIN_8;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// 配置PB6和PB7为输入,用于编码器反馈
GPIO_InitStruct.Pin = GPIO_PIN_6 | GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
// 初始化TIM1用于PWM输出
void TIM_PWM_Init(void) {
TIM_OC_InitTypeDef sConfigOC = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
__HAL_RCC_TIM1_CLK_ENABLE();
htim1.Instance = TIM1;
htim1.Init.Prescaler = 72 - 1; // 设置分频系数
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = 1000 - 1; // 设置计数周期
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
if (HAL_TIM_PWM_Init(&htim1) != HAL_OK) {
while (1); // 错误处理
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 500; // 初始占空比50%
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_OC_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK) {
while (1); // 错误处理
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
}
// 初始化TIM3用于编码器模式
void TIM_Encoder_Init(void) {
TIM_Encoder_InitTypeDef sConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
__HAL_RCC_TIM3_CLK_ENABLE();
htim3.Instance = TIM3;
htim3.Init.Prescaler = 0;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 65535;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Encoder_Init(&htim3, &sConfig) != HAL_OK) {
while (1); // 错误处理
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig);
HAL_TIM_Encoder_Start(&htim3, TIM_CHANNEL_ALL);
}
```
#### PID控制器实现
PID控制器用于根据编码器反馈调整PWM占空比,从而控制电机速度。以下是PID控制器的实现代码:
```c
typedef struct {
float Kp;
float Ki;
float Kd;
float SetPoint;
float Error;
float LastError;
float Integral;
float Output;
} PID_t;
void PID_Init(PID_t *pid, float Kp, float Ki, float Kd, float SetPoint) {
pid->Kp = Kp;
pid->Ki = Ki;
pid->Kd = Kd;
pid->SetPoint = SetPoint;
pid->Error = 0;
pid->LastError = 0;
pid->Integral = 0;
pid->Output = 0;
}
float PID_Compute(PID_t *pid, float Input) {
pid->Error = pid->SetPoint - Input;
pid->Integral += pid->Error;
float Derivative = pid->Error - pid->LastError;
pid->Output = pid->Kp * pid->Error + pid->Ki * pid->Integral + pid->Kd * Derivative;
pid->LastError = pid->Error;
return pid->Output;
}
```
#### 循迹虚线功能主循环
在主循环中,读取编码器值并使用PID控制器调整PWM占空比,从而实现循迹虚线功能。
```c
int main(void) {
SystemClock_Config();
GPIO_Init();
TIM_PWM_Init();
TIM_Encoder_Init();
PID_t pid;
PID_Init(&pid, 0.5, 0.01, 0.1, 1000); // 设置目标值为1000
while (1) {
uint32_t encoder_value = __HAL_TIM_GET_COUNTER(&htim3); // 获取编码器值
float pwm_duty_cycle = PID_Compute(&pid, encoder_value); // 计算PWM占空比
// 限制占空比范围
if (pwm_duty_cycle > 1000) pwm_duty_cycle = 1000;
if (pwm_duty_cycle < 0) pwm_duty_cycle = 0;
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, pwm_duty_cycle); // 设置PWM占空比
HAL_Delay(10); // 延时以便稳定
}
}
```
### 注意事项
- 编码器反馈的精度直接影响PID控制效果,需确保编码器安装正确[^1]。
- PID参数(Kp、Ki、Kd)需要根据具体硬件进行调优[^2]。
阅读全文
相关推荐

















