找回密码
 立即注册

QQ登录

只需一步,快速开始

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

分享STM32平衡小车参考程序

[复制链接]
跳转到指定楼层
楼主
ID:184978 发表于 2020-12-24 11:29 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
  1. //MCU:Mega16;晶振:8MHz;
  2. //PWM:4KHz;滤波器频率:100Hz;系统频率:100Hz;10ms;
  3. #include <iom16v.h>
  4. #include <macros.h>
  5. #include <math.h>

  6. //#define checkbit(var,bit)     (var&(0x01<<(bit)))     /*定义查询位函数*/
  7. //#define setbit(var,bit)     (var|=(0x01<<(bit)))     /*定义置位函数*/
  8. //#define clrbit(var,bit)     (var&=(~(0x01<<(bit)))) /*定义清零位函数*/


  9. //-------------------------------------------------------
  10. //输出端口初始化
  11. void PORT_initial(void)
  12. {
  13.         DDRA=0B00000000;
  14.         PINA=0X00;
  15.         PORTA=0X00;
  16.        
  17.         DDRB=0B00000000;
  18.         PINB=0X00;
  19.         PORTB=0X00;
  20.        
  21.         DDRC=0B00010000;
  22.         PINC=0X00;
  23.         PORTC=0X00;
  24.        
  25.         DDRD=0B11110010;
  26.         PIND=0X00;
  27.         PORTD=0X00;
  28. }


  29. //-------------------------------------------------------
  30. //定时器1初始化
  31. void T1_initial(void)                                       
  32. {
  33.         TCCR1A|=(1<<COM1A1)|(1<<WGM10)|(1<<COM1B1);                                //T1:8位快速PWM模式、匹配时清0,TOP时置位
  34.         TCCR1B|=(1<<WGM12)|(1<<CS11);                        //PWM:8分频:8M/8/256=4KHz;
  35. }


  36. //-------------------------------------------------------
  37. //定时器2初始化
  38. void T2_initial(void)                        //T2:计数至OCR2时产生中断
  39. {
  40.         OCR2=0X4E;                        //T2:计数20ms(0X9C)10ms(0X4E)时产生中断;
  41.         TIMSK|=(1<<OCIE2);
  42.         TCCR2|=(1<<WGM21)|(1<<CS22)|(1<<CS21)|(1<<CS20);                        //CTC模式,1024分频
  43. }


  44. //-------------------------------------------------------
  45. //外部中断初始化
  46. void INT_initial(void)
  47. {
  48.         MCUCR|=(1<<ISC01)|(1<<ISC00)|(1<<ISC11)|(1<<ISC10);                        //INT0、INT1上升沿有效
  49.         GICR|=(1<<INT0)|(1<<INT1);                        //外部中断使能
  50. }


  51. //-------------------------------------------------------
  52. //串口初始化;
  53. void USART_initial( void )
  54. {       
  55.         UBRRH = 0X00;
  56.         UBRRL = 51;                //f=8MHz;设置波特率:9600:51;19200:25;
  57.         UCSRB = (1<<RXEN)|(1<<TXEN);                //接收器与发送器使能;
  58.         UCSRC = (1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1);                //设置帧格式: 8 个数据位, 1 个停止位;
  59.        
  60.         UCSRB|=(1<<RXCIE);                //USART接收中断使能
  61. }


  62. //-------------------------------------------------------
  63. //串口发送数据;
  64. void USART_Transmit( unsigned char data )
  65. {
  66.         while ( !( UCSRA & (1<<UDRE)));                //等待发送缓冲器为空;
  67.         UDR = data;                //将数据放入缓冲器,发送数据;
  68. }


  69. //-------------------------------------------------------
  70. //串口接收数据中断,确定数据输出的状态;
  71. #pragma interrupt_handler USART_Receive_Int:12
  72. static char USART_State;
  73. void USART_Receive_Int(void)
  74. {
  75.         USART_State=UDR;//USART_Receive();
  76. }


  77. //-------------------------------------------------------
  78. //计算LH侧轮速:INT0中断;
  79. //-------------------------------------------------------
  80. static int speed_real_LH;
  81. //-------------------------------------------------------
  82. #pragma interrupt_handler SPEEDLHINT_fun:2
  83. void SPEEDLHINT_fun(void)
  84. {
  85.         if (0==(PINB&BIT(0)))
  86.         {
  87.                 speed_real_LH-=1;
  88.         }
  89.         else
  90.         {
  91.                 speed_real_LH+=1;
  92.         }
  93. }


  94. //-------------------------------------------------------
  95. //计算RH侧轮速,:INT1中断;
  96. //同时将轮速信号统一成前进方向了;
  97. //-------------------------------------------------------
  98. static int speed_real_RH;
  99. //-------------------------------------------------------
  100. #pragma interrupt_handler SPEEDRHINT_fun:3
  101. void SPEEDRHINT_fun(void)
  102. {
  103.         if (0==(PINB&BIT(1)))
  104.         {
  105.                 speed_real_RH+=1;
  106.         }
  107.         else
  108.         {
  109.                 speed_real_RH-=1;
  110.         }
  111. }


  112. //-------------------------------------------------------
  113. //ADport采样:10位,采样基准电压Aref
  114. //-------------------------------------------------------
  115. static int AD_data;
  116. //-------------------------------------------------------
  117. int ADport(unsigned char port)
  118. {
  119.         ADMUX=port;
  120.         ADCSRA|=(1<<ADEN)|(1<<ADSC)|(1<<ADPS1)|(1<<ADPS0);                        //采样频率为8分频;
  121.         while(!(ADCSRA&(BIT(ADIF))));
  122.         AD_data=ADCL;
  123.         AD_data+=ADCH*256;
  124.         AD_data-=512;
  125.         return (AD_data);
  126. }


  127. //*
  128. //-------------------------------------------------------
  129. //Kalman滤波,8MHz的处理时间约1.8ms;
  130. //-------------------------------------------------------
  131. static float angle, angle_dot;                 //外部需要引用的变量
  132. //-------------------------------------------------------
  133. static const float Q_angle=0.001, Q_gyro=0.003, R_angle=0.5, dt=0.01;
  134.                         //注意:dt的取值为kalman滤波器采样时间;
  135. static float P[2][2] = {
  136.                                                         { 1, 0 },
  137.                                                         { 0, 1 }
  138.                                                 };
  139.        
  140. static float Pdot[4] ={0,0,0,0};

  141. static const char C_0 = 1;

  142. static float q_bias, angle_err, PCt_0, PCt_1, E, K_0, K_1, t_0, t_1;
  143. //-------------------------------------------------------
  144. void Kalman_Filter(float angle_m,float gyro_m)                        //gyro_m:gyro_measure
  145. {
  146.         angle+=(gyro_m-q_bias) * dt;
  147.        
  148.         Pdot[0]=Q_angle - P[0][1] - P[1][0];
  149.         Pdot[1]=- P[1][1];
  150.         Pdot[2]=- P[1][1];
  151.         Pdot[3]=Q_gyro;
  152.        
  153.         P[0][0] += Pdot[0] * dt;
  154.         P[0][1] += Pdot[1] * dt;
  155.         P[1][0] += Pdot[2] * dt;
  156.         P[1][1] += Pdot[3] * dt;
  157.        
  158.        
  159.         angle_err = angle_m - angle;
  160.        
  161.        
  162.         PCt_0 = C_0 * P[0][0];
  163.         PCt_1 = C_0 * P[1][0];
  164.        
  165.         E = R_angle + C_0 * PCt_0;
  166.        
  167.         K_0 = PCt_0 / E;
  168.         K_1 = PCt_1 / E;
  169.        
  170.         t_0 = PCt_0;
  171.         t_1 = C_0 * P[0][1];

  172.         P[0][0] -= K_0 * t_0;
  173.         P[0][1] -= K_0 * t_1;
  174.         P[1][0] -= K_1 * t_0;
  175.         P[1][1] -= K_1 * t_1;
  176.        
  177.        
  178.         angle        += K_0 * angle_err;
  179.         q_bias        += K_1 * angle_err;
  180.         angle_dot = gyro_m-q_bias;
  181. }
  182. //*/

  183. /*
  184. //-------------------------------------------------------
  185. //互补滤波
  186. //-------------------------------------------------------
  187. static float angle,angle_dot;                 //外部需要引用的变量
  188. //-------------------------------------------------------       
  189. static float bias_cf;
  190. static const float dt=0.01;
  191. //-------------------------------------------------------
  192. void complement_filter(float angle_m_cf,float gyro_m_cf)
  193. {
  194.         bias_cf*=0.998;                        //陀螺仪零飘低通滤波;500次均值;
  195.         bias_cf+=gyro_m_cf*0.002;
  196.         angle_dot=gyro_m_cf-bias_cf;
  197.         angle=(angle+angle_dot*dt)*0.90+angle_m_cf*0.05;       
  198.         //加速度低通滤波;20次均值;按100次每秒计算,低通5Hz;
  199. }
  200. */       




  201. //-------------------------------------------------------
  202. //AD采样;
  203. //以角度表示;
  204. //加速度计:1.2V=1g=90°;满量程:1.3V~3.7V;
  205. //陀螺仪:0.5V~4.5V=-80°~+80°;满量程5V=200°=256=200°;
  206. //-------------------------------------------------------
  207. static float gyro,acceler;
  208. //-------------------------------------------------------
  209. void AD_calculate(void)
  210. {
  211.        
  212.         acceler=ADport(2)+28;                        //角度校正
  213.         gyro=ADport(3);       
  214.        
  215.         acceler*=0.004069;                //系数换算:2.5/(1.2*512);
  216.         acceler=asin(acceler);
  217.         gyro*=0.00341;                        //角速度系数:(3.14/180)* 100/512=0.01364;       
  218.        
  219.         Kalman_Filter(acceler,gyro);
  220.         //complement_filter(acceler,gyro);
  221. }
  222.        


  223. //-------------------------------------------------------
  224. //PWM输出
  225. //-------------------------------------------------------
  226. void PWM_output (int PWM_LH,int PWM_RH)
  227. {
  228.         if (PWM_LH<0)
  229.         {
  230.                 PORTD|=BIT(6);
  231.                 PWM_LH*=-1;
  232.         }
  233.         else
  234.         {
  235.                 PORTD&=~BIT(6);
  236.         }
  237.        
  238.         if (PWM_LH>252)
  239.         {
  240.                 PWM_LH=252;
  241.         }
  242.        
  243.        
  244.         if (PWM_RH<0)
  245.         {
  246.                 PORTD|=BIT(7);
  247.                 PWM_RH*=-1;
  248.         }
  249.         else
  250.         {
  251.                 PORTD&=~BIT(7);
  252.         }
  253.        
  254.         if (PWM_RH>252)
  255.         {
  256.                 PWM_RH=252;
  257.         }
  258.        
  259.                
  260.         OCR1AH=0;
  261.         OCR1AL=PWM_LH;                        //OC1A输出;
  262.        
  263.         OCR1BH=0;
  264.         OCR1BL=PWM_RH;                        //OC1B输出;
  265.        
  266. }




  267. //-------------------------------------------------------
  268. //计算PWM输出值
  269. //车辆直径:76mm; 12*64pulse/rev; 1m=3216pulses;
  270. //-------------------------------------------------------       
  271. //static int speed_diff,speed_diff_all,speed_diff_adjust;
  272. //static float K_speed_P,K_speed_I;
  273. static float K_voltage,K_angle,K_angle_dot,K_position,K_position_dot;
  274. static float K_angle_AD,K_angle_dot_AD,K_position_AD,K_position_dot_AD;
  275. static float position,position_dot;
  276. static float position_dot_filter;
  277. static float PWM;
  278. static int speed_output_LH,speed_output_RH;
  279. static int Turn_Need,Speed_Need;
  280. //-------------------------------------------------------       
  281. void PWM_calculate(void)       
  282. {
  283.         if ( 0==(~PINA&BIT(1)) )        //左转
  284.         {
  285.                 Turn_Need=-40;
  286.         }
  287.         else if ( 0==(~PINB&BIT(2)) )         //右转
  288.         {
  289.                 Turn_Need=40;
  290.         }
  291.         else        //不转
  292.         {
  293.                 Turn_Need=0;
  294.         }
  295.        
  296.         if ( 0==(~PINC&BIT(0)) )        //前进
  297.         {
  298.                 Speed_Need=-2;
  299.         }
  300.         else if ( 0==(~PINC&BIT(1)) )        //后退
  301.         {
  302.                 Speed_Need=2;
  303.         }
  304.         else        //不动
  305.         {
  306.                 Speed_Need=0;
  307.         }
  308.        
  309.         K_angle_AD=ADport(4)*0.007;
  310.         K_angle_dot_AD=ADport(5)*0.007;
  311.         K_position_AD=ADport(6)*0.007;
  312.         K_position_dot_AD=ADport(7)*0.007;

  313.         position_dot=(speed_real_LH+speed_real_RH)*0.5;
  314.        
  315.         position_dot_filter*=0.85;                //车轮速度滤波
  316.         position_dot_filter+=position_dot*0.15;       
  317.        
  318.         position+=position_dot_filter;
  319.         //position+=position_dot;       
  320.         position+=Speed_Need;
  321.        
  322.         if (position<-768)                //防止位置误差过大导致的不稳定
  323.         {
  324.                 position=-768;
  325.         }
  326.         else if  (position>768)
  327.         {
  328.                 position=768;
  329.         }
  330.        
  331.         PWM = K_angle*angle *K_angle_AD + K_angle_dot*angle_dot *K_angle_dot_AD +
  332.                                         K_position*position *K_position_AD + K_position_dot*position_dot_filter *K_position_dot_AD;
  333.        
  334.        
  335.         speed_output_RH = PWM - Turn_Need;
  336.         speed_output_LH = - PWM - Turn_Need ;
  337.        
  338.         /*
  339.         speed_diff=speed_real_RH-speed_real_LH;                        //左右轮速差PI控制;
  340.         speed_diff_all+=speed_diff;
  341.         speed_diff_adjust=(K_speed_P*speed_diff+K_speed_I*speed_diff_all)/2;
  342.         */
  343.                
  344.         PWM_output (speed_output_LH,speed_output_RH);       
  345. }

  346. //-------------------------------------------------------
  347. //定时器2中断处理
  348. //-------------------------------------------------------
  349. static unsigned char temp;
  350. //-------------------------------------------------------
  351. #pragma interrupt_handler T2INT_fun:4
  352. void T2INT_fun(void)                                               
  353. {
  354.         AD_calculate();
  355.        
  356.         PWM_calculate();
  357.        
  358.         if(temp>=4)                        //10ms即中断;每秒计算:100/4=25次;
  359.         {               
  360.                 if (USART_State==0X30)                //ASCII码:0X30代表字符'0'
  361.                 {
  362.                         USART_Transmit(angle*57.3+128);
  363.                         USART_Transmit(angle_dot*57.3+128);
  364.                         USART_Transmit(128);       
  365.                 }
  366.                 else if(USART_State==0X31)                //ASCII码:0X30代表字符'1'
  367.                 {
  368.                         USART_Transmit(speed_output_LH+128);
  369.                         USART_Transmit(speed_output_RH+128);                       
  370.                         USART_Transmit(128);
  371.                 }
  372.                 else if(USART_State==0X32)                //ASCII码:0X30代表字符'2'
  373.                 {
  374.                         USART_Transmit(speed_real_LH+128);
  375.                         USART_Transmit(speed_real_RH+128);
  376.                         USART_Transmit(128);
  377.                 }
  378.                 else if(USART_State==0X33)                //ASCII码:0X30代表字符'3'
  379.                 {
  380.                         USART_Transmit(K_angle+128);
  381.                         USART_Transmit(K_angle_dot+128);
  382.                         USART_Transmit(K_position_dot+128);
  383.                 }                               
  384.                 temp=0;                               
  385.         }
  386.         speed_real_LH=0;
  387.         speed_real_RH=0;       
  388.         temp+=1;       
  389. }



  390. //-------------------------------------------------------
  391. int i,j;
  392. //-------------------------------------------------------
  393. void main(void)
  394. {
  395.         PORT_initial();
  396.         T2_initial();
  397.         INT_initial();
  398.         USART_initial ();
  399.        
  400.         SEI();
  401.        
  402.         K_position=0.8 * 0.209;                //换算系数:(256/10) * (2*pi/(64*12))=0.20944;//256/10:电压换算至PWM,256对应10V;
  403.         K_angle=34 * 25.6;                //换算系数:256/10 =25.6;
  404.         K_position_dot=1.09 * 20.9;                //换算系数:(256/10) * (25*2*pi/(64*12))=20.944;
  405.         K_angle_dot=2 * 25.6;                //换算系数:256/10 =25.6;
  406.        
  407.         for (i=1;i<=500;i++)                //延时启动PWM,等待卡尔曼滤波器稳定
  408.         {
  409.                 for (j=1;j<=300;j++);;
  410.                
  411.         }
  412.         T1_initial();
  413.                
  414.         while(1)
  415.         {
  416.                 ;
  417.         }
  418. }
复制代码


ProjectRII.7z

1.35 MB, 下载次数: 9, 下载积分: 黑币 -5

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

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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