自平衡小车-3B 四路PWM控制两个轮前后转动 代码

 

 
代码设计:  目的: 四路PWM控制两个轮前后转动(转速、方向、同步)
 
  基于例子SDK_2.2.1_LPCXpresso54114\boards\lpcxpresso54114\driver_examples\sctimer\simple_pwm修改。
  配置管脚Port 11/2/3/4对于SCTSCT0_OUT4-PWM4SCT0_OUT5-PWM5SCT0_OUT6-PWM6SCT0_OUT7-PWM7
       Port 025/26, 是LED6/7绿灯,亮用于标记两个轮子转动方向。增加到 pin_mux.c
 
  1. #define PORT0_IDX                        0u   /*!< Port index */
  2. #define PORT1_IDX                        1u   /*!< Port index */
  3.  
  4. #define PIN1_IDX                         1u   
  5. #define PIN2_IDX                         2u   
  6. #define PIN3_IDX                         3u   
  7. #define PIN4_IDX                         4u   
  8.  
  9. const uint32_t port1_pin1_config = (
  10.     IOCON_PIO_FUNC3 |                                        /* Pin is configured as SCT0_OUT2 */
  11.     IOCON_PIO_MODE_INACT |                                   /* No addition pin function */
  12.     IOCON_PIO_INV_DI |                                       /* Input function is not inverted */
  13.     IOCON_PIO_DIGITAL_EN |                                   /* Enables digital function */
  14.     IOCON_PIO_INPFILT_OFF |                                  /* Input filter disabled */
  15.     IOCON_PIO_OPENDRAIN_DI                                   /* Open drain is disabled */
  16.   );
  17.   IOCON_PinMuxSet(IOCON, PORT1_IDX, PIN1_IDX, port1_pin1_config); 
  18.   IOCON_PinMuxSet(IOCON, PORT1_IDX, PIN2_IDX, port1_pin1_config);
  19.   IOCON_PinMuxSet(IOCON, PORT1_IDX, PIN3_IDX, port1_pin1_config); 
  20.   IOCON_PinMuxSet(IOCON, PORT1_IDX, PIN4_IDX, port1_pin1_config);
  21.  
  22.   const uint32_t port0_pin25_config = (
  23.     IOCON_FUNC0 |                                        /*IO   Pin is configured as FC4_CTS_SDA_SSEL0 */
  24.           IOCON_GPIO_MODE |                                  /* I2C mode */
  25.     IOCON_MODE_PULLUP |
  26.    // IOCON_PIO_INV_DI |                                       /* Input function is not inverted */
  27.     IOCON_PIO_DIGITAL_EN |                                   /* Enables digital function */
  28.     IOCON_PIO_INPFILT_OFF                                   /* Input filter disabled */
  29.   //  IOCON_PIO_I2CDRIVE_LOW |                                 /* Low drive: 4 mA */
  30.   //  IOCON_PIO_I2CFILTER_EN                                   /* I2C 50 ns glitch filter enabled */
  31.   );
  32.   IOCON_PinMuxSet(IOCON, PORT0_IDX, 25, port0_pin25_config); /* PORT0 PIN25 */
  33.   IOCON_PinMuxSet(IOCON, PORT0_IDX, 26, port0_pin25_config); /* PORT0 PIN26 */
复制代码

 

  主要代码:
  SCT初始化;Port 11/2/3/4SCT0_OUT-PWM4/5/6/7四管脚输出PWM配置:高有效、占空比、基本时钟记数频率、共同循环周期(率48KHz) 以及每个对应的事件(其实就是脉冲发生和周期的记数匹配以产生PWM);最后开始SCT,就有PWM发生了。
注意一个PWM对应一个event标记,它们在改变占空比是要用
  1. sctimer_config_t sctimerInfo;
  2.     sctimer_pwm_signal_param_t pwmParam;
  3.     uint32_t sctimerClock;
  4. ..........
  5.         GPIO->DIR[0] |=  1U << 25;
  6.         GPIO->DIR[0] |=  1U << 26;
  7.  
  8. SCTIMER_GetDefaultConfig(&sctimerInfo);
  9.  
  10.     /* Initialize SCTimer module */
  11.     SCTIMER_Init(SCT0, &sctimerInfo);
  12.  
  13.     /* Configure first PWM with frequency 24kHZ from output 4 5      kSCTIMER_CenterAlignedPwm  kSCTIMER_EdgeAlignedPwm*/
  14.     pwmParam.output = kSCTIMER_Out_4;
  15.     pwmParam.level = kSCTIMER_HighTrue;
  16.     pwmParam.dutyCyclePercent = 40;
  17.     if (SCTIMER_SetupPwm(SCT0, &pwmParam,kSCTIMER_CenterAlignedPwm , 48000U, sctimerClock, &event4) == kStatus_Fail)
  18.     {
  19.         return -1;
  20.     }
  21.         
  22.     pwmParam.output = kSCTIMER_Out_5;
  23.     pwmParam.level = kSCTIMER_HighTrue;
  24.     pwmParam.dutyCyclePercent = 40;
  25.     if (SCTIMER_SetupPwm(SCT0, &pwmParam, kSCTIMER_CenterAlignedPwm, 48000U, sctimerClock, &event5) == kStatus_Fail)
  26.     {
  27.         return -1;
  28.     }
  29.  
  30.    /*  Configure second PWM with different duty cycle but same frequency as before */
  31.     pwmParam.output = kSCTIMER_Out_6;
  32.     pwmParam.level = kSCTIMER_HighTrue;
  33.     pwmParam.dutyCyclePercent = 45;
  34.     if (SCTIMER_SetupPwm(SCT0, &pwmParam, kSCTIMER_CenterAlignedPwm, 48000U, sctimerClock, &event6) == kStatus_Fail)
  35.     {
  36.         return -1;
  37.     }                                                                    
  38.    pwmParam.output = kSCTIMER_Out_7;
  39.     pwmParam.level = kSCTIMER_HighTrue;
  40.     pwmParam.dutyCyclePercent = 45;
  41.     if (SCTIMER_SetupPwm(SCT0, &pwmParam, kSCTIMER_CenterAlignedPwm, 48000U, sctimerClock, &event7) == kStatus_Fail)
  42.     {
  43.         return -1;
  44.     }
  45.                 
  46.     /* Start the timer */
  47.     SCTIMER_StartTimer(SCT0, kSCTIMER_Counter_L);
  48.    
复制代码

 

  另配置使用了一个CTIMER0记数匹配中断,用于定时中断更改占空比以改变电机转动的速度。
 
  1. #define CTIMER CTIMER0                 /* Timer 0 */
  2. #define CTIMER_MAT_OUT kCTIMER_Match_0 
  3.  
  4.    ctimer_config_t config;
  5.     ctimer_match_config_t matchConfig;
  6.      CTIMER_GetDefaultConfig(&config);
  7.  
  8.     CTIMER_Init(CTIMER, &config);
  9.                 
  10.     matchConfig.enableCounterReset =  true;      //mat1 后复位 重记数  控制测量周期
  11.     matchConfig.enableCounterStop = false;//true;//      //mat后不停止
  12.     matchConfig.matchValue = BUS_CLK_FREQ /2000;//200;//0 ;   // BUS_CLK_FREQ/1  即1秒   
  13.     matchConfig.outControl = kCTIMER_Output_NoAction; //无输出关联 
  14.     matchConfig.outPinInitState = false;    // 无效  
  15.     matchConfig.enableInterrupt = true;//       //匹配不中断
  16.     CTIMER_SetupMatch(CTIMER, kCTIMER_Match_1, &matchConfig);   //Timer3 mat1 no out 
  17.  
  18.     CTIMER_RegisterCallBack(CTIMER, &ctimer_callback_table[0], kCTIMER_SingleCallback);//kCTIMER_MultipleCallback);  //kCTIMER_MultipleCallback);  //echo fall intr
  19.                 
  20.     CTIMER_StartTimer(CTIMER);   //开始
  21.  
复制代码
 
中断响应:
定时中断更改占空比以改变电机转动的速度、方向、LED灯同步指示。
1)      占空比以小间隔逐渐线性改变, 以实现较平滑的逐渐加减速和反向,而不是突然的改变。
2)    Port 0的25/26,用分别对应正反转动方向,LED灯亮灭分别对应一个方向的加减速。

 

  1. void ctimer_match1_callback(uint32_t flags)
  2. {
  3.         if(GorB==1)
  4.         {
  5.                 if(GPIO->B[0][25] ==1)
  6.                 {
  7.                                 PRINTF("\r\n int 1 outpu 0.25  0 \r\n");
  8.  
  9.                         SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_6, sp/10+ad, event6);   //  右轮 前进    
  10.                         SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_7, 1, event7);
  11.                         SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_5, sp/10, event5); //  左轮 前进                
  12.                         SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_4, 1, event4);
  13.                         sp +=dsp ;
  14.                         if (sp>upsp)
  15.                                 GPIO->B[0][25] =0;                                      
  16.                 }
  17.                 else
  18.                 {
  19.                                 PRINTF("\r\n int 0 outpu 0.25  1 \r\n");
  20.         /*                SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_4, sp, event4);
  21.                         SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_5, 1, event5); //  左轮 后退
  22.                         
  23.                         SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_6, 1, event6);   //  右轮 后退
  24.                         SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_7, sp, event7);
  25.         */        
  26.                         SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_6, sp/10+ad, event6);   //  右轮 前进  +16
  27.                         SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_7, 1, event7);
  28.                         SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_5, sp/10, event5); //  左轮 前进
  29.                         
  30.                         SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_4, 1, event4);
  31.                         
  32.                         
  33.                         sp -=dsp ;
  34.                         if (sp<lwsp)
  35.                         {
  36.                                 GPIO->B[0][25] =1; 
  37.                                 GorB=0;
  38.                         }
  39.                 }
  40.         }
  41.         else
  42.                 if(GPIO->B[0][26] ==1)
  43.                 {
  44.                                 PRINTF("\r\n int 1 outpu 0.26  0 \r\n");
  45.                         SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_7, sp/10+ad, event7);
  46.                         SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_6, 1, event6);   //  右轮 后退 +16
  47.                         SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_4, sp/10, event4);
  48.                         SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_5, 1, event5); //  左轮 后退
  49.                         
  50.                         sp +=dsp ;
  51.                         if (sp>upsp)
  52.                                 GPIO->B[0][26] =0;
  53.                 }
  54.                 else
  55.                 {
  56.                                 PRINTF("\r\n int 0 outpu 0.26  1 \r\n");
  57.                         SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_7, sp/10+ad, event7);
  58.                         SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_6, 1, event6);   //  右轮 后退 +16
  59.                         SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_4, sp/10, event4);
  60.                         SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_5, 1, event5); //  左轮 后退
  61.                         
  62.                         sp -=dsp ;
  63.                         if (sp<lwsp)
  64.                         {
  65.                                 GPIO->B[0][26] =1; 
  66.                                 GorB=1;
  67.                         }
  68.                 }                
  69.         
  70.         
  71.  
  72. ctimer_callback_t ctimer_callback_table[] =
  73. {
  74.     ctimer_match1_callback,//NULL,
  75.     // ctimer_cap_callback,
  76.     NULL,
  77.     NULL,//ctimer_match1_callback,
  78.     NULL,
  79.           NULL,
  80.     //ctimer_cap_callback,
  81.     NULL,
  82.     NULL,
  83.     NULL
  84. };
复制代码


 

注意事项和问题:
1)   更改占空比实际是在停止和再启SCT之间修改的,四线就这样了4次,应考虑不用库函数代码,在一次停启之间修改四个占空比;
2)   SCT停止时,只是停的是记数器,有可能某管脚只好PWM处于高电位,这下电机会疯狂旋转!
3)   不能使用0和100做占空比,这里用的电机驱动不是用独立的线控制正反转方向,所以正反转动方向控制通过把对应2线之一的占空比设为1实现。
4)   电机通过减速齿轮带动轮子空转,发现旋转阻力不均,不仅占空比与转速不是线性关系,轮子和轴不同角度阻力也不相同(同占空比下转动也不均匀、不太重现)。这还是空转啊,实际岂不是更不均匀了。这个这个我不懂了,可能可能机械转动转动的世界不太理想。也许需要测速反馈控制才能定速控制(这个电机的测速分辨不高,而平衡车是微动,我很怀疑有没用用)。
5)   带动轮子的空转阻力也不小了,占空比20以下不转,30以上才算转,两个轮子阻力还不一样。
6)   看这个头重脚轻的东西,严重怀疑这个能否实现平衡车??
7)   不知道,SCT是否能一个匹配触发多个输出呢?有空再研究吧。
 
现在论坛禁止上传视频文件,只好转为动态gif图吧。
 
 
倒置空转,正反转视频:
我临时使用一个手机电池(7.3V, 3400mAh)经升压模块(已经烧了一个了!)10V供电机驱动。
 
 
 
先悬绳保持,观察正反转视频:(支架用废光盘做的)





系列: