[应用方案]

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

[复制链接]
3434|18
手机看帖
扫描二维码
随时随地手机跟帖
iwqt1983|  楼主 | 2017-3-25 14:26 | 显示全部楼层 |阅读模式
本帖最后由 iwqt1983 于 2017-3-25 14:27 编辑

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

采用的芯片是MINI58ZDE。源代码: Mini5D_fly.zip (143.15 KB)
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 | 显示全部楼层
好代码,中文注释,再也不担心看不懂学不会了。

使用特权

评论回复
huangcunxiake| | 2017-3-25 22:09 | 显示全部楼层
适用于各种驱动电路。配置时调一个函数,即可改变输出极性,以适用于各种驱动电路。

使用特权

评论回复
天灵灵地灵灵| | 2017-3-25 22:31 | 显示全部楼层
要保证不过压,不过流,不过热。很对。

使用特权

评论回复
wt.liu| | 2017-3-25 23:26 | 显示全部楼层
好应用!

使用特权

评论回复
玛尼玛尼哄| | 2017-3-25 23:52 | 显示全部楼层
mini都可以跑这么牛的算法。

使用特权

评论回复
hameyou| | 2017-3-26 00:29 | 显示全部楼层
不错,无刷电机驱动,收藏了!

使用特权

评论回复
shcshc1234| | 2017-3-26 14:16 | 显示全部楼层
mark~

使用特权

评论回复
heisexingqisi| | 2017-3-26 16:48 | 显示全部楼层
第一个PWM周期是个研究问题。

使用特权

评论回复
天凉好个秋| | 2017-5-9 17:38 | 显示全部楼层
资料很好,请问楼主,有没有做好的板子供学习学习

使用特权

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

使用特权

评论回复
yiyigirl2014| | 2017-5-14 15:42 | 显示全部楼层
非常实用的,搭建了电路测试,棒极了。

使用特权

评论回复
mycdh| | 2017-5-23 15:54 | 显示全部楼层
楼主位给的链接怎么都打不开了?

使用特权

评论回复
734774645| | 2017-5-23 22:35 | 显示全部楼层
好东西,资料代码还是中文注释。

使用特权

评论回复
suxiaowei| | 2018-10-15 18:14 | 显示全部楼层
这个不错,新唐老是搞的很神秘啊,资料都不公开

使用特权

评论回复
888WWW| | 2020-5-28 10:31 | 显示全部楼层
不错,学习,感谢楼主

使用特权

评论回复
jerow| | 2020-5-28 22:16 | 显示全部楼层
从头到尾,介绍的都很详细,果断支持。

使用特权

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

本版积分规则

21

主题

315

帖子

5

粉丝