基于51单片机PID算法控制直流电机转速且数码管显示实际转速与设定速度的项目工程
Posted achenweiqianga
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于51单片机PID算法控制直流电机转速且数码管显示实际转速与设定速度的项目工程相关的知识,希望对你有一定的参考价值。
#include<reg52.h> #include<stdio.h> #define uchar unsigned char #define uint unsigned int unsigned char code Duan[]={0x3F, 0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};//共阴极数码管0-9段码表,高电平导通数码管段显示,低电平导通数码管位显示。 unsigned char Data_Buffer[8]={0,0,0,0,0,0,0,0};//声明数据缓存变量 sbit AddSpeed=P1^1;//位定义加速按键端口 sbit SubSpeed=P1^2;//位定义减速按键端口 sbit PWM_FC=P1^0;//位定义脉冲宽度输入端口 int e ,e1 ,e2 ;//声明当前偏差值变量、之后偏差值变量、再后偏差值变量 int out=0;//PID调节后输出偏差值变量 uint SetSpeed=0;//声明设定速度变量 uint cnt=0;//定时器1中断次数变量 uint Inpluse=0;//声明脉冲计数变量、 uint ActualSpeed=0;//声明实际速度变量 uint PWMTime;//声明脉冲宽度时间变量 float uk ,uk1 ,duk ;//声明目前总偏差值变量、之后偏差值总变量、偏差值总变量 float Kp=0.36,Ki=0.05,Kd=0.016;//声明比例系数、积分系数、微分系数 void PIDControl();//PID控制函数 void SystemInit();//系统初始化函数 void delay(uchar x);//延时函数 void PWMOUT();//脉冲宽度输出函数 void SpeedSet();//设定速度函数 void SegRefre();//数码管显示刷新函数 /**************主函数************/ void main() { SystemInit();//系统初始化函数 while(1) { SpeedSet();//设定速度函数 SegRefre();//数码管显示刷新函数 PWMOUT();//脉冲宽度输出函数 } } void delay(uchar x)//延时函数 { uint i,j; for(i=x;i>0;i--) for(j=50;j>0;j--); } void PIDControl()//PID控制函数 { e=SetSpeed-ActualSpeed;//计算当前偏差值变量 duk=(Kp*(e-e1)+Ki*e+Kd*(e-2*e1+e2));//PID连续系统离散化增量型PID算法,算出总偏差值变量。 uk=duk+uk1;//计算偏差值总变量加上之后偏差值总变量之和赋给目前总偏差值变量 out=(int)uk;//强制类型转化为整数型的目前总偏差值变量赋给PID调节后输出偏差值变量 if(out>100)//判断PID调节后输出偏差值变量是否大于100 { out=100;//PID调节后输出偏差值变量为100 } else if(out<0)//判断PID调节后输出偏差值变量是否小于0 { out=0;//PID调节后输出偏差值变量为0 } uk1=uk;//目前总偏差值变量赋给之后偏差值总变量 e2=e1;//之前偏差值变量赋给之后偏差值变量 e1=e;//当前偏差值变量赋给之前偏差值变量 PWMTime=out;//PID调节后输出偏差值变量赋给脉冲宽度时间变量 } void PWMOUT()//脉冲宽度输出函数 { if(cnt<PWMTime)//判断定时器1中断次数变量是否小于脉冲宽度时间变量 { PWM_FC=1;//脉冲宽度输入端口输出高电平 } else { PWM_FC=0;//脉冲宽度输入端口输出低电平 } if(cnt>100)//判断定时器1中断次数变量是否大于100 cnt=0;//定时器1中断次数变量归0 } void SystemInit()//系统初始化函数 { TMOD=0X21;//定时器0方式1,定时器1方式2。 TH0=0xf8;//初装定时器0高八位寄存器定时数值 TL0=0x50 ;//初装定时器0低八位寄存器定时数值,即2毫秒。 TH1=0xC0;//初装定时器1高八位寄存器定时数值 TL1=0XC0;//初装定时器1低八位寄存器定时数值,即16毫秒。 EA=1;//开总中断 EX0=1;//开外部中断0 IT0=1;//外部中断0下降沿触发 ET0=1;//开定时器0中断允许 ET1=1;//开定时器1中断允许 TR0=1;//开定时器0中断 TR1=1;//开定时器1中断 e =0;//偏差值变量为0 e1=0;//之后偏差值变量为0 e2=0;//再后偏差值变量为0 } void SpeedSet()//设定速度函数 { if(AddSpeed==0)//判断加速键是否按下 { delay(200);//延时 if(AddSpeed==0)//再次判断加速键是否按下 { SetSpeed+=10;//设定速度变量每次加10 if(SetSpeed>3500)//判断设定速度变量是否大于3500 { SetSpeed=3500;//设定速度变量归为3500 } } } if(SubSpeed==0)//判断减速键是否按下 { delay(200);//延时 if(SubSpeed==0)//再次判断减速键是否按下 { SetSpeed-=10;//设定速度变量每次减10 if(SetSpeed<0)//判断设定速度变量是否小于0 SetSpeed=0;//设定速度变量归0 } } } void SegRefre()//数码管显示刷新函数 { Data_Buffer[0]=SetSpeed/1000;//设定速度变量千位数 Data_Buffer[1]=SetSpeed%1000/100;//设定速度变量百位数 Data_Buffer[2]=SetSpeed%100/10;//设定速度变量十位数 Data_Buffer[3]=SetSpeed%10;//设定速度变量个位数 Data_Buffer[4]=ActualSpeed/1000;//实际速度变量千位数 Data_Buffer[5]=ActualSpeed%1000/100;//实际速度变量百位数 Data_Buffer[6]=ActualSpeed%100/10;//实际速度变量十位数 Data_Buffer[7]=ActualSpeed%10;//实际速度变量个位数 } void int0() interrupt 0//外部中断0函数 { Inpluse++;//脉冲计数变量加加 } void Time0() interrupt 1//定时器0中断服务函数 { static unsigned char Bit=0;//数码管位码静态变量,退出程序,其数值保留。 static unsigned int time=0;//转速测量周期变量 TH0=0xf8;//重装定时器0高八位寄存器计数值 TL0=0x50 ;//重装定时器0低八位寄存器计数值,即2毫秒。 time++;//转速测量周期变量加加 if(time>500)//判断转速测量周期变量是否大于500,等于500就是500x2毫秒=1000毫秒,也就是1s。 { time=0;//转速测量周期变量归0 ActualSpeed=Inpluse;//脉冲计数变量表示实际速度变量 Inpluse=0;//脉冲计数变量归0 PIDControl();//PID控制函数 } PWMOUT();//脉冲宽度输出函数 Bit++;//数码管位码选择位变量 if(Bit>8)//判断数码管位码选择位变量是否大于8 Bit=0;//数码管位码选择位变量归0 P0=0xff;//数码管位码显示关闭 P2=Duan[Data_Buffer[Bit]];//数码管段码显示 switch(Bit)//数码管位码变量选择位 { case 0: P0=0X7F;//实际速度变量千位 break; case 1: P0=0XBF;//实际速度变量百位 break; case 2: P0=0XDF;//实际速度变量十位 break; case 3: P0=0XEF;//实际速度变量个位 break; case 4: P0=0XF7;//设定速度变量千位 break; case 5: P0=0XFB;//设定速度变量百位 break; case 6: P0=0XFD;//设定速度变量十位 break; case 7: P0=0XFE;//设定速度变量个位 break; } } void Timer1() interrupt 3//定时器1中断服务函数 { cnt++;//定时器1中断次数变量 }
以上是关于基于51单片机PID算法控制直流电机转速且数码管显示实际转速与设定速度的项目工程的主要内容,如果未能解决你的问题,请参考以下文章
基于51单片机PWM调速数码管显示测速L298芯片控制直流电机正反运转的项目工程