找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 606|回复: 0
收起左侧

基于51单片机PID算法控制电机转速程序Proteus仿真图

[复制链接]
ID:1122159 发表于 2024-6-7 12:47 | 显示全部楼层 |阅读模式
一个用51单片机实现2个电机pid调速的源程序,Proteus仿真的版本是8.17,只能用新版打开,电路原理图在帖子最后
单片机源程序如下:
  1. #include<reg52.h>
  2. #include"lcd1602.h"
  3. #include"delay.h"
  4. sfr T2MOD = 0x0c9;
  5. #define uchar unsigned char
  6. #define uint unsigned int

  7. sbit Q0 = P2^4;
  8. sbit Q1 = P2^5;
  9. sbit Q2 = P2^6;
  10. sbit Q3 = P2^7;

  11. sbit PWM         = P1^7;
  12. sbit UP             = P1^0;
  13. sbit DOWM         = P1^1;
  14. sbit GORB        = P2^3; //换相
  15. sbit ADDSPEED     = P1^2;
  16. sbit SUBSPEED    = P1^3;

  17. uint tuint = 65535;
  18. uint tpwm = 1;    //pwm周期为10000us tpwm变量表示pwm高电平时间,也相当于占空比 (仿真时,频率高时,电机反应慢。在实物上要加大频率)
  19. uchar t1_flag = 0;

  20. uint pulse = 0;
  21. uint t0_flag = 0;
  22. uchar t2_flag = 0;
  23. bit t2_over = 0;
  24. bit Just_Get = 1;


  25. #define     ZZ         { Q0 = 0;Q1 = 0;Q2 = 1;Q3 = 1;}    //正转
  26. #define     FZ         { Q0 = 1;Q1 = 1;Q2 = 0;Q3 = 0;}    //反转
  27. #define     STOP    { Q0 = 1;Q1 = 0;Q2 = 1;Q3 = 0;}    //停止
  28. //禁止出现 Q0 = 0;Q1 = 1;Q2 = 0;Q3 = 1; 不然会烧掉mos管

  29. //************************ PID *************************************
  30. float now = 0,bef = 0,bbef = 0;     //本次采样值,上次采样值,上上次采样值
  31. float err_now,err_bef,err_bbef;        //当前偏差,上次偏差,上上次偏差
  32. float error_add = 0;                //所有偏差之和
  33. float set = 25;                        //设定值

  34. float kp = 25;
  35. float ki = 25;
  36. float kd = 0;

  37. //*****************************************************************

  38. void delayms(uint ms)//延时?个 ms
  39. {
  40.     uchar a,b,c;
  41.     while(ms--)
  42.     {
  43.       for(c=1;c>0;c--)
  44.         for(b=142;b>0;b--)
  45.             for(a=2;a>0;a--);
  46.     }
  47. }

  48. void timer_init()
  49. {
  50.     EA = 1;
  51.     ET0 = 1;
  52.     ET1 = 1;
  53.     ET2 = 1;
  54.    
  55.     TMOD = 0x15; //定时器0 计数模式 定时器1模式1
  56.     T2MOD = 0x01;
  57.    
  58.     TH0 = TL0 = 255;
  59.     TH2 = 0x3C;
  60.     TL2 = 0xB0;        //50MS
  61.    
  62. }
  63. void timer1() interrupt 3
  64. {
  65.     if(t1_flag == 0)
  66.     {
  67.         t1_flag = 1;
  68.         PWM = 1;
  69.         TH1 = (tuint - tpwm + 1)/256;
  70.         TL1 = (tuint - tpwm + 1)%256;
  71.         
  72.     }
  73.     else
  74.     {
  75.         t1_flag = 0;
  76.         PWM = 0;
  77.         TH1 = (tuint - 10000 + tpwm + 1)/256;
  78.         TL1 = (tuint - 10000 + tpwm + 1)%256;
  79.     }
  80. }

  81. void timer0() interrupt 1
  82. {
  83.     TH0 = TL0 = 255;
  84.     t0_flag++;
  85. }
  86. void timer2() interrupt 5
  87. {
  88.     TF2 = 0;
  89.     TH2 = 0x3C;
  90.     TL2 = 0xB0;        //50MS
  91.    
  92.     t2_flag++;
  93.    
  94.     if(t2_flag == 2)
  95.     {
  96.         TR0 = 0;
  97.         TR2 = 0;
  98.         t2_flag = 0;
  99.         t2_over = 1;    //表示100ms时间到
  100.     }
  101. }
  102. void GetPulse()
  103. {
  104.     t0_flag = 0;
  105.     t2_flag = 0;
  106.    
  107.     TH0 = TL0 = 255;
  108.     TH2 = 0x3C;
  109.     TL2 = 0xB0;        //50MS
  110.    
  111.     TR0 = 1;
  112.     TR2 = 1;
  113. }

  114. int PID()    //增量式PID
  115. {
  116.     int change;

  117.     err_now = set - now;
  118.     err_bef = set - bef;
  119.     err_bbef = set - bbef;
  120.    
  121.     change = kp*(err_now - err_bef) + ki*err_now + kd*(err_now - 2*err_bef + err_bbef);
  122.    
  123. /*   
  124.     if(set >= now)
  125.     {   
  126.         if(set - now > 1)
  127.             change = kp*(err_now - err_bef) + ki*err_now + kd*(err_now - 2*err_bef + err_bbef);
  128.         else
  129.             change = 0.2*kp*(err_now - err_bef) + 0.5*ki*err_now + kd*(err_now - 2*err_bef + err_bbef);
  130.     }
  131.     else if(now > set)
  132.     {
  133.         if(now - set > 1)
  134.             change = kp*(err_now - err_bef) + ki*err_now + kd*(err_now - 2*err_bef + err_bbef);
  135.         else
  136.             change = 0.2*kp*(err_now - err_bef) + 0.5*ki*err_now + kd*(err_now - 2*err_bef + err_bbef);
  137.             
  138.     }
  139. */
  140.    
  141.     //change = (kp + ki + kd)*(set - now) + (-kp - 2*kd)*(set - bef) + kd*(set - bbef);
  142.     //change = kp*(set - now) + ki*(set - bef) + kd*(set - bbef);
  143.     if(change > 0)
  144.     {
  145.         printchar(1,10,'+');   
  146.         printuint(1,11,4,change);
  147.         
  148.     }
  149.     else if(change < 0)
  150.     {   
  151.         printchar(1,10,'-');
  152.         printuint(1,11,4,-change);
  153.     }
  154.     else if(change == 0)
  155.     {   
  156.         printchar(1,10,' ');
  157.         printword(1,11," 0  ");

  158.     }
  159.    
  160.     return(change);
  161. }

  162. int PID2()        //位置式PID
  163. {
  164.    
  165.     int num = 0;
  166.     static num_bef = 0;
  167.    
  168.     err_now = set - now;
  169.     err_bef = set - bef;
  170.    
  171.     error_add = error_add + err_now;  //误差累加。一旦误差为0则error_add的值不变,PID输出值不变

  172.     num = kp*err_now + ki*error_add + kd*(err_now - err_bef);
  173.    
  174. /*   
  175.     if(set - now >= 0)
  176.     {   
  177.         if(set - now > 1)
  178.             num = kp*err_now + ki*error_add + kd*(err_now - err_bef);
  179.         else
  180.             num = 0.1*kp*err_now + ki*error_add + kd*(err_now - err_bef);
  181.     }
  182.     else
  183.     {
  184.         if(now - set > 1)
  185.             num = kp*err_now + ki*error_add + kd*(err_now - err_bef);
  186.         else
  187.             num = 0.1*kp*err_now + ki*error_add + kd*(err_now - err_bef);
  188.             
  189.     }
  190.     */
  191.    
  192.     if(num > num_bef)
  193.     {
  194.         printchar(1,10,'+');   
  195.         printuint(1,11,4,num - num_bef);
  196.     }
  197.     else if(num < num_bef)
  198.     {
  199.         printchar(1,10,'-');   
  200.         printuint(1,11,4,num_bef - num);
  201.     }
  202.     else
  203.     {   
  204.         printchar(1,10,' ');
  205.         printuint(1,11,4,0);
  206.     }
  207.    
  208.     num_bef = num;
  209.    
  210.     return((uint)num);
  211. }

  212. void main()
  213. {   
  214.    
  215.     lcd_init();
  216.     timer_init();
  217.     TH1 = TL1 = 255;
  218.    
  219.     printword(0,0,"P:");        //比例系数
  220.     printword(0,5,"S:");        //设定值
  221.     printword(1,0,"TPWM:");        //当前占空比
  222.     printword(0,10,"PS:");        //当前电机反馈的每秒脉冲数
  223.    
  224.     while(1)
  225.     {
  226.         if(GORB == 1)
  227.         {    ZZ;        }
  228.         else
  229.         {    FZ;        }
  230.         
  231.         if(ADDSPEED == 0)
  232.     {
  233.         delay_ms(150);
  234.     if(ADDSPEED == 0)
  235.     {
  236.             set++;
  237.     }
  238. }
  239.         
  240.         if(SUBSPEED == 0)
  241.                 {
  242.         delay_ms(150);
  243.     if(SUBSPEED == 0)
  244.     {
  245.             set--;
  246.     }
  247. }
  248.             
  249.         
  250.         if(Just_Get == 1)
  251.         {   
  252.             Just_Get = 0;
  253.             GetPulse();
  254.         }
  255.         else if(t2_over == 1)
  256.         {   
  257.             t2_over = 0;
  258.             Just_Get = 1;
  259.             pulse = t0_flag;
  260.             bbef = bef;
  261.             bef = now;
  262.             now = t0_flag;
  263.             
  264.             if(set != 0)
  265.             {
  266.                 TR1 = 1;
  267.             }
  268.             else
  269.             {
  270.                 TR1 = 0;
  271.                 PWM = 0;
  272.             }
  273.             
  274.         //    tpwm = tpwm + PID();        //增量式PID
  275.             tpwm = PID2();                //位置式PID
  276.                     
  277.         }
  278.         
  279.         if(UP == 0)
  280.             kp = kp + 1;
  281.         if(DOWM == 0)
  282.             kp = kp - 1;
  283.         
  284.         printuint(0,2,3,kp);
  285.         printuint(0,7,3,set);
  286.         printuint(1,5,4,tpwm);
  287.         printuint(0,13,5,pulse);

  288.     }
  289.    
  290. }
复制代码

上下电机pid调节

上下电机pid调节

左右电机pid调节

左右电机pid调节

Proteus8.17版本的仿真程序.7z

212.97 KB, 下载次数: 20, 下载积分: 黑币 -5

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表