51单片机PID控制直流电机(proteus仿真)

Dream_Chaser2015 2015-06-18 07:03:26
51单片机利用PID算法控制直流电机的程序,内含proteus仿真。刚刚入门的小菜鸟,希望大家多多指教。看看程序中有没有改进的地方,如何缩短调整时间?相互交流,相互学习。

/*****************************************************************************************
*文件名:pid.c
*文件描述:PID控制电机转速
*作者:
*创建日期:2015/6/17
*****************************************************************************************/

#include <reg51.h>
#include <intrins.h>

sbit plus_10=P1^3; //对各个按钮进行位定义
sbit minus_10=P1^4;
sbit plus=P1^5;
sbit minus=P1^6;
sbit enter=P1^7;
sbit PWM_OUT1=P1^1;
sbit PWM_OUT2=P1^0;
sbit dir=P1^2;

struct PID //定义PID结构体
{
int SetValue; //设定值
// long SumError; //误差
double Proportion; //比例系数
double Integral; //积分系数
double Derivative; //微分系数
int LastError;
int PrevError;
}sPID,*sptr= &sPID;

int PWM,PWM_temp=1,count0=0,Speed_Set,Seep_Measure,counter_100ms,counter_10ms;
bit flag_100ms,flag_10ms,start,plus_10_lock=1,minus_10_lock=1,plus_lock=1,
minus_lock=1,enter_lock=1;
char num[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f};//0~9 对应数码

/*****************************************************************************************
*函数名:void delayms(unsigned char x)
*函数功能:简单延时 支持0~255ms
*函数参数:x 延时时间
*****************************************************************************************/
void delayms(unsigned char x)
{
unsigned char i ;
while(x--)
for(i = 0 ; i < 120 ; i++) ;
}
/*****************************************************************************************
*函数名:void display(void)
*函数功能:显示函数
*函数参数:无
*****************************************************************************************/
void display(void)
{
P2 =0x7f; P0 = num[Speed_Set/100];delayms(2);
P2 =0xbf; P0 = num[Speed_Set % 100 / 10];delayms(2);
P2 =0xdf; P0 = num[Speed_Set % 10];delayms(2);
P2 =0xfb; P0 = num[Seep_Measure / 100];delayms(2);
P2 =0xfd; P0 = num[Seep_Measure % 100/10];delayms(2);
P2 =0xfe; P0 = num[Seep_Measure % 10]; delayms(2);
if(start&&dir)
{
P2=0xf7;P0=0x40;delayms(2);
}
}
/*****************************************************************************************
*函数名:void keyscan(void)
*函数功能:按键扫描
*函数参数:无
*****************************************************************************************/
void keyscan(void)
{
static unsigned char plus_10_delay,minus_10_delay,plus_delay,minus_delay,enter_delay;
if(plus_10==0)
{
if(plus_10_lock&&++plus_10_delay>=2)
{
plus_10_lock=0;
if(Speed_Set<170)
Speed_Set+=10;
else Speed_Set=10;
}
}
else
{
plus_10_lock=1;
plus_10_delay=0;
}
if(minus_10==0)
{
if(minus_10_lock&&++minus_10_delay>=2)
{
minus_10_lock=0;
if(Speed_Set>10)
Speed_Set-=10;
else Speed_Set=170;
}
}
else
{
minus_10_lock=1;
minus_10_delay=0;
}
if(plus==0)
{
if(plus_lock&&++plus_delay>2)
{
plus_lock=0;
if(Speed_Set<170)
Speed_Set+=1;
else Speed_Set=0;
}
}
else
{
plus_lock=1;
plus_delay=0;
}
if(minus==0)
{
if(minus_lock&&++minus_delay>2)
{
minus_lock=0;
if(Speed_Set>0)
Speed_Set-=1;
else Speed_Set=170;
}
}
else
{
minus_lock=1;
minus_delay=0;
}
if(enter==0)
{
if(enter_lock&&++enter_delay>2)
{
enter_lock=0;
sptr->SetValue =Speed_Set;
start=1;
}
}
else
{
enter_lock=1;
enter_delay=0;
}
}

/*****************************************************************************************
*函数名:void timer0(void)
*函数功能:定时器0 中断函数
*函数参数:无
*****************************************************************************************/
void timer0(void) interrupt 1
{
TH0=0xfc; //定时1ms
TL0=0x18;
if(++counter_100ms>=100)
{
counter_100ms=0;
flag_100ms=1;
}
if(++counter_10ms>=10)
{
flag_10ms=1;
counter_10ms=0;
}
if(PWM&&--PWM_temp==0)
{
PWM_OUT1=!PWM_OUT1;
if(PWM_OUT1) PWM_temp=PWM;
else PWM_temp=100-PWM; //PWM周期小于等于采样周期
}
}

/*****************************************************************************************
*函数名:void EIRQ0(void)
*函数功能:外部中断0处理函数 记录脉冲个数
*函数参数:无
*****************************************************************************************/
void EIRQ0(void) interrupt 0
{
count0++;
}

/*****************************************************************************************
*函数名:viod PIDInit(void)
*函数功能:PID参数初始化
*函数参数:无
*****************************************************************************************/
void PIDInit(void)
{
// sptr->SumError = 0;
sptr->LastError = 0; //Error[-1]
sptr->PrevError = 0; //Error[-2]
sptr->Proportion = 2.3; //比例系数
sptr->Integral = 1.2; //积分系数
sptr->Derivative = 0.1; //微分系数
sptr->SetValue = 0;
}

/*****************************************************************************************
*函数名:int PID_Calc(int MeasureValue)
*函数功能:PID算法 调节PWM增量
*函数参数:MeasureValue 测得的速度值 PID_Adjust 返回值 PWM误差修正值
*****************************************************************************************/
int PID_Calc(int MeasureValue)
{
register int iError, PID_Adjust;
iError = sptr->SetValue - MeasureValue; //计算增加量
PID_Adjust = (int)(sptr->Proportion * iError //E[k]项
- sptr->Integral * sptr->LastError //E[k-1]项
+ sptr->Derivative * sptr->PrevError); //E[k-2]项
//存储当前误差以便后面计算
sptr->PrevError = sptr->LastError;
sptr->LastError = iError;
//返回增量值
return (PID_Adjust);
}

/*****************************************************************************************
*函数名:void main(void)
*函数功能:主函数
*函数参数:无
*****************************************************************************************/
void main(void)
{
TMOD=0x01;
TH0=0xfc;
TL0=0x18;
IT0=1;
EX0=1;
ET0=1;
TR0=1;
EA=1;
PWM_OUT1=0 ;
PWM_OUT2=0;
PIDInit();
while(1)
{
if(flag_100ms) //100ms采集一次脉冲数
{
Seep_Measure=count0; //(600/600)*count0
count0=0;
flag_100ms=0;
if(start==1) //调整PWM
{
int PWM_PID;
PWM_PID=PID_Calc(Seep_Measure);
if((PWM+0.5*PWM_PID)<99&&(PWM+0.5*PWM_PID)>1) //防止调节比例过大 造成PWM值超出范围
PWM=PWM+0.5*PWM_PID; //0.5用于保证速度调整跨度过大时PWM不会过界
}
}
if(flag_10ms)
{
keyscan();
display();
flag_10ms=0;
}
}
}


不能上传附件???!!
...全文
4395 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
Camaro、 2019-06-16
  • 打赏
  • 举报
回复
求 keil 和 protues 文件 337078588@qq.com 好人一生平安
qq_45029205 2019-05-08
  • 打赏
  • 举报
回复
求keil和protues文件😭846721588@qq.com
  • 打赏
  • 举报
回复
万能的博主!正在学习中,能发下你的protues仿真图不,好人一生平安!!!!787377625@qq.com
arvin-huang 2017-08-04
  • 打赏
  • 举报
回复
1209459220@qq.com 谢谢楼主
qq_34954658 2017-08-03
  • 打赏
  • 举报
回复
正在学PID,谢谢楼主了!
  • 打赏
  • 举报
回复
谢了,本人学生,自学PID正愁没有观摩的代码呢
qq_17640453 2017-07-30
  • 打赏
  • 举报
回复
1256537745@qq.com 谢谢楼主
My-sf 2017-06-30
  • 打赏
  • 举报
回复
楼主,L298下面是啥,显示的液晶选的是那款,可以发一下Proteus仿真吗?,谢谢,pyh9025@163.com
wklzxtqtt 2017-06-20
  • 打赏
  • 举报
回复
请问可以吧proteus仿真给一下吗,我们最近也做这个
qq_38179810 2017-05-03
  • 打赏
  • 举报
回复
请问有proteus仿真步进电机PID控制的吗?谢谢各位大神
qq_38179810 2017-05-03
  • 打赏
  • 举报
回复
2734501925@qq.com 谢谢
qq_35488335 2017-03-28
  • 打赏
  • 举报
回复
学习一下,不错的方法
lgc980 2016-12-23
  • 打赏
  • 举报
回复
605108925@qq.com 谢谢
lgc980 2016-12-23
  • 打赏
  • 举报
回复
楼主在不,能发一下仿真程序吗?这个有点模糊
qq_36976219 2016-12-11
  • 打赏
  • 举报
回复
求proteus电路图,2201898562@qq.com,先谢过。
三里十步 2016-06-29
  • 打赏
  • 举报
回复
马住,,,一会过来看看
qq_32738061 2016-02-16
  • 打赏
  • 举报
回复
求proteus电路图,185792848@qq.com,先谢过。
qq_25368261 2015-10-07
  • 打赏
  • 举报
回复
求proteus电路图,2544132986@qq.com,先谢过。
worldy 2015-06-20
  • 打赏
  • 举报
回复
int PID_Calc(int MeasureValue) { register int iError, PID_Adjust; iError = sptr->SetValue - MeasureValue; //计算增加量 PID_Adjust = (int)(sptr->Proportion * iError //E[k]项 - sptr->Integral * sptr->LastError //E[k-1]项//为什么是减的?为什么是上次误差?误差积分值呢? + sptr->Derivative * sptr->PrevError); //E[k-2]项//微分体现在哪? //存储当前误差以便后面计算 sptr->PrevError = sptr->LastError; sptr->LastError = iError; //返回增量值 return (PID_Adjust); }
worldy 2015-06-20
  • 打赏
  • 举报
回复
引用 3 楼 u011241080 的回复:
P*iError+I*(iError-LastError)+D*(iError-2*LastError+PrevError)
请教,这个公式积分环节在哪?微分环节为什么是iError-2*LastError+PrevError?
加载更多回复(2)

27,375

社区成员

发帖
与我相关
我的任务
社区描述
硬件/嵌入开发 单片机/工控
社区管理员
  • 单片机/工控社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧