本帖最后由 夜的空 于 2016-7-3 12:22 编辑
最近参加了个校园电子设计比赛,是关于平衡板系统的,做完后想跟大家一起分享一下我自己做的,有资料和程序分享,哪里有不好欢迎纠正,图片及作品后续更新。 一、任务 设计并制作一套平衡板系统,其机械结构如图1所示。 电机轴固定在平衡板的中心,控制电机使平衡板能够完成规定角度的转动完成相应的动作。 二、要求 1. 基本要求 (1)在底板与地面平行的条件下,平衡板从竖直位置开始,实现5s内顺时针转动到45°的位置。 (2)在底板与地面平行的条件下,平衡板从竖直位置开始,实现5s内达到水平位置的功能。 (3)在底板与地面平行的条件下,平衡板从竖直位置开始,实现5s内转动到指定角度的功能。(转动角度范围:0°~180°) (4)在底板与地面成45°的条件下,平衡板从竖直位置开始,实现3s内达到水平位置的功能。 2. 发挥部分 (1)在底板与地面平行、平衡板为水平状态的条件下,实现在平衡板末端放上装有一定量水的水瓶(水量尽量多),平衡板在5s内仍然能够保持水平。 (2)实现平衡板初始状态为水平的时候,以底板一端为旋转中心,另一端抬起任意的角度(角度范围:0°~45°)静止3s后,平衡板仍然保持水平,然后在平衡板的任意末端放置水瓶能维持至少10s不滑落。 (3)其他。 程序: /************************************************************************************* * 平衡杆系统 * 传感器使用的是MPU6050,串口方式通信 * 步进电机驱动正转A/ A/B B AB A AB/ B/ A/B/ 4线半步八拍方式 * 步进电机驱动反转A/B/ B/ AB/ A AB B A/B A/ **************************************************************************************/ #include "lcd.h" #include #include #include <time.h> #include #include //***it I01 = P1^2; //步进电机的驱动引脚,将 //***it I11 = P1^3; //***it I02 = P1^4; //***it I12 = P1^5; ***it beep=P3^1; float PP=1,II=0,DD=0; struct p_i_d{ int error2;//当前误差 float pre_error;//前一次误差 float dir_angle;//目标角度 }PID; int pid_value,angle_speed,pid_value1; float angle,error1;
int code a[8]={0x20,0x30,0x10,0x18,0x08,0x0c,0x04,0x24}; char jiaodu[4]={0,0,0,0}; uchar code table0[]={"angle: !"}; uchar code table1[]="input angle:!"; uchar code table2[]="angle:!"; int count=0,flag=0,jiaodu_date,error=0,k=0,lcd_count,angle_count; int i,t,count_cmp,l=1,KeyValue1=0; unsigned char Re_buf[11],ucStrw[6],ucStra[6],counter=0,time1_flag,quit; unsigned char ucStrAngle[6]; char key_count=0,beep_count; void input_angle(void); void balance(void); void output_angle(int error_value);
/*******************主函数**************************/ void main() { uchar clear=0,key; PID.dir_angle=90; lcd_init(); P2M0=0xff; P2M1=0x00; //将P2设置为推挽输出 P0M0=0xff; P0M1=0x00; lcdsel = 1; time_init(); time1_init(); print_start(); while(1) { key=key_find(); /****************输入0~180度的角度***********************/ while(key==12) { if(clear==0||quit==14) { lcd_com(0x01); clear=1; } if(quit==14) { lcd_com(0x01); delayms(10); print_start(); break; } input_angle();// balance(); // }quit=0; clear=0; }
} /****************木板的平衡函数***********************/ void balance(void) { char m; lcd_com(0x80); while(table2[m] != '!') { lcd_dat(table2[m]); m++; } print(90-angle); /*******************************************/ angle = ((short)(ucStrAngle[1]<<8| ucStrAngle[0]))/32768.0*180;//传感器读取角度 PID.error2 = angle - PID.dir_angle;//计算当前误差 if(PID.error2<0) { error1=-PID.error2; }else error1=PID.error2; pid_value = PP*error1/0.9;//计算并脉冲个数并输出给电机 if(pid_value==180)pid_value=pid_value-3; if(angle_count==1){output_angle(pid_value);angle_count=0;} delayms(5); } /**************************角度输入函数************************************/ void input_angle(void) { int m=0; lcd_com(0x80+40); // while(table1[m] != '!') { lcd_dat(table1[m]); m++; } KeyValue1=key_find(); if(KeyValue1!=17)key_count++;//按键按下的次数 if(key_count==1&&KeyValue1!=17) {if(l==1){lcd_com(0x80+0x4d);lcd_dat('0'+KeyValue1);l++;} jiaodu[1]=KeyValue1*100; } if(key_count==2&&KeyValue1!=17) {if(l==2){lcd_com(0x80+0x4e);lcd_dat('0'+KeyValue1);l++;} jiaodu[2]=KeyValue1*10; } if(key_count==3&&KeyValue1!=17) {if(l==3){lcd_com(0x80+0x4f);lcd_dat('0'+KeyValue1);l++;} jiaodu[3]=KeyValue1; } if(KeyValue1==15||KeyValue1==14)//判断按键是否按下 {ET0 = 1; ES=0;//关闭串口中断,不接受数据 l=1; key_count=0; if(KeyValue1!=14)PID.dir_angle=90-(jiaodu[1]+jiaodu[2]+jiaodu[3]); if(KeyValue1==14)quit=14; lcd_com(0x01); } } /**************************步进电机脉冲输出函数************************************/ void output_angle(int error_value) { while(1) { ES=0; if(error_value==0){break;} if(time1_flag==1)//定时器控制步进电机的速度 { if(error_value==0){break;} time1_flag=0; if(PID.error2<0)// { switch(i) { case 0: P1=a[0];i=1;break; case 1: P1=a[1];i=2;break; case 2: P1=a[2];i=3;break; case 3: P1=a[3];i=4;break; case 4: P1=a[4];i=5;break; case 5: P1=a[5];i=6;break; case 6: P1=a[6];i=7;break; case 7: P1=a[7];i=0;break; } }else{ switch(i) { case 0: P1=a[6];i=7;break; case 1: P1=a[7];i=0;break; case 2: P1=a[0];i=1;break; case 3: P1=a[1];i=2;break; case 4: P1=a[2];i=3;break; case 5: P1=a[3];i=4;break; case 6: P1=a[4];i=5;break; case 7: P1=a[5];i=6;break; } } k++; if(k==error_value) { ES=1;break; } } } k=0; error=0; ES=1; } ////////////////////////////////////////////////////// void Timer0() interrupt 1 { char g=0; TH0 = 0x0b1; //20ms定时,用于控制步进电机的速度 TL0 = 0x068; time1_flag=1; } /******************MPU6050的数据读取***********************/ void ser() interrupt 4 { angle_count=1; if (RI) { RI=0; Re_buf[counter]=SBUF; if(counter==0&&Re_buf[0]!=0x55) { return;} //判断数据头是不是0x55
counter++; if(counter==11) // { counter=0; // switch(Re_buf [1]) { case 0x51://¼ÓËٶȰü ucStra[0]=Re_buf[2]; ucStra[1]=Re_buf[3]; ucStra[2]=Re_buf[4]; ucStra[3]=Re_buf[5]; ucStra[4]=Re_buf[6]; ucStra[5]=Re_buf[7]; break;
case 0x52: //½ÇËٶȰü ucStrw[0]=Re_buf[2]; ucStrw[1]=Re_buf[3]; ucStrw[2]=Re_buf[4]; ucStrw[3]=Re_buf[5]; ucStrw[4]=Re_buf[6]; ucStrw[5]=Re_buf[7]; break; case 0x53: //½Ç¶È°ü ucStrAngle[0]=Re_buf[2]; ucStrAngle[1]=Re_buf[3]; ucStrAngle[2]=Re_buf[4]; ucStrAngle[3]=Re_buf[5]; ucStrAngle[4]=Re_buf[6]; ucStrAngle[5]=Re_buf[7]; break; } } } }
|