- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);//Open TIM4 clock
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//open gpioB clock
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;//GPIO 1
- GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IPU;//浮空输入 上拉输入
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(GPIOA, &GPIO_InitStructure);
- TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
- TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
- TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
- TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//TIM向上计数模式
- TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
- NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
- NVIC_Init(&NVIC_InitStructure);
- TIM5_ICInitStructure.TIM_Channel = TIM_Channel_2;
- TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
- TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
- TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_div1;
- TIM5_ICInitStructure.TIM_ICFilter = 0x3;//Filter:过滤
- TIM_PWMIConfig(TIM5, &TIM5_ICInitStructure);//PWM输入配置
- TIM_SelectInputTrigger(TIM5, TIM_TS_TI2FP2);//选择有效输入端
- TIM_SelectSlaveMode(TIM5, TIM_SlaveMode_Reset);//配置为主从复位模式
- TIM_SelectMasterSlaveMode(TIM5, TIM_MasterSlaveMode_Enable);//启动定时器的被动触发
- TIM_ITConfig(TIM5, TIM_IT_CC2|TIM_IT_Update, ENABLE);//中断配置
- TIM_ClearITPendingBit(TIM5, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位
- TIM_Cmd(TIM5, ENABLE);
- }
- void TIM5_IRQHandler(void)
- {
- {
- if (TIM_GetITStatus(TIM5, TIM_IT_CC2) != RESET)//捕获1发生捕获事件
- {
- duty_TIM5=TIM_GetCapture1(TIM5); //采集占空比
- if(TIM_GetCapture2(TIM5)>600)period_TIM5=TIM_GetCapture2(TIM5);
- CollectFlag_TIM5 = 0;
- }
- }
- TIM_ClearITPendingBit(TIM5, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位
- }
复制代码
PID部分:
准备部分:先定义PID结构体:- typedef struct
- {
- int setpoint;//设定目标
- int sum_error;//误差累计
- float proportion ;//比例常数
- float integral ;//积分常数
- float derivative;//微分常数
- int last_error;//e[-1]
- int prev_error;//e[-2]
- }PIDtypedef;
复制代码
这里注意一下成员的数据类型,依据实际需要来定的。
在文件中定义几个关键变量:
- floatKp =0.32; //比例常数
- floatTi =0.09 ; //积分时间常数
- float Td =0.0028 ;//微分时间常数
- #define T0.02 //采样周期
- #define KiKp*(T/Ti)// Kp Ki Kd 三个主要参数
- #define KdKp*(Td/T)
复制代码
C语言好像用#define 什么什么对程序不太好,各位帮忙写个优化办法看看呢? 用const?
PID.H里面主要的几个函数:
- void PIDperiodinit(u16 arr,u16 psc);//PID 采样定时器设定
- void incPIDinit(void);//初始化,参数清零清零
- int incPIDcalc(PIDtypedef*PIDx,u16 nextpoint);//PID计算
- void PID_setpoint(PIDtypedef*PIDx,u16 setvalue);//设定 PID预期值
- void PID_set(float pp,float ii,float dd);//设定PIDkp ki kd三个参数
- void set_speed(float W1,float W2,float W3,float W4);//设定四个电机的目标转速
复制代码
PID处理过程:
岔开一下:这里我控制的是电机的转速w,实际上电机的反馈波形的频率f、电机转速w、控制信号PWM的占空比a三者是大致线性的正比的关系,这里强调这个的目的是
因为楼主在前期一直搞不懂我控制的转速怎么和TIM4输出的PWM的占空比联系起来,后来想清楚里面的联系之后通过公式把各个系数算出来了。
正题:控制流程是这样的,首先我设定我需要的车速(对应四个轮子的转速),然后PID就是开始响应了,它先采样电机转速,得到偏差值E,带入PID计算公式,得到调整量也就是最终更改了PWM的占空比,不断调节,直到转速在稳态的一个小范围上下浮动。
上面讲到的“得到调整量”就是增量PID的公式:
- int incPIDcalc(PIDtypedef *PIDx,u16 nextpoint)
- {