找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 643|回复: 2
打印 上一主题 下一主题
收起左侧

请教一个PID程序问题分析

[复制链接]
跳转到指定楼层
楼主
ID:1064364 发表于 2023-7-24 10:41 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
pidout1=90 +   PIDcontrol(setjiaodu,jiaodu);        //pid算式这个90是哪里来的?具体指什么?

  1. #include <reg52.h>
  2. #include <intrins.H>
  3. #include <math.H>
  4. #include <stdio.h>   
  5. #define     u8              unsigned char
  6. #define     uchar          unsigned char
  7. #define     uint           unsigned int
  8. #define     u16           unsigned int
  9. #define  uchar unsigned char
  10. #define  uint unsigned int
  11. typedef unsigned char  Uint8;       /* defined for unsigned 8-bits integer variable       无符号8位整型变量  */
  12. typedef unsigned int   Uint16;      /* defined for unsigned 16-bits integer variable       无符号16位整型变量 */
  13. typedef unsigned long  Uint32;      /* defined for unsigned 32-bits integer variable       无符号32位整型变量 */

  14. sbit LCD_RS = P1^0;   //液晶1602  RS端口   
  15. sbit LCD_RW = P1^1;   //液晶1602  RS端口         
  16. sbit LCD_EP = P1^2;   //液晶1602  EN端口
  17. sbit PWM_PIN0 = P2^0 ;
  18. sbit PWM_PIN1 = P2^1 ;
  19. int setjiaodu = 40;//占空比最大100 6 16
  20. u16 pwm;//占空比最大100 6 16

  21. sbit  Key_Set   = P1^3 ;
  22. sbit  Key_Up    = P1^4 ;
  23. sbit  Key_Dowm  = P1^5 ;

  24. uchar code table[] = {":               "};      //设定速度初始化
  25. uchar code table1[] = {"                "}; //  动态显示初始化
  26. uchar n , i,x,table2[5],table3[5],ge,shi,bai,flag1,key1n,temp;

  27. ///***********延时1MS程序***/
  28. void  delay(uint z)
  29. {  uint x,y;
  30.    for(x=z;x>0;x--)
  31.    for(y=80;y>0;y--);

  32. }

  33. float kp = 0.70;
  34. float ki = 0.0005;
  35. float kd = 0.001;
  36. float ee,eeh,p;    //PID误差和误差累计
  37. float pidout1,pidout2,pidout3;                  
  38. float PIDcontrol( int  uset ,  int feedback)        //pid算式
  39. {                                                                                                      
  40.         float duk,D;   
  41.         eeh=ee;  
  42.     ee=uset*1.0-feedback*1.0;
  43.     p += ee;   
  44.     D = ee -eeh;
  45.       duk=kp*ee+ki*p-kd*D;
  46.     return duk;
  47. }



  48. /******液晶写命令************/
  49. void  write_com(uchar com)
  50. {     LCD_RS=0;
  51.   
  52.     P0=com    ;
  53. //    delay(1);
  54.     LCD_EP=1;
  55.     delay(1);
  56.     LCD_EP=0;
  57. }
  58. /*****************/
  59. /********液晶写数据***********/
  60. void  write_data(uchar  date)
  61. {      LCD_RS=1;

  62.     P0=date    ;
  63. //delay(1);
  64.     LCD_EP=1;
  65.     delay(1);
  66.     LCD_EP=0;

  67. }
  68. /*****************************/
  69. /********显示动态速度数据*********/
  70. void display_val(unsigned int zhuan)
  71. {

  72.   table2[0]=zhuan/10000+0x30;           //取万位   
  73.   table2[1]=(zhuan%10000)/1000+0x30;   //取千位
  74.   table2[2]=(zhuan%1000)/100+0x30;     //取百位
  75.   table2[3]=(zhuan%100)/10+0x30;       //取十位   
  76.   table2[4]=zhuan%10+0x30;              //取个位

  77. //  write_com(0x80+0x40+7);
  78. //   write_data(table2[0]);
  79. //   write_com(0x80+0x40+8);
  80. //    write_data(table2[1]);
  81.    write_com(0x80+0x40+4);
  82.    //write_data(table2[2]);
  83.    //write_com(0x80+0x40+10);
  84.    write_data(table2[3]);
  85.    //write_com(0x80+0x40+11);
  86.    write_data(table2[4]);         
  87.      
  88. }
  89. void dis(int z,unsigned int zhua,int x,int y)
  90. {
  91.      
  92.   table2[0]=zhua/10000+0x30;           //取万位   
  93.   table2[1]=(zhua%10000)/1000+0x30;   //取千位
  94.   table2[2]=(zhua%1000)/100+0x30;     //取百位
  95.   table2[3]=(zhua%100)/10+0x30;       //取十位   
  96.   table2[4]=zhua%10+0x30;              //取个位
  97.     if(z==1)
  98.   write_com(0x80+x);
  99.     if(z==2)
  100.   write_com(0x80+0x40+x);
  101. //  write_data(table2[0]);
  102.   //  write_data(table2[1]);
  103.    write_data(table2[2]);
  104.      if(y==1)
  105.         write_data('.');
  106.    write_data(table2[3]);
  107. //         if(y==2)
  108. //        write_data('.');
  109.    write_data(table2[4]);
  110.    write_com(0x80+16);   
  111.            
  112.      
  113. }
  114. void dis0(int z,int zhua,int x,int y)
  115. {
  116.         if(zhua>0)   
  117.         {
  118.             table2[0]=zhua/10000+0x30;           //取万位   
  119.             table2[1]=' ';   //取千位
  120.             table2[2]=(zhua%1000)/100+0x30;     //取百位
  121.             table2[3]=(zhua%100)/10+0x30;       //取十位   
  122.             table2[4]=zhua%10+0x30;              //取个位
  123.             if(z==1)
  124.             write_com(0x80+x);
  125.             if(z==2)
  126.             write_com(0x80+0x40+x-1);
  127.             write_data(table2[1]);
  128.             write_data(table2[2]);
  129.             write_data(table2[3]);
  130.             write_data(table2[4]);
  131.             write_com(0x80+16);   
  132.      }
  133.   else   
  134.     {
  135.           zhua=abs(zhua);
  136.           table2[0]=zhua/10000+0x30;           //取万位   
  137.             table2[1]='-';   //取千位
  138.             table2[2]=(zhua%1000)/100+0x30;
  139.             table2[3]=(zhua%100)/10+0x30;       //取十位   
  140.             table2[4]=zhua%10+0x30;              //取个位
  141.             if(z==1)
  142.             write_com(0x80+x);
  143.             if(z==2)
  144.             write_com(0x80+0x40+x-1);
  145.             write_data(table2[1]);
  146.              write_data(table2[2]);
  147.              write_data(table2[3]);
  148.             write_data(table2[4]);
  149.              write_com(0x80+16);
  150.     }        
  151.      
  152. }

  153. /*--------------------------液晶初始化-----------------------------*/
  154. void  init_lcd()
  155. {     
  156.         LCD_EP=0;
  157.        write_com(0x38);
  158.        write_com(0x08);
  159.        write_com(0x06);  
  160.        write_com(0x0c);
  161.        write_com(0x01);
  162. //初始化显示
  163.     write_com(0x80+2);                     
  164.     for(i=0;i<13;i++)
  165.     {
  166.         write_data(table[i]);                     
  167.         delay(3);
  168.     }
  169.     write_com(0x80+0x40);                       
  170.     for(i=0;i<14;i++)
  171.     {
  172.         write_data(table1[i]);                     
  173.         delay(3);
  174.     }  

  175. }
  176.     void PWMInit()
  177. {

  178.     TMOD|=0x01;         //模式设置,00000001,可见采用的是定时器0,工作与模式1(M1=0,M0=1)。
  179.     TR0=1;             //打开定时器
  180.     TH0=0Xff;         //定时器设置,每隔100微秒发起一次中断。
  181.     TL0=0Xc1;
  182.     ET0=1;             //开定时器0中断
  183.     EA=1;             //开总中断   
  184. }


  185. sbit ADCS     = P2^4; //ADC0832 片选
  186. sbit ADCLK  = P2^5; //ADC0832 时钟
  187. sbit ADDI     = P2^6; //ADC0832 数据输入        /*因为单片机的管脚是双向的,且ADC0832的数据输入输出不同时进行,
  188. sbit ADDO     = P2^6; //ADC0832 数据输出        /*为节省单片机引脚,简化电路所以输入输出连接在同一个引脚上

  189. static unsigned char Adc0832(unsigned char channel)
  190. {
  191.     Uint8 i=0;
  192.     Uint8 j;
  193.     Uint16 dat=0;
  194.     Uint8 ndat=0;
  195.     Uint8  Vot=0;

  196.     if(channel==0)channel=2;
  197.     if(channel==1)channel=3;
  198.     ADDI=1;
  199.     _nop_();
  200.     _nop_();
  201.     ADCS=0;//拉低CS端
  202.     _nop_();
  203.     _nop_();
  204.     ADCLK=1;//拉高CLK端
  205.     _nop_();
  206.     _nop_();
  207.     ADCLK=0;//拉低CLK端,形成下降沿1
  208.     _nop_();
  209.     _nop_();
  210.     ADCLK=1;//拉高CLK端
  211.     ADDI=channel&0x1;
  212.     _nop_();
  213.     _nop_();
  214.     ADCLK=0;//拉低CLK端,形成下降沿2
  215.     _nop_();
  216.     _nop_();
  217.     ADCLK=1;//拉高CLK端
  218.     ADDI=(channel>>1)&0x1;
  219.     _nop_();
  220.     _nop_();
  221.     ADCLK=0;//拉低CLK端,形成下降沿3
  222.     ADDI=1;//控制命令结束
  223.     _nop_();
  224.     _nop_();
  225.     dat=0;
  226.     for(i=0;i<8;i++)
  227.     {
  228.         dat|=ADDO;//收数据
  229.         ADCLK=1;
  230.         _nop_();
  231.         _nop_();
  232.         ADCLK=0;//形成一次时钟脉冲
  233.         _nop_();
  234.         _nop_();
  235.         dat<<=1;
  236.         if(i==7)dat|=ADDO;
  237.     }
  238.     for(i=0;i<8;i++)
  239.     {
  240.         j=0;
  241.         j=j|ADDO;//收数据
  242.         ADCLK=1;
  243.         _nop_();
  244.         _nop_();
  245.         ADCLK=0;//形成一次时钟脉冲
  246.         _nop_();
  247.         _nop_();
  248.         j=j<<7;
  249.         ndat=ndat|j;
  250.         if(i<7)ndat>>=1;
  251.     }
  252.     ADCS=1;//拉低CS端
  253.     ADCLK=0;//拉低CLK端
  254.     ADDO=1;//拉高数据端,回到初始状态
  255.     dat<<=8;
  256.     dat|=ndat;

  257.     return(dat);            //return ad data
  258. }

  259. Uint16 ReadAdc(unsigned char channel,unsigned int Number)//channel为通道 Number为输出值最大值
  260. {
  261.     Uint8 Read_AD;
  262.     Uint16        AdResult;
  263.     Read_AD = Adc0832(channel);
  264.     AdResult = (Uint32)4*Read_AD*Number/255;//255
  265.     return AdResult;
  266. }   
  267. #define KEYDELAY 20
  268. void KeyScanDeal(Uint8 sMenu,Uint16 *Setnumb1,float *Setnumb2,float *Setnumb3,float *Setnumb4)
  269. {
  270.    
  271.     static Uint8 Menu = 0;

  272.     if(Key_Set == 0)
  273.     {
  274.             Menu ++;
  275.             if(Menu > sMenu)
  276.                 Menu = 0;
  277.             while(Key_Set == 0);
  278.     }
  279.    
  280.     switch (Menu)
  281.     {
  282.             case 1:
  283.             {
  284.                 if(Key_Up == 0)
  285.                 {
  286.                         delay(KEYDELAY);
  287.                         if(Key_Up == 0 && (*Setnumb1) < 100)
  288.                         {        
  289.                                 (*Setnumb1) =*Setnumb1 + 1;
  290.                         }
  291.                 }
  292.                 else if(Key_Dowm == 0 && (*Setnumb1) > 0)
  293.                 {
  294.                         delay(KEYDELAY);
  295.                         if(Key_Dowm == 0)
  296.                         {
  297.                                 (*Setnumb1) =*Setnumb1 - 1;
  298.                         }
  299.                 }
  300.                 break;
  301.             }
  302.             case 2:
  303.             {
  304.                 if(Key_Up == 0 && (*Setnumb2) < 100)
  305.                 {
  306.                         delay(KEYDELAY);
  307.                         if(Key_Up == 0)
  308.                         {
  309.                                 (*Setnumb2) =*Setnumb2 + 0.01;
  310.                         }
  311.                 }
  312.                 else if(Key_Dowm == 0 && (*Setnumb2) > 0)
  313.                 {
  314.                         delay(KEYDELAY);
  315.                         if(Key_Dowm == 0)
  316.                         {
  317.                                 (*Setnumb2) =*Setnumb2 -0.01;
  318.                         }
  319.                 }
  320.                 break;
  321.             }
  322.             case 3:
  323.             {
  324.                 if(Key_Up == 0 && (*Setnumb3) < 50)
  325.                 {
  326.                         delay(KEYDELAY);
  327.                         if(Key_Up == 0)
  328.                         {
  329.                                 (*Setnumb3) =*Setnumb3 + 0.0001;
  330.                         }
  331.                 }
  332.                 else if(Key_Dowm == 0)
  333.                 {
  334.                         delay(KEYDELAY);
  335.                         if(Key_Dowm == 0 && (*Setnumb3) > 0)
  336.                         {
  337.                                 (*Setnumb3) =*Setnumb3 -0.0001;
  338.                         }
  339.                 }
  340.                 break;
  341.             }
  342.             case 4:
  343.             {
  344.                 if(Key_Up == 0 && (*Setnumb4) < 59)
  345.                 {
  346.                         delay(KEYDELAY);
  347.                         if(Key_Up == 0)
  348.                         {
  349.                                 (*Setnumb4) =*Setnumb4 + 0.001;
  350.                         }
  351.                 }
  352.                 else if(Key_Dowm == 0 && (*Setnumb4) > 0)
  353.                 {
  354.                         delay(KEYDELAY);
  355.                         if(Key_Dowm == 0)
  356.                         {
  357.                                 (*Setnumb4) =*Setnumb4 -0.001;
  358.                         }
  359.                 }
  360.                 break;
  361.             }
  362.     }
  363. }
  364.                                     


  365. void main()
  366. {   
  367.     Uint8 i = 0;
  368.     int jiaodu = 0;
  369.     PWMInit();
  370.     LCD_RW=0;
  371.     init_lcd();                        // 初始化液晶显示  
  372.     PWMInit();
  373.     PWM_PIN1 = 1;
  374.     while(1)   
  375.     {     
  376.         i ++;
  377.         if(i%5 ==0)
  378.         {
  379.             KeyScanDeal(4,&setjiaodu,&kp,&ki,&kd);            
  380.           dis(1,setjiaodu,0,2);
  381.           dis(1,jiaodu,6,2);
  382.           dis(2,kp*100,0,2);
  383.           dis(2,ki*10000,5,2);
  384.             dis(2,kd*1000,9,2);
  385.                     
  386.         }

  387.             jiaodu = ReadAdc(0,80) - 156;

  388.         pidout1=90 +   PIDcontrol(setjiaodu,jiaodu);        //pid算式

  389.             if(pidout1 > 100)
  390.             {
  391.                 pwm = 99;
  392.             }
  393.             else if(pidout1 <1)
  394.             {
  395.                 pwm = 1;
  396.             }
  397.             else
  398.             {
  399.                 pwm = pidout1;
  400.             }
  401.     }
  402. }

  403. void time0() interrupt 1
  404. {
  405.     static  int cnt = 0;

  406.    
  407.     if(cnt <= pwm)
  408.     {
  409.         PWM_PIN0 = 1;
  410.     }
  411.     else
  412.     {
  413.         PWM_PIN0 = 0;
  414.     }
  415.    
  416.         cnt++;
  417.    
  418.   if(cnt > 100)
  419.     {
  420.         cnt = 0;
  421.     }        
  422.     TH0=0Xff;
  423.     TL0=0Xc1;
  424.    
  425. }
复制代码
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:883242 发表于 2023-7-24 15:33 | 只看该作者
明显是PWM需要加上这个常数,为什么要加只能去查你的单片机手册PWM寄存器部分。
回复

使用道具 举报

板凳
ID:94031 发表于 2023-7-24 15:33 | 只看该作者
PID系统和实际现场联系非常紧密,离开实际现场,有些程序不好理解很正常。这里的90是编程者根据调试觉得,有这个90系统会比较快达到平衡。这里的90是输出从90开始控制调整,而不是0或其他.
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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