找回密码
 立即注册

QQ登录

只需一步,快速开始

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

龙邱自平衡车清华方案自由滑行版(直立行走)源码

[复制链接]
跳转到指定楼层
楼主
实物图:

平衡车单片机源程序如下:
  1. /*
  2. **********************************************************
  3. 飞思卡尔智能车程序  直立行走例程
  4. 北京龙丘智能科技      
  5. Designed by longqiu
  6. E-mail:chiusir@yahoo.cn
  7. 软件版本:V1.2
  8. ------------------------------------
  9. Code Warrior 5.1
  10. Target : MC9S12XS128
  11. Crystal: 16.000Mhz
  12. busclock:40.000MHz
  13. pllclock:80.000MHz
  14. ------------------------------------  
  15. 程序使用说明:  
  16. 该工程里写出电磁组直立行走的参考方案,通过程序可以实现小车自由滑行。
  17. ==========================================================   
  18. 陀螺仪模块电路说明:   
  19. 角度计算采用清华硬件电路,详见40.pdf(电磁组直立行车参考设计方案20.pdf)
  20. 第54页,图3-23.一个运算放大器实现角度计算   
  21. ==========================================================
  22. 接线说明
  23. 清华版陀螺仪放置的时候,记得ENC-03在下,加速度在上
  24. 放置方向跟电机的接线也有关系的。  
  25. -----------------------------------------
  26. 单片机  | 龙邱陀螺仪模块 |
  27. --------+----------------+---------------
  28. AD0     |  gyro角速度    |
  29. AD1     |  ang角度       |
  30. =========================================
  31. 单片机  |  电机驱动模块  |  车模电机
  32. --------+----------------+---------------
  33. PP7     |  IN4     OUT1  |  右边电机正
  34. PB1     |  IN3     OUT2  |  右边电机负
  35. PB0     |  IN2     OUT3  |  左边电机正
  36. PP3     |  IN1     OUT4  |  左边电机负   
  37. 单片机5V|  Vmcu          |
  38. ===========================================================

  39. 调整步骤:
  40. 1.下载程序到单片机,
  41. 2.进入在线调试状态,
  42. 3.把车竖直立起来达到平衡状态,在线查看寄存器数值
  43.    根据平衡状态下的ANG,确定ANG_center数值
  44.    根据平衡状态下的GYRO,确定GYRO_center数值
  45. 4.中心数值确定后,再调整PD参数
  46.     P系数相当于倒立摆的回复力。这个参数应该大于重力加速度的等效数值车模才能够保持直立。
  47.     随着该参数逐步增大,车模开始能够保持直立。进一步增大该参数会引起车模震荡。
  48.     D系数相当于倒立摆的阻尼力。该参数可以有效抑制车模的的震荡。当该参数过大的时候,车模开始抖动。

  49.     D系数,先令D=0,然后逐步增加P,直到车模发生震荡,再增加D消除震荡,直到车模开始抖动;
  50.     然后增加P,消除抖动;
  51. 5.反复几次后就可以找到适当的P,D。
  52. 6.小车基本平衡后用户可以根据需要添加速度控制和寻线算法,比赛的重点就在这里,各尽其能!

  53. ==========================================================                                                                        

  54. ***********************************************************
  55. */
  56. #include <hidef.h>         
  57. #include "derivative.h"   

  58. #define PWM_DIR0  PORTB_PB0   //电机方向控制
  59. #define PWM_DIR1  PORTB_PB1   //电机方向控制

  60. word AD_CAIJI[2]={0,0};         //采集的AD数值临时存放数组
  61. word AD_QIUHE[2]={0,0};         //求和临时存放数组
  62. word AD_JUNZHI[2]={0,0};        //平均值
  63. volatile byte PIT_CNT=0;        //中断计数
  64. volatile int  ANG=0;            //角度,前倾变大,后倾变小,平衡时候ANG_center =
  65. volatile int  GYRO=0;           //角速度,前倾变小,后倾变大,静止时候为GYRO_center=?

  66. volatile int  PID1_P=15;         //P系数,pwm3   
  67. volatile int  PID1_D=6;          //D系数,pwm3
  68. volatile int  PID2_P=15;         //P系数,pwm7
  69. volatile int  PID2_D=6;          //D系数,pwm7
  70. volatile int  ANG_center =319;  //AD的初始值,每个模块数值都不一样,跟换模块需要重新确定该值
  71. volatile int  GYRO_center=367;  //角速度初始值,电机不动时候静止状态下采集的数值
  72. volatile int  AD_number=20;     //求和数量
  73. volatile word DTY1=0;            //临时变量
  74. volatile word DTY2=0;            //临时变量
  75. volatile word DTYMAX=245;       //PWM占空比最大值

  76. #define FDOWN 253               //前向倒下时的角度数值
  77. #define BDOWN 190               //后向倒下

  78. void Delay_us(word x)
  79. {
  80.   byte i = 0,j = 0;
  81.         while(x--)
  82.         {
  83.           for(i=0;i<20;i++)
  84.             for(j=0;j<2;j++);         
  85.         }
  86.         return;
  87. }
  88. void Delay_ms(word x)
  89. {
  90.   byte i = 0,j = 0;
  91.         while(x--)
  92.         {
  93.           for(i=0;i<200;i++)
  94.             for(j=0;j<200;j++);         
  95.         }
  96.         return;           
  97. }

  98. /****************************初始化设备**************************************/
  99. void fAD_Init(void)
  100. {
  101.     ATD0CTL1=0b00100000;//   10 位精度
  102.     ATD0CTL2=0b01000000;//   禁止外部触发,标志位快速清零,中断禁止
  103.     ATD0CTL3=0b10100000;/*   7;右对齐无符号;
  104.                              6~3:转换序列长度为4;
  105.                              No FIFO模式,Freeze模式下继续转换?  */
  106.     ATD0CTL4=0b00000111;//   4AD采样周期,ATDClock=[BusClock*0.5]/[PRS+1]  ; PRS=15, divider=32 ?
  107.     ATD0CTL5=0b00110000;//   特殊通道禁止,多通道采样,扫描模式连续采样,开始为 AN0
  108.     ATD0DIEN=0b00000000;//   禁止数字输入   
  109.     return;
  110. }
  111. //-----PWM初始化程序------//
  112. void fPWM_Init(void)
  113. {
  114.     PWME=0x00;        /* 禁止PWM输出*/
  115.     PWMCTL=0x00;      //通道不级联
  116.     PWMCAE=0X00;      //0左对齐 1中心对齐
  117.     PWMPRCLK=0X11;    //2分频
  118.     PWMCLK=0XFF;      /*时钟选择寄存器,  0选择ClockX 1选择ClockSX.
  119.                       通道0,1,4,5用ClockA或ClockSA,通道2,3,6,7用ClockB或ClockSB   
  120.                       设置后,0、1用ClockA,4、5用ClockSA,2、3用ClockB,6、7用ClockSB   */
  121.     PWMSCLA=50;       //ClockSA=ClockA/(2*PWMSCLA)=20000k/(2*50)=200KHZ
  122.     PWMSCLB=5;        //ClockSB=ClockA/(2*PWMSCLB)=20000k/(2*5)=2MHZ
  123.     PWMPOL=0X00;      //输出极性选择 0起始为低电平 1起始为高电平
  124.       
  125.     PWMPER1=250;      //200KHZ/250=800HZ  
  126.     PWMDTY1=100;      /*左对齐,起始输出为高电平时,占空比=(PWMDTY3+1)/(PWMPER0+1) */  
  127.   
  128.     PWMPER3=250;      //2M/250=8KHZ                             
  129.     PWMDTY3=0;        /*左对齐,起始输出为高电平时,占空比=(PWMDTY3+1)/(PWMPER0+1) */   
  130.     PWMPER7=250;                                   
  131.     PWMDTY7=0;      

  132.     PWME_PWME1=0;     //启动PWM输出
  133.     PWME_PWME3=1;
  134.     PWME_PWME7=1;  
  135.     return;
  136. }

  137. void SetBusCLK_40M(void)
  138. {   
  139.     CLKSEL=0X00;                                //disengage PLL to system
  140.     PLLCTL_PLLON=1;                        //turn on PLL
  141.     SYNR =0xc0 | 0x04;                        
  142.     REFDV=0x80 | 0x01;
  143.     POSTDIV=0x00;       //pllclock=2*osc*(1+SYNR)/(1+REFDV)=80MHz;
  144.     _asm(nop);          //BUS CLOCK=40M
  145.     _asm(nop);
  146.     while(!(CRGFLG_LOCK==1));          //when pll is steady ,then use it;
  147.     CLKSEL_PLLSEL =1;                        //engage PLL to system;
  148. }
  149. void fDEV_Init()
  150. {        
  151.           SetBusCLK_40M();
  152.           fAD_Init();
  153.     fPWM_Init();  
  154.     return;
  155. }  

  156. /***************     定时器函数1ms     *****/   
  157. void fPIT_Init(void)   //定时中断初始化函数 1MS定时中断设置
  158. {
  159.     PITCFLMT_PITE=0; //定时中断通道关     
  160.     PITCE_PCE0=1;    //定时器通道 0使能  定时1ms用
  161.     PITMUX_PMUX0=1;  //定时器通道 0选择8位计数器1
  162.     PITMTLD1=40-1;   //8位计数器0初值设定。40分频,在 40MHzBusClock下,为 1MHz。即 1us.
  163.     PITLD0=1000-1;   //16位计数器初值设定。1000*1us=1ms
  164.     PITINTE_PINTE0=1;//开中断,定时器中断通道 0中断使能   
  165.     PITCFLMT_PITE=1; //定时器通道使能
  166.     return;
  167. }

  168. void fAD_CAIJI(unsigned int *AD_val)    //AD采集两个通道
  169. {
  170.           while(!ATD0STAT2_CCF0);//0通道转换完成前等待,采集角速度
  171.           *AD_val=ATD0DR0;
  172.           AD_val++;
  173.           while(!ATD0STAT2_CCF1);//1通道转换完成前等待,采集角度
  174.           *AD_val=ATD0DR1;           
  175.           return;
  176. }

  177. void fAD_QIUHE(void)
  178. {
  179.     word i;
  180.    
  181.    
  182.     for(i=0;i<AD_number;i++)
  183.       {
  184.         fAD_CAIJI(AD_CAIJI);                                            
  185.         AD_QIUHE[0]+=AD_CAIJI[0];     //获取AD0通道值的20次和
  186.         AD_QIUHE[1]+=AD_CAIJI[1];     //获取AD1通道值的20次和
  187.       }
  188.     return;   
  189. }   

  190. void fAD_QIUJUNZHI()                  //求平均值
  191. {
  192.     AD_JUNZHI[0]=(word)AD_QIUHE[0]/AD_number;
  193.     AD_JUNZHI[1]=(word)AD_QIUHE[1]/AD_number;
  194.     AD_QIUHE[0]=0;                     
  195.     AD_QIUHE[1]=0;
  196.     return;   
  197. }
  198.                                                      
  199. void fPWM_KONGZHI(void)               //电机控制
  200. {   
  201.     GYRO=AD_JUNZHI[0];                //求得角速度                                       
  202.     ANG =AD_JUNZHI[1];                //求得角度
  203.     /***********************正转****************/
  204.     //角度,前倾变大,后倾变小,平衡时候ANG_center
  205.     /*
  206.     //摔倒处理
  207.     if ((ANG > FDOWN)|| (ANG < BDOWN) )
  208.     {
  209.         PWM_DIR0=1;            
  210.         PWM_DIR1=1;
  211.         PWMDTY7=PWMDTY3=0;
  212.         PWMPOL=0X00;
  213.         return;
  214.     } */
  215.     if (ANG > ANG_center)            
  216.     {   //   fAD_QIUJUNZHI();            
  217.         DTY1=((ANG - ANG_center ) * PID1_P + (GYRO_center-GYRO) / PID1_D);
  218.         DTY2=((ANG - ANG_center ) * PID2_P + (GYRO_center-GYRO) / PID2_D);     
  219.         if(DTY1>=DTYMAX) DTY1=DTYMAX;
  220.         if(DTY2>=DTYMAX) DTY2=DTYMAX;  
  221.         PWM_DIR0=1;            
  222.         PWM_DIR1=1;
  223.         PWMDTY3=(byte)DTY1;
  224.         PWMDTY7=(byte)DTY2;
  225.         
  226.         PWMPOL=0X00;      //输出极性选择 0起始为低电平 1起始为高电平        
  227.     }   
  228.     //Delay_us(5);        
  229.     /**********************反转***************/
  230.     else if (ANG<ANG_center)              
  231.     {
  232.         DTY1=(( ANG_center - ANG ) * PID1_P + (GYRO - GYRO_center) / PID1_D );
  233.         DTY2=(( ANG_center - ANG ) * PID2_P + (GYRO - GYRO_center) / PID2_D );                        
  234.         if(DTY1>=DTYMAX) DTY1=DTYMAX;   
  235.         if(DTY2>=DTYMAX) DTY2=DTYMAX;         
  236.         PWM_DIR0=0;
  237.         PWM_DIR1=0;
  238.         PWMDTY3=(byte)DTY1;
  239.         PWMDTY7=(byte)DTY2;
  240.                PWMPOL=0Xff;               
  241.     }
  242.     return;   
  243. }

  244. void main(void)
  245. {
  246.     byte key=0;
  247.    
  248.     DDRA=0xFF;
  249.     PORTA=0x00;
  250.     DDRB=0XFF;
  251.     PORTB=0X00;  
  252.     DDRE=0;
  253.     fDEV_Init();
  254.     key=PORTE;
  255.     PWME_PWME1=1;     //启动PWM输出
  256.     //while(key==PORTE){//按下E口任意按键,退出自标定角度的初始值,蜂鸣器停止响
  257.         //fAD_QIUJUNZHI();      
  258.         //ANG_center=AD_JUNZHI[1]; //求得角度初始值
  259.         Delay_ms(5);
  260.     //}
  261.     PWME_PWME1=0;     //关闭PWM输出
  262.     fPIT_Init();
  263.     EnableInterrupts;                     
  264.     for(;;)
  265.     {
  266.    
  267.     }
  268. }   

  269. #pragma CODE_SEG __NEAR_SEG NON_BANKED
  270. //1ms中断
  271. void interrupt 66 PIT0_ISR(void)
  272. {
  273.     PITTF_PTF0=1;           //清中断标志位
  274.     PIT_CNT++;
  275.    
  276.     if(PIT_CNT==1)
  277.     {      
  278.        fAD_QIUHE() ;        //取20次AD输入的和        
  279.     }
  280.     else if(PIT_CNT==2)
  281.        fAD_QIUJUNZHI();     //20次AD输入的平均值
  282.    
  283.     else if(PIT_CNT==3)
  284.       //ANGCulate();        //PD调节
  285.        fPWM_KONGZHI();      //电机pwm输出
  286.     //else if(PIT_CNT==4)
  287.       // ANGControl();      //直立控制
  288. ……………………

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

所有资料51hei提供下载:

龙邱自平衡车清华方案自由滑行版.rar (215.32 KB, 下载次数: 54)


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

使用道具 举报

沙发
ID:417080 发表于 2019-4-30 00:13 | 只看该作者
大佬,这是用的啥软件啊
回复

使用道具 举报

板凳
ID:737781 发表于 2020-4-27 09:29 | 只看该作者
是龙邱k60的吗
回复

使用道具 举报

地板
ID:712298 发表于 2020-5-4 15:15 | 只看该作者
sadbkj 发表于 2019-4-30 00:13
大佬,这是用的啥软件啊

这是Codewarrior 5.1,应该是基于XS128单片机的
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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