找回密码
 立即注册

QQ登录

只需一步,快速开始

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

要求平衡杆能在正负30°的范围内平衡。现在我只能让其在水平位置以下平衡

[复制链接]
跳转到指定楼层
楼主
         要求平衡杆能在正负30°的范围内平衡。现在我只能让其在水平位置以下平衡,到了水平位置以上就不能平衡,会飞到上面去了。     求大神指导,不胜感激!
附上程序:
  1. #include <reg52.h>
  2. #include <intrins.h>
  3. #include <math.h>
  4. #define _Nop() _nop_()
  5. #define nop() _nop_()
  6. #include<stdio.h>
  7. #define uchar unsigned char
  8. #define uint unsigned int
  9. #define delayNOP(); {_nop_();_nop_();_nop_();_nop_();};
  10. #define LCD_data P0
  11. sbit LCD_RS=P2^3;
  12. sbit LCD_RW=P2^4;
  13. sbit LCD_EN=P2^5;
  14. sbit LCD_PSB=P3^3;
  15. unsigned int c,d,e,f,m,n,p;
  16. uchar code dis1[]={"单轴螺旋桨悬浮系"};
  17. uchar code dis2[]={"角度:"};
  18. uchar code dis3[]={"调整时间:"};
  19. uchar code dis4[]={"°"};
  20. uchar code dis5[]={"秒"};

  21. sbit lowspeed=P3^6;           //K3
  22. sbit autospeed=P3^4;   //K1  !!!之前的K4与LCD12864端口冲突了!!!
  23. sbit pmw=P3^5;
  24. sbit ADC0832_CLK = P1^4;
  25. sbit ADC0832_DIO = P1^5;
  26. sbit ADC0832_CS = P2^0;
  27. unsigned int chuzhi0=0xb9b0,chuzhi1=0xf830,time,time1;
  28. unsigned char ADC_flag,balance=0x9f;
  29. unsigned char kaiguan=1;
  30. unsigned char jiaodu[20];
  31. unsigned char jiaodu1,jiaodu2,jiaodu3;
  32. unsigned int angle; /*实测角度值*/
  33. float setjiaodu=0;
  34. float Pro=0.01,
  35.           I=0.0001,
  36.           De=0,
  37.           lasterror=0,
  38.           pre_error=0,
  39.           sumerror=0;


  40. unsigned char ADC0832_Read(unsigned char ch){
  41.         unsigned char i,ADC_buff=0,temp=0;
  42.         ADC0832_CS = 1;
  43.         ADC0832_DIO = 1;   
  44.         ADC0832_CLK = 0;
  45.         ADC0832_CS = 0;
  46.         nop();
  47.         ADC0832_CLK = 1;
  48.         nop();
  49.         ADC0832_CLK = 0;
  50.         ADC0832_DIO = 1;  
  51.         nop();
  52.         ADC0832_CLK = 1;
  53.         nop();
  54.         ADC0832_CLK = 0;
  55.         if(ch==0)
  56.                 ADC0832_DIO = 0;
  57.         else
  58.                 ADC0832_DIO = 1;
  59.         ADC0832_CLK = 1;
  60.         nop();
  61.         ADC0832_CLK = 0;
  62.         nop();  
  63.         ADC0832_DIO = 1;
  64.         nop();
  65.         ADC0832_CLK = 1;
  66.         nop();
  67.         for(i=0;i<8;i++){                 
  68.                 nop();
  69.                 ADC0832_CLK = 0;
  70.                 nop();
  71.                 nop();
  72.                 ADC_buff=ADC_buff<<1;
  73.                 if(ADC0832_DIO==1)
  74.                         ADC_buff=ADC_buff+1;  
  75.                 ADC0832_CLK = 1;                        
  76.                 }
  77.         for(i=0;i<8;i++){
  78.                 temp = temp>>1;
  79.                 if(ADC0832_DIO==1)
  80.                         temp = temp | 0x80;
  81.                 ADC0832_CLK = 1;
  82.                 nop();
  83.                 ADC0832_CLK = 0;
  84.                 nop();
  85.                 }
  86.         ADC0832_CS = 1;
  87.         ADC0832_CLK = 1;
  88.         if(temp == ADC_buff)
  89.                 ADC_flag = 1;
  90.         else
  91.                 ADC_flag = 0;
  92.         return ADC_buff;         
  93. }
  94. //1MS为单位的延时程序
  95. void xianshi2();
  96. unsigned int set_to_dat(float a)
  97. {
  98.     float b;
  99.     if(a>0)
  100.       {b=256/5*(2*sqrt(1-((3.1415*a/180)*(3.1415*a/180)))+2.5);}
  101.     else
  102.       {b=256/5*(2.5-2*sqrt(1-((3.1415*a/180)*(3.1415*a/180))));}
  103.     return b;
  104. }
  105. unsigned int ADC0832da_to_Angle(unsigned char da)
  106. {
  107.         /*将输入的数据转换成角度值*/
  108.         float Volage;
  109.         float Angle;
  110.         int zhuan;
  111.         Volage =da*5.0/256;
  112.         if(0.5*Volage-1.25>=0){
  113.                 Angle = (float)(asin(0.5*Volage-1.25))*180/3.1415;
  114.             zhuan=(float)((asin(0.5*Volage-0.25*5)*180/3.1415)*100);
  115.         }
  116.         else{
  117.                 Angle = (float)(asin(1.25-0.5*Volage))*180/3.1415;
  118.             zhuan=(float)((asin(1.25-0.5*Volage)*180/3.1415)*100);
  119.                 }
  120.         return zhuan;        
  121. }
  122. void delay_1ms(uchar x)
  123. {
  124.     uchar j;
  125.     while(x--){
  126.         for(j=0;j<125;j++)
  127.             {;}
  128.         }   
  129. }

  130. void delay(unsigned int a);
  131. ///////////////////以下是LCD12864驱动程序//////////////////////////////

  132. bit lcd_busy()                   //检查LCD忙状态
  133. {                          
  134.     bit result;
  135.     LCD_RS = 0;
  136.     LCD_RW = 1;
  137.     LCD_EN = 1;
  138.     delayNOP();
  139.     result = (bit)(P0&0x80);
  140.     LCD_EN = 0;
  141.     return(result);
  142. }
  143. void lcd_wcmd(uchar cmd)//写指令数据到LCD
  144. {                          
  145.    while(lcd_busy());
  146.     LCD_RS = 0;
  147.     LCD_RW = 0;
  148.     LCD_EN = 0;
  149.     _nop_();
  150.     _nop_();
  151.     P0 = cmd;
  152.     delayNOP();
  153.     LCD_EN = 1;
  154.     delayNOP();
  155.     LCD_EN = 0;  
  156. }
  157. void lcd_wdat(uchar dat) //写显示数据到LCD
  158. {                          
  159.    while(lcd_busy());
  160.     LCD_RS = 1;
  161.     LCD_RW = 0;
  162.     LCD_EN = 0;
  163.     P0 = dat;
  164.     delayNOP();
  165.     LCD_EN = 1;
  166.     delayNOP();
  167.     LCD_EN = 0;
  168. }

  169. void lcd_init()                         //LCD初始化设定
  170. {
  171.         delay(15);
  172.     LCD_PSB = 1;         //并口方式
  173.     delay(5);
  174.     lcd_wcmd(0x34);      //扩充指令操作
  175.     delay(5);
  176.     lcd_wcmd(0x30);      //基本指令操作
  177.     delay(5);
  178.     lcd_wcmd(0x0C);      //显示开,关光标
  179.     delay(5);
  180.     lcd_wcmd(0x01);      //清除LCD的显示内容
  181.     delay(5);
  182. }

  183. ////////////////以上是LCD12864驱动程序////////////////////////////
  184. void xianshi()
  185. {        

  186.   if(jiaodu2<128){
  187.         lcd_wcmd(0X93);
  188.     delay_1ms(15);
  189.     lcd_wcmd(0X93);
  190.     delay_1ms(15);
  191.     lcd_wcmd(0X93);
  192.         delay_1ms(15);
  193.         lcd_wdat(0x2B);
  194.         delay_1ms(5);                    
  195.         }else{
  196.         lcd_wcmd(0X93);
  197.         delay_1ms(5);
  198.         lcd_wdat(0x2D);
  199.         delay_1ms(5);}  
  200.     lcd_wcmd(0x94);
  201.         lcd_wdat(c+0x30);
  202.         delay_1ms(20);
  203.     lcd_wdat(d+0x30);
  204.         delay_1ms(20);
  205.         lcd_wdat(0x2E);
  206.         delay_1ms(5);
  207.     lcd_wdat(e+0x30);
  208.         delay_1ms(20);
  209.         lcd_wdat(f+0x30);
  210.         delay_1ms(20);                     
  211. }
  212. void xianshi2()
  213. {
  214.          lcd_wcmd(0X8D);
  215.         lcd_wdat(m+0x30);
  216.         delay_1ms(5);
  217.     lcd_wdat(n+0x30);
  218.         delay_1ms(5);
  219.         lcd_wdat(0x2E);
  220.         delay_1ms(5);
  221.     lcd_wdat(p+0x30);
  222.         delay_1ms(5);
  223. }
  224. void pid();
  225. void main(){
  226.     uchar i;
  227.         lcd_init();                   /*LCD初始化*/
  228.         lcd_wcmd(0X80);                                                 //设置显示位置为第一行的第1个字符
  229.            for(i=0;i<16;i++){lcd_wdat(dis1[i]);}         //显示字符
  230.     lcd_wcmd(0X90);                          //设置显示位置为第二行的第2个字符
  231.     for(i=0;i<6;i++){lcd_wdat(dis2[i]);}
  232.          lcd_wcmd(0X88);                          //设置显示位置为第三行的第3个字符
  233.     for(i=0;i<10;i++){lcd_wdat(dis3[i]);}
  234.         lcd_wcmd(0X97);                          //设置显示位置为第四行的第3个字符
  235.     for(i=0;i<2;i++){lcd_wdat(dis4[i]);}
  236.         lcd_wcmd(0X8F);                          //设置显示位置为第五行的第3个字符
  237.     for(i=0;i<2;i++){lcd_wdat(dis5[i]);}
  238.         IT0=0;
  239.         EX0=1;
  240.         IT1=0;
  241.         EX1=1;
  242.         TMOD=0x11;
  243.         TH0=chuzhi1>>8;
  244.         TL0=chuzhi1;
  245.         ET0=1;
  246.         EA=1;
  247.         TR0=1;
  248.         while(1){
  249.                 if(lowspeed==0){                                   //初始化
  250.                         delay(20);
  251.                         if(lowspeed==0){
  252.                                 chuzhi0=0xb5c8;
  253.                                 chuzhi1=0xfc18;
  254.                         }
  255.                 }
  256.                 if(autospeed==0){
  257.                         delay(20);
  258.                         if(autospeed==0){
  259.                                 kaiguan=1;
  260.                                 balance=0x90;
  261.                                 //balance=(char)set_to_dat(setjiaodu);
  262.                                 pid();
  263.                         }
  264.                 }               
  265.         }
  266. }
  267. void shezhi() interrupt 1{                           //调节占空比
  268.         if(pmw==1){
  269.                 TH0=chuzhi0>>8;
  270.                 TL0=chuzhi0;
  271.                 pmw=0;
  272.         }
  273.         else{
  274.                 TH0=chuzhi1>>8;
  275.                 TL0=chuzhi1;
  276.                 pmw=1;
  277.         }
  278.         TF0=0;        
  279. }
  280. void shezhi1() interrupt 0{
  281.         chuzhi0=0xb5c8;
  282.         chuzhi1=0xfc18;
  283.         kaiguan=0;
  284. }
  285. void shezhi2() interrupt 3{
  286.         time++;
  287.         TH1=0X3C;
  288.         TL1=0XB0;
  289.         TF1=0;
  290. }
  291. /*void shezhi3() interrupt 2{
  292.         //balance=0x9c;
  293. }        */
  294. void delay(unsigned int a){
  295.         unsigned b=50,c=130;
  296.         for(;a>0;a--){
  297.                 for(;b>0;b--)
  298.                         for(;c>0;c--);
  299.         }
  300. }
  301. void pid2();
  302. void pid(){
  303.         unsigned char chazhi,chazhi1,chazhi2,button,change,j=3,i;
  304.         while(kaiguan==1){
  305.                 for(i=0;i<20;i++){
  306.                         jiaodu[i]=ADC0832_Read(0);
  307.                         delay(200);
  308.                 }
  309.                 jiaodu3=jiaodu[0];
  310.                 jiaodu1=(jiaodu[0]+jiaodu[1]+jiaodu[2]+jiaodu[3]+jiaodu[4]+jiaodu[5]+jiaodu[6]+jiaodu[7]+jiaodu[8]+jiaodu[9])/10;
  311.                 jiaodu2=(jiaodu[10]+jiaodu[11]+jiaodu[12]+jiaodu[13]+jiaodu[14]+jiaodu[15]+jiaodu[16]+jiaodu[17]+jiaodu[18]+jiaodu[19])/10;
  312.                
  313.         angle=ADC0832da_to_Angle(jiaodu2); //将采集值转换为角度值
  314.                 chazhi=abs(jiaodu2-balance);
  315.                 chazhi1=abs(jiaodu1-balance);
  316.                 chazhi2=abs(jiaodu3-balance);
  317.                 change=chazhi/8+1;
  318.                 if((chazhi>=20)&&(button==0)){
  319.                         button=1;
  320.                         TH1=0x3c;
  321.                         TL1=0xb0;
  322.                         ET1=1;
  323.                         TR1=1;
  324.                 }
  325.                 if((chazhi<=3)&&(button==1)&&(chazhi1<=3)&&(chazhi2<=3)){
  326.                         button=0;
  327.                         ET1=0;
  328.                         TR1=0;
  329.                         time1=(time*10)/20;
  330.                   /*此处添加显示平衡时间的子函数,平衡时间为已经设好的变量“time”*/
  331.                         m=time1/100;
  332.                      n=time1%100/10;
  333.                       p=time1%10;
  334.                         xianshi2();  
  335.                 //        time=0;           
  336.                         pid2();
  337.         
  338.                 }
  339.                 c=angle/1000;
  340.                 d=angle%1000/100;
  341.                 e=angle%1000%100/10;
  342.                 f=angle%10;
  343.                 j--;
  344.                 if(j==0){
  345.                     xianshi();
  346.                         j=3;
  347.                 }  /*此处添加显示当前角度的子程序,角度值为已经设好的变量“jiaodu2”*/
  348.         
  349.                 if(jiaodu2=jiaodu1){
  350.                         if((jiaodu2>balance)&&(chuzhi0<0xb9b0)&&(chazhi>=2)){
  351.                                 chuzhi0=chuzhi0+change;                                                                         //改变占空比
  352.                                 chuzhi1=chuzhi1-change;
  353.                         }
  354.                         if((jiaodu2<balance)&&(chuzhi0>0xb5c8)&&(chazhi>=2)){
  355.                                 chuzhi0=chuzhi0-change;
  356.                                 chuzhi1=chuzhi1+change;        
  357.                         }
  358.                 }
  359.                 if(jiaodu2>jiaodu1){
  360.                         if((jiaodu2>=balance)&&(chuzhi0<0xb9b0)&&(chazhi>=2)){
  361.                                 chuzhi0=chuzhi0+change;
  362.                                 chuzhi1=chuzhi1-change;
  363.                         }
  364.                 }
  365.                 if(jiaodu2<jiaodu1){
  366.                         if((jiaodu2<=balance)&&(chuzhi0>0xb5c8)&&(chazhi>=2)){
  367.                                 chuzhi0=chuzhi0-change;
  368.                                 chuzhi1=chuzhi1+change;
  369.                         }
  370.                 }        
  371.         }
  372.         return;
  373. }

  374. void pid2(){

  375.         float derror,error,change;
  376.         unsigned char jiaodu0,button,j;
  377.                 while(1)
  378.                 {
  379.               jiaodu0=ADC0832_Read(0);
  380.                 c=angle/1000;
  381.                 d=angle%1000/100;
  382.                 e=angle%1000%100/10;
  383.                 f=angle%10;
  384.                 j--;
  385.         
  386.                     xianshi();
  387.                
  388.                 error=(float)abs(balance-jiaodu0);
  389.                 sumerror+=error;
  390.                 derror=lasterror-pre_error;
  391.                 pre_error=lasterror;
  392.                 lasterror=error;
  393.                 change=Pro*error+I*sumerror+De*derror;
  394.           // change=error/10+1;
  395.                 if(change>500)
  396.                    {
  397.                       change=500;
  398.                     }
  399.                 if((error>=20)&&(button==0)){
  400.                         button=1;
  401.                         TH1=0x3c;
  402.                         TL1=0xb0;
  403.                         ET1=1;
  404.                         TR1=1;
  405.                 }
  406.                 if((jiaodu>balance)&&(chuzhi0<0xb9b0)&&(error>=2)){
  407.                                 chuzhi0=chuzhi0-(int)change;
  408.                                 chuzhi1=chuzhi1+(int)change;
  409.                                         }
  410.                 if((jiaodu<balance)&&(chuzhi0>0xb5c8)&&(error>=2)){
  411.                                 chuzhi0=chuzhi0+(int)change;
  412.                                   chuzhi1=chuzhi1-(int)change;        
  413.                         }
  414.                         if(error<2){
  415.                         button=0;
  416.                         ET1=0;
  417.                         TR1=0;
  418.                         time1=(time*10)/20;
  419.                   /*此处添加显示平衡时间的子函数,平衡时间为已经设好的变量“time”*/
  420.                         m=time1/100;
  421.                      n=time1%100/10;
  422.                     p=time1%10;
  423.                         xianshi2();
  424.                         time=0;
  425.                 }

  426.           }
  427.                 return;
  428. }                                

复制代码
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:72781 发表于 2016-4-1 02:35 | 只看该作者
代码太长,不知道咋看啊,你知道PID吧,估计向上平衡角度的时候,参数是正反馈了,比如角度预期是20度,测的角度是21度,这个时候应该向下一度,但是由于你用的-20度时候的参数,就变成加一度,然后偏差越来越大,试试是不是这个原因?我没看程序,猜的。
回复

使用道具 举报

板凳
ID:111420 发表于 2016-4-3 19:29 | 只看该作者
暗光 发表于 2016-4-1 02:35
代码太长,不知道咋看啊,你知道PID吧,估计向上平衡角度的时候,参数是正反馈了,比如角度预期是20度,测 ...

谢谢                        
回复

使用道具 举报

地板
ID:111420 发表于 2016-4-8 10:17 | 只看该作者
暗光 发表于 2016-4-1 02:35
代码太长,不知道咋看啊,你知道PID吧,估计向上平衡角度的时候,参数是正反馈了,比如角度预期是20度,测 ...

那正反馈的该怎么调参数?
回复

使用道具 举报

5#
ID:72781 发表于 2016-4-8 11:52 | 只看该作者
123go 发表于 2016-4-8 10:17
那正反馈的该怎么调参数?

分段设置参数,一个正一个负就好,你仔细理解一下平衡过程试试
回复

使用道具 举报

6#
ID:111420 发表于 2016-5-5 17:58 | 只看该作者
暗光 发表于 2016-4-1 02:35
代码太长,不知道咋看啊,你知道PID吧,估计向上平衡角度的时候,参数是正反馈了,比如角度预期是20度,测 ...

有没有优化PID的例程,感觉网上的PID程序都差不多
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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