打印
[应用方案]

成熟的Mini5D直流无刷电机代码——节省研发时间

[复制链接]
3984|18
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
iwqt1983|  楼主 | 2017-3-25 14:26 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 iwqt1983 于 2017-3-25 14:27 编辑

成熟的Mini5D直流无刷电机代码——节省研发时间

采用的芯片是MINI58ZDE。源代码: Mini5D_fly.zip (143.15 KB)



可以到立创商城上采购, 才3元出头一片,性价比很高的。

http://www.nuvoton-m0.com/forum. ... age=1&extra=#pid144

成熟的Mini5D直流无刷电机代码——节省研发时间 [复制链接]
电梯直达
跳转到指定楼层 楼主
Angus 发表于 2013-12-23 15:55:08 | 只看该作者 |只看大图 回帖奖励
本帖最后由 Angus 于 2017-3-22 10:03 编辑


特性简介 :  启转很顺,加速很快, 输出短路不烧功率管, 适用于各种 BLDC
1>,可实现多种方式的 无霍尔 BLDC 控制,在 航模、吸尘器、电动扳手、割草机、电锯 等领域已有量产案例。
2>,启用 Brake 功能,过流立即关断MOS。经测试,即使在电机转动时短接输出,也不会烧功率管
3>,PWM 触发 ADC, 同步测量瞬间电流,实时监控电流峰值和平均值, 给 MOS 最及时的保护
4>,电机转动时,PWM 频率也可以随时改变
5>,120度方波、150 度方波,随时转换,非常简单
6>,上 MOS 做 PWM, 下 MOS 做 PWM, 还是上下轮换做 PWM, 改一个变量——"相指针偏移值"就可随时转换
7>,无霍尔转动、有霍尔转动,随时转换。 比如低速按霍尔转,高速无霍尔模式转。
8>,适用于各种驱动电路。配置时调一个函数,即可改变输出极性,以适用于各种驱动电路。
       代码已含有 PPM 校正,电机蜂鸣、调速或稳速等部分,为便于理解整体思路,尽量简化,不常用的功能代码中已略去, 若需要请咨寻芯唐。

Mini5xxD 版芯片特有功能:
1>写一个寄存器完成“PWM引脚切换+ GPIO口输出值改变 + 模拟比较器输入引脚切换”。
2>定时器溢出时,有自动换相功能。
芯唐BLDC方案 Mini5D 代码   Mini5D_fly.zip (143.15 KB, 下载次数: 10749) ,上电即以20%电压转动便于测试,注释掉 161 行才接受PPM调速

如何不烧功率管
    首先要保证不过压,不过流,不过热。这三点我就不细说了。我这里要说的是,要仔细考滤每一个细节。比如上电配置阶段,如果把引脚先配置为输出模式(写 PMD ), 再写输出值(DOUT),有没有想到,把引脚配置为输出模式时,输出缺省值1立即从引脚输出(然后再改写输出值),这里会不会让功率管短时间导通? 会产生一个大电流冲击或者烧管子吗?
     再比如启转的时候,写 PWM 占空比值,再让功率管导通,让电机动起来,占空比值写入后,要下一个周期约几十微秒后才会有效,功率管导通的第一个 PWM 周期,会不会占空比很大, 会有大电流冲击吗 ?   另外,启转时自举电容有电吗? 上功率管能良好导通吗?
    普通的数字电子设备,毫秒级时间的信号不对,都不会有大电流,也就不会对电路造成损害。而对电机控制来说,几微秒的信号不对,可能都会烧掉功率管。
      细节决定好坏! 我们这套代码,经过长期优化和测试,到目前为止,细节考滤很周到,可以节省你很多思考、研发和测试的时间!

代码总体思路解说:http://www.nuvoton-m0.com/forum. ... 1458&extra=page%3D1
启转的解说:http://www.nuvoton-m0.com/forum. ... 1593&extra=page%3D1
高压 BLDC 原理图   Mini5D_BLDC.pdf (56.26 KB, 下载次数: 7808) 短路保护电路,  测电流等,不用可去掉。ACMP1检过零, 有更多 ADC 可用。
  
Mini51ZDE 电调——启转快,转速高,最高电转速 30万转以上
  



Mini52LDE 电动工具——低速按霍尔转,速度再低转矩不反;  高速无霍尔转,消除霍尔偏差
  



310V (220V的峰值)高压,无霍尔 BLDC 控制器——PWM1 控制过零分压比,启转效果最佳
  


48V BLDC 控制器, 启用 Brake 功能,转动时输出线短路,功率管也不会烧。
  



25.7万转/分, 高速时的电压波形
  



转动中, 变为互补模式——下MOS 同步整流MOS发热变小,同时减速较快
  



转动中断电, 又突然加电压的波形
  



4转/秒, 低速下的波形
  
   



上臂做 PWM 的电机端电压波形, 适用于高压BLDC
  



下臂做 PWM 波形, 下臂开关速度快
  



上下臂轮流做 PWM 的电机端波形, 上下MOS发热均衡
  



沙发
yiyigirl2014| | 2017-3-25 14:58 | 只看该作者
#include  "Mini5D_BLDC_V16.h"
#include  "Mini5D_BLDC.h"               

uint32_t  volatile Duty_Command ;                          // 调速旋钮要求的占空比,范围 0 ~ CNR
uint32_t  volatile Pulse_Current ;                         // PPM 当前值,P3.6中断代码里得到这个值
uint32_t  volatile PulseTick ;                             // PPM 上沿时刻
uint32_t           Pulse_Min    = 1000 ;                   // PPM 最小值,缺省1000us
uint32_t           Pulse_Length = 1000 ;                   // PPM 最大值与最小值的差
////=====================================================================================            
////UART0 Initial ///////////////////////////////////////////////////////////////////////
void UART0_Init(uint32_t Baud)                  
{
  UART0->FUN_SEL = 0  ;                                    //UART 模式
  UART0->LCR     = 0x0007 ;                                //8bit, 2-stop, no parity
  UART0->BAUD    = 0x30000000 + 22118400/Baud - 2 ;        //UART 时钟 22M
  UART0->FCR     = 0x00020020 ;                            //RTS trigger:8, FIFO trigger:8 BYTE
  UART0->IER     = 0 ;                                   
}
/////////////////////////////////////////////////////////////////////////////////////////
// Configure P2.23456 & P0.4 as PWM function pin.  configure P1.0345 as ACMP input pin
void GPIO_Init(void)
{                                          // P01配置成OUT模式,才能由PHCHG控制,QB模式不行      
                                   // P0.014567六个, DOUT的初值在函数PWM_ACMP0_T0_T1_Init()中配置
  GPIO0->PMD  = Px7_QB | Px6_QB | Px5_QB | Px1_OUT | Px0_OUT ;   // P0.1 可以为 A-
  GCR->P0_MFP = 0xF010 ;                                         // P0.4_PWM5, P0.0567_SPI
                                
  GPIO1->DOUT = 0 ;
  GPIO1->PMD  = Px5_OUT | Px4_OUT |Px3_OUT | Px2_OUT | Px0_OUT ; // P1.02345 五个
  GPIO1->OFFD = 0x00FF0000 ;                               // 数字输入通道全关闭
  GCR->P1_MFP = 0x303D ;                                   // P1.023_ADC123, P1.45_ACMP0
                                   // GPIO2->DOUT 的初值在函数PWM_ACMP0_T0_T1_Init()中配置
  GPIO2->PMD  = Px6_OUT | Px5_OUT | Px4_OUT | Px3_OUT | Px2_OUT ;   
  GCR->P2_MFP = 0x7C00 ;                                   // P2.23456,五个,PWM01234

  GPIO3->DOUT = 0xFF ;                                     // P3.012456 六个
  GPIO3->OFFD = 0x00BF0000 ;                               // 只接通36的数字输入通道
  GPIO3->PMD  = Px6_QB  ;                                  // P3.0245_CMP1,P3.6_T1EX,P3.1_ADC7  
  GCR->P3_MFP = 0x01003376 ;                                 

  GPIO4->DOUT = 0xFF ;
  GPIO4->PMD  = Px7_QB | Px6_QB ;                          // P4.67,ICE接口
  GCR->P4_MFP = 0 ;                                

  GPIO5->DOUT = 0xFF ;                                     // P5.012345 六个,(QFN33没有P5.5)
  GPIO5->PMD  = Px5_QB | Px4_QB | Px2_QB | Px1_QB | Px0_QB ;   
  GCR->P5_MFP = 0x0008 ;                                   // P5.3_ADC0
   
  GPIO3->ISR  = 0xFF ;                                     // Clear ISR  
  GPIO3->IMD  = 0 ;                                        // Edge interrupt mode
  GPIO3->IER  = 0x00400040 ;                               // 位16~23上沿使能,0~7下沿中断使能
  GPIO3->DBEN = 0x40 ;                                     // 1 mean De-bounce
  GPIODBNCE   = 0x2B ;                                                                   // De-bounce time = 2048HCLK

  NVIC_SetPriority(GPIO234_IRQn, 2);                       // Interrupt priority = 2
  NVIC->ISER[0] = 1<<GPIO234_IRQn ;                                                            
  
  GPIO5->ISR  = 0xFF ;                                     // Clear ISR  
  GPIO5->IMD  = 0 ;                                        // Edge interrupt mode
  GPIO5->IER  = 0x00000004 ;                               // 位16~23上沿使能,0~7下沿中断使能
  GPIO5->DBEN = 0x04 ;                                     // P5.2 Enable De-bounce

  NVIC_SetPriority(EINT1_IRQn, 2) ;                        // Interrupt priority = 2
//  NVIC->ISER[0] = 1<<EINT1_IRQn ;                        // 按键
}
//=======================================================================================
// MAIN function                                                               
//---------------------------------------------------------------------------------------
int main(void)
{  
  uint32_t   Adc_Vin, Adc_Tempera, temp32, LastDuty = ~0 ;
   
  PWM_ACMP0_T0_T1_Init() ;      
  ADC->CR     = ADCR_EN ;                                  // 尽早使能ADC,需100us稳定
  ADC->ADSAMP = 4 ;                                        // 采样时间 1+8CLK
  ADC->ADTDCR = 0 ;                                 
                 //PWM频率: 5=22.1KHz, 6=18.4KHz, 7=15.8KHz, 8=13.8KHz, 10=11KHz, 14=7.9K
  PWM_one_percent = 10 ;                                                     
  PWM->CNR0       = 100*PWM_one_percent - 1 ;              // 设置 PWM 周期, PWM 时钟 11.0592MHz                 
  PWM->CNR1       = 100*PWM_one_percent - 1 ;                     
  Duty_Min        =   9*PWM_one_percent ;                  // 电压小于Duty_Min停转
       
//  UART0_Init(115200) ;
  GPIO_Init() ;         
  // 检测 BOD 电压是否配置为 3.7V 以下保持复位 //////////////////////////////////////////
  CLK->AHBCLK |= CLK_ISP_EN ;
  FMC->ISPCON |= FMC_CFGUEN | FMC_EN_ ;
  FMC->ISPADR  = 0x00300000 ;                              // Config0
  FMC->ISPCMD  = FMC_READ_0 ;                              // Read config0
  FMC->ISPTRG  = 1 ;
  while(FMC->ISPTRG & 1) ;
  temp32 = FMC->ISPDAT ;
  if((temp32 & 0x00F004C1) != 0x00400481){           
    FMC->ISPCMD = FMC_ERASE ;   
    FMC->ISPTRG = 1 ;
    while(FMC->ISPTRG & 1) ;
    FMC->ISPDAT = (temp32 & 0xFF0FFF3F) | 0x00400481 ;     // 把 BOD 电压写成 3.7V 以下复位
    FMC->ISPCMD = FMC_WRITE ;                              
    FMC->ISPTRG = 1 ;
    while(FMC->ISPTRG & 1) ;
    GCR->IPRST_CTL1 = 1 ;                                  // 芯片复位
  }
  FMC->ISPCON &= ~(FMC_CFGUEN | FMC_EN_) ;
  CLK->AHBCLK &= ~CLK_ISP_EN ;  
  LOCKREG();  
  ///////////////////////////////////////////////////////////////////////////////////////
  gFlag     = 0 ;                                          // 清0标志
  ACMP_Flag = 0 ;                                          
  TIMER1->EXCON = TEX_DEBO_EN |TEX_EN | TEX_CAP_FALL_RISE; // 开始捕获速度脉冲
  Duty_Current  = 15*PWM_one_percent ;                     
  Motor_Beep(50*1000,900) ;  ++pPhase ;                    // AB 蜂鸣 50ms
  Motor_Beep(50*1000,800) ;                                // AC 蜂鸣
  if(Pulse_Current > 1600){                                // 一上电 >60% 认为推杆已推到最高
    Pulse_Length = Pulse_Current ;
    while(Pulse_Current > 1400) ;                          // 等推杆到40%以下
    Delayus(500*1000) ;                                    // 再等半秒
    Motor_Beep(50*1000,900) ;
    Pulse_Min    = Pulse_Current ;  
    Pulse_Length = Pulse_Length - Pulse_Min - 50 ;         // 推杆最大值减最小值
    Motor_Beep(50000,800) ;                              
  }
  Pulse_Length = ((100*PWM_one_percent)<<16)/Pulse_Length; // 得到 PPM 校正系数
  Motor_Beep(50000,600) ;                                 

  ///////////////////////////////////////////////////////////////////////////////////////                                                                                    
  ADC->SR |= ADSR_ADF ;
  NVIC_SetPriority(ADC_IRQn, 0) ;                          // 最高优先级, 及时处理过流情况      
  NVIC->ISER[0] = 1 << ADC_IRQn ;              
  ADC->CR |= ADCR_PWM_TRG | ADCR_TRG_EN ;                  // 启动ADC,若要ADC限流功能要使能ADC中断
  while(1){
    //// 测旋钮,温度,电压,电流 ==========================================================
    temp32 = ADC->DR ;   
    if(temp32 & 0x20000){          // ADC数据有效,读清0,防真打开ADC寄存器窗时,可能会被防真器清0  
      temp32 &= 0x03FF ;
      switch(ADC->CHER & 0xFF){  
        case ADC2_VIN :
          Adc_Vin = (Adc_Vin + temp32) >> 1 ;              // 相当于低通滤波器                                      

          ADC->CHER = ADC3_TEMP ;                                      
          break ;  
        
        case ADC3_TEMP :
          Adc_Tempera = (Adc_Tempera + temp32) >> 1 ;  
                                                  
        default :                                          
          ADC->CHER = ADC2_VIN ;              
      }
    }
    ////=================================================================================
    if(gFlag & Flag_PPM_OK){ gFlag &= ~Flag_PPM_OK ;                    // 有PPM信号, 更新占空比     
      if(Pulse_Current <= Pulse_Min) Duty_Command = 0 ;
      else Duty_Command=((Pulse_Current - Pulse_Min)*Pulse_Length)>>16; // 变到 0 ~ CNR0左右   
      Duty_Target = Duty_Command ;   
    }
    else{
      temp32 = PulseTick ;
      if(((TIMER1->DR - temp32)&0xFFFFFF) > 3000*1000){    // 3 秒无 PPM 调速信号
        PulseTick   = TIMER1->DR ;
        Duty_Target = (Duty_Target*7) >> 3 ;               // 目标占空比降为 87.5%
      }
    }       
    Duty_Target = 20*PWM_one_percent ;                     // 用于测试
   
    if((LastDuty ==0)&&(Duty_Target)){                           // 突然加电
      if(PeriodNow > 3000) BLDC_Start(PeriodMax, 0);       // 快速调整速度
      if(Duty_Current < Duty_Min) Duty_Current = Duty_Min ;                                              
    }
    LastDuty = Duty_Target ;   
       
    BLDC_Control() ;       // BLDC监控函数: 控制BLDC的启转、停转, 并调整输出电压、导通角、输出方式  
    ////===== 其它任务放此 ==============================================================
  }
}

void GPIO234_IRQHandler(void)                              // 调速脉宽测量  
{                                                         
  uint32_t temp32 ;                                    
  
//  if(GPIO3->ISR & 0x40){                                 // GPIO234无其它中断,此句略
    if(GPIO3->PIN & 0x40) PulseTick = TIMER1->CAP ;        // PPM 上沿时刻
    else{
      temp32 = ((TIMER1->CAP - PulseTick)&0xFFFFFF) ;      // PPM 宽度,微秒数
      if(temp32 < 2500){Pulse_Current = temp32; gFlag |= Flag_PPM_OK; }         
    }
    TIMER1->EXISR = ~0 ;                                   // 清中断标志
//  }       //  End of "if(GPIO3->ISR & 0x40)"
  GPIO3->ISR = ~0 ;                                        // 清中断标志
}

void SysTick_Handler(void)                                 // 100ms 中断一次
{       
  ++TickRelay ;
#if 0                                                             // 打印速度信息
  {
    uint32_t static Cnt = 0, flag = 0 ;
    uint8_t  str[] = "Duty=   %         rpm\n\r" ;
      
    if(++Cnt >= 5){  Cnt = 0 ; flag ^= 1 ;                 // 0.1s X 5 =0.5S
      if(flag == 0){  
        HexToStr(60000000/PeriodAvg, &str[16]) ;           // 转速转换成字符
        Tx0FillFiFo(&str[10],13) ;                         // Tx0 写入 13 个字符
      }
      else{  
        HexToStr(PWM->CMR0/PWM_one_percent, &str[7]) ;     // 占空比转换成字符
        Tx0FillFiFo(str,10) ;                              // Tx0 写入 10 个字符
      }
    }      
  }
#endif       
}

使用特权

评论回复
板凳
yiyigirl2014| | 2017-3-25 14:59 | 只看该作者
这个太难得了,果断撸了。

使用特权

评论回复
地板
zhuomuniao110| | 2017-3-25 17:34 | 只看该作者
好代码,中文注释,再也不担心看不懂学不会了。

使用特权

评论回复
5
huangcunxiake| | 2017-3-25 22:09 | 只看该作者
适用于各种驱动电路。配置时调一个函数,即可改变输出极性,以适用于各种驱动电路。

使用特权

评论回复
6
天灵灵地灵灵| | 2017-3-25 22:31 | 只看该作者
要保证不过压,不过流,不过热。很对。

使用特权

评论回复
7
wt.liu| | 2017-3-25 23:26 | 只看该作者
好应用!

使用特权

评论回复
8
玛尼玛尼哄| | 2017-3-25 23:52 | 只看该作者
mini都可以跑这么牛的算法。

使用特权

评论回复
9
hameyou| | 2017-3-26 00:29 | 只看该作者
不错,无刷电机驱动,收藏了!

使用特权

评论回复
10
shcshc1234| | 2017-3-26 14:16 | 只看该作者
mark~

使用特权

评论回复
11
heisexingqisi| | 2017-3-26 16:48 | 只看该作者
第一个PWM周期是个研究问题。

使用特权

评论回复
12
天凉好个秋| | 2017-5-9 17:38 | 只看该作者
资料很好,请问楼主,有没有做好的板子供学习学习

使用特权

评论回复
13
zhuotuzi| | 2017-5-13 23:42 | 只看该作者
看到官方都提供了mini51的电机驱动方式的方案,应该很给力。

使用特权

评论回复
14
yiyigirl2014| | 2017-5-14 15:42 | 只看该作者
非常实用的,搭建了电路测试,棒极了。

使用特权

评论回复
15
mycdh| | 2017-5-23 15:54 | 只看该作者
楼主位给的链接怎么都打不开了?

使用特权

评论回复
16
734774645| | 2017-5-23 22:35 | 只看该作者
好东西,资料代码还是中文注释。

使用特权

评论回复
17
suxiaowei| | 2018-10-15 18:14 | 只看该作者
这个不错,新唐老是搞的很神秘啊,资料都不公开

使用特权

评论回复
18
888WWW| | 2020-5-28 10:31 | 只看该作者
不错,学习,感谢楼主

使用特权

评论回复
19
jerow| | 2020-5-28 22:16 | 只看该作者
从头到尾,介绍的都很详细,果断支持。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

21

主题

316

帖子

5

粉丝