[GD32E231 DIY大赛] 05. 自动喂鱼机器人之PWM篇
[复制链接]
[GD32E231 DIY大赛] 05. 自动喂鱼机器人之PWM篇
一般机器人控制都离不开舵机控制,这里先简单讲解一下舵机的基本工作原理:
舵机的控制信号为周期是 20ms 的脉宽调制(PWM)信号,其中脉冲宽度从 0.5ms-2.5ms,相对应舵盘的位置为 0-180 度,呈线性变化。也就是说,给它提供一定的脉宽,它的输出轴就会保持在一个相对应的角度上,无论外界转矩怎样改变,直到给它提供一个另外宽度的脉冲信号,它才会改变输出角度到新的对应的位置上。
一般而言,舵机的基准信号都是周期为20ms,宽度为1.5ms。这个基准信号定义的位置为中间位置。其中间位置的脉冲宽度是一定的,那就是1.5ms。
我是参考: https://blog.csdn.net/weixin_38075894/article/details/80027600.
20ms基准频率就是50Hz, 这个一般的单片机都是很容易生成的。
我的机械臂上的舵机型号是MG90S,是一个小舵机,机械臂是4自由度的,因此就是4个。
GD32E231的定时器功能是非常强大的,TIMER2可以同时输出四个通道的PWM,PWM可以设定不同的脉宽。
因为GD32E231start开发板,兼容arduino接口,因此我采用了arduino的转接板,转接板仅仅是转接功能,具体如下:
具体的接口配置:
PB4 TIMER2_CH0 D3
PB5 TIMER2_CH1 D4
PB0 TIMER2_CH2 D9
PB1 TIMER2_CH3 D8
- void gpio_config(void);
- void pwm_timer_clock_enable(void);
- void pwm_timer_config(uint32_t timer);
复制代码
- void gpio_config(void)
- {
- rcu_periph_clock_enable(RCU_GPIOB);
-
- /* configure PB2 output 0 */
- gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_PIN_2);
- gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_2);
- gpio_bit_reset(GPIOB, GPIO_PIN_2);//disable opa, ENA is connected to PB2, ENA = 0, diable opa, else, enable ENA, NOT be float
-
- /* configure PB4(TIMER2 CH0) as alternate function */
- gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_4);
- gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_4);
- gpio_af_set(GPIOB, GPIO_AF_1, GPIO_PIN_4);
-
- /* configure PB5(TIMER2 CH1) as alternate function */
- gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_5);
- gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_5);
- gpio_af_set(GPIOB, GPIO_AF_1, GPIO_PIN_5);
-
- /* configure PB0(TIMER2 CH2) as alternate function */
- gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_0);
- gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_0);
- gpio_af_set(GPIOB, GPIO_AF_1, GPIO_PIN_0);
-
- /* configure PB1(TIMER2 CH3) as alternate function */
- gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_1);
- gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_1);
- gpio_af_set(GPIOB, GPIO_AF_1, GPIO_PIN_1);
-
- }
复制代码- /*!
- \brief enable clock of the TIMER peripheral
- \param[in] none
- \param[out] none
- \retval none
- */
- void pwm_timer_clock_enable()
- {
- rcu_periph_clock_enable(RCU_TIMER2);
- }
复制代码- void pwm_timer_config(uint32_t timer)
- {
- /* -----------------------------------------------------------------------
- TIMER2CLK is 100KHz
-
- TIMER2 channel0 duty cycle = (25000/ 50000)* 100 = 50%
- ----------------------------------------------------------------------- */
- timer_oc_parameter_struct timer_ocintpara;
- timer_parameter_struct timer_initpara;
-
- timer_deinit(timer);
-
- /* TIMER configuration */
- timer_initpara.prescaler = 719;
- timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
- timer_initpara.counterdirection = TIMER_COUNTER_UP;
- timer_initpara.period = 1999;
- timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
- timer_initpara.repetitioncounter = 0;
- timer_init(timer,&timer_initpara);
-
- /* configurate CH0 in PWM mode0 */
- timer_ocintpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
- timer_ocintpara.outputstate = TIMER_CCX_ENABLE;
-
- timer_channel_output_config(timer,TIMER_CH_0,&timer_ocintpara);
- timer_channel_output_pulse_value_config(timer,TIMER_CH_0,150-1);
- timer_channel_output_mode_config(timer,TIMER_CH_0,TIMER_OC_MODE_PWM0);
- timer_channel_output_shadow_config(timer,TIMER_CH_0,TIMER_OC_SHADOW_DISABLE);
- timer_auto_reload_shadow_enable(timer);
- timer_enable(timer);
- delay_1ms(500);
- timer_disable(timer);
-
- timer_channel_output_config(timer,TIMER_CH_1,&timer_ocintpara);
- timer_channel_output_pulse_value_config(timer,TIMER_CH_1,150-1);
- timer_channel_output_mode_config(timer,TIMER_CH_1,TIMER_OC_MODE_PWM0);
- timer_channel_output_shadow_config(timer,TIMER_CH_1,TIMER_OC_SHADOW_DISABLE);
- timer_auto_reload_shadow_enable(timer);
- timer_enable(timer);
- delay_1ms(500);
- timer_disable(timer);
-
- timer_channel_output_config(timer,TIMER_CH_2,&timer_ocintpara);
- timer_channel_output_pulse_value_config(timer,TIMER_CH_2,250-1);
- timer_channel_output_mode_config(timer,TIMER_CH_2,TIMER_OC_MODE_PWM0);
- timer_channel_output_shadow_config(timer,TIMER_CH_2,TIMER_OC_SHADOW_DISABLE);
- timer_auto_reload_shadow_enable(timer);
- timer_enable(timer);
- delay_1ms(500);
- timer_disable(timer);
-
- timer_channel_output_config(timer,TIMER_CH_3,&timer_ocintpara);
- timer_channel_output_pulse_value_config(timer,TIMER_CH_3,160-1); //160~200, Claw form close to open
- timer_channel_output_mode_config(timer,TIMER_CH_3,TIMER_OC_MODE_PWM0);
- timer_channel_output_shadow_config(timer,TIMER_CH_3,TIMER_OC_SHADOW_DISABLE);
-
- timer_auto_reload_shadow_enable(timer);
- timer_enable(timer);
- delay_1ms(500);
- }
复制代码
然后,如果要改变特定通道的PWM宽度,可以用timer_channel_output_pulse_value_config(TIMER2,TIMER_CH_0, value)函数.
由于舵机瞬态电流比较大,务必增大电流或者制作专用驱动电路,否则GD32E231会因为电压瞬间降低而引起复位。
我这里采用5V 3A的供电加上USB供电,并且在程序中,平滑PWM值的改变,才勉强实现系统的稳定工作。
可以采用这种法法来实现舵机平滑切换:
- /*!
- \brief config the specific steering motor 0,1,2,3
- \param[in] motor_tag: 0,1,2,3; pulse: 50~250, mid=150 0.5ms~2.5ms
- \param[out] none
- \retval none
- */
- void control_motor(uint8_t motor_tag, uint32_t pulse)
- {
- uint8_t i;
-
- if(motor_tag == 0)
- {
- if(pulse>=current_value[0])
- {
- for(i=current_value[0];i <= pulse; i++) //in case of big current to pulse MCU system
- {
- timer_channel_output_pulse_value_config(TIMER2,TIMER_CH_0,i-1);
- delay_1ms(20);
- }
- }
- else
- {
- for(i=current_value[0];i >= pulse; i--) //in case of big current to pulse MCU system
- {
- timer_channel_output_pulse_value_config(TIMER2,TIMER_CH_0,i-1);
- delay_1ms(20);
- }
- }
-
- current_value[0] = pulse;
- }
- else if (motor_tag == 1)
- {
- if(pulse>=current_value[1])
- {
- for(i=current_value[1];i <= pulse; i++) //in case of big current to pulse MCU system
- {
- timer_channel_output_pulse_value_config(TIMER2,TIMER_CH_1,i-1);
- delay_1ms(20);
- }
- }
- else
- {
- for(i=current_value[1];i >= pulse; i--) //in case of big current to pulse MCU system
- {
- timer_channel_output_pulse_value_config(TIMER2,TIMER_CH_1,i-1);
- delay_1ms(20);
- }
- }
- current_value[1] = pulse;
- }
- else if (motor_tag == 2)
- {
- if(pulse>=current_value[2])
- {
- for(i=current_value[2];i <= pulse; i++) //in case of big current to pulse MCU system
- {
- timer_channel_output_pulse_value_config(TIMER2,TIMER_CH_2,i-1);
- delay_1ms(30);
- }
- }
- else
- {
- for(i=current_value[2];i >= pulse; i--) //in case of big current to pulse MCU system
- {
- timer_channel_output_pulse_value_config(TIMER2,TIMER_CH_2,i-1);
- delay_1ms(30);
- }
- }
- current_value[2] = pulse;
- }
- else if (motor_tag == 3)
- {
- if(pulse>=current_value[3])
- {
- for(i=current_value[3];i <= pulse; i++) //in case of big current to pulse MCU system
- {
- timer_channel_output_pulse_value_config(TIMER2,TIMER_CH_3,i-1);
- delay_1ms(20);
- }
- }
- else
- {
- for(i=current_value[3];i >= pulse; i--) //in case of big current to pulse MCU system
- {
- timer_channel_output_pulse_value_config(TIMER2,TIMER_CH_3,i-1);
- delay_1ms(50);
- }
- }
- current_value[3] = pulse;
- }
-
- }
复制代码
主函数中:
- pwm_timer_clock_enable();
- pwm_timer_config(TIMER2);
复制代码
|