找回密码
 立即注册

QQ登录

只需一步,快速开始

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

基于STC15W的风力摆控制系统设计 带视频与程序(电赛测控题)

[复制链接]
跳转到指定楼层
楼主
风力摆视频演示:


元件清单:



单片机源程序如下:
  1. //========================================================================
  2. //        城建学院电子实验室
  3. //        修改日期2017.07.30
  4. //        版本V1.0
  5. //========================================================================
  6. //特别声明:此程序
  7. //         
  8. //
  9. //
  10. //                                 MCU工作频率:24MHz
  11. //=========================================================================

  12. #include <STC15F2K60S2.h>        //STC15系列通用头文件
  13. #include <intrins.h>                //STC特殊命令符号声明
  14. #include <MPU6050.H>                //MPU6050数字陀螺仪
  15. #include <STC15W4KPWM.H>        //单片机所有IO口初始化-PWM口初始化
  16. #include <IMU.H>                        
  17. #include <math.H>

  18. bit busy,flag=0;
  19. int ich1=0,ich2=0,ich3=0,ich4=0,ich5=0,ich6=0;                //匿名科技上位机
  20. //==================================================//
  21. //  PID算法变量
  22. //==================================================//
  23. int speed1=0,speed2=0,speed3=0,speed4=0;//电机速度参数
  24. int PWM1=0,PWM2=0,PWM3=0,PWM4=0;                //加载至PWM模块的参数
  25. float Angle=0;
  26. char mode=1;
  27. //*****************角度参数*************************************************
  28. float Last_Angle_gx=0;                                          //外上一次陀螺仪数据
  29. float Last_Angle_gy=0;                                                  //上一次陀螺仪数据
  30. double Gyro_y=0,Gyro_x=0,Gyro_z=0;        //Y轴陀螺仪数据暂存
  31. double Accel_x=0,Accel_y=0,Accel_z=0;          //X轴加速度值暂存
  32. double Angle_ax=0,Angle_ay=0,Angle_az=0;  //由加速度计算的加速度(弧度制)
  33. double Angle_gy=0,Angle_gx=0,Angle_gz=0;  //由角速度计算的角速率(角度制)
  34. float data AngleX=0,AngleY=0;                                  //四元数解算出的欧拉角
  35. double Ax=0,Ay=0;                    //加入遥控器控制量后的角度
  36. double Vx=0,Vy=0;                    //加入遥控器控制量后的角度
  37. float ierrorx=0,ierrory=0; //误差积分 积分根据情况,目前测试情况不需要积分
  38. //****************姿态处理和PID*********************************************
  39. float FR1=0,FR2=0;            //xy轴期望角度
  40. float  data PID_Output;                                //PID最终输出量

  41. float xdata Last_Ax=0;
  42. float xdata Last_Ay=0;
  43. float xdata Last_vx=0;
  44. float xdata Last_vy=0;


  45. float R=0.20f;//摆幅半长 (m)
  46. unsigned int time=0;
  47. float A1=0,A2=0;

  48. sbit key1=P2^0;
  49. sbit key2=P2^1;
  50. sbit key3=P2^2;
  51. sbit key4=P2^3;




  52. //==================================================//
  53. //   PID 手动微调参数值
  54. //==================================================//
  55. // P值适当调,D值可以给很大!!! P值过大系统就会荡

  56. #define Out_XP        4.5f        
  57. #define        Out_XI  0.0f         //I根据情况,目前不需要I
  58. #define        Out_XD  2200.0f        

  59. #define        Out_YP        Out_XP
  60. #define        Out_YI        Out_XI
  61. #define        Out_YD        Out_XD

  62. #define PI 3.15459
  63. #define T 1601//单摆周期(ms) 根据单摆公式用杆长计算

  64. //--------------------------------------------------//
  65. //  PID算法飞控自平衡 函数
  66. //--------------------------------------------------//
  67. void Flight(void)interrupt 1
  68. {
  69.     time+=10;
  70.         Gyro_x = GetData(GYRO_XOUT_H);//读出 X轴陀螺仪数据
  71.         Gyro_y = GetData(GYRO_YOUT_H);//读出 Y轴陀螺仪数据
  72.         Gyro_z = GetData(GYRO_ZOUT_H);//读出 Z轴陀螺仪数据        
  73.         Accel_y= GetData(ACCEL_YOUT_H);//读出 X轴加速度数据
  74.         Accel_x= GetData(ACCEL_XOUT_H);//读出 Y轴陀螺仪数据                  
  75.         Accel_z= GetData(ACCEL_ZOUT_H);//读出 Z轴加速度数据
  76.         //姿态数据算法 (借鉴STC官方算法)
  77.         Last_Angle_gx=Angle_gx;   //储存上一次角速度数据
  78.         Last_Angle_gy=Angle_gy;          //储存上一次角速度数据
  79.         Angle_ax=(Accel_x)/8192;  //加速度处理
  80.         Angle_az=(Accel_z)/8192;  //加速度量程 +-4g/S
  81.         Angle_ay=(Accel_y)/8192;  //转换关系   8192LSB/g
  82.         Angle_gx=(Gyro_x)/65.5+4;   //陀螺仪处理
  83.         Angle_gy=(Gyro_y)/65.5+3;   //陀螺仪量程 +-500度/S
  84.         Angle_gz=(Gyro_z)/65.5;   //转换关系65.5LSB/度

  85. //***********************************四元数解算***********************************
  86.         IMUupdate(Angle_gx*0.0174533,Angle_gy*0.0174533,Angle_gz*0.0174533,Angle_ax,Angle_ay,Angle_az);//0.174533为PI/180 目的是将角度转弧度

  87. //****平衡算法***********************************************************************



  88.     FR1=A1*sin(2*PI*time/T);        //X轴控制
  89.         if(mode==3) FR2=A2*cos(2*PI*time/T); //Y轴控制
  90.         else if(mode==4) FR2=A2*cos(2*PI*time/(T/2)); //Y轴控制
  91.         else   FR2=A2*sin(2*PI*time/T); //Y轴控制
  92.         

  93.         if(time >= 1601)time=0;


  94. //************** MPU6050 X轴指向 ***********************************************************
  95.     Ax=FR1-(AngleX+2);   //X轴偏差

  96.         ich1=Ax;
  97.         ich2=Ay;
  98.         ich3=0;                 
  99.         ich4=0;
  100.         ich5=0;
  101.         ich6=0;

  102.         ierrorx +=Last_Ax-Ax;

  103.     PID_Output = Ax*Out_XP +Out_XI*ierrorx+(Last_Ax-Ax)*Out_XD;        //PID

  104.         if(PID_Output >  1000)        PID_Output =  1000;  //输出量限幅
  105.         if(PID_Output < -1000)        PID_Output = -1000;
  106.         
  107.         speed1 =0+ PID_Output;        speed3 =0- PID_Output;

  108.         Last_Ax=Ax;

  109. //**************MPU6050 Y轴指向**************************************************

  110.           Ay=FR2-(AngleY);  //Y轴偏差

  111.         ierrory +=Last_Ay-Ay;

  112.     PID_Output = Ay*Out_YP +Out_YI*ierrory+(Last_Ay-Ay)*Out_XD;        //PID

  113.         if(PID_Output >  1000)        PID_Output =  1000;  //输出量限幅
  114.         if(PID_Output < -1000)        PID_Output = -1000;
  115.                
  116.         speed2 =0+ PID_Output;        speed4 = 0- PID_Output;
  117.                         
  118.         Last_Ay=Ay;           

  119. //************************PID控制数值***************************************************
  120. //**************将速度参数加载至PWM模块*************************************************        
  121.         //速度参数控制,防止超过PWM参数范围0-1000
  122.         if(speed1>1000)speed1=1000;else if(speed1<0)speed1=0;PWM1=(speed1);                // 5
  123.         if(speed2>1000)speed2=1000;else if(speed2<0)speed2=0;PWM2=(speed2);                // 3
  124.         if(speed3>1000)speed3=1000;else if(speed3<0)speed3=0;PWM3=(speed3);                // 4
  125.         if(speed4>1000)speed4=1000;else if(speed4<0)speed4=0;PWM4=(speed4);                // 2   

  126.         PWM(1000-PWM1,1000-PWM2,1000-PWM3,1000-PWM4);
  127. }
  128.          
  129. //--------------------------------------------------//
  130. //  时间延时 函数
  131. //--------------------------------------------------//
  132. void Delay(unsigned int x)
  133. {
  134.         unsigned int i,j;
  135.     for(i=0;i<x;i++)
  136.     for(j=0;j<250;j++);
  137. }
  138. //--------------------------------------------------//
  139. //  定时器0 初始化函数 V2.0
  140. //--------------------------------------------------//


  141. void Timer0Init(void)        //10毫秒@24.000MHz
  142. {
  143.         TR0 = 0;
  144.         AUXR &= 0x7F;        //定时器时钟12T模式
  145.         TMOD &= 0xF0;        //设置定时器模式
  146.         IE  = 0x82;
  147.         TL0 = 0xE0;                //设置定时初值
  148.         TH0 = 0xB1;                //设置定时初值
  149.         TF0 = 0;                //清除TF0标志
  150.         TR0 = 1;                //定时器0开始计时

  151. }

  152. //--------------------------------------------------//
  153. //  上位机串口 初始化函数 V2.0
  154. //  波特率115200,24MHZ
  155. //--------------------------------------------------//

  156. void Usart_Init()  //波特率115200,24MHZ
  157. {
  158.     SCON = 0x50;        
  159.         AUXR |= 0x40;               
  160.         AUXR &= 0xFE;               
  161.         TMOD &= 0x0F;        
  162.         TL1 = 0xcc;               
  163.         TH1 = 0xFF;               
  164.         ET1 = 0;               
  165.         TR1 = 1;        
  166. }

  167. void SendData(unsigned char dat)
  168. {
  169.     while (busy);            
  170.      busy = 1;
  171.     SBUF = dat;               
  172. }
  173. void Send(int Ax,int Ay,int Az,int Gx,int Gy,int Gz)
  174. {
  175.         unsigned char sum=0;
  176.         ES = 1;  
  177.         SendData(0xAA);   
  178.         SendData(0xAA);   
  179.         SendData(0x02);   
  180.         SendData(12);     
  181.         SendData(Ax>>8);     
  182.         SendData(Ax);  
  183.         SendData(Ay>>8);
  184.         SendData(Ay);
  185.         SendData(Az);
  186.         SendData(Az>>8);
  187.         SendData(Gx);
  188.         SendData(Gx>>8);
  189.         SendData(Gy);
  190.         SendData(Gy>>8);
  191.         SendData(Gz);
  192.         SendData(Gz>>8);
  193.         sum+=0xAA;sum+=0xAA;sum+=0x02;sum+=12;
  194.         sum+=Ax>>8;sum+=Ax;sum+=Ay>>8;sum+=Ay;sum+=Az>>8;sum+=Az;
  195.         sum+=Gx>>8;sum+=Gx;sum+=Gy>>8;sum+=Gy;sum+=Gz>>8;sum+=Gz;
  196.         SendData(sum);  
  197.         ES = 0;   
  198. }


  199. void mode1()
  200. {        
  201.         A1=0;
  202.         A2=0;
  203. }

  204. void mode2()
  205. {        
  206.         A1=(atan(R*cos(PI/180*Angle)/0.75))* 57.2957795f;//根据摆幅算出角度A         0.75m摆长
  207.         A2=(atan(R*sin(PI/180*Angle)/0.75))* 57.2957795f;//根据摆幅算出角度A

  208.         /*if(0==key3)
  209.         {
  210.                 Delay(10);
  211.                 if(key3==0) Angle+=15;
  212.                 if(Angle>=360) Angle=0;
  213.                 while(!key1);
  214.         }
  215.         if(key4==0)
  216.         {
  217.                 Delay(10);
  218.                 if(key4==0) Angle-=15;
  219.                 if(Angle<=-360) Angle=0;
  220.                 while(!key4);
  221.         }*/
  222. }

  223. void mode3()
  224. {        
  225.         A1=(atan(R*cos(PI/180*Angle)/0.75))* 57.2957795f;//根据摆幅算出角度A         0.75m摆长
  226.         /*if(key3==0)
  227.         {
  228.                 Delay(10);
  229.                 if(key3==0) flag=~flag;
  230.                 while(!key3);
  231.         }*/
  232.         if(!flag)  A2=A1;
  233.         else      A2=0-A1;
  234. }

  235. void mode4()
  236. {        
  237.         A1=(atan(R*cos(PI/180*Angle)/0.75))* 57.2957795f;//根据摆幅算出角度A         0.75m摆长
  238.         A2=A1/2;
  239. }

  240. //--------------------------------------------------//
  241. //  程序 主函数
  242. //--------------------------------------------------//
  243. void main(void)
  244. {
  245.         PWMGO();                //初始化PWM
  246.         Usart_Init();//串口初始化
  247.         Delay(10);    // 延时 100
  248.         InitMPU6050();        //初始化MPU-6050
  249.         Delay(100);    // 延时 100
  250.         Timer0Init();        //初始化定时器        
  251.         EA = 1;
  252.         while(1)
  253.         {
  254.                 Send(ich1,ich2,ich3,ich4,ich5,ich6);  //串口发送数据                                
  255.                 Delay(1);
  256.                 /*if(key1==0)
  257. ……………………

  258. …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码

所有资料51hei提供下载:
风力摆杆.zip (95.8 KB, 下载次数: 42)


评分

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

查看全部评分

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

使用道具 举报

沙发
ID:1 发表于 2017-9-6 17:01 | 只看该作者
MPU-6050.C
  1. //========================================================================
  2. //        城建学院电子实验室
  3. //        修改日期2017.07.30
  4. //        版本V1.0
  5. //========================================================================
  6. //特别声明:此程序
  7. //         
  8. //
  9. //
  10. //                                 MCU工作频率:24MHz
  11. //=========================================================================
  12. #include <STC15F2K60S2.h>        //STC15F2K60S2 STC15系列通用头文件
  13. #include <intrins.h>
  14. #include <MPU6050.H>

  15. sbit    SCL=P3^5;                        //IIC时钟引脚定义
  16. sbit    SDA=P3^4;                        //IIC数据引脚定义

  17. typedef unsigned char uchar;
  18. typedef unsigned char uint;       
  19. void  InitMPU6050();                //初始化MPU6050
  20. void  Delay2us();
  21. void  I2C_Start();
  22. void  I2C_Stop();
  23. bit   I2C_RecvACK();
  24. void  I2C_SendByte(uchar dat);
  25. uchar I2C_RecvByte();
  26. void  I2C_ReadPage();
  27. void  I2C_WritePage();
  28. uchar Single_ReadI2C(uchar REG_Address);                                        //读取I2C数据
  29. void  Single_WriteI2C(uchar REG_Address,uchar REG_data);        //向I2C写入数据
  30. //I^C时序中延时设置,具体参见各芯片的数据手册  6050推荐最小1.3us 但是会出问题,这里延时实际1.9us左右
  31. void Delay2us()       
  32. {
  33.         unsigned char i;
  34.         i = 11;
  35.         while (--i);
  36. }
  37. //**************************************
  38. //I2C起始信号
  39. //**************************************
  40. void I2C_Start()
  41. {
  42.     SDA = 1;                    //拉高数据线
  43.     SCL = 1;                    //拉高时钟线
  44.     Delay2us();                 //延时
  45.     SDA = 0;                    //产生下降沿
  46.     Delay2us();                 //延时
  47.     SCL = 0;                    //拉低时钟线
  48. }
  49. //**************************************
  50. //I2C停止信号
  51. //**************************************
  52. void I2C_Stop()
  53. {
  54.     SDA = 0;                    //拉低数据线
  55.     SCL = 1;                    //拉高时钟线
  56.     Delay2us();                 //延时
  57.     SDA = 1;                    //产生上升沿
  58.     Delay2us();                 //延时
  59. }
  60. //**************************************
  61. //I2C接收应答信号
  62. //**************************************
  63. bit I2C_RecvACK()
  64. {
  65.     SCL = 1;                    //拉高时钟线
  66.     Delay2us();                 //延时
  67.     CY = SDA;                   //读应答信号
  68.     SCL = 0;                    //拉低时钟线
  69.     Delay2us();                 //延时
  70.     return CY;
  71. }
  72. //**************************************
  73. //向I2C总线发送一个字节数据
  74. //**************************************
  75. void I2C_SendByte(uchar dat)
  76. {
  77.     uchar i;
  78.     for (i=0; i<8; i++)         //8位计数器
  79.     {
  80.         dat <<= 1;              //移出数据的最高位
  81.         SDA = CY;               //送数据口
  82.         SCL = 1;                //拉高时钟线
  83.         Delay2us();             //延时
  84.         SCL = 0;                //拉低时钟线
  85.         Delay2us();             //延时
  86.     }
  87.     I2C_RecvACK();
  88. }
  89. //**************************************
  90. //从I2C总线接收一个字节数据
  91. //**************************************
  92. uchar I2C_RecvByte()
  93. {
  94.     uchar i;
  95.     uchar dat = 0;
  96.     SDA = 1;                    //使能内部上拉,准备读取数据,
  97.     for (i=0; i<8; i++)         //8位计数器
  98.     {
  99.         dat <<= 1;
  100.         SCL = 1;                //拉高时钟线
  101.         Delay2us();             //延时
  102.         dat |= SDA;             //读数据
  103.         SCL = 0;                //拉低时钟线
  104.         Delay2us();             //延时
  105.     }
  106.     return dat;
  107. }
  108. //**************************************
  109. //向I2C设备写入一个字节数据
  110. //**************************************
  111. void Single_WriteI2C(uchar REG_Address,uchar REG_data)
  112. {
  113.     I2C_Start();                  //起始信号
  114.     I2C_SendByte(SlaveAddress);   //发送设备地址+写信号
  115.     I2C_SendByte(REG_Address);    //内部寄存器地址,
  116.     I2C_SendByte(REG_data);       //内部寄存器数据,
  117.     I2C_Stop();                   //发送停止信号
  118. }
  119. //**************************************
  120. //从I2C设备读取一个字节数据
  121. //**************************************
  122. uchar Single_ReadI2C(uchar REG_Address)
  123. {
  124.         uchar REG_data;
  125.         I2C_Start();                   //起始信号
  126.         I2C_SendByte(SlaveAddress);    //发送设备地址+写信号
  127.         I2C_SendByte(REG_Address);     //发送存储单元地址,从0开始
  128.         I2C_Start();                   //起始信号
  129.         I2C_SendByte(SlaveAddress+1);  //发送设备地址+读信号
  130.         REG_data=I2C_RecvByte();       //读出寄存器数据
  131.        
  132.         SDA = 1;                    //写应答信号
  133.         SCL = 1;                    //拉高时钟线
  134.         Delay2us();                 //延时
  135.         SCL = 0;                    //拉低时钟线
  136.         Delay2us();                 //延时
  137.        
  138.         I2C_Stop();                    //停止信号
  139.         return REG_data;
  140. }

  141. //**************************************
  142. //初始化MPU6050
  143. //**************************************
  144. void InitMPU6050()
  145. {
  146.         Single_WriteI2C(PWR_MGMT_1, 0x00);        //解除休眠状态
  147.         Single_WriteI2C(SMPLRT_DIV, 0x07);  //陀螺仪125hz
  148.         Single_WriteI2C(CONFIG, 0x04);      //21HZ滤波 延时A8.5ms G8.3ms  此处取值应相当注意,延时与系统周期相近为宜
  149.         Single_WriteI2C(GYRO_CONFIG, 0x08); //陀螺仪500度/S 65.5LSB/g
  150.         Single_WriteI2C(ACCEL_CONFIG, 0x08);//加速度+-4g  8192LSB/g
  151. }
  152. //**************************************
  153. //合成数据
  154. //**************************************
  155. int GetData(uchar REG_Address)
  156. {
  157.         char H,L;
  158.         H=Single_ReadI2C(REG_Address);
  159.         L=Single_ReadI2C(REG_Address+1);
  160.         return (H<<8)+L;   //合成数据
  161. }

  162.        
复制代码
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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