无刷直流电机调试问题,跪求大神解答!!!

2019-07-15 14:54发布

电机启动完成停在BC相序就转不动了,P1.3的电压和P5.4的电压基本相同,无法进入比较器中断。下面是程序代码和原理图。
#define MAIN_Fosc                24000000L        //定义主时钟
#include "STC15Fxxxx.H"
//CMPCR1
#define        CMPEN        0x80        //1: 允许比较器, 0: 禁止,关闭比较器电源
#define        CMPIF        0x40        //比较器中断标志, 包括上升沿或下降沿中断, 软件清0
#define        PIE                0x20        //1: 比较结果由0变1, 产生上升沿中断
#define        NIE                0x10        //1: 比较结果由1变0, 产生下降沿中断
#define        PIS                0x08        //输入正极性选择, 0: 选择外部P5.5做正输入,           1: 由ADCIS[2:0]所选择的ADC输入端做正输入.
#define        NIS                0x04        //输入负极性选择, 0: 选择内部BandGap电压BGv做负输入, 1: 选择外部P5.4做输入.
#define        CMPOE        0x02        //1: 允许比较结果输出到P1.2, 0: 禁止.
#define        CMPRES        0x01        //比较结果, 1: CMP+电平高于CMP-,  0: CMP+电平低于CMP-,  只读

//CMPCR2
#define        INVCMPO        0x80        //1: 比较器输出取反,  0: 不取反
#define        DISFLT        0x40        //1: 关闭0.1uF滤波,   0: 允许
#define        LCDTY        0x3F        //, 比较结果变化延时周期数

        sbit PWM2_L = P5^5;
        sbit PWM1_L = P3^6;
        sbit PWM0_L = P3^3;

u8        Step;           //相数
u8        PWM_Value; // 决定PWM占空比的值
bit        B_RUN;                //电机运行标志位
u8        PWW_Set;        //给定占空比
u8        cnt10ms;        //10ms时隙
u8        timeOut;        //堵转超时
u8  FLAG,FLAG2;
unsigned char  buffer[3];                                          
unsigned char rec_flag=0;        //等于0等待接受 等于1正在接受 extern uchar pwm1;

/*************************/
void        Delay_n_ms(u8 dly)
{
        u16        j;
        do
        {
                j = MAIN_Fosc / 13000;        //延时1ms, 主程序在此节拍下运行
                while(--j)        ;
        }while(--dly);
}
void Delay50us()                //@24.000MHz
{
        unsigned char i, j;
        i = 2;
        j = 39;
        do
        {
                while (--j);
        } while (--i);
}
void StepXL(void) // 换相序列函数
{
switch(Step)                                                //连接12V位高端,连接地为低端
  {       
          //CCAP0H表示A相高端
        //CCAP1H表示C相高端
        //CCAP2H表示B相高端
        //PWM1_L-P3.6表示B相低端
        //PWM0_L-P3.3表示A相低端
        //PWM2_L-P5.5表示C相低端
   case 0:  // AB
                           CCAP0H = PWM_Value;        PWM0_L = 1;                   // 打开A相的高端                       
                        CCAP1H = 0;                        PWM2_L = 0;                // 关闭C相
                        CCAP2H = 0xff;                PWM1_L = 0;                // 打开B相的低端
                        ADC_CONTR = 0XED;                        // 选择P1.5作为ADC输入 即c相电压
                        CMPCR1 = 0x9C;                                //下降沿中断
          break;
   case 1:  // AC
                          CCAP0H = PWM_Value;        PWM0_L = 1;                   // 打开A相的高端                       
                        CCAP1H = 0xff;            PWM2_L = 0;                // 打开C相的低端
                        CCAP2H = 0;                        PWM1_L = 0;                // 关闭B相
                        ADC_CONTR = 0XEC;                                        // 选择P1.4作为ADC输入 即B相电压
                        CMPCR1 = 0xAC;                                                //上升沿中断
      break;
   case 2:  // BC                                 
                          CCAP0H = 0;                        PWM0_L = 0;                   // 关闭A相                         
                        CCAP1H = 0xff;            PWM2_L = 0;                // 打开C相的低端
                        CCAP2H = PWM_Value;        PWM1_L = 1;                // 打开B相的高端
                        ADC_CONTR = 0XEB;                                        // 选择P1.3作为ADC输入 即a相电压
                        CMPCR1 = 0x9C;                                                //下降沿中断
      break;
   case 3:  // BA
                          CCAP0H = 0xff;                PWM0_L = 0;                   // 打开A相的低端                       
                        CCAP1H = 0;                    PWM2_L = 0;                // 关闭C相
                        CCAP2H = PWM_Value;        PWM1_L = 1;                // 打开B相的高端
                        ADC_CONTR = 0XED;                                        // 选择P1.5作为ADC输入 即c相电压
                        CMPCR1 = 0xAC;                                                //上升沿中断
      break;
   case 4: // CA
                          CCAP0H = 0xff;                PWM0_L = 0;                   // 打开A相的低端                         
                        CCAP1H = PWM_Value;        PWM2_L = 1;                // 打开C相的高端
                        CCAP2H = 0;                        PWM1_L = 0;                // 关闭B相
                        ADC_CONTR = 0XEC;                                        // 选择P1.4作为ADC输入 即B相电压
                        CMPCR1 = 0x9C;                                                //下降沿中断
      break;
   case 5: // CB
                          CCAP0H = 0;                        PWM0_L = 0;                   // 关闭A相                         
                        CCAP1H = PWM_Value;        PWM2_L = 1;                // 打开C相的高端
                        CCAP2H = 0xff;                PWM1_L = 0;                // 打开B相的低端
                        ADC_CONTR = 0XEB;                                        // 选择P1.3作为ADC输入 即a相电压
                        CMPCR1 = 0xAC;                                                //上升沿中断
          break;
        default:
                break;
  }               
}
void PWM_Init(void)
{
        PWM0_L = 0;
        PWM1_L = 0;
        PWM2_L = 0;
        P3n_push_pull(0x80);
        P1n_push_pull(0x03);
        CMOD = 5 << 1; //选择系统时钟/4为时钟源,即PWM频率=24M/4/256=23.4K
        CL=0;                        // PCA计数器清零
        CH=0;
       
        PCA_PWM0 = 0X00;
        CCAP0H=0;    // 初始化占空比为0%   H的值装载到L中
        CCAP0L=0;
        CCAPM0=0x42;        // 设置为PWM模式
       
        PCA_PWM1 = 0X00;
        CCAP1H=0;    // 初始化占空比为0%
        CCAP1L=0;
        CCAPM1=0x42;        // 设置为PWM模式
       
        PCA_PWM2 = 0X00;
        CCAP2H=0;    // 初始化占空比为0%
        CCAP2L=0;
        CCAPM2=0x42;        // 设置为PWM模式
       
        CR = 1;
}

void ADC_Init(void)
{
        P1M1 |=  0x38;        P1M0 &= 0xC7;          //仅输入
        P1ASF = 0X38; // 开通P1.3 P1.4 P1.5的AD输入口
}

u8 StartMotor(void)
{
        u16 timer,i;
        CMPCR1&=~CMPEN;                                         //禁用比较器`
        PWM_Value = 30;                // 初始占空比=30/256=11.7%
        Step = 0;
        StepXL();                        // 初始位置
        Delay_n_ms(5);                //delay_ms(5);
        timer = 300;

        while(1)                                                                                          //
        {
                for(i=0; i<timer; i++)        Delay50us();  //                 9.6S        --换相时间越来越短,加速过程

                 timer -= timer /15 + 1;  //
                if(timer < 25)        {FLAG=1;return(1);}

                if( Step < 5)        Step++;
                else                        Step = 0;
                StepXL();
        }
}

void UART_init(void)                   //9600bps@24MHz
{
        SCON = 0x50;                        //8位数据,可变波特率
        AUXR |= 0x04;                        //定时器2时钟为Fosc,即1T
        T2L = 0x8F;                                //设定定时初值
        T2H = 0xFD;                                //设定定时初值
        AUXR |= 0x01;                        //串口1选择定时器2为波特率发生器
        AUXR |= 0x10;                        //启动定时器2       
        ES      =   1;                    //允许串口中断
    EA      =   1;                    //开总中断
}

void UART_send_byte(unsigned int bytea)
{
        ES     =   0;  //关串口中断
    TI     =   0;  //清零串口发送完成中断请求标志
    SBUF   =   bytea;
    while(TI ==0); //等待发送完成
    TI     =   1;  //清零串口发送完成中断请求标志
    ES     =   1;  //允许串口中断
}

void Communication_Decode(void)  
{
        if((buffer[0]==0xaa)&&(buffer[2]==0xbb))                 
        {
                PWW_Set=buffer[1];
        }               
        UART_send_byte(PWW_Set);
        UART_send_byte(Step);
        UART_send_byte(FLAG);
        UART_send_byte(FLAG2);
}

void UART_Interrupt_Receive(void) interrupt 4
{       

        static u8 i;
       
   if(RI)
    {
       RI  =   0;
                if(rec_flag==0)         {        if(SBUF==0xff){ rec_flag=1;        i=0; }         }

                else
                {
                        if(SBUF==0xff)                { rec_flag=0; if(i==3){ Communication_Decode();}        i=0;}
                        else          {        buffer[i]=SBUF;        i++; }
                }                                             
    }
    else
    {}               
}

void CMP_INT(void) interrupt 21                                                 //比较器中断
{
        CMPCR1 &= ~CMPIF; // 需软件清除中断标志位           CMPCR1&= 0xbf
        if(Step<5)        Step++;
        else                Step = 0;
        StepXL();
        TimeOut = 10;        //10ms超时
        FLAG2 = 1;
}

void CMP_Init(void)
{
        CMPCR1 = 0;
        CMPCR2 = 0;

//        CMPCR1&=~PIS;                                         //选择外部管脚P5.5(CMP+)为比较器的正极输入源
        CMPCR1|=PIS;                                         //选择ADCIS[2:0]所选的ADCIN为比较器的正端输入源

//        CMPCR1&=~NIS;                                          //选择内部BandGap电压BGV为比较器的负极输入源
        CMPCR1|=NIS;                                         //选择外部引脚P5.4(CMP-)为比较器的负极输入源

        CMPCR1&=~CMPOE;                                         //禁用比较器的比较结果输出
//        CMPCR1|=CMPOE;                                         //使能比较器的比较结果输出到P1.2
                 
        CMPCR2&=~INVCMPO;                                 //比较器结果正常输出到P1.2
//        CMPCR2|=INVCMPO;                                 //比较器结果取反输出到P1.2
                 
        CMPCR2&=~DISFLT;                                 //使能比较器输出端的0.1us滤波电路
//        CMPCR2|=DISFLT;                                         //禁用比较器输出端的0.1us滤波电路
                         
//        CMPCR2&=~LCDTY;                                         //比较器结果不去抖动,直接输出
        CMPCR2|=(DISFLT&0x3C);                         //比较器经过60个时钟后再输出



        CMPCR1|=PIE;                                         //上升沿中断                                                
//        CMPCR1|=NIE;                                         //下降沿中断

//        CMPCR1|=CMPEN;                                         //使能比较器
        CMPCR1&=~CMPEN;                                         //禁用比较器

        EA=1;
}
/**********************************************/
void main(void)
{
        FLAG = 0;
        FLAG2= 0;
        PWM_Init();
        ADC_Init();
        CMP_Init();
        UART_init();

        PWW_Set = 0;                                 //占空比预设值为0
        cnt10ms = 0;                                 //
        TimeOut = 0;                                 //清除time溢出标志

        EA  = 1;                                          // 打开总中断
       
        while (1)
        {
        Delay_n_ms(1);                                  //延时1ms, 主程序在此节拍下运行

                if(TimeOut > 0)                         ///溢出
                {
                        if(--TimeOut == 0)         //堵转超时
                        {
                                CCAP0H=0;        CCAP1H=0;        CCAP2H=0;  // 占空比为0
                                PWM0_L=0;        PWM1_L=0;        PWM2_L=0;
                                CMPCR1&=~CMPEN;                                         //禁用比较器
                                Delay_n_ms(250);        //堵转时,延时1秒再启动
                                Delay_n_ms(250);
                                Delay_n_ms(250);
                                Delay_n_ms(250);
                                PWW_Set   = 0;
                                PWM_Value = 0;
                                B_RUN  = 0;
                                TimeOut = 0;
                        }
                }                                                                                                                         //此时TimeOut为0

                if(!B_RUN && (PWW_Set >= 30))                // PWM_Set >= 30, 并且马达未运行, 则启动马达
                {
                        StartMotor();                                        // 启动马达
                        CMPCR1 &= ~0X40;                                 // 需软件清除中断标志位
                        CMPCR1|=CMPEN;                                        //使能比较器
                        B_RUN = 1;
                        TimeOut = 0;
                }
               
                if(++cnt10ms >= 10)                                        // 10ms时隙
                {
                        cnt10ms = 0;
                        if(B_RUN)
                        {
                                if(PWM_Value < PWW_Set)        PWM_Value++;
                                if(PWM_Value > PWW_Set)        PWM_Value--;
                                if(PWM_Value < 20)        // 停转
                                {
                                        PWM_Value = 0;
                                        B_RUN = 0;
                                        CCAP0H=0;        CCAP1H=0;        CCAP2H=0;  // 占空比为0
                                        PWM0_L=0;        PWM1_L=0;        PWM2_L=0;
                                        CMPCR1&=~CMPEN;                                         //禁用比较器
                                }
                        }
                }
        }
}



图片1.png
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
5条回答
WAITXHURT
2019-07-15 18:54
你提供的信息太少了,很难精确判断,如什么电机?极对数?是否带载?BEMF是否正常?启动失败时转子运转正常?
根据你的程序猜测你用的是航模电机,初始速度偏高,这样就使励磁电流要大,也就是pwm开通大,如果跟不上,就会导致失步,甚至只是转子振动,仔细调整定位pwm,初始速度,加速曲线这几个参数,还有,没看到你开环启动后进入闭环的代码,也没打开BEMF中断检测


QQ截图20160302094837.png

一周热门 更多>