#include "main.h"
#include "i2c.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "math.h"
#include "oled.h"
#include "stdio.h"
#include <string.h>
#define KEY1 HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_3)
#define KEY0 HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_4)
#define PPR 13
#define ENCODER_MULTIPLY 4
#define GEAR_RATIO 20
// 计算每圈对应的计数
#define COUNTS_PER_REV (PPR * ENCODER_MULTIPLY * GEAR_RATIO)
/* 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 */
/* 速度环PID参数 */
float InnerTarget=0, InnerActual=0,Innerout=0;//目标值,实际值,输出值ֵ
float InnerKp=1.5;
float InnerKi=0.18;
float InnerKd=0.1;//比例项积分项微分项的权重
float InnerError0=0,InnerError1=0,InnerErrorInt=0,InnerIntout=0;//本次误差,上次误差,误差积分
/* 位置环PID参数 */
float PositionTarget = 0, PositionActual = 0, Positionout = 0;//目标值,实际值,输出值ֵ
float PositionKp = 0.4;
float PositionKi = 0.0;
float PositionKd = 0.03;//比例项积分项微分项的权重
float PositionError0 = 0, PositionError1 = 0, PositionErrorInt = 0, PositionIntOut = 0;//本次误差,上次误差,误差积分
extern unsigned char Hzk[][32];
uint32_t ccr_value=0;
uint32_t arr_value;
unsigned int x=0;
int motor_direction;
uint8_t rx_data;
unsigned char* word0=(uint8_t *)"**<qianchen>**";
unsigned char* time=(uint8_t *)"*>2025-07-06<*";
unsigned char* word1=(uint8_t *)"Count:";
unsigned char* word2=(uint8_t *)"PWM:";
unsigned char* word3=(uint8_t *)"Speed:";
unsigned char* word4=(uint8_t *)"Target:";
unsigned char* word5=(uint8_t *)"Actual:";
unsigned char* word6=(uint8_t *)"Out:";
unsigned char* word7=(uint8_t *)"P_T:";
unsigned char* word8=(uint8_t *)"P_A:";
unsigned char* word9=(uint8_t *)"P_O:";
unsigned char* word10=(uint8_t *)"I_T:";
unsigned char* word11=(uint8_t *)"I_A:";
unsigned char* word12=(uint8_t *)"I_O:";
uint16_t count;
float speed=0.0;
uint8_t str_buff[64];
void delay(unsigned int x)
{
while(x--);
}
void Scan_Keys()
{
if(KEY0==GPIO_PIN_RESET)
{
delay(1000);
if(KEY0==GPIO_PIN_RESET)
{
while(KEY0==GPIO_PIN_RESET);
PositionTarget+=300;
}
}
if(KEY1==GPIO_PIN_RESET)
{
delay(1000);
if(KEY1==GPIO_PIN_RESET)
{
while(KEY1==GPIO_PIN_RESET);
PositionTarget-=300;
}
}
}
void OLED_display_info()
{
OLED_Clear();
OLED_ShowString(8,0,word0,sizeof(word0));
OLED_ShowString(5,1,time,sizeof(time));
// OLED_ShowString(8,2,word1,sizeof(word1));
// OLED_ShowString(8,3,word2,sizeof(word2));
// OLED_ShowString(8,4,word3,sizeof(word3));
// OLED_ShowString(8,5,word4,sizeof(word4));
// OLED_ShowString(8,6,word5,sizeof(word5));
// OLED_ShowString(8,7,word6,sizeof(word6));
OLED_ShowString(8,2,word7,sizeof(word7));
OLED_ShowString(8,3,word8,sizeof(word8));
OLED_ShowString(8,4,word9,sizeof(word9));
OLED_ShowString(8,5,word10,sizeof(word10));
OLED_ShowString(8,6,word11,sizeof(word11));
OLED_ShowString(8,7,word12,sizeof(word12));
// OLED_ShowCHinese(0,3,0);
// OLED_ShowCHinese(18,3,1);
// OLED_ShowCHinese(36,3,2);
// OLED_ShowCHinese(54,3,3);
// OLED_ShowCHinese(0,6,4);
// OLED_ShowCHinese(18,6,5);
// OLED_ShowCHinese(36,6,6);
// OLED_ShowCHinese(54,6,7);
}
void OLED_display_dat()
{
// sprintf((char*)str_buff,"%5d",count);
// OLED_ShowString(64,2,str_buff,sizeof(str_buff));
//
// arr_value = __HAL_TIM_GET_AUTORELOAD(&htim2); // 获取ARR值
// float duty_cycle = ((float)ccr_value / arr_value) * 100.0f; // 计算占空比
//
// sprintf((char*)str_buff,"%+.0f",duty_cycle);
// OLED_ShowString(64,3,str_buff,sizeof(str_buff));
//
// sprintf((char*)str_buff,"%+.0f",speed);
// OLED_ShowString(64,4,str_buff,sizeof(str_buff));
sprintf((char*)str_buff,"%+.0f",PositionTarget);
OLED_ShowString(64,2,str_buff,sizeof(str_buff));
sprintf((char*)str_buff,"%+.0f",PositionActual);
OLED_ShowString(64,3,str_buff,sizeof(str_buff));
sprintf((char*)str_buff,"%+.0f",Positionout);
OLED_ShowString(64,4,str_buff,sizeof(str_buff));
sprintf((char*)str_buff,"%+.0f",InnerTarget);
OLED_ShowString(64,5,str_buff,sizeof(str_buff));
sprintf((char*)str_buff,"%+.0f",InnerActual);
OLED_ShowString(64,6,str_buff,sizeof(str_buff));
sprintf((char*)str_buff,"%+.0f",Innerout);
OLED_ShowString(64,7,str_buff,sizeof(str_buff));
}
uint16_t last_count = 0;
uint16_t last_time_ms = 0;
//void calculate_speed()
//{
// count = __HAL_TIM_GET_COUNTER(&htim3);
// uint16_t current_time_ms = HAL_GetTick();
// int16_t diff_count = count - last_count;
// float delta_time_sec = (current_time_ms - last_time_ms) / 1000.0f;
//
// if (delta_time_sec > 0)
// {
// float rpm = ((float)diff_count / (float)COUNTS_PER_REV) * 60.0f / delta_time_sec;
//
// speed=rpm;
//
// InnerActual=speed/1220.0f*100;
//
// InnerError1 = InnerError0;
// InnerError0 = InnerTarget - InnerActual;
//// ErrorInt += Error0;
// InnerIntOut += InnerKi * InnerError0;
//
// /*积分项输出限幅*/
// if(InnerIntOut>1000)InnerIntOut=1000;
// if(InnerIntOut<0)InnerIntOut=0;
//
// Innerout = InnerKp * InnerError0 + InnerIntOut + InnerKd * (InnerError0 - InnerError1);
//
// if(Innerout > 1000)Innerout = 1000;
// if(Innerout < 0)Innerout = 0;
//
// __HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_1,Innerout);
// }
// last_count = count;
// last_time_ms = current_time_ms;
//}
void set_motor_direction_and_pwm(float pwm_value)
{
// 限制PWM范围
pwm_value = fmaxf(fminf(pwm_value, 1000.0f), 0);
// 设置方向引脚(假设DIR_PIN控制方向)
if (motor_direction > 0)
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET); // 正转
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET); // 反转
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET);
}
// 设置PWM占空比
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, pwm_value);
}
void calculate_Position()
{
count = __HAL_TIM_GET_COUNTER(&htim3);
uint16_t current_time_ms = HAL_GetTick();
int16_t diff_count = count - last_count;
float delta_time_sec = (current_time_ms - last_time_ms) / 1000.0f;
if (delta_time_sec > 0)
{
// float rpm = ((float)diff_count / (float)COUNTS_PER_REV) * 60.0f / delta_time_sec;
//
// speed=rpm;
// 更新位置实际值(编码器脉冲累计)
PositionActual += diff_count;
// 位置环控制:计算误差和方向
PositionError0 = PositionTarget - PositionActual;
motor_direction = (PositionError0 >= 0) ? 1 : -1; // 目标>实际时正转,否则反转
// 位置环PID输出(取绝对值作为速度目标)
PositionErrorInt += PositionError0;
PositionIntOut = PositionKp * PositionError0 + PositionKi * PositionErrorInt;
// 限制积分输出
PositionIntOut = fmaxf(fminf(PositionIntOut, 1000.0f), -1000.0f);
// 速度环目标值(绝对值)
InnerTarget = fabs(PositionIntOut);
// 速度环目标值(绝对值)
InnerTarget = fabs(PositionIntOut);
// 速度环控制(InnerActual为编码器脉冲差值)
InnerError0 = InnerTarget - fabs(diff_count);
InnerIntout += InnerKi * InnerError0;
InnerIntout = fmaxf(fminf(InnerIntout, 1000.0f), 0); // 速度环输出非负
Innerout = InnerKp * InnerError0 + InnerIntout;
Innerout = fmaxf(fminf(Innerout, 1000.0f), 0);
// 设置电机方向和PWM
set_motor_direction_and_pwm(Innerout);
// //速度环实际值 = 本周期编码器脉冲差值(或累计值)
// InnerActual = PositionActual;
//
// //位置环控制
// PositionError1 = PositionError0;
// PositionError0 = PositionTarget - PositionActual;
// PositionErrorInt += PositionError0;
//
// /*积分项输出限幅*/
// if(PositionIntOut>1000)PositionIntOut=1000;
// if(PositionIntOut<0)PositionIntOut=0;
// Positionout = PositionKp * PositionError0 + PositionKi * PositionErrorInt + PositionKd * (PositionError0 - PositionError1);
// // 确定方向和速度目标
// motor_direction = (Positionout >= 0) ? 1 : -1;
// if(motor_direction==1)
// {
// HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1, GPIO_PIN_SET);
// HAL_GPIO_WritePin(GPIOA,GPIO_PIN_2, GPIO_PIN_RESET);
// }
// else if(motor_direction==-1)
// {
// HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1, GPIO_PIN_RESET);
// HAL_GPIO_WritePin(GPIOA,GPIO_PIN_2, GPIO_PIN_SET);
// }
// InnerTarget = fabs(Positionout);
// InnerTarget = Positionout;
// InnerError1 = InnerError0;
// InnerError0 = InnerTarget - InnerActual;
//// ErrorInt += Error0;
// InnerIntout += InnerKi * InnerError0;
//
// /*积分项输出限幅*/
// if(InnerIntout>1000)InnerIntout=1000;
// if(InnerIntout<0)InnerIntout=0;
//
// Innerout = InnerKp * InnerError0 + InnerIntout + InnerKd * (InnerError0 - InnerError1);
//
// if(Innerout > 1000)Innerout = 1000;
// if(Innerout < 0)Innerout = 0;
//
// __HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_1,Innerout);
}
last_count = count;
last_time_ms = current_time_ms;
}
//void dianjispeed()
//{
// switch(x)
// {
// case 0: PositionTarget = 0; break;
// case 1: PositionTarget = 300; break;
// case 2: PositionTarget = 500; break;
// case 3: PositionTarget = 800; break;
// }
//// __HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_1,ccr_value);
//}
//void Send_PID_Data(float target, float actual, float output)
//{
// char buffer[64];
// sprintf(buffer, "T:%.2f,A:%.2f,O:%.2f\r\n", target, actual, output);
// HAL_UART_Transmit(&huart1, (uint8_t*)buffer, strlen(buffer), HAL_MAX_DELAY);
//}
/* 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_TIM2_Init();
// MX_TIM3_Init();
// MX_I2C1_Init();
// MX_TIM4_Init();
// MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
// OLED_Init();
// OLED_display_info();
// // 启动编码器
// HAL_TIM_Encoder_Start(&htim3,TIM_CHANNEL_ALL);
// // 启动串口接收中断
// HAL_UART_Receive_IT(&huart1, &rx_data, 1);
// 启动定时器并启用中断
HAL_TIM_Base_Start_IT(&htim4);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1, GPIO_PIN_SET);
// HAL_GPIO_WritePin(GPIOA,GPIO_PIN_2, GPIO_PIN_RESET);
HAL_TIM_PWM_Start_IT(&htim2,TIM_CHANNEL_1);
// PositionActual = 0; // 初始化位置实际值
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
Scan_Keys();
// Send_PID_Data(PositionTarget, PositionActual, Positionout);
// dianjispeed();
// __HAL_TIM_SET_COUNTER(&htim3,0);
// HAL_Delay(500);
}
/* 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_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();
}
}
/* USER CODE BEGIN 4 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim == &htim4)
{
calculate_Position(); // 计算速度
OLED_display_dat(); // 更新 OLED 显示
}
}
以上是用位置环速度环双环PID算法控制MG310编码器电机的代码,如果改为控制步进电机转动指定角度该如何修改以上代码?
最新发布