找回密码
 立即注册

QQ登录

只需一步,快速开始

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

江湖救急 如何将pid算法 写入单片机中

[复制链接]
跳转到指定楼层
楼主
ID:183114 发表于 2017-3-24 17:06 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
  老师要求 机械臂中要加入智能算法 ,可是我完全是外行 ,请问 如何将pid 模糊算法加入单片机中
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:155507 发表于 2017-3-24 19:46 | 只看该作者

  1. //一个典型的PID处理程序,包含了最常用的PID算法的基本架构,没有包含输入输出处理部分。适合新手了解PID结构,入门学习用。

  2. /*
  3. 注意:
  4. 使用不同的MCU的时候,需要进行相应的简化和改写。而且由于单片机的处理速度和ram资源的限制,一般不采用浮点数运算。而将所有参数全部用整数,运算到最后再除以一个2的N次方数据(相当于移位),作类似定点数运算。这样可大大提高运算速度,根据控制精度的不同要求,当精度要求很高时,注意保留移位引起的“余数”,做好余数补偿就好了。
  5. */

  6. #include<reg51.h>
  7. #include<intrins.h>
  8. #include<math.h>
  9. #include<string.h>

  10. struct PID {
  11.         unsigned int SetPoint; // 设定目标 Desired Value
  12.         unsigned int Proportion; // 比例常数 Proportional Const
  13.         unsigned int Integral; // 积分常数 Integral Const
  14.         unsigned int Derivative; // 微分常数 Derivative Const
  15.         unsigned int LastError; // Error[-1]
  16.         unsigned int PrevError; // Error[-2]
  17.         unsigned int SumError; // Sums of Errors
  18. };
  19. struct PID spid; // PID Control Structure
  20. unsigned int rout; // PID Response (Output)
  21. unsigned int rin; // PID Feedback (Input)
  22. sbit data1=P1^0;
  23. sbit clk=P1^1;
  24. sbit plus=P2^0;
  25. sbit subs=P2^1;
  26. sbit stop=P2^2;
  27. sbit output=P3^4;
  28. sbit DQ=P3^3;
  29. unsigned char flag,flag_1=0;
  30. unsigned char high_time,low_time,count=0;//占空比调节参数
  31. unsigned char set_temper=35;
  32. unsigned char temper;
  33. unsigned char i;
  34. unsigned char j=0;
  35. unsigned int s;
  36. /***********************************************************
  37.                 延时子程序,延时时间以12M晶振为准,延时时间为30us×time
  38.                 ***********************************************************/
  39. void delay(unsigned char time)
  40. {
  41.         unsigned char m,n;
  42.         for(n=0;n<time;n++)
  43.         for(m=0;m<2;m++){}
  44. }
  45. /***********************************************************
  46.                 写一位数据子程序
  47.                 ***********************************************************/
  48. void write_bit(unsigned char bitval)
  49. {
  50.         EA=0;
  51.         DQ=0; /*拉低DQ以开始一个写时序*/
  52.         if(bitval==1)
  53.         {
  54.                 _nop_();
  55.                 DQ=1; /*如要写1,则将总线置高*/
  56.         }
  57.         delay(5); /*延时90us供DA18B20采样*/
  58.         DQ=1; /*释放DQ总线*/
  59.         _nop_();
  60.         _nop_();
  61.         EA=1;
  62. }
  63. /***********************************************************
  64.                 写一字节数据子程序
  65. ***********************************************************/
  66. void write_byte(unsigned char val)
  67. {
  68.         unsigned char i;
  69.         unsigned char temp;
  70.         EA=0;
  71.         TR0=0;
  72.         for(i=0;i<8;i++) /*写一字节数据,一次写一位*/
  73.         {
  74.                 temp=val>>i; /*移位操作,将本次要写的位移到最低位*/
  75.                 temp=temp&1;
  76.                 write_bit(temp); /*向总线写该位*/
  77.         }
  78.         delay(7); /*延时120us后*/
  79.         // TR0=1;
  80.         EA=1;
  81. }
  82. /***********************************************************
  83.                 读一位数据子程序
  84. ***********************************************************/
  85. unsigned char read_bit()
  86. {
  87.         unsigned char i,value_bit;
  88.         EA=0;
  89.         DQ=0; /*拉低DQ,开始读时序*/
  90.         _nop_();
  91.         _nop_();
  92.         DQ=1; /*释放总线*/
  93.         for(i=0;i<2;i++){}
  94.         value_bit=DQ;
  95.         EA=1;
  96.         return(value_bit);
  97. }
  98. /***********************************************************
  99.                 读一字节数据子程序
  100. ***********************************************************/
  101. unsigned char read_byte()
  102. {
  103.         unsigned char i,value=0;
  104.         EA=0;
  105.         for(i=0;i<8;i++)
  106.         {
  107.                 if(read_bit()) /*读一字节数据,一个时序中读一次,并作移位处理*/
  108.                 value|=0x01<<i;
  109.                 delay(4); /*延时80us以完成此次都时序,之后再读下一数据*/
  110.         }
  111.         EA=1;
  112.         return(value);
  113. }
  114. /***********************************************************
  115.                 复位子程序
  116. ***********************************************************/
  117. unsigned char reset()
  118. {
  119.         unsigned char presence;
  120.         EA=0;
  121.         DQ=0; /*拉低DQ总线开始复位*/
  122.         delay(30); /*保持低电平480us*/
  123.         DQ=1; /*释放总线*/
  124.         delay(3);
  125.         presence=DQ; /*获取应答信号*/
  126.         delay(28); /*延时以完成整个时序*/
  127.         EA=1;
  128.         return(presence); /*返回应答信号,有芯片应答返回0,无芯片则返回1*/
  129. }
  130. /***********************************************************
  131.                 获取温度子程序
  132. ***********************************************************/
  133. void get_temper()
  134. {
  135.         unsigned char i,j;
  136.         do
  137.         {
  138.                 i=reset(); /*复位*/
  139.         }  while(i!=0); /*1为无反馈信号*/
  140.         i=0xcc; /*发送设备定位命令*/
  141.         write_byte(i);
  142.         i=0x44; /*发送开始转换命令*/
  143.         write_byte(i);
  144.         delay(180); /*延时*/
  145.         do
  146.         {
  147.                 i=reset(); /*复位*/
  148.         }  while(i!=0);
  149.         i=0xcc; /*设备定位*/
  150.         write_byte(i);
  151.         i=0xbe; /*读出缓冲区内容*/
  152.         write_byte(i);
  153.         j=read_byte();   
  154.         i=read_byte();
  155.         i=(i<<4)&0x7f;
  156.         s=(unsigned int)(j&0x0f);            //得到小数部分
  157.         s=(s*100)/16;
  158.         j=j>>4;
  159.         temper=i|j; /*获取的温度放在temper中*/
  160. }
  161. /*====================================================================================================
  162.                 Initialize PID Structure

  163. =====================================================================================================*/
  164. void PIDInit (struct PID *pp)
  165. {
  166.         memset ( pp,0,sizeof(struct PID));           //全部初始化为0
  167. }
  168. /*====================================================================================================
  169.                 PID计算部分

  170. =====================================================================================================*/
  171. unsigned int PIDCalc( struct PID *pp, unsigned int NextPoint )
  172. {
  173.         unsigned int dError,Error;
  174.         Error = pp->SetPoint - NextPoint;          // 偏差           
  175.         pp->SumError += Error;                     // 积分                                   
  176.         dError = pp->LastError - pp->PrevError;    // 当前微分  
  177.         pp->PrevError = pp->LastError;                           
  178.         pp->LastError = Error;                                       
  179.         return (pp->Proportion * Error             // 比例项           
  180.         + pp->Integral * pp->SumError              // 积分项
  181.         + pp->Derivative * dError);                // 微分项
  182. }
  183. /***********************************************************
  184.                 温度比较处理子程序
  185. ***********************************************************/
  186. void compare_temper()
  187. {
  188.         unsigned char i;
  189.         if(set_temper>temper)      //是否设置的温度大于实际温度
  190.         {
  191.                 if(set_temper-temper>1)         //设置的温度比实际的温度是否是大于1度
  192.                 {
  193.                         high_time=100;                     //如果是,则全速加热
  194.                         low_time=0;
  195.                 }
  196.                 else                                         //如果是在1度范围内,则运行PID计算
  197.                 {
  198.                         for(i=0;i<10;i++)
  199.                         {
  200.                                 get_temper();                          //获取温度
  201.                                 rin = s; // Read Input
  202.                                 rout = PIDCalc ( &spid,rin ); // Perform PID Interation
  203.                         }
  204.                         if (high_time<=100)
  205.                         high_time=(unsigned char)(rout/800);
  206.                         else
  207.                         high_time=100;
  208.                         low_time= (100-high_time);
  209.                 }
  210.         }
  211.         else if(set_temper<=temper)
  212.         {
  213.                 if(temper-set_temper>0)
  214.                 {
  215.                         high_time=0;
  216.                         low_time=100;
  217.                 }
  218.                 else
  219.                 {
  220.                         for(i=0;i<10;i++)
  221.                         {
  222.                                 get_temper();
  223.                                 rin = s; // Read Input
  224.                                 rout = PIDCalc ( &spid,rin ); // Perform PID Interation
  225.                         }
  226.                         if (high_time<100)
  227.                         high_time=(unsigned char)(rout/10000);
  228.                         else
  229.                         high_time=0;
  230.                         low_time= (100-high_time);
  231.                 }
  232.         }
  233.         // else
  234.         // {}
  235. }
  236. /*****************************************************
  237.                 T0中断服务子程序,用于控制电平的翻转 ,40us*100=4ms周期
  238. ******************************************************/
  239. void serve_T0() interrupt 1 using 1
  240. {
  241.         if(++count<=(high_time))
  242.         output=1;
  243.         else if(count<=100)
  244.         {
  245.                 output=0;
  246.         }
  247.         else
  248.         count=0;
  249.         TH0=0x2f;
  250.         TL0=0xe0;
  251. }
  252. /*****************************************************
  253.                 串行口中断服务程序,用于上位机通讯
  254. ******************************************************/
  255. void serve_sio() interrupt 4 using 2
  256. {
  257.         /* EA=0;
  258.                 RI=0;
  259.                 i=SBUF;
  260.                 if(i==2)
  261.                 {
  262.                 while(RI==0){}
  263.                 RI=0;
  264.                 set_temper=SBUF;
  265.                 SBUF=0x02;
  266.                 while(TI==0){}
  267.                 TI=0;
  268.                 }
  269.                 else if(i==3)
  270.                 {
  271.                 TI=0;
  272.                 SBUF=temper;
  273.                 while(TI==0){}
  274.                 TI=0;
  275.                 }
  276.                 EA=1; */
  277. }
  278. void disp_1(unsigned char disp_num1[6])
  279. {
  280.         unsigned char n,a,m;
  281.         for(n=0;n<6;n++)
  282.         {
  283.                 // k=disp_num1[n];
  284.                 for(a=0;a<8;a++)
  285.                 {
  286.                         clk=0;
  287.                         m=(disp_num1[n]&1);
  288.                         disp_num1[n]=disp_num1[n]>>1;
  289.                         if(m==1)
  290.                         data1=1;
  291.                         else
  292.                         data1=0;
  293.                         _nop_();
  294.                         clk=1;
  295.                         _nop_();
  296.                 }
  297.         }
  298. }
  299. /*****************************************************
  300.                 显示子程序
  301.                 功能:将占空比温度转化为单个字符,显示占空比和测得到的温度
  302. ******************************************************/
  303. void display()
  304. {
  305.         unsigned char code number[]={0xfc,0x60,0xda,0xf2,0x66,0xb6,0xbe,0xe0,0xfe,0xf6};
  306.         unsigned char disp_num[6];
  307.         unsigned int k,k1;
  308.         k=high_time;
  309.         k=k%1000;
  310.         k1=k/100;
  311.         if(k1==0)
  312.         disp_num[0]=0;
  313.         else
  314.         disp_num[0]=0x60;
  315.         k=k%100;
  316.         disp_num[1]=number[k/10];
  317.         disp_num[2]=number[k%10];
  318.         k=temper;
  319.         k=k%100;
  320.         disp_num[3]=number[k/10];
  321.         disp_num[4]=number[k%10]+1;
  322.         disp_num[5]=number[s/10];
  323.         disp_1(disp_num);
  324. }
  325. /***********************************************************
  326.                 主程序
  327. ***********************************************************/
  328. void main()
  329. {
  330.         unsigned char z;
  331.         unsigned char a,b,flag_2=1,count1=0;
  332.         unsigned char phil[]={2,0xce,0x6e,0x60,0x1c,2};
  333.         TMOD=0x21;
  334.         TH0=0x2f;
  335.         TL0=0x40;
  336.         SCON=0x50;
  337.         PCON=0x00;
  338.         TH1=0xfd;
  339.         TL1=0xfd;
  340.         PS=1;
  341.         EA=1;
  342.         EX1=0;
  343.         ET0=1;
  344.         ES=1;
  345.         TR0=1;
  346.         TR1=1;
  347.         high_time=50;
  348.         low_time=50;
  349.         PIDInit ( &spid );    // Initialize Structure
  350.         spid.Proportion = 10; // Set PID Coefficients  比例常数 Proportional Const
  351.         spid.Integral = 8;    //积分常数 Integral Const
  352.         spid.Derivative =6;   //微分常数 Derivative Const
  353.         spid.SetPoint = 100; // Set PID Setpoint 设定目标 Desired Value
  354.         while(1)
  355.         {
  356.                 if(plus==0)
  357.                 {
  358.                         EA=0;
  359.                         for(a=0;a<5;a++)
  360.                         for(b=0;b<102;b++){}
  361.                         if(plus==0)
  362.                         {
  363.                                 set_temper++;
  364.                                 flag=0;
  365.                         }
  366.                 }
  367.                 else if(subs==0)
  368.                 {
  369.                         for(a=0;a<5;a++)
  370.                         for(b=0;a<102;b++){}
  371.                         if(subs==0)
  372.                         {
  373.                                 set_temper--;
  374.                                 flag=0;
  375.                         }
  376.                 }
  377.                 else if(stop==0)
  378.                 {
  379.                         for(a=0;a<5;a++)
  380.                         for(b=0;b<102;b++){}
  381.                         if(stop==0)
  382.                         {
  383.                                 flag=0;
  384.                                 break;
  385.                         }
  386.                         EA=1;
  387.                 }
  388.                 get_temper();
  389.                 b=temper;
  390.                 if(flag_2==1)
  391.                 a=b;
  392.                 if((abs(a-b))>5)
  393.                 temper=a;
  394.                 else
  395.                 temper=b;
  396.                 a=temper;
  397.                 flag_2=0;
  398.                 if(++count1>30)
  399.                 {
  400.                         display();
  401.                         count1=0;
  402.                 }
  403.                 compare_temper();
  404.         }
  405.         TR0=0;
  406.         z=1;
  407.         while(1)
  408.         {
  409.                 EA=0;
  410.                 if(stop==0)
  411.                 {
  412.                         for(a=0;a<5;a++)
  413.                         for(b=0;b<102;b++){}
  414.                         if(stop==0)
  415.                         disp_1(phil);
  416.                         // break;
  417.                 }
  418.                 EA=1;
  419.         }
  420. }

复制代码
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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