STM32F103做主控自制无刷电机(BLDC)控制器 有感/无感

转自:https://blog.csdn.net/snail_dongbin/article/details/82803076

源文件地址:https://download.csdn.net/download/snail_dongbin/10681696

https://blog.csdn.net/zs525600560/article/details/78228098

STM32F103做主控自制无刷电机(BLDC)控制器
支持 有感/无感 两种模式

2018年9月21日
星期五
snail_dongbin

很早之前就想做一款无刷电机控制器,忙于工作一直没有弄。最近有点时间画板,打样,焊接,调试,总算顺利的转起来。期间也遇到很多问题,上网查资料,自己量波形前前后后搞了差不多近一个月,(中间又出差一周)总算搞的差不多了,特意写个总结。

先来秀个板子外观,100*60mm 中等大小。DC 12V输入,设计最大电流10A.
(实际没试过那么大的电机,手头的电机也就5 6A的样子)
硬件上可以切换有感(HALL)和无感(EMF)两种模式,外部滑动变阻器调速 预留有 PWM输入、刹车、正反转、USB和uart等接口。

先来说下原理无刷电机其实就是直流电机,和传统的dc电机是一样的,只是把有刷的电滑环变成了电子换向器。
具体参考网络介绍 https://blog.csdn.net/dddxxxx/article/details/52564571

在这里插入图片描述

在这里插入图片描述

因为少了电滑环的摩擦所以寿命 静音方面有了很大的提升,转速也更高。

当然难点就在如何获取当前转子的位置好换相,所以又分为两种 有感和无感。

有感就是在电机端盖的部位加装霍尔传感器分别相隔30度或60度。
无感就是靠检测悬浮相的感应电动势过零点(后面在细讲)。
当然各有各的优缺点,有感在低速方面好,可以频繁启停换相。无感的结构简单成本低,航模上应用居多。

先说有感,电源首先被分成了3个绕组 U V W这个交流电还是有区别的。
它只是3个h桥按一定的顺序导通模拟出来的,本质还是直流电。
电机靠hall位置按一定顺序换相,转速与电压电流有关。这一点切记,不是换的越快转的越快。(位置决定换相时刻,电压决定转速)一般调速就是调电压,6步pwm方式是目前常用的。当然后续还有foc等更好算法。

硬件部分网上基本都是成熟的方案。三相H桥,H桥一般有上臂mos和下臂mos组成,如果只是简单的做演示上臂选pmos下臂选nmos控制电路简单直接用单片机的io就可以驱动。但是pmos低内阻的价格高。功率上面很难做大。
这也就是为什么基本所有的商业控制器全是nmos的原因。
但是上臂用nmos存在一个问题vgs控制电压大与vcc 4v以上才能完全导通。为了简化电路采用了ir公司出的驱动ic,它内部有自举升压电路。外部仅需一个续流的二极管及储能电容即可。

在这里插入图片描述
有感模式控制相对简单,3个霍尔传感器输出一般都是数字信号,分压后直接接单片机io.

在这里插入图片描述
当然控制方式上也就简单很多,三个霍尔接中断输入,在中断处理程序中根据组合状态换相,程序上也没什么复杂的。主程序 一直检测ad值,改变pwm占空比,及电流保护等。
如下一个典型的换相代码。 Stm32 有两个高级定时器tim1 tim8 可以输出4组互补型pwm,还可以设定死区时间等,使用上非常方便。

switch(step)
{
case 4: //B+ C-
/* Next step: Step 2 Configuration -------------------------------------- */
TIM_CCxCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCx_Disable);
TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCxN_Disable);

  /*  Channel1 configuration */
  /*  Channel2 configuration */    
  TIM_SetCompare2(BLDC_TIMx,BLDC_TIM_PERIOD);
  TIM_CCxCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCx_Enable);
  /*  Channel3 configuration */
  TIM_SetCompare3(BLDC_TIMx,BLDC_TIM_PERIOD*speed_duty/1000);
  TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCxN_Enable);
  break;
case 5: //B+ A-
  /* Next step: Step 3 Configuration -------------------------------------- */      
  TIM_CCxCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCx_Disable);
  TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCxN_Disable);
  
  /*  Channel1 configuration */
  TIM_SetCompare1(BLDC_TIMx,BLDC_TIM_PERIOD*speed_duty/1000);
  TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCxN_Enable);

  /*  Channel2 configuration */
  TIM_SetCompare2(BLDC_TIMx,BLDC_TIM_PERIOD);
  TIM_CCxCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCx_Enable);
  /*  Channel3 configuration */
  break;
case 1: //C+ A-
  /* Next step: Step 4 Configuration -------------------------------------- */
  TIM_CCxCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCx_Disable);
  TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCxN_Disable);

  /*  Channel1 configuration */
  TIM_SetCompare1(BLDC_TIMx,BLDC_TIM_PERIOD*speed_duty/1000);
  TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCxN_Enable);
  
  /*  Channel2 configuration */ 
  /*  Channel3 configuration */
  TIM_SetCompare3(BLDC_TIMx,BLDC_TIM_PERIOD);
  TIM_CCxCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCx_Enable);
  break;
case 3: //C+ B-
  /* Next step: Step 5 Configuration -------------------------------------- */
  TIM_CCxCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCx_Disable);
  TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCxN_Disable);    

  /*  Channel1 configuration */      
  /*  Channel2 configuration */   
  TIM_SetCompare2(BLDC_TIMx,BLDC_TIM_PERIOD*speed_duty/1000);
  TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCxN_Enable);

  /*  Channel3 configuration */      
  TIM_SetCompare3(BLDC_TIMx,BLDC_TIM_PERIOD);
  TIM_CCxCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCx_Enable);
  break;
case 2: //A+ B-
  /* Next step: Step 6 Configuration -------------------------------------- */
  TIM_CCxCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCx_Disable);
  TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCxN_Disable);
  
  /*  Channel1 configuration */
  TIM_SetCompare1(BLDC_TIMx,BLDC_TIM_PERIOD);
  TIM_CCxCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCx_Enable);
  /*  Channel2 configuration */
  TIM_SetCompare2(BLDC_TIMx,BLDC_TIM_PERIOD*speed_duty/1000);
  TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCxN_Enable);
  /*  Channel3 configuration */
  break;
case 6: //A+ C-
  /* Next step: Step 1 Configuration -------------------------------------- */
  TIM_CCxCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCx_Disable);
  TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCxN_Disable);
  
  /*  Channel1 configuration */
  TIM_SetCompare1(BLDC_TIMx,BLDC_TIM_PERIOD);
  TIM_CCxCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCx_Enable);
  /*  Channel2 configuration */      
  /*  Channel3 configuration */
  TIM_SetCompare3(BLDC_TIMx,BLDC_TIM_PERIOD*speed_duty/1000);
  TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCxN_Enable);
  break;
default:
  TIM_CCxCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCx_Disable);
  TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCxN_Disable);
  TIM_CCxCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCx_Disable);
  TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCxN_Disable);
  TIM_CCxCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCx_Disable);
  TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCxN_Disable);
  break;
}

下图为uvw三相的霍尔检测到的电平及w相的波形。


下图为 uvw三相波形及w相霍尔电平

在这里插入图片描述
下图为 w相电平, w相上臂on 下臂pwm ,w相霍尔信号。

在这里插入图片描述

下图为w相ir2304芯片输出,上臂电压可明显看到已高于vcc,下臂为pwm信号

在这里插入图片描述

在这里插入图片描述
在说说无感模式,由于没有了霍尔,电机无法知道转子当前的位置所以就无法换相,而感应电动势也只有在转起来之后才有,所以无感模式的启动是个难点。
一般方法都是分三段法 ,1 预定位 2 启动 3进入闭环反馈

正如网友说的江湖一层纸,戳破不值半文钱。
1 预定为就是强制给某一相通电一段时间,让电机定位到这个位置。
占空比30-50%不要太大,可能会发热。
2 启动,就是逐步的强制换相,当然要有个加速的过程,使电机转起来。
这个过程太慢会抖动反转,太快会丢步。参数需要一点点试,有点像控制步进电机。要能使电机转的能产生电动势,我也是参照的德国MK 电调的算法
每次延时时间比上一次少1/25,形成一个加速的过程,直到电机完全转起来产生足够的电动势。
3 闭环反馈控制换相跟有感差不多一样。

speed_duty=30; //30% start
BLDC_PHASE_CHANGE(Step[Phase]); //固定一相
Delay_MS(200);

speed_duty=pwm; 
timer = 300;
while(1)
{
    for(i=0;i<timer; i++) 
    {
        Delay_US(120);      //等待
    } 
    timer-= timer/25+1;
    if(timer < 25) 
    {         
        if(TEST_MANUELL)
        {
            timer = 25;   //开环强制换向
        }
        else
        {    
            bldc_dev.motor_state=RUN;
            break; 
        }                
    }    
    Phase++;
    Phase %= 6;    
    BLDC_PHASE_CHANGE(Step[Phase]); //
}

说到感应电动势很多人不明白,先来说说电流,电机线圈的内阻通常很小比如0.2欧,电机的电压比如10v,按理来说电流100a为何电机不烧哪??
其实电机线圈在通电的一瞬间并不是完全导通的,因为有反向电动感应势的存在,可能有-9.8v。10v-9.8v = 0.2v /0.2 = 1A.这样算起来电流还合理。
在说说那个初中学习的法拉第 ,当线圈切割磁场时会产生感应电动势,根据右手定则。。。。。。。。。不懂的自行上网搜。

在这里插入图片描述

如下图当ac相在通电12v的情况下,静止状态下正中间中性点理论为6v,但是转起来就不一定了,因为b相实际是在切割磁场,是会产生电动势的。而电动势的大小正负取决与当前在磁场ns极的位置。当切割ns时为-1,切割sn时为1,平行时为0.

在这里插入图片描述

利用这一特性不就刚好可以获得转子的位置吗?

在这里插入图片描述

首先检测电路网上已经一大很成熟了。
如下图,当然很多时候需要在4.7k对地的电阻上并一个100nf的电容,做一个低通滤波。也可以在软件中做滤波处理。

我们所要做的就是检测这个悬浮相的电动势过零点。
网上常用的两种方法 1 单片机ad采集。2 比较器比较。
我选择了比较器lm339价格已经很便宜了。在高速上比ad有明显优势。
只要比较cin bin ain 与n点的压差即可获得零点。

在这里插入图片描述

在这里插入图片描述

理想很完美,现实很残酷,实际中根本得不到这么完美的波形。
如下图,这个已经是比较好的了,还是有很多毛刺。这个给单片机中断,肯定一大堆问题,严重的换错相烧mos管。

在这里插入图片描述

在这里插入图片描述
为什么会有这些毛刺哪,有些还挺有规律。
参考了网上的介绍,这中间还有一个叫消磁的东西。

在这里插入图片描述
原理不深究了,反正时间很短,软件上做一个滤波消掉就可以了。

进入中断函数后做如下处理 ,定时器的中断我暂时用的20us。

const unsigned int FilterNums = 0xff;
static unsigned int nums =0;
static unsigned int Queue_UStatus =0;
static unsigned int Queue_VStatus =0;
static unsigned int Queue_WStatus =0;
static unsigned char EMF_SVal =0;
unsigned char Filter_U_Status=0;
unsigned char Filter_V_Status=0;
unsigned char Filter_W_Status=0;
unsigned char EMF_Val=0;
unsigned int status_h;
unsigned int status_l;
unsigned int Delay30deg =0;

/* 清除中断标志位 */
if ( TIM_GetITStatus(TIM3 , TIM_IT_Update) != RESET )
{    
TIM_ClearITPendingBit(TIM3 , TIM_FLAG_Update);

    nums++;
//缓存io状态
    Queue_UStatus= Queue_UStatus <<1;//左移
    Queue_VStatus= Queue_VStatus <<1;
    Queue_WStatus= Queue_WStatus <<1;
    
    Queue_UStatus |= EMF_U_STATUS; //赋值
    Queue_VStatus |= EMF_V_STATUS;
    Queue_WStatus |= EMF_W_STATUS;
    
    //连续检测消除杂波
    status_h = Queue_UStatus &FilterNums;
    if(status_h == FilterNums) Filter_U_Status = 1;
    else if(status_h == 0x0) Filter_U_Status = 0;
    else return;

    status_h = Queue_VStatus &FilterNums;
    if(status_h == FilterNums) Filter_V_Status = 1;
    else if(status_h == 0x0) Filter_V_Status = 0;
    else return;
    
    status_h = Queue_WStatus & FilterNums;
    if(status_h == FilterNums) Filter_W_Status = 1;
    else if(status_h == 0x0) Filter_W_Status = 0;
    else return;
    
    //边沿检测
    status_l = UEMF_Edge(Filter_U_Status); //U 检测边沿
    if(status_l == 1) nums =0;          //上升沿
    else if(status_l == 0)            //下降沿
    {
        Delay30deg = nums/4;  
    }
    if(VEMF_Edge(Filter_V_Status))//V 检测边沿
    { nums =0; }
    
    if(WEMF_Edge(Filter_W_Status))//W 检测边沿
    { nums =0; }
    //30度延时换相                        
    if(nums == Delay30deg) 
    {    
        EMF_Val = (Filter_U_Status<<2 )| (Filter_V_Status<<1) |Filter_W_Status;

        if(EMF_SVal == EMF_Val) return;
        EMF_SVal = EMF_Val; //更新值
        
        EMF_EXTI_Callback(EMF_Val);
    }

}

至于网上说检测到过零点后,延时30度换相,对电源效率有影响。我试了下,好像没什么明显的差异。也有人说在大功率的电机下不延时反而更平滑等等。真实怎样有待各位实际实验了。

最后秀几张转起来的照片

在这里插入图片描述

硬盘电机 无感模式

硬盘电机 无感模式

在这里插入图片描述

电动工具电机 有感模式

在这里插入图片描述

加装散热片的样子。
--------------------- 
作者:snail_dongbin 
来源:CSDN 
原文:https://blog.csdn.net/snail_dongbin/article/details/82803076 
版权声明:本文为博主原创文章,转载请附上博文链接!

  • 5
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
BLDC三段式启动是一种用于无霍尔传感器的BLDC电机的启动方法。在这种启动方法中,通过特定的步骤逐渐将电机从停止状态加速到运行状态。引用中提到了BLDC三段式启动的几个步骤: 1. 转子预定位(Rotor Pre-alignment):在这一阶段,电机会先进行转子位置的初始定位。这可以通过给电机施加特定的电流序列来实现,以确定转子位置。 2. 外同步加速(External Synchronization Acceleration):在这一阶段,电机会继续加速,直到达到设定的速度阈值。这可以通过逐渐增加电机的驱动电压来实现。 3. 运行状态切换(Run State Transition):在这一阶段,电机已经加速到设定的速度,并转变为稳定运行状态。在这个阶段,可以根据需要进行一些额外的操作,如调整速度或改变转向等。 BLDC三段式启动的目的是在启动过程中逐渐增加电机的速度和转子位置的准确度,以确保电机能够平稳地运行,并且能够正确地执行所需的任务。这种启动方法通常用于无霍尔传感器的BLDC电机控制系统中,以替代传统的霍尔传感器启动方法。引用中提供了一个可用于STM32F10X系列的BLDC电机驱动控制示波器波形,可以用于验证启动过程中的波形输出是否正确。此外,引用中还提供了一个带有角度闭环控制和速度闭环控制的BLDC电机驱动控制的Simulink仿真模型,可以用于进一步学习和理解BLDC电机的控制原理。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [学习无霍尔传感器的BLDC方波调速记录](https://blog.csdn.net/YCX1227/article/details/109381094)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [反电动势检测BLDC驱动STM32例程](https://download.csdn.net/download/sinat_16137931/10913590)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [BLDC电机控制simulink仿真](https://download.csdn.net/download/weixin_43015338/48944748)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值