本文已参与「新人创作礼」活动,一起开启创作之路
所需元件
STM32F103开发板、L298N一个、带编码器的直流电机一个(如下图所示,淘宝上有很多)

系统框图





#include "TIM_Encoder.h" float RPM_1=0; //存储上一次测速结果 void TIM_Encoder_Init(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_ICInitTypeDef TIM_ICInitStructure; GPIO_InitTypeDef GPIO_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); //使能定时器4的时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能PB端口时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; //端口配置 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入 GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化GPIOB TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); TIM_TimeBaseStructure.TIM_Prescaler = 0x0; // 预分频器 TIM_TimeBaseStructure.TIM_Period = 65535; //设定计数器自动重装值 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //选择时钟分频:不分频 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数 TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); TIM_EncoderInterfaceConfig(TIM4, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式3 TIM_ICStructInit(&TIM_ICInitStructure); TIM_ICInitStructure.TIM_ICFilter = 10; TIM_ICInit(TIM4, &TIM_ICInitStructure); TIM_ClearFlag(TIM4, TIM_FLAG_Update); //清除TIM的更新标志位 TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE); //Reset counter TIM_SetCounter(TIM4,0); TIM_Cmd(TIM4, ENABLE); } int GetTIMCounter(void) //获取计数值 { int count=TIM_GetCounter(TIM4); return count; } float GetRPM(int count) //计算转速 { // int RPM=count/2496*2000+0.5;//30ms计算一次(pid.T=30),60000ms为1min,也就是1min计算了2000次,2496=13*4*48表示转动一圈的脉冲数,48表示1:48的减速比 float RPM=count*0.8f+0.5f; //等同于上式,2000/2496约等于0.8 if(RPM>1000) //过滤掉不合理的结果,仍然使用上次的速度,在按键设定速度的时候或者在减速为0时会有非常的大的错误测速结果,具体原因还未查清 { { return RPM_1; } RPM_1=RPM; //更新 return RPM; }
PID.c
#include "PID.h" PID pid; //int time=0; void PID_Init() { pid.Sv=400; //用户设定转速400 pid.Kp=0.3; //比例 pid.Ki=0.015; //积分 pid.Kd=0; //微分 pid.pwmcycle=100; //pwm周期100us pid.T=30; //PID计算周期30ms pid.OUT0=0; pid.C1ms=0; pid.SEk=0; pid.Ek=0; pid.Ek_1=0; pid.DelEk=0; pid.Dout=0; pid.Iout=0; pid.Pout=0; } void PID_Calc(float data) //pid计算 { float out; pid.Pv=data; pid.Ek=pid.Sv-pid.Pv; //得到当前的偏差值 pid.Pout=pid.Kp*pid.Ek; //比例输出 pid.SEk+=pid.Ek; //历史偏差总和 if(pid.SEk<(-50)) { pid.SEk=(-50); } pid.DelEk=pid.Ek-pid.Ek_1; //最近两次偏差之差 pid.Iout=pid.Ki*pid.SEk; //积分输出 if(pid.Iout<(-10)) { pid.Iout=(-10); } pid.Dout=pid.Kd*pid.DelEk; //微分输出 out= pid.Pout+ pid.Iout+ pid.Dout; if(out>pid.pwmcycle) { pid.OUT=pid.pwmcycle; } else if(out<=0) { pid.OUT=pid.OUT0; } else { pid.OUT=out+0.5f; //四舍五入 } pid.Ek_1=pid.Ek; //更新偏差 pid.C1ms=0; }
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。
评论(0)