无刷直流电机比较流行,很多电机内部加入霍尔元件,通过霍尔元件可以知道电机转子的位置,根据这个位置给电机相线供电,这样电机就转起来了。框图如下所示 霍尔元件输出与相线输入电压的关系可以让BLDC电机厂家提供,一般都提供这个对应关系表,如下图所示 有了上面这些足可以让我们设计电路编写程序让电机转起来! 有上面的框图可以看出,3相电机的驱动需要六个mos管,一般用的是NMOS,大功率的NMOS比较便宜。大功率MOS管有较大的结电容,控制电压也高些,无法用单片机直接驱动,所以需要驱动电路。驱动芯片组成的驱动电路比较简单,常见的有IR2110S,我这里用IR2110S设计了MOS驱动电路,如下图所示,其中C24和D5是自举电路,为了控制Q3抬高电压。 3片IR2110S驱动6个NMOS,如下图 霍尔元件供电是5V,他的输出一般也是5V,可以分压后给单片机用。 单片机用流行STM32,他有高级定时器T1,T8,可以输出3对互补的PWM波,还有刹车信号输入,这些特性对于电机的可控制非常合适。电路如下图所示 BLDC电机控制用到单片机定时器及IO中断,初始化部分如下 void tiM_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct; TIM_OCInitTypeDef TIM_OCInitStructure; TIM_BDTRInitTypeDef TIM_BDTRInitStructure; EXTI_InitTypeDef EXTI_InitStructure;// NVIC_InitTypeDef NVIC_InitStructure; TIM_ICInitTypeDef TIM_ICInitStructure; // ¿ªÆô¶¨Ê±Æ÷ʱÖÓ,¼´ÄÚ²¿Ê±ÖÓCK_INT=72M RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_TIM1, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); // Êä³ö±È½ÏͨµÀ1 GPIO ³õʼ»¯ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 ; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); //»ô¶ûÊäÈë GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 ; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource0); EXTI_InitStructure.EXTI_Line=EXTI_Line0; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource6); EXTI_InitStructure.EXTI_Line= EXTI_Line6; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource7); EXTI_InitStructure.EXTI_Line= EXTI_Line7; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); TIM_DeInit(TIM1); //½«ÍâÉèTIM1¼Ä´æÆ÷ÖØÉèΪȱʡֵ TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1 ; TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up ; TIM_TimeBaseInitStruct.TIM_Period = 1000 ; TIM_TimeBaseInitStruct.TIM_Prescaler = 3 ; TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM1, &TIM_TimeBaseInitStruct ) ; /* ¶¨Ê±Æ÷Êä³öͨµÀ1ģʽÅäÖà */ TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; TIM_OCInitStructure.TIM_Pulse = 1000; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OCInitStructure.TIM_OCNPolarity= TIM_OCNPolarity_High; TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set; TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Set; TIM_OC1Init(TIM1, &TIM_OCInitStructure); TIM_OC2Init(TIM1, &TIM_OCInitStructure); TIM_OC3Init(TIM1, &TIM_OCInitStructure); /* Automatic Output enable, Break, dead time and lock configuration*/ TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable; TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable; TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_OFF; TIM_BDTRInitStructure.TIM_DeadTime = 1; TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable; TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High; TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable; TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure); TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable); TIM_OC2PreloadConfig(TIM1,TIM_OCPreload_Enable); TIM_OC3PreloadConfig(TIM1,TIM_OCPreload_Enable); TIM_ARRPreloadConfig(TIM1, ENABLE); TIM_Cmd(TIM1, ENABLE); TIM_CtrlPWMOutputs(TIM1, ENABLE); TIM_CCxCmd(TIM1,TIM_Channel_1,TIM_CCx_Enable); TIM_CCxNCmd(TIM1,TIM_Channel_1,TIM_CCxN_Enable); TIM_CCxCmd(TIM1,TIM_Channel_2,TIM_CCx_Enable); TIM_CCxNCmd(TIM1,TIM_Channel_2,TIM_CCxN_Enable); TIM_CCxCmd(TIM1,TIM_Channel_3,TIM_CCx_Enable); TIM_CCxNCmd(TIM1,TIM_Channel_3,TIM_CCxN_Enable); } 让电机转起来需要知道电机转子的位置,根据霍尔相位对应表驱动电机相线,程序里用中断获取霍尔电平的变化。 void EXTI0_IRQHandler(void) { int i,j; IF(EXTI_GetITStatus(EXTI_Line0)!=RESET) { EXTI_ClearITPendingBit(EXTI_Line0); step=((GPIOA->IDR & GPIO_Pin_6)>>6)+((GPIOA->IDR & GPIO_Pin_7)>>6)+((GPIOB->IDR & GPIO_Pin_0)<<2); if(start==1) { TIM1->CCER=PHASE_CHANGE[step]; int_count1++; } } } void EXTI9_5_IRQHandler(void) { int i,j; if(EXTI_GetITStatus(EXTI_Line6)!=RESET) { EXTI_ClearITPendingBit(EXTI_Line6); step=((GPIOA->IDR & GPIO_Pin_6)>>6)+((GPIOA->IDR & GPIO_Pin_7)>>6)+((GPIOB->IDR & GPIO_Pin_0)<<2); if(start==1) { TIM1->CCER=PHASE_CHANGE[step]; int_count2++; } } if(EXTI_GetITStatus(EXTI_Line7)!=RESET) { EXTI_ClearITPendingBit(EXTI_Line7); step=((GPIOA->IDR & GPIO_Pin_6)>>6)+((GPIOA->IDR & GPIO_Pin_7)>>6)+((GPIOB->IDR & GPIO_Pin_0)<<2); if(start==1) { TIM1->CCER=PHASE_CHANGE[step]; int_count3++; } } } 检测到变化后改变定时器输出,从而使电机相线得到驱动,我在程序里做好了数组,把得到了位置通过数组给定时器CCER寄存器,这样电机就转起来了 int PHASE_CHANGE[7]={0x0000,0x0104,0x0041,0x0140,0x0410,0x0014,0x0401}; 这是霍尔输出与PWM输出波形的截图 这是定时器3对PWM的输出截图 这是电机和电路板 这是程序 201909141747 BLDC.rar ———————————————— 更多精彩内容关注我的博客 https://blog.csdn.net/gd1984812/article/details/100834511 |
共8条
1/1 1 跳转至页
[经验] STM32控制BLDC-如何让电机转起来 有原理图有程序
关键词: STM32 BLDC- 电机
共8条
1/1 1 跳转至页
回复
有奖活动 | |
---|---|
【有奖活动】分享技术经验,兑换京东卡 | |
话不多说,快进群! | |
请大声喊出:我要开发板! | |
【有奖活动】EEPW网站征稿正在进行时,欢迎踊跃投稿啦 | |
奖!发布技术笔记,技术评测贴换取您心仪的礼品 | |
打赏了!打赏了!打赏了! |
打赏帖 | |
---|---|
与电子爱好者谈读图四被打赏50分 | |
与电子爱好者谈读图二被打赏50分 | |
【FRDM-MCXN947评测】Core1适配运行FreeRtos被打赏50分 | |
【FRDM-MCXN947评测】双核调试被打赏50分 | |
【CPKCORRA8D1B评测】---移植CoreMark被打赏50分 | |
【CPKCORRA8D1B评测】---打开硬件定时器被打赏50分 | |
【FRDM-MCXA156评测】4、CAN loopback模式测试被打赏50分 | |
【CPKcorRA8D1评测】--搭建初始环境被打赏50分 | |
【FRDM-MCXA156评测】3、使用FlexIO模拟UART被打赏50分 | |
【FRDM-MCXA156评测】2、rt-thread MCXA156 BSP制作被打赏50分 |