基于C语言及51单片机的PID控制电机调速详解(附详细代码及Protsus仿真) 您所在的位置:网站首页 单片机远程控制电机 基于C语言及51单片机的PID控制电机调速详解(附详细代码及Protsus仿真)

基于C语言及51单片机的PID控制电机调速详解(附详细代码及Protsus仿真)

2024-07-13 12:04| 来源: 网络整理| 查看: 265

        本文章将利用最简单的软件和硬件--51单片机和Proteus仿真软件,由简及深地介绍PID控制电机调速的相关技术。

1.认识PWM脉宽调制技术

      在介绍PWM脉宽调制技术之前,我们先在proteus上搭建如下模型,观察小灯的亮灭变化。

         在这个模型中,我省去了单片机的复位电路和灯的上拉电阻。这不影响我们观察仿真结果,但实际使用时要加上。接着用keil软件,用以下程序生成hex文件,添加到上面的模型中。

#include #define MAX 0x50 #define MIN 0x00 #define TIMELINE 11 #define TRUE 1 #define FALSE 0 unsigned int TimeCounter; int ArrowFlg=0; unsigned char upCounter,downCounter; sbit LED=P2^0;//PWM输出口 void T0Deal() interrupt 1 using 0//控制PWM的高低电平,upCount代表高电平的时间单位量,downCount代表低电平时间单位量 { TH0=0xf1; TL0=0xf1; TR0=1; TimeCounter++; if(TimeCounter==TIMELINE) { if((upCounter==MAX)&&(downCounter==MIN)) { ArrowFlg=FALSE; } if((upCounter==MIN)&&(downCounter==MAX)) { ArrowFlg=TRUE; } if(ArrowFlg==TRUE) { upCounter++; downCounter--; } else { upCounter--; downCounter++; } TimeCounter=0; } } void Delay(unsigned int i)//延时函数 { unsigned int j; while(i--) { for(j=0;j0;c--) for(b=142;b>0;b--) for(a=2;a>0;a--); } } void timer_init() { EA = 1; ET0 = 1; ET1 = 1; ET2 = 1; TMOD = 0x15; //定时器0 计数模式 定时器1模式1 T2MOD = 0x01; TH0 = TL0 = 255; TH2 = 0x3C; TL2 = 0xB0; //50MS } void timer1() interrupt 3 { if(t1_flag == 0) { t1_flag = 1; PWM = 1; TH1 = (tuint - tpwm + 1)/256; TL1 = (tuint - tpwm + 1)%256; } else { t1_flag = 0; PWM = 0; TH1 = (tuint - 10000 + tpwm + 1)/256; TL1 = (tuint - 10000 + tpwm + 1)%256; } } void timer0() interrupt 1 { TH0 = TL0 = 255; t0_flag++; } void timer2() interrupt 5 { TF2 = 0; TH2 = 0x3C; TL2 = 0xB0; //50MS t2_flag++; if(t2_flag == 2) { TR0 = 0; TR2 = 0; t2_flag = 0; t2_over = 1; //表示100ms时间到 } } void GetPulse() { t0_flag = 0; t2_flag = 0; TH0 = TL0 = 255; TH2 = 0x3C; TL2 = 0xB0; //50MS TR0 = 1; TR2 = 1; } int PID() //增量式PID { int change; err_now = set - now; err_bef = set - bef; err_bbef = set - bbef; change = kp*(err_now - err_bef) + ki*err_now + kd*(err_now - 2*err_bef + err_bbef); /* if(set >= now) { if(set - now > 1) change = kp*(err_now - err_bef) + ki*err_now + kd*(err_now - 2*err_bef + err_bbef); else change = 0.2*kp*(err_now - err_bef) + 0.5*ki*err_now + kd*(err_now - 2*err_bef + err_bbef); } else if(now > set) { if(now - set > 1) change = kp*(err_now - err_bef) + ki*err_now + kd*(err_now - 2*err_bef + err_bbef); else change = 0.2*kp*(err_now - err_bef) + 0.5*ki*err_now + kd*(err_now - 2*err_bef + err_bbef); } */ //change = (kp + ki + kd)*(set - now) + (-kp - 2*kd)*(set - bef) + kd*(set - bbef); //change = kp*(set - now) + ki*(set - bef) + kd*(set - bbef); if(change > 0) { printchar(1,10,'+'); printuint(1,11,4,change); } else if(change < 0) { printchar(1,10,'-'); printuint(1,11,4,-change); } else if(change == 0) { printchar(1,10,' '); printword(1,11," 0 "); } return(change); } int PID2() //位置式PID { int num = 0; static num_bef = 0; err_now = set - now; err_bef = set - bef; error_add = error_add + err_now; //误差累加。一旦误差为0则error_add的值不变,PID输出值不变 num = kp*err_now + ki*error_add + kd*(err_now - err_bef); /* if(set - now >= 0) { if(set - now > 1) num = kp*err_now + ki*error_add + kd*(err_now - err_bef); else num = 0.1*kp*err_now + ki*error_add + kd*(err_now - err_bef); } else { if(now - set > 1) num = kp*err_now + ki*error_add + kd*(err_now - err_bef); else num = 0.1*kp*err_now + ki*error_add + kd*(err_now - err_bef); } */ if(num > num_bef) { printchar(1,10,'+'); printuint(1,11,4,num - num_bef); } else if(num < num_bef) { printchar(1,10,'-'); printuint(1,11,4,num_bef - num); } else { printchar(1,10,' '); printuint(1,11,4,0); } num_bef = num; return((uint)num); } void main() { lcd_init(); timer_init(); TH1 = TL1 = 255; printword(0,0,"P:"); //比例系数 printword(0,5,"S:"); //设定值 printword(1,0,"TPWM:"); //当前占空比 printword(0,10,"PS:"); //当前电机反馈的每秒脉冲数 while(1) { if(GORB == 1) { ZZ; } else { FZ; } if(ADDSPEED == 0) set++; if(SUBSPEED == 0) set--; if(Just_Get == 1) { Just_Get = 0; GetPulse(); } else if(t2_over == 1) { t2_over = 0; Just_Get = 1; pulse = t0_flag; bbef = bef; bef = now; now = t0_flag; if(set != 0) { TR1 = 1; } else { TR1 = 0; PWM = 0; } // tpwm = tpwm + PID(); //增量式PID tpwm = PID2(); //位置式PID } if(UP == 0) kp = kp + 1; if(DOWM == 0) kp = kp - 1; printuint(0,2,3,kp); printuint(0,7,3,set); printuint(1,5,4,tpwm); printuint(0,13,5,pulse); } }

        PWM脉冲实质上是通过定时器1来负责产生的。函数GetPulse()借助定时器的延时定时采集电机的脉冲信号。PID和PID2分别是增量式PID和位置式PID的程序代码。希望读者能通过注释读懂程序的工作流程,也可以自行注释掉相关代码来看看不同PID控制方式下的效果。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有