×

使用STC8H1K28-LQFP32来驱动无刷三相直流电机

消耗积分:0 | 格式:zip | 大小:0.00 MB | 2023-02-22

xjbworld278

分享资料个


/*---------------------------------------------------------------------*/
/* --- STC MCU International Limited ----------------------------------*/
/* --- STC 1T Series MCU Demo Programme -------------------------------*/
/* --- Mobile: 13922805190 --------------------------------------------*/
/* --- Fax: 0513-55012956,55012947,55012969 ---------------------------*/
/* --- Tel: 0513-55012928,55012929,55012966 ---------------------------*/
/* --- Web: www.GXWMCU.com   www.stcmcu.com ---------------------------*/
/* --- QQ:  800003751 -------------------------------------------------*/
/* 如果要在程序中使用此代码,请在程序中注明使用了宏晶科技的资料及程序   */
/*---------------------------------------------------------------------*/


/*************    功能说明    **************

本程序试验使用STC8H1K28-LQFP32来驱动带霍尔传感器的无刷三相直流电机.

PWM的捕捉中断功能用来检测霍尔信号.
P0.3接的电位器控制转速, 处于中间位置为停止, 逆时针旋转电位器电压降低电机为逆时针转, 顺时针旋转电位器电压升高电机为顺时针转.
关于带霍尔传感器三相无刷直流电机的原理, 用户自行学习了解, 本例不予说明.

******************************************/


#define MAIN_Fosc        24000000L    //定义主时钟

#include    "STC8Hxxx.h"


#define ADC_START    (1<<6)    /* 自动清0 */
#define ADC_FLAG    (1<<5)    /* 软件清0 */

#define    ADC_SPEED    1        /* 0~15, ADC时钟 = SYSclk/2/(n+1) */
#define    RES_FMT        (1<<5)    /* ADC结果格式 0: 左对齐, ADC_RES: D9 D8 D7 D6 D5 D4 D3 D2, ADC_RESL: D1 D0 0  0  0  0  0  0 */
                            /*             1: 右对齐, ADC_RES: 0  0  0  0  0  0  D9 D8, ADC_RESL: D7 D6 D5 D4 D3 D2 D1 D0 */

#define CSSETUP        (0<<7)    /* 0~1,  ADC通道选择时间      0: 1个ADC时钟, 1: 2个ADC时钟,  默认0(默认1个ADC时钟) */
#define CSHOLD        (1<<5)    /* 0~3,  ADC通道选择保持时间  (n+1)个ADC时钟, 默认1(默认2个ADC时钟)                */
#define SMPDUTY        20        /* 10~31, ADC模拟信号采样时间  (n+1)个ADC时钟, 默认10(默认11个ADC时钟)                */
                            /* ADC转换时间: 10位ADC固定为10个ADC时钟, 12位ADC固定为12个ADC时钟.                 */

sbit PWM1   = P1^0;
sbit PWM1_L = P1^1;
sbit PWM2   = P1^2;
sbit PWM2_L = P1^3;
sbit PWM3   = P1^4;
sbit PWM3_L = P1^5;

u8    step;        //切换步骤
u8    PWM_Value;    // 决定PWM占空比的值
bit    B_RUN;        //运行标志
u8    PWW_Set;    //目标PWM设置
u8    YouMen;        //油门
bit    B_direct;    //转向, 0顺时针, 1逆时针
bit    B_4ms;        //4ms定时标志


/*************************/


//========================================================================
// 函数: u16    Get_ADC10bitResult(u8 channel))    //channel = 0~15
//========================================================================
u16    Get_ADC10bitResult(u8 channel)    //channel = 0~15
{
    u8 i;
    ADC_RES = 0;
    ADC_RESL = 0;
    ADC_CONTR = 0x80 | ADC_START | channel; 
    NOP(5);            //
    i = 255;        //超时限制
    while(i != 0)
    {
        i--;
        if((ADC_CONTR & ADC_FLAG) != 0)    break;    //等待ADC结束
    }
    ADC_CONTR &= ~ADC_FLAG;
    return    ((u16)ADC_RES * 256 + (u16)ADC_RESL);
}


void    Delay_500ns(void)
{
    NOP(6);
}

void StepMotor(void) // 换相序列函数
{
    PWMB_IER   = 0;
    PWMB_CCER1 = 0;
    PWMB_CCER2 = 0;

    step = P2 & 0x07;    //P2.0-HALL_A P2.1-HALL_B P2.2-HALL_C
    if(!B_direct)    //顺时针
    {
        switch(step)
        {
        case 2:  // 010, P2.0-HALL_A下降沿  PWM3, PWM2_L=1        //顺时针
                PWMA_ENO = 0x00;    PWM1_L=0;    PWM3_L=0;
                Delay_500ns();
                PWMA_ENO = 0x10;    // 打开C相的高端PWM
                PWM2_L = 1;            // 打开B相的低端
                PWMB_CCER2 = (0x01+0x00);    //P2.2 0x01:允许输入捕获, +0x00:上升沿, +0x02:下降沿
                PWMB_IER   = 0x08;            //P2.2 使能中断
                break;
        case 6:  // 110, P2.2-HALL_C上升沿  PWM3, PWM1_L=1
                PWMA_ENO = 0x10;    PWM2_L=0;    PWM3_L=0;    // 打开C相的高端PWM
                Delay_500ns();
                PWM1_L = 1;            // 打开A相的低端
                PWMB_CCER1 = (0x10+0x20);    //P2.1 0x10:允许输入捕获, +0x00:上升沿, +0x20:下降沿
                PWMB_IER   = 0x04;            //P2.1 使能中断
                break;
        case 4:  // 100, P2.1-HALL_B下降沿  PWM2, PWM1_L=1
                PWMA_ENO = 0x00;    PWM2_L=0;    PWM3_L=0;
                Delay_500ns();
                PWMA_ENO = 0x04;    // 打开B相的高端PWM
                PWM1_L = 1;            // 打开A相的低端
                PWMB_CCER1 = (0x01+0x00);    //P2.0 0x01:允许输入捕获, +0x00:上升沿, +0x02:下降沿
                PWMB_IER   = 0x02;            //P2.0 使能中断
                break;
        case 5:  // 101, P2.0-HALL_A上升沿  PWM2, PWM3_L=1
                PWMA_ENO = 0x04;    PWM1_L=0;    PWM2_L=0;    // 打开B相的高端PWM
                Delay_500ns();
                PWM3_L = 1;            // 打开C相的低端
                PWMB_CCER2 = (0x01+0x02);    //P2.2 0x01:允许输入捕获, +0x00:上升沿, +0x02:下降沿
                PWMB_IER   = 0x08;            //P2.2 使能中断
                break;
        case 1:  // 001, P2.2-HALL_C下降沿  PWM1, PWM3_L=1
                PWMA_ENO = 0x00;    PWM1_L=0;    PWM2_L=0;
                Delay_500ns();
                PWMA_ENO = 0x01;    // 打开A相的高端PWM
                PWM3_L = 1;            // 打开C相的低端
                PWMB_CCER1 = (0x10+0x00);    //P2.1 0x10:允许输入捕获, +0x00:上升沿, +0x20:下降沿
                PWMB_IER   = 0x04;            //P2.1 使能中断
                break;
        case 3:  // 011, P2.1-HALL_B上升沿  PWM1, PWM2_L=1
                PWMA_ENO = 0x01;    PWM1_L=0;    PWM3_L=0;    // 打开A相的高端PWM
                Delay_500ns();
                PWM2_L = 1;            // 打开B相的低端
                PWMB_CCER1 = (0x01+0x02);    //P2.0 0x01:允许输入捕获, +0x00:上升沿, +0x02:下降沿
                PWMB_IER   = 0x02;            //P2.0 使能中断
                break;

        default:
                break;
        }
    }

    else    //逆时针
    {
        switch(step)
        {
        case 4:  // 100, P2.0-HALL_A下降沿  PWM1, PWM2_L=1        //逆时针
                PWMA_ENO = 0x00;    PWM1_L=0;    PWM3_L=0;
                Delay_500ns();
                PWMA_ENO = 0x01;    // 打开A相的高端PWM
                PWM2_L = 1;            // 打开B相的低端
                PWMB_CCER1 = (0x10+0x00);    //P2.1 0x10:允许输入捕获, +0x00:上升沿, +0x20:下降沿
                PWMB_IER   = 0x04;            //P2.1 使能中断
                break;
        case 6:  // 110, P2.1-HALL_B上升沿  PWM1, PWM3_L=1
                PWMA_ENO = 0x01;    PWM1_L=0;    PWM2_L=0;    // 打开A相的高端PWM
                Delay_500ns();
                PWM3_L = 1;            // 打开C相的低端
                PWMB_CCER2 = (0x01+0x02);    //P2.2 0x01:允许输入捕获, +0x00:上升沿, +0x02:下降沿
                PWMB_IER   = 0x08;            //P2.2 使能中断
                break;
        case 2:  // 010, P2.2-HALL_C下降沿  PWM2, PWM3_L=1
                PWMA_ENO = 0x00;    PWM1_L=0;    PWM2_L=0;
                Delay_500ns();
                PWMA_ENO = 0x04;    // 打开B相的高端PWM
                PWM3_L = 1;            // 打开C相的低端
                PWMB_CCER1 = (0x01+0x00);    //P2.0 0x01:允许输入捕获, +0x00:上升沿, +0x02:下降沿
                PWMB_IER   = 0x02;            //P2.0 使能中断
                break;
        case 3:  // 011, P2.0-HALL_A上升沿  PWM2, PWM1_L=1
                PWMA_ENO = 0x04;    PWM2_L=0;    PWM3_L=0;    // 打开B相的高端PWM
                Delay_500ns();
                PWM1_L = 1;            // 打开A相的低端
                PWMB_CCER1 = (0x10+0x20);    //P2.1 0x10:允许输入捕获, +0x00:上升沿, +0x20:下降沿
                PWMB_IER   = 0x04;            //P2.1 使能中断
                break;
        case 1:  // 001, P2.1-HALL_B下降沿  PWM3, PWM1_L=1
                PWMA_ENO = 0x00;    PWM2_L=0;    PWM3_L=0;
                Delay_500ns();
                PWMA_ENO = 0x10;    // 打开C相的高端PWM
                PWM1_L = 1;            // 打开A相的低端
                PWMB_CCER2 = (0x01+0x00);    //P2.2 0x01:允许输入捕获, +0x00:上升沿, +0x02:下降沿
                PWMB_IER   = 0x08;            //P2.2 使能中断
                break;
        case 5:  // 101, P2.2-HALL_C上升沿  PWM3, PWM2_L=1
                PWMA_ENO = 0x10;    PWM1_L=0;    PWM3_L=0;    // 打开C相的高端PWM
                Delay_500ns();
                PWM2_L = 1;            // 打开B相的低端
                PWMB_CCER1 = (0x01+0x02);    //P2.0 0x01:允许输入捕获, +0x00:上升沿, +0x02:下降沿
                PWMB_IER   = 0x02;            //P2.0 使能中断
                break;
    
        default:
                break;
        }
    }
}


void PWMA_config(void)
{
    P_SW2 |= 0x80;        //SFR enable  

    PWM1   = 0;
    PWM1_L = 0;
    PWM2   = 0;
    PWM2_L = 0;
    PWM3   = 0;
    PWM3_L = 0;
    P1n_push_pull(0x3f);

    PWMA_PSCR = 3;        // 预分频寄存器, 分频 Fck_cnt = Fck_psc/(PSCR[15:0}+1), 边沿对齐PWM频率 = SYSclk/((PSCR+1)*(AAR+1)), 中央对齐PWM频率 = SYSclk/((PSCR+1)*(AAR+1)*2).
    PWMA_DTR  = 24;        // 死区时间配置, n=0~127: DTR= n T,   0x80 ~(0x80+n), n=0~63: DTR=(64+n)*2T,  
                        //                0xc0 ~(0xc0+n), n=0~31: DTR=(32+n)*8T,   0xE0 ~(0xE0+n), n=0~31: DTR=(32+n)*16T,
    PWMA_ARR    = 255;    // 自动重装载寄存器,  控制PWM周期
    PWMA_CCER1  = 0;
    PWMA_CCER2  = 0;
    PWMA_SR1    = 0;
    PWMA_SR2    = 0;
    PWMA_ENO    = 0;
    PWMA_PS     = 0;
    PWMA_IER    = 0;
//    PWMA_ISR_En = 0;

    PWMA_CCMR1  = 0x68;        // 通道模式配置, PWM模式1, 预装载允许
    PWMA_CCR1   = 0;        // 比较值, 控制占空比(高电平时钟数)
    PWMA_CCER1 |= 0x05;        // 开启比较输出, 高电平有效
    PWMA_PS    |= 0;        // 选择IO, 0:选择P1.0 P1.1, 1:选择P2.0 P2.1, 2:选择P6.0 P6.1, 
//    PWMA_ENO   |= 0x01;        // IO输出允许,  bit7: ENO4N, bit6: ENO4P, bit5: ENO3N, bit4: ENO3P,  bit3: ENO2N,  bit2: ENO2P,  bit1: ENO1N,  bit0: ENO1P
//    PWMA_IER   |= 0x02;        // 使能中断

    PWMA_CCMR2  = 0x68;        // 通道模式配置, PWM模式1, 预装载允许
    PWMA_CCR2   = 0;        // 比较值, 控制占空比(高电平时钟数)
    PWMA_CCER1 |= 0x50;        // 开启比较输出, 高电平有效
    PWMA_PS    |= (0<<2);    // 选择IO, 0:选择P1.2 P1.3, 1:选择P2.2 P2.3, 2:选择P6.2 P6.3, 
//    PWMA_ENO   |= 0x04;        // IO输出允许,  bit7: ENO4N, bit6: ENO4P, bit5: ENO3N, bit4: ENO3P,  bit3: ENO2N,  bit2: ENO2P,  bit1: ENO1N,  bit0: ENO1P
//    PWMA_IER   |= 0x04;        // 使能中断

    PWMA_CCMR3  = 0x68;        // 通道模式配置, PWM模式1, 预装载允许
    PWMA_CCR3   = 0;        // 比较值, 控制占空比(高电平时钟数)
    PWMA_CCER2 |= 0x05;        // 开启比较输出, 高电平有效
    PWMA_PS    |= (0<<4);    // 选择IO, 0:选择P1.4 P1.5, 1:选择P2.4 P2.5, 2:选择P6.4 P6.5, 
//    PWMA_ENO   |= 0x10;        // IO输出允许,  bit7: ENO4N, bit6: ENO4P, bit5: ENO3N, bit4: ENO3P,  bit3: ENO2N,  bit2: ENO2P,  bit1: ENO1N,  bit0: ENO1P
//    PWMA_IER   |= 0x08;        // 使能中断

    PWMA_BKR    = 0x80;        // 主输出使能 相当于总开关
    PWMA_CR1    = 0x81;        // 使能计数器, 允许自动重装载寄存器缓冲, 边沿对齐模式, 向上计数,  bit7=1:写自动重装载寄存器缓冲(本周期不会被打扰), =0:直接写自动重装载寄存器本(周期可能会乱掉)
    PWMA_EGR    = 0x01;        //产生一次更新事件, 清除计数器和与分频计数器, 装载预分频寄存器的值
//    PWMA_ISR_En = PWMA_IER;    //设置标志允许通道1~4中断处理
}

//    PWMA_PS   = (0<<6)+(0<<4)+(0<<2)+0;    //选择IO, 4项从高到低(从左到右)对应PWM1 PWM2 PWM3 PWM4, 0:选择P1.x, 1:选择P2.x, 2:选择P6.x, 
//  PWMA_PS    PWM4N PWM4P    PWM3N PWM3P    PWM2N PWM2P    PWM1N PWM1P
//    00       P1.7  P1.6     P1.5  P1.4     P1.3  P1.2     P1.1  P1.0
//    01       P2.7  P2.6     P2.5  P2.4     P2.3  P2.2     P2.1  P2.0
//    02       P6.7  P6.6     P6.5  P6.4     P6.3  P6.2     P6.1  P6.0
//    03       P3.3  P3.4      --    --       --    --       --    --

//========================================================================
// 函数: void PWMB_config(void)
// 描述: PPWM配置函数。
// 参数: noe.
// 返回: none.
// 版本: V1.0, 2021-5-10
// 备注: 
//========================================================================
void PWMB_config(void)
{
    P_SW2 |= 0x80;        //SFR enable  

    PWMB_PSCR = 11;    // 预分频寄存器, 分频 Fck_cnt = Fck_psc/(PSCR[15:0]+1), 边沿对齐PWM频率 = SYSclk/((PSCR+1)*(AAR+1)), 中央对齐PWM频率 = SYSclk/((PSCR+1)*(AAR+1)*2).
    PWMB_DTR  = 0;    // 死区时间配置, n=0~127: DTR= n T,   0x80 ~(0x80+n), n=0~63: DTR=(64+n)*2T,  
                    //                0xc0 ~(0xc0+n), n=0~31: DTR=(32+n)*8T,   0xE0 ~(0xE0+n), n=0~31: DTR=(32+n)*16T,
    PWMB_CCER1  = 0;
    PWMB_CCER2  = 0;
    PWMB_CR1    = 0;        // 使能计数器, 允许自动重装载寄存器缓冲, 边沿对齐模式, 向上计数,  bit7=1:写自动重装载寄存器缓冲(本周期不会被打扰), =0:直接写自动重装载寄存器本(周期可能会乱掉)
    PWMB_CR2    = 0;
    PWMB_SR1    = 0;
    PWMB_SR2    = 0;
    PWMB_ENO    = 0;    //IO禁止输出PWM,  bit6: ENO8P, bit4: ENO7P,  bit2: ENO5P,  bit0: ENO4P
    PWMB_PS     = 0;
    PWMB_IER    = 0;

    PWMB_CCMR1  = 0x31;        // 通道5模式配置, 配置成输入通道, 8个时钟滤波
//    PWMB_CCER1 |= (0x01+0x02);    // 0x01:允许输入捕获, +0x00:上升沿, +0x02:下降沿
    PWMB_PS    |= 0;        // 选择IO, 0:选择P2.0, 1:选择P1.7, 2:选择P0.0, 3:选择P7.4,
//    PWMB_IER   |= 0x02;        // 使能中断

    PWMB_CCMR2  = 0x31;        // 通道6模式配置, 配置成输入通道, 8个时钟滤波
//    PWMB_CCER1 |= (0x10+0x20);    // 0x10:允许输入捕获, +0x00:上升沿, +0x20:下降沿
    PWMB_PS    |= (0<<2);    // 0:选择P2.1, 1:选择P5.4, 2:选择P0.1, 3:选择P7.5, 
//    PWMB_IER   |= 0x04;        // 使能中断

    PWMB_CCMR3  = 0x31;        // 通道7模式配置, 配置成输入通道, 8个时钟滤波
//    PWMB_CCER2 |= (0x01+0x02);    // 0x01:允许输入捕获, +0x00:上升沿, +0x02:下降沿
    PWMB_PS    |= (0<<4);    // 选择IO, 0:选择P2.2, 1:选择P3.3, 2:选择P0.2, 3:选择P7.6, 
//    PWMB_IER   |= 0x08;        // 使能中断

    PWMB_EGR    = 0x01;        //产生一次更新事件, 清除计数器和预分频计数器, 装载预分频寄存器的值
    PWMB_SMCR   = 0x60;
    PWMB_BKR    = 0x00;        //主输出使能 相当于总开关
    PWMB_CR1   |= 0x01;        // 使能计数器, 允许自动重装载寄存器缓冲, 边沿对齐模式, 向上计数,  bit7=1:写自动重装载寄存器缓冲(本周期不会被打扰), =0:直接写自动重装载寄存器本(周期可能会乱掉)

//    P2n_standard(0x07);    //通道5 6 7输出IO设置为准双向口
}

//    PWMB_PS   = (0<<6)+(0<<4)+(0<<2)+0;    //选择IO, 4项从高到低(从左到右)对应PWM8 PWM7 PWM6 PWM5
//  PWMB_PS    PWM8    PWM7    PWM6    PWM5
//    00       P2.3    P2.2    P2.1    P2.0
//    01       P3.4    P3.3    P5.4    P1.7
//    02       P0.3    P0.2    P0.1    P0.0
//    03       P7.7    P7.6    P7.5    P7.4


//========================================================================
// 函数: void PWMB_ISR(void) interrupt PWMB_VECTOR
// 描述: PWMB中断处理程序. 捕获数据通过 TIM1-> CCRnH / TIM1-> CCRnL 读取
// 参数: None
// 返回: none.
// 版本: V1.0, 2021-6-1
//========================================================================
void PWMB_ISR(void) interrupt PWMB_VECTOR
{
    PWMB_SR1 = 0;    //清除中断标志
    PWMB_SR2 = 0;    //清除中断标志

    if(B_RUN)    StepMotor();    //换相
}

 

void ADC_config(void)    //ADC初始化函数
{
    P1n_pure_input(0xc0);    //P1.7 P1.6设置为高阻输入
    P0n_pure_input(0x0f);    //P0.3~P0.0设置为高阻输入
    ADC_CONTR = 0x80 + 6;    //ADC on + channel
    ADCCFG = RES_FMT + ADC_SPEED;
    P_SW2 |=  0x80;    //访问XSFR
    ADCTIM = CSSETUP + CSHOLD + SMPDUTY;
}


void Timer0_config(void)    //Timer0初始化函数
{
    Timer0_16bitAutoReload(); // T0工作于16位自动重装
    Timer0_12T();
    TH0 = (65536UL-MAIN_Fosc/12 / 250) / 256; //4ms
    TL0 = (65536UL-MAIN_Fosc/12 / 250) % 256;
    TR0 = 1; // 打开定时器0

    ET0 = 1;// 允许ET0中断
}

void Timer0_ISR(void) interrupt 1    //Timer0中断函数
{
    B_4ms = 1;    //4ms定时标志
//    if(B_RUN)    StepMotor();    //换相, 增加定时器里换相可以保证启动成功.
}


/**********************************************/
void main(void)
{
    P2n_standard(0xf8);
    P3n_standard(0xbf);
    P5n_standard(0x10);
    
    
    PWMA_config();
    PWMB_config();
    ADC_config();
    Timer0_config();    //Timer0初始化函数
    PWW_Set = 0;

    EA  = 1; // 打开总中断

    while (1)
    {
        if(B_4ms)        // 4ms时隙
        {
            B_4ms = 0;

            YouMen  = (u8)(Get_ADC10bitResult(11) >> 2);    //油门是8位的, P0.3 ADC11-->控制电位器输入
            if(YouMen >= 128)    PWW_Set = YouMen - 128, B_direct = 0;    //顺时针
            else                PWW_Set = 127 - YouMen, B_direct = 1;    //逆时针
            PWW_Set *= 2;    //PWM设置值0~254

            if(!B_RUN && (PWW_Set >= 30))        // PWM_Set >= 30, 并且电机未运行, 则启动电机
            {
                PWM_Value = 30;            //启动电机的最低PWM, 根据具体电机而定
                PWMA_CCR1L = PWM_Value;    //输出PWM
                PWMA_CCR2L = PWM_Value;
                PWMA_CCR3L = PWM_Value;
                B_RUN = 1;        //标注运行
                StepMotor();    //启动换相
            }

            if(B_RUN)    //正在运行中
            {
                if(PWM_Value < PWW_Set)    PWM_Value++;    //油门跟随电位器, 调速柔和
                if(PWM_Value > PWW_Set)    PWM_Value--;
                if(PWM_Value < 20)    // 停转
                {
                    B_RUN = 0;
                    PWMB_IER   = 0;
                    PWMB_CCER1 = 0;
                    PWMB_CCER2 = 0;
                    PWM_Value = 0;
                    PWMA_ENO  = 0;
                    PWMA_CCR1L = 0;
                    PWMA_CCR2L = 0;
                    PWMA_CCR3L = 0;
                    PWM1_L=0;
                    PWM2_L=0;
                    PWM3_L=0;
                }
                else
                {
                    PWMA_CCR1L = PWM_Value;
                    PWMA_CCR2L = PWM_Value;
                    PWMA_CCR3L = PWM_Value;
                }
            }
        }

    }
}

 

 

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

评论(0)
发评论

下载排行榜

全部0条评论

快来发表一下你的评论吧 !