这是我刚大学毕业参加工作开发的第一个项目,经过长达半个月的查阅资料和实验终于驱动无刷电机。我发现这个网站没有关于gd32驱动带霍尔传感器的程序,特此开源分享给大家。但是这个程序还有一些问题,电机驱动后换相的不够平稳,电机噪音大,且抖动,希望路过的大佬可以指导一下怎么优化程序。感谢!
无刷电机的驱动,主要是换相,带上霍尔传感器可以精确的读出电机当前所处的相位,再根据当前霍尔值换相这些基础的这里就不多说了,随便一搜网上全是的,建议先去搞懂它的驱动原理,再看程序。下面直接上程序。
void gpio_config(void)
{
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_GPIOB);
gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLDOWN, GPIO_PIN_0);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0);
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_8);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_8);
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_9);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_10);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
gpio_af_set(GPIOA, GPIO_AF_2, GPIO_PIN_8);
gpio_af_set(GPIOA, GPIO_AF_2, GPIO_PIN_9);
gpio_af_set(GPIOA, GPIO_AF_2, GPIO_PIN_10);
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_13);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13);
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_14);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_14);
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_15);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_15);
gpio_af_set(GPIOB, GPIO_AF_2, GPIO_PIN_13);
gpio_af_set(GPIOB, GPIO_AF_2, GPIO_PIN_14);
gpio_af_set(GPIOB, GPIO_AF_2, GPIO_PIN_15);
//霍尔引脚初始化
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_4);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_4);//HB
gpio_af_set(GPIOB, GPIO_AF_1, GPIO_PIN_4);
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_5);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5);//HA
gpio_af_set(GPIOB, GPIO_AF_1, GPIO_PIN_5);
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_8);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_8);//HC
gpio_af_set(GPIOB, GPIO_AF_1, GPIO_PIN_8);
}
这里PWM输出用到六个引脚,做三路PWM互补输出给电机上下桥臂导通。三个霍尔引脚复用为定时输入,为后面定时器捕获输入信号做准备。
下面就是开启两个定时器,定时器2输入捕获霍尔引脚信号,并且输出一个TRGE信号给定时器0,定时器0输出三路互补PWM信号驱动电机
void timer0_config(void)
{
timer_oc_parameter_struct timer_ocintpara={0};
timer_parameter_struct timer_initpara={0};
timer_break_parameter_struct timer_Breakinitpara={0};
timer_ic_parameter_struct timer_icinitpara = {0};
timer_parameter_struct timer_initpara2={0};
gpio_config();
rcu_periph_clock_enable(RCU_TIMER0);
rcu_periph_clock_enable(RCU_TIMER2);
timer_deinit(TIMER2);
timer_initpara2.prescaler = 0; // 预分频:72MHz / 72 = 1MHz
timer_initpara2.alignedmode = TIMER_COUNTER_EDGE;
timer_initpara2.counterdirection = TIMER_COUNTER_UP; // 向上计数模式
timer_initpara2.period = (65536 - 1);
timer_initpara2.clockdivision = TIMER_CKDIV_DIV1; // 输入时钟1分频
timer_init(TIMER2,&timer_initpara2);
timer_icinitpara.icpolarity = TIMER_IC_POLARITY_RISING;
timer_icinitpara.icselection = TIMER_IC_SELECTION_DIRECTTI;
timer_icinitpara.icprescaler = TIMER_IC_PSC_DIV1; // 时钟1分频
timer_icinitpara.icfilter =0;
timer_input_capture_config(TIMER2, TIMER_CH_0, &timer_icinitpara);
timer_master_output_trigger_source_select(TIMER2,TIMER_TRI_OUT_SRC_CH0);//触发源为捕获比较触发 主模式
timer_channel_control_shadow_config(TIMER2,ENABLE );
timer_auto_reload_shadow_enable(TIMER2);// 使能重装载影子
timer_hall_mode_config(TIMER2,TIMER_HALLINTERFACE_ENABLE);//使能定时器霍尔传感器模式
timer_master_slave_mode_config(TIMER2, TIMER_MASTER_SLAVE_MODE_ENABLE); // 使能主模式
timer_primary_output_config(TIMER2,ENABLE);//开启主模式输出
timer_interrupt_flag_clear(TIMER2, TIMER_INT_FLAG_CH0); // 清除通道0中断标志位
timer_interrupt_enable(TIMER2, TIMER_INT_CH0); // 使能通道0中断
nvic_irq_enable(TIMER2_IRQn, 0); // 使能中断服务,抢占优先级为0
timer_enable(TIMER2); // 使能定时器2
timer_deinit(TIMER0);//初始化定时器0
timer_initpara.prescaler = 0;
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
timer_initpara.counterdirection = TIMER_COUNTER_UP;
timer_initpara.period = 9999;
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
timer_initpara.repetitioncounter = 0;
timer_init(TIMER0, &timer_initpara);
timer_ocintpara.outputstate = TIMER_CCX_ENABLE;
timer_ocintpara.outputnstate = TIMER_CCXN_ENABLE;
timer_ocintpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
timer_ocintpara.ocnpolarity = TIMER_OCN_POLARITY_HIGH;
timer_ocintpara.ocidlestate = TIMER_OC_IDLE_STATE_LOW;
timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
timer_channel_output_config(TIMER0, TIMER_CH_0, &timer_ocintpara);
timer_channel_output_config(TIMER0, TIMER_CH_1, &timer_ocintpara);
timer_channel_output_config(TIMER0, TIMER_CH_2, &timer_ocintpara);
timer_master_slave_mode_config(TIMER0, TIMER_MASTER_SLAVE_MODE_ENABLE);//使能主从模式
// timer_slave_mode_select(TIMER0,TIMER_SLAVE_MODE_RESTART);//从模式选择 重启模式
timer_slave_mode_select(TIMER0,TIMER_SLAVE_MODE_EXTERNAL0);//从模式选择 外部时钟源模式
timer_input_trigger_source_select(TIMER0,TIMER_SMCFG_TRGSEL_ITI0);//内部触发源配置为外部触发
timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_0,3999);
timer_channel_output_mode_config(TIMER0, TIMER_CH_0, TIMER_OC_MODE_PWM0);
timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_1, 3999);
timer_channel_output_mode_config(TIMER0, TIMER_CH_1, TIMER_OC_MODE_PWM0);
timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_2,3999);
timer_channel_output_mode_config(TIMER0, TIMER_CH_2, TIMER_OC_MODE_PWM0);
timer_primary_output_config(TIMER0, ENABLE);
timer_enable(TIMER0);
}
在定时器2的输入捕获中断里检测霍尔值,并发送给电机驱动换相函数。这里定时器2开启了霍尔模式,三个霍尔引脚在内部异或到CH0上,任何一路引脚发生电平转换,都会触发中断,并给定时器0信号。下面是定时器2中断函数。
void TIMER2_IRQHandler(void)
{
uint16_t hall_phase;
if(timer_interrupt_flag_get(TIMER2, TIMER_INT_FLAG_CH0)!=RESET)
{
timer_interrupt_flag_clear(TIMER2, TIMER_INT_FLAG_CH0); // 清除中断标志
hall_phase=Hall_Gets_phase();
BLDC_Convet(hall_phase);
}
}
然后是获取霍尔值的函数,定时器2只能捕获到信号的跳变还不能直接获取霍尔值,所以需要有一个函数获取三个霍尔引脚的霍尔值,最后取低三位。
uint16_t Hall_Gets_phase()//获取霍尔传感器引脚电平
{
uint16_t phase=0;
phase |=gpio_input_bit_get(GPIOB,GPIO_PIN_5);
phase <<=1;
phase |=gpio_input_bit_get(GPIOB,GPIO_PIN_4);
phase <<=1;
phase |=gpio_input_bit_get(GPIOB,GPIO_PIN_8);
return (phase&0x0007);
}
最后是换相函数,这个根据电机换相原理给上下桥臂导通上电即可
void BLDC_Convet(uint16_t phase)
{
switch(phase) //
{
case 0x00: //AB ---- Q1 Q5
{
timer_channel_output_state_config(TIMER0,TIMER_CH_0,TIMER_CCX_ENABLE);//CC1E
timer_channel_complementary_output_state_config(TIMER0,TIMER_CH_0,TIMER_CCXN_ENABLE);//CC1NE
timer_channel_output_mode_config(TIMER0, TIMER_CH_0, TIMER_OC_MODE_PWM0);
timer_channel_output_state_config(TIMER0,TIMER_CH_1,TIMER_CCX_ENABLE);//CC1E
timer_channel_complementary_output_state_config(TIMER0,TIMER_CH_1,TIMER_CCXN_ENABLE);//CC1NE
timer_channel_output_mode_config(TIMER0, TIMER_CH_1, TIMER_OC_MODE_PWM0);
timer_channel_output_state_config(TIMER0,TIMER_CH_2,TIMER_CCX_ENABLE);//CC1E
timer_channel_complementary_output_state_config(TIMER0,TIMER_CH_2,TIMER_CCXN_ENABLE);//CC1NE
timer_channel_output_mode_config(TIMER0, TIMER_CH_2, TIMER_OC_MODE_PWM0);
timer_event_software_generate(TIMER0,TIMER_SWEVG_CMTG);
}
break;
case 6: //AB ---- Q1 Q5
{
timer_channel_output_state_config(TIMER0,TIMER_CH_0,TIMER_CCX_ENABLE);//CC1E
timer_channel_complementary_output_state_config(TIMER0,TIMER_CH_0,TIMER_CCXN_DISABLE);//CC1NE
timer_channel_output_mode_config(TIMER0, TIMER_CH_0, TIMER_OC_MODE_PWM0);
timer_channel_output_state_config(TIMER0,TIMER_CH_1,TIMER_CCX_DISABLE);//CC1E
timer_channel_complementary_output_state_config(TIMER0,TIMER_CH_1,TIMER_CCXN_ENABLE);//CC1NE
timer_channel_output_mode_config(TIMER0, TIMER_CH_1, TIMER_OC_MODE_HIGH);
timer_channel_output_state_config(TIMER0,TIMER_CH_2,TIMER_CCXN_ENABLE);//CC1E
timer_channel_complementary_output_state_config(TIMER0,TIMER_CH_2,TIMER_CCXN_ENABLE);//CC1NE
timer_channel_output_mode_config(TIMER0, TIMER_CH_2, TIMER_OC_MODE_LOW);
timer_event_software_generate(TIMER0,TIMER_SWEVG_CMTG);
}
break;
case 5://0x01: //AC ---- Q1 Q6
{
timer_channel_output_state_config(TIMER0,TIMER_CH_0,TIMER_CCX_ENABLE);//CC1E
timer_channel_complementary_output_state_config(TIMER0,TIMER_CH_0,TIMER_CCXN_DISABLE);//CC1NE
timer_channel_output_mode_config(TIMER0, TIMER_CH_0, TIMER_OC_MODE_PWM0);
timer_channel_output_state_config(TIMER0,TIMER_CH_1,TIMER_CCX_DISABLE);//CC1E
timer_channel_complementary_output_state_config(TIMER0,TIMER_CH_1,TIMER_CCXN_ENABLE);//CC1NE
timer_channel_output_mode_config(TIMER0, TIMER_CH_1, TIMER_OC_MODE_LOW);
timer_channel_output_state_config(TIMER0,TIMER_CH_2,TIMER_CCX_DISABLE);//CC1E
timer_channel_complementary_output_state_config(TIMER0,TIMER_CH_2,TIMER_CCXN_ENABLE);//CC1NE
timer_channel_output_mode_config(TIMER0, TIMER_CH_2, TIMER_OC_MODE_HIGH);
timer_event_software_generate(TIMER0,TIMER_SWEVG_CMTG);
}
break;
case 4: //BC ---- Q2 Q6
{
timer_channel_output_state_config(TIMER0,TIMER_CH_1,TIMER_CCX_ENABLE);//CC1E
timer_channel_complementary_output_state_config(TIMER0,TIMER_CH_1,TIMER_CCXN_DISABLE);//CC1NE
timer_channel_output_mode_config(TIMER0, TIMER_CH_1, TIMER_OC_MODE_PWM0);
timer_channel_output_state_config(TIMER0,TIMER_CH_0,TIMER_CCX_DISABLE);//CC1E
timer_channel_complementary_output_state_config(TIMER0,TIMER_CH_0,TIMER_CCXN_ENABLE);//CC1NE
timer_channel_output_mode_config(TIMER0, TIMER_CH_0, TIMER_OC_MODE_LOW);
timer_channel_output_state_config(TIMER0,TIMER_CH_2,TIMER_CCX_DISABLE);//CC1E
timer_channel_complementary_output_state_config(TIMER0,TIMER_CH_2,TIMER_CCXN_ENABLE);//CC1NE
timer_channel_output_mode_config(TIMER0, TIMER_CH_2, TIMER_OC_MODE_HIGH);
timer_event_software_generate(TIMER0,TIMER_SWEVG_CMTG);
}
break;
case 3: //BA ---- Q2 Q4
{
timer_channel_output_state_config(TIMER0,TIMER_CH_1,TIMER_CCX_ENABLE);//CC1E
timer_channel_complementary_output_state_config(TIMER0,TIMER_CH_1,TIMER_CCXN_DISABLE);//CC1NE
timer_channel_output_mode_config(TIMER0, TIMER_CH_1, TIMER_OC_MODE_PWM0);
timer_channel_output_state_config(TIMER0,TIMER_CH_2,TIMER_CCX_DISABLE);//CC1E
timer_channel_complementary_output_state_config(TIMER0,TIMER_CH_2,TIMER_CCXN_ENABLE);//CC1NE
timer_channel_output_mode_config(TIMER0, TIMER_CH_2, TIMER_OC_MODE_LOW);
timer_channel_output_state_config(TIMER0,TIMER_CH_0,TIMER_CCX_DISABLE);//CC1E
timer_channel_complementary_output_state_config(TIMER0,TIMER_CH_0,TIMER_CCXN_ENABLE);//CC1NE
timer_channel_output_mode_config(TIMER0, TIMER_CH_0, TIMER_OC_MODE_HIGH);
timer_event_software_generate(TIMER0,TIMER_SWEVG_CMTG);
}
break;
case 2: //CA ---- Q3 Q4
{
timer_channel_output_state_config(TIMER0,TIMER_CH_1,TIMER_CCX_DISABLE);//CC1E
timer_channel_complementary_output_state_config(TIMER0,TIMER_CH_1,TIMER_CCXN_DISABLE);//CC1NE
timer_channel_output_mode_config(TIMER0, TIMER_CH_1, TIMER_OC_MODE_LOW);
timer_channel_output_state_config(TIMER0,TIMER_CH_2,TIMER_CCX_ENABLE);//CC1E
timer_channel_complementary_output_state_config(TIMER0,TIMER_CH_2,TIMER_CCXN_DISABLE);//CC1NE
timer_channel_output_mode_config(TIMER0, TIMER_CH_2, TIMER_OC_MODE_PWM0);
timer_channel_output_state_config(TIMER0,TIMER_CH_0,TIMER_CCX_DISABLE);//CC1E
timer_channel_complementary_output_state_config(TIMER0,TIMER_CH_0,TIMER_CCXN_ENABLE);//CC1NE
timer_channel_output_mode_config(TIMER0, TIMER_CH_0, TIMER_OC_MODE_HIGH);
timer_event_software_generate(TIMER0,TIMER_SWEVG_CMTG);
}
break;
case 1: //CB ---- Q3 Q5
{
timer_channel_output_state_config(TIMER0,TIMER_CH_1,TIMER_CCX_DISABLE);//CC1E
timer_channel_complementary_output_state_config(TIMER0,TIMER_CH_1,TIMER_CCXN_ENABLE);//CC1NE
timer_channel_output_mode_config(TIMER0, TIMER_CH_1, TIMER_OC_MODE_HIGH);
timer_channel_output_state_config(TIMER0,TIMER_CH_2,TIMER_CCX_DISABLE);//CC1E
timer_channel_complementary_output_state_config(TIMER0,TIMER_CH_2,TIMER_CCXN_ENABLE);//CC1NE
timer_channel_output_mode_config(TIMER0, TIMER_CH_2, TIMER_OC_MODE_PWM0);
timer_channel_output_state_config(TIMER0,TIMER_CH_0,TIMER_CCX_DISABLE);//CC1E
timer_channel_complementary_output_state_config(TIMER0,TIMER_CH_0,TIMER_CCXN_ENABLE);//CC1NE
timer_channel_output_mode_config(TIMER0, TIMER_CH_0, TIMER_OC_MODE_LOW);
timer_event_software_generate(TIMER0,TIMER_SWEVG_CMTG);
}
break;
default:break;
}
}
代码缺陷很多,希望路过大佬指导,感谢感谢感谢!