自平衡小车-3B 四路PWM控制两个轮前后转动 代码
代码设计: 目的: 四路PWM控制两个轮前后转动(转速、方向、同步)
基于例子SDK_2.2.1_LPCXpresso54114\boards\lpcxpresso54114\driver_examples\sctimer\simple_pwm修改。
配置管脚:Port 1的1/2/3/4对于SCTSCT0_OUT4-PWM4、SCT0_OUT5-PWM5、SCT0_OUT6-PWM6、SCT0_OUT7-PWM7,
Port 0的25/26, 是LED6/7绿灯,亮用于标记两个轮子转动方向。增加到 pin_mux.c
-
#define PORT0_IDX 0u /*!< Port index */
-
#define PORT1_IDX 1u /*!< Port index */
-
-
#define PIN1_IDX 1u
-
#define PIN2_IDX 2u
-
#define PIN3_IDX 3u
-
#define PIN4_IDX 4u
-
-
const uint32_t port1_pin1_config = (
-
IOCON_PIO_FUNC3 | /* Pin is configured as SCT0_OUT2 */
-
IOCON_PIO_MODE_INACT | /* No addition pin function */
-
IOCON_PIO_INV_DI | /* Input function is not inverted */
-
IOCON_PIO_DIGITAL_EN | /* Enables digital function */
-
IOCON_PIO_INPFILT_OFF | /* Input filter disabled */
-
IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */
-
);
-
IOCON_PinMuxSet(IOCON, PORT1_IDX, PIN1_IDX, port1_pin1_config);
-
IOCON_PinMuxSet(IOCON, PORT1_IDX, PIN2_IDX, port1_pin1_config);
-
IOCON_PinMuxSet(IOCON, PORT1_IDX, PIN3_IDX, port1_pin1_config);
-
IOCON_PinMuxSet(IOCON, PORT1_IDX, PIN4_IDX, port1_pin1_config);
-
-
const uint32_t port0_pin25_config = (
-
IOCON_FUNC0 | /*IO Pin is configured as FC4_CTS_SDA_SSEL0 */
-
IOCON_GPIO_MODE | /* I2C mode */
-
IOCON_MODE_PULLUP |
-
// IOCON_PIO_INV_DI | /* Input function is not inverted */
-
IOCON_PIO_DIGITAL_EN | /* Enables digital function */
-
IOCON_PIO_INPFILT_OFF /* Input filter disabled */
-
// IOCON_PIO_I2CDRIVE_LOW | /* Low drive: 4 mA */
-
// IOCON_PIO_I2CFILTER_EN /* I2C 50 ns glitch filter enabled */
-
);
-
IOCON_PinMuxSet(IOCON, PORT0_IDX, 25, port0_pin25_config); /* PORT0 PIN25 */
-
IOCON_PinMuxSet(IOCON, PORT0_IDX, 26, port0_pin25_config); /* PORT0 PIN26 */
复制代码
主要代码:
SCT初始化;Port 1的1/2/3/4即SCT0_OUT-PWM4/5/6/7四管脚输出PWM配置:高有效、占空比、基本时钟记数频率、共同循环周期(频率48KHz) 以及每个对应的事件(其实就是脉冲发生和周期的记数匹配以产生PWM);最后开始SCT,就有PWM发生了。
注意一个PWM对应一个event标记,它们在改变占空比是要用。
-
sctimer_config_t sctimerInfo;
-
sctimer_pwm_signal_param_t pwmParam;
-
uint32_t sctimerClock;
-
..........
-
GPIO->DIR[0] |= 1U << 25;
-
GPIO->DIR[0] |= 1U << 26;
-
-
SCTIMER_GetDefaultConfig(&sctimerInfo);
-
-
/* Initialize SCTimer module */
-
SCTIMER_Init(SCT0, &sctimerInfo);
-
-
/* Configure first PWM with frequency 24kHZ from output 4 5 kSCTIMER_CenterAlignedPwm kSCTIMER_EdgeAlignedPwm*/
-
pwmParam.output = kSCTIMER_Out_4;
-
pwmParam.level = kSCTIMER_HighTrue;
-
pwmParam.dutyCyclePercent = 40;
-
if (SCTIMER_SetupPwm(SCT0, &pwmParam,kSCTIMER_CenterAlignedPwm , 48000U, sctimerClock, &event4) == kStatus_Fail)
-
{
-
return -1;
-
}
-
-
pwmParam.output = kSCTIMER_Out_5;
-
pwmParam.level = kSCTIMER_HighTrue;
-
pwmParam.dutyCyclePercent = 40;
-
if (SCTIMER_SetupPwm(SCT0, &pwmParam, kSCTIMER_CenterAlignedPwm, 48000U, sctimerClock, &event5) == kStatus_Fail)
-
{
-
return -1;
-
}
-
-
/* Configure second PWM with different duty cycle but same frequency as before */
-
pwmParam.output = kSCTIMER_Out_6;
-
pwmParam.level = kSCTIMER_HighTrue;
-
pwmParam.dutyCyclePercent = 45;
-
if (SCTIMER_SetupPwm(SCT0, &pwmParam, kSCTIMER_CenterAlignedPwm, 48000U, sctimerClock, &event6) == kStatus_Fail)
-
{
-
return -1;
-
}
-
pwmParam.output = kSCTIMER_Out_7;
-
pwmParam.level = kSCTIMER_HighTrue;
-
pwmParam.dutyCyclePercent = 45;
-
if (SCTIMER_SetupPwm(SCT0, &pwmParam, kSCTIMER_CenterAlignedPwm, 48000U, sctimerClock, &event7) == kStatus_Fail)
-
{
-
return -1;
-
}
-
-
/* Start the timer */
-
SCTIMER_StartTimer(SCT0, kSCTIMER_Counter_L);
-
复制代码
另配置使用了一个CTIMER0记数匹配中断,用于定时中断更改占空比以改变电机转动的速度。
-
#define CTIMER CTIMER0 /* Timer 0 */
-
#define CTIMER_MAT_OUT kCTIMER_Match_0
-
-
ctimer_config_t config;
-
ctimer_match_config_t matchConfig;
-
CTIMER_GetDefaultConfig(&config);
-
-
CTIMER_Init(CTIMER, &config);
-
-
matchConfig.enableCounterReset = true; //mat1 后复位 重记数 控制测量周期
-
matchConfig.enableCounterStop = false;//true;// //mat后不停止
-
matchConfig.matchValue = BUS_CLK_FREQ /2000;//200;//0 ; // BUS_CLK_FREQ/1 即1秒
-
matchConfig.outControl = kCTIMER_Output_NoAction; //无输出关联
-
matchConfig.outPinInitState = false; // 无效
-
matchConfig.enableInterrupt = true;// //匹配不中断
-
CTIMER_SetupMatch(CTIMER, kCTIMER_Match_1, &matchConfig); //Timer3 mat1 no out
-
-
CTIMER_RegisterCallBack(CTIMER, &ctimer_callback_table[0], kCTIMER_SingleCallback);//kCTIMER_MultipleCallback); //kCTIMER_MultipleCallback); //echo fall intr
-
-
CTIMER_StartTimer(CTIMER); //开始
-
复制代码
定时中断更改占空比以改变电机转动的速度、方向、LED灯同步指示。
1) 占空比以小间隔逐渐线性改变, 以实现较平滑的逐渐加减速和反向,而不是突然的改变。
2) Port 0的25/26,用分别对应正反转动方向,LED灯亮灭分别对应一个方向的加减速。
-
void ctimer_match1_callback(uint32_t flags)
-
{
-
if(GorB==1)
-
{
-
if(GPIO->B[0][25] ==1)
-
{
-
PRINTF("\r\n int 1 outpu 0.25 0 \r\n");
-
-
SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_6, sp/10+ad, event6); // 右轮 前进
-
SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_7, 1, event7);
-
SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_5, sp/10, event5); // 左轮 前进
-
SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_4, 1, event4);
-
sp +=dsp ;
-
if (sp>upsp)
-
GPIO->B[0][25] =0;
-
}
-
else
-
{
-
PRINTF("\r\n int 0 outpu 0.25 1 \r\n");
-
/* SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_4, sp, event4);
-
SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_5, 1, event5); // 左轮 后退
-
-
SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_6, 1, event6); // 右轮 后退
-
SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_7, sp, event7);
-
*/
-
SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_6, sp/10+ad, event6); // 右轮 前进 +16
-
SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_7, 1, event7);
-
SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_5, sp/10, event5); // 左轮 前进
-
-
SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_4, 1, event4);
-
-
-
sp -=dsp ;
-
if (sp<lwsp)
-
{
-
GPIO->B[0][25] =1;
-
GorB=0;
-
}
-
}
-
}
-
else
-
if(GPIO->B[0][26] ==1)
-
{
-
PRINTF("\r\n int 1 outpu 0.26 0 \r\n");
-
SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_7, sp/10+ad, event7);
-
SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_6, 1, event6); // 右轮 后退 +16
-
SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_4, sp/10, event4);
-
SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_5, 1, event5); // 左轮 后退
-
-
sp +=dsp ;
-
if (sp>upsp)
-
GPIO->B[0][26] =0;
-
}
-
else
-
{
-
PRINTF("\r\n int 0 outpu 0.26 1 \r\n");
-
SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_7, sp/10+ad, event7);
-
SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_6, 1, event6); // 右轮 后退 +16
-
SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_4, sp/10, event4);
-
SCTIMER_UpdatePwmDutycycle(SCT0, kSCTIMER_Out_5, 1, event5); // 左轮 后退
-
-
sp -=dsp ;
-
if (sp<lwsp)
-
{
-
GPIO->B[0][26] =1;
-
GorB=1;
-
}
-
}
-
-
-
}
-
-
ctimer_callback_t ctimer_callback_table[] =
-
{
-
ctimer_match1_callback,//NULL,
-
// ctimer_cap_callback,
-
NULL,
-
NULL,//ctimer_match1_callback,
-
NULL,
-
NULL,
-
//ctimer_cap_callback,
-
NULL,
-
NULL,
-
NULL
-
};
复制代码
注意事项和问题:
1) 更改占空比实际是在停止和再启SCT之间修改的,四线就这样了4次,应考虑不用库函数代码,在一次停启之间修改四个占空比;
2) SCT停止时,只是停的是记数器,有可能某管脚只好PWM处于高电位,这下电机会疯狂旋转!
3) 不能使用0和100做占空比,这里用的电机驱动不是用独立的线控制正反转方向,所以正反转动方向控制通过把对应2线之一的占空比设为1实现。
4) 电机通过减速齿轮带动轮子空转,发现旋转阻力不均,不仅占空比与转速不是线性关系,轮子和轴不同角度阻力也不相同(同占空比下转动也不均匀、不太重现)。这还是空转啊,实际岂不是更不均匀了。这个这个我不懂了,可能可能机械转动转动的世界不太理想。也许需要测速反馈控制才能定速控制(这个电机的测速分辨不高,而平衡车是微动,我很怀疑有没用用)。
5) 带动轮子的空转阻力也不小了,占空比20以下不转,30以上才算转,两个轮子阻力还不一样。
6) 看这个头重脚轻的东西,严重怀疑这个能否实现平衡车??
7) 不知道,SCT是否能一个匹配触发多个输出呢?有空再研究吧。
现在论坛禁止上传视频文件,只好转为动态gif图吧。
倒置空转,正反转视频:
我临时使用一个手机电池(7.3V, 3400mAh)经升压模块(已经烧了一个了!)到10V供电机驱动。
先悬绳保持,观察正反转视频:(支架用废光盘做的)
系列: