STC单片机驱动BLDC无刷直流电机(无HALL)官方示例

本文档提供了STC8系列单片机驱动BLDC无刷直流电机的示例代码,详细解释了代码中的结构体定义、寄存器配置以及中断服务函数。示例适用于无HALL传感器的57BL02马达,并涉及PWM控制、马达换相和速度调整等关键功能。在实际应用中,可能需要针对官方头文件的不匹配问题进行代码适配。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

STC单片机驱动BLDC无刷直流电机(无HALL)官方示例

文档资料里面的驱动代码,如果直接拷贝到新工厂项目下,直接编译是会报错的,主要是所使用的头文件,与包含的头文件里面有些特殊功能寄存器没有被定义,这一点只能说明,官方的头文件更新不及时,它们内部所使用的头文件已经有了,而发布出来的没有更新,另外一个原因就是头文件使用规范问题,给出的示例代码中所包含的头文件是STC8H8K.h,在Keil里面能加载到的该系列头文件STC8.Hstc8h.h

  • ✨这是Keil目录下可以看到的所有STC给出的头文件

所以我怀疑官方资料案例里面所使用的头文件STC8H8K.h应该是内部的。当你拷贝文档中的示例代码出来进行编译是就会出现找不到各种寄存器定义的报错地方。(STC是不是分工不均,做文档资料上1000页的人员很多,做技术底层文档资料的没有人做。每次去STC下个单片机型号的文档阅读,一份资料没有上1000页的内容我都怀疑是不是没下载成功)

在这里插入图片描述

⛳程序代码说明

编译不通过的代码我就不放出来了,这里放出来的是编译没有问题的代码,是从另外一个工具里面拷贝出来的,不过也是需要改动,不然编译报错,主要原因是没有将定义的结构体初始化,怀疑漏掉了一行,TIM_TypeDef *TIM1,*TIM2;对代码是否能使用我也表示怀疑,因为里面使用了TIM1TIM2,这两个结构体变量都是来自一个结构体,二后面给出的#define TIM1_BaseAddress 0xFEC0 #define TIM2_BaseAddress 0xFEE0并没看到使用。我在结构体下面新增了一句TIM_TypeDef *TIM1,*TIM2;初始化结构体。

  • 代码来源工具:STCcube单片机工具

下载地址:https://www.stcisp.com/stccube/stccube.zip

在这里插入图片描述

📝工程代码


//BLDC无刷直流电机驱动(无HALL)
//测试工作频率为11.0592MHz
//本例程实现如下功能: 通过3组PWM通道控制无霍尔马达运转
//本例程仅适用57BL02马达在24V无负载条件下演示

#include "stc8h.h"
#include "intrins.h"

typedef unsigned char   u8;
typedef unsigned int    u16;

typedef struct TIM_struct
{
    volatile unsigned char CR1;     /*!< control register 1 */
    volatile unsigned char CR2;     /*!< control register 2 */
    volatile unsigned char SMCR;    /*!< Synchro mode control register */
    volatile unsigned char ETR;     /*!< external trigger register */
    volatile unsigned char IER;     /*!< interrupt enable register*/
    volatile unsigned char SR1;     /*!< status register 1 */
    volatile unsigned char SR2;     /*!< status register 2 */
    volatile unsigned char EGR;     /*!< event generation register */
    volatile unsigned char CCMR1;   /*!< CC mode register 1 */
    volatile unsigned char CCMR2;   /*!< CC mode register 2 */
    volatile unsigned char CCMR3;   /*!< CC mode register 3 */
    volatile unsigned char CCMR4;   /*!< CC mode register 4 */
    volatile unsigned char CCER1;   /*!< CC enable register 1 */
    volatile unsigned char CCER2;   /*!< CC enable register 2 */
    volatile unsigned char CNTRH;   /*!< counter high */
    volatile unsigned char CNTRL;   /*!< counter low */
    volatile unsigned char PSCRH;   /*!< prescaler high */
    volatile unsigned char PSCRL;   /*!< prescaler low */
    volatile unsigned char ARRH;    /*!< auto-reload register high */
    volatile unsigned char ARRL;    /*!< auto-reload register low */
    volatile unsigned char RCR;     /*!< Repetition Counter register */
    volatile unsigned char CCR1H;   /*!< capture/compare register 1 high */
    volatile unsigned char CCR1L;   /*!< capture/compare register 1 low */
    volatile unsigned char CCR2H;   /*!< capture/compare register 2 high */
    volatile unsigned char CCR2L;   /*!< capture/compare register 2 low */
    volatile unsigned char CCR3H;   /*!< capture/compare register 3 high */
    volatile unsigned char CCR3L;   /*!< capture/compare register 3 low */
    volatile unsigned char CCR4H;   /*!< capture/compare register 3 high */
    volatile unsigned char CCR4L;   /*!< capture/compare register 3 low */
    volatile unsigned char BKR;     /*!< Break Register */
    volatile unsigned char DTR;     /*!< dead-time register */
    volatile unsigned char OISR;    /*!< Output idle register */
}TIM_TypeDef;

TIM_TypeDef *TIM1,*TIM2;

#define TIM1_BaseAddress    0xFEC0
#define TIM2_BaseAddress    0xFEE0

#define TRUE        1
#define FALSE       0

#define RV09_CH     6

#define TIM1_Period     ((u16)280)
#define TIM1_STPulse    ((u16)245)

#define START       0x1A
#define RUN         0x1B
#define STOP        0x1C
#define IDLE        0x1D

#define TIM1_OCMODE_MASK        ((u8)0x70)
#define TIM1_OCCE_ENABLE        ((u8)0x80)
#define TIM1_OCCE_DISABLE       ((u8)0x00)
#define TIM1_OCMODE_TIMING      ((u8)0x00)
#define TIM1_OCMODE_ACTIVE      ((u8)0x10)
#define TIM1_OCMODE_INACTIVE    ((u8)0x20)
#define TIM1_OCMODE_TOGGLE      ((u8)0x30)
#define TIM1_FORCE_INACTIVE     ((u8)0x40)
#define TIM1_FORCE_ACTIVE       ((u8)0x50)
#define TIM1_OCMODE_PWMA        ((u8)0x60)
#define TIM1_OCMODE_PWMB        ((u8)0x70)
#define CC1_POLARITY_HIGH       ((u8)0x02)
#define CC1N_POLARITY_HIGH      ((u8)0x08)
#define CC2_POLARITY_HIGH       ((u8)0x20)
#define CC2N_POLARITY_HIGH      ((u8)0x80)
#define CC1_POLARITY_LOW        ((u8)~0x02)
#define CC1N_POLARITY_LOW       ((u8)~0x08)
#define CC2_POLARITY_LOW        ((u8)~0x20)
#define CC2N_POLARITY_LOW       ((u8)~0x80)
#define CC1_OCENABLE            ((u8)0x01)
#define CC1N_OCENABLE           ((u8)0x04)
#define CC2_OCENABLE            ((u8)0x10)
#define CC2N_OCENABLE           ((u8)0x40)
#define CC1_OCDISABLE           ((u8)~0x01)
#define CC1N_OCDISABLE          ((u8)~0x04)
#define CC2_OCDISABLE           ((u8)~0x10)
#define CC2N_OCDISABLE          ((u8)~0x40)
#define CC3_POLARITY_HIGH       ((u8)0x02)
#define CC3N_POLARITY_HIGH      ((u8)0x08)
#define CC4_POLARITY_HIGH       ((u8)0x20)
#define CC4N_POLARITY_HIGH      ((u8)0x80)
#define CC3_POLARITY_LOW        ((u8)~0x02)
#define CC3N_POLARITY_LOW       ((u8)~0x08)
#define CC4_POLARITY_LOW        ((u8)~0x20)
#define CC4N_POLARITY_LOW       ((u8)~0x80)
#define CC3_OCENABLE            ((u8)0x01)
#define CC3N_OCENABLE           ((u8)0x04)
#define CC4_OCENABLE            ((u8)0x10)
#define CC4N_OCENABLE           ((u8)0x40)
#define CC3_OCDISABLE           ((u8)~0x01)
#define CC3N_OCDISABLE          ((u8)~0x04)
#define CC4_OCDISABLE           ((u8)~0x10)
#define CC4N_OCDISABLE          ((u8)~0x40)

void UART_INIT();
void DelayXus(unsigned char delayTime);
void DelayXms( unsigned char delayTime);
unsigned int ADC_Convert(u8 ch);
void PWM_Init(void);
void SPEED_ADJ();
unsigned char RD_HALL();
void MOTOR_START();
void MOTOR_STOP();
unsigned char KEY_detect();

unsigned char Timer0_cnt=0xb0;
unsigned int HA=0;
unsigned int Motor_speed;
unsigned char Motor_sta = IDLE;
unsigned char BRK_occur=0;
unsigned int TIM2_CAP1_v=0;
unsigned int CAP1_avg=0;
unsigned char CAP1_cnt=0;
unsigned long CAP1_sum=0;

void main(void)
{
	 	
    unsigned int temp=0;
    unsigned int ADC_result=0;
	
    P_SW2= 0x80;
    P1 = 0x00;
    P0M1 = 0x0C;
    P0M0 = 0x01;
    P1M1 = 0xc0;
    P1M0 = 0x3F;
    P2M1 = 0x00;
    P2M0 = 0x38;
    P3M1 = 0x88;
    P3M0 = 0x02;

    ET0=1;
    TR0=0;
    ADCCFG = 0x0f;
    ADC_CONTR = 0x80;

    PWMA_ENO = 0x3F;                            //PWMA输出使能
    PWMB_ENO = 0x00;                            //PWMB输出使能
    PWMA_PS  = 0x00;                            //PWMA pin 选择
    PWMB_PS  = 0xD5;                            //PWMB pin 选择

    /**********************************************************
    输出比较模式 PWMx_duty = [CCRx/(ARR + 1)]*100
    ***********************************************************/
    /************PWMB  BMF输入 ****************/
     时基单元 

    TIM2-> PSCRL = 15;
    TIM2-> ARRH = 0xff;                         //自动重装载寄存器,计数器 overflow 点
    TIM2-> ARRL = 0xff;
    TIM2-> CCR4H = 0x00;
    TIM2-> CCR4L = 0x05;
     通道配置 
    TIM2-> CCMR1 = 0xf3;                        //通道模式配置
    TIM2-> CCMR2 = 0xf1;
    TIM2-> CCMR3 = 0xf1;
    TIM2-> CCMR4 = 0x70;
    TIM2-> CCER1 = 0x11;
    TIM2-> CCER2 = 0x11;
     模式配置 
    TIM2-> CR2 = 0xf0;
    TIM2-> CR1 = 0x81;
    TIM2-> SMCR = 0x44;
     使能 & 中断配置 
    TIM2-> BKR = 0x80;                          //主输出使能
    TIM2-> IER = 0x02;                          //使能中断
    /************PWMA 控制马达换相 ****************/
     时基单元 
    TIM1-> PSCRH = 0x00;                        //预分频寄存器
    TIM1-> PSCRL = 0x00;
    TIM1-> ARRH = (u8)(TIM1_Period >> 8);
    TIM1-> ARRL = (u8)(TIM1_Period);
     通道配置 
    TIM1-> CCMR1 = 0x70;                        //通道模式配置
    TIM1-> CCMR2 = 0x70;
    TIM1-> CCMR3 = 0x70;
    TIM1-> CCER1 = 0x11;                        //配置通道输出使能和极性
    TIM1-> CCER2 = 0x01;                        //配置通道输出使能和极性
    TIM1-> OISR = 0xAA;                         //配置 MOE=0 时各通道输出电平
     模式配置 
    TIM1-> CR1 = 0xA0;
    TIM1-> CR2 = 0x24;
    TIM1-> SMCR = 0x20;
    TIM1-> BKR = 0x0c;
     使能 & 中断配置 
    TIM1-> CR1 |= 0x01;                         //使能计数器
    EA = 1;

    UART_INIT();

    while (1)
    {
        switch(Motor_sta)
        {
            case START:
                MOTOR_START();
                Motor_sta = RUN;
                for(temp = TIM1_STPulse; temp > ADC_result; temp--) //开环启动
                {
                    ADC_result = (ADC_Convert(RV09_CH)/4);
                    TIM1-> CCR1H = (u8)(temp >> 8);
                    TIM1-> CCR1L = (u8)(temp);
                    TIM1-> CCR2H = (u8)(temp >> 8);
                    TIM1-> CCR2L = (u8)(temp);
                    TIM1-> CCR3H = (u8)(temp >> 8);
                    TIM1-> CCR3L = (u8)(temp);
                    DelayXms(10);
                }
                break;
            case RUN:
                SPEED_ADJ();    //马达调速
                if((BRK_occur == TRUE))
                Motor_sta = STOP;
                break;
            case STOP:
                MOTOR_STOP();
                Motor_sta = IDLE;
                break;
            case IDLE:
                if(KEY_detect()==1)
                Motor_sta = START;              //启动马达
                BRK_occur = FALSE;
                Motor_speed = 0;
                CAP1_avg = 0;
                CAP1_cnt = 0;
                CAP1_sum = 0;
                break;
        }
    }
}

void TIM0_ISR() interrupt 1
{
    if(Motor_sta == START)
    {
        if(Timer0_cnt<0xe0) Timer0_cnt++;
        TH0=Timer0_cnt;

        switch(HA%6)
        {
        case 0:
            TIM1-> CCMR3 &= ~TIM1_OCMODE_MASK;
            TIM1-> CCMR3 |= TIM1_FORCE_INACTIVE;
            TIM1-> CCMR1 &= ~TIM1_OCMODE_MASK;
            TIM1-> CCMR1 |= TIM1_OCMODE_PWMB;
            break;
        case 1:
            TIM1-> CCER1 &= CC2N_POLARITY_LOW;
            TIM1-> CCER2 |= CC3N_POLARITY_HIGH;
             break;
        case 2:
            TIM1-> CCMR1 &= ~TIM1_OCMODE_MASK;
            TIM1-> CCMR1 |= TIM1_FORCE_INACTIVE;
            TIM1-> CCMR2 &= ~TIM1_OCMODE_MASK;
            TIM1-> CCMR2 |= TIM1_OCMODE_PWMB;
            break;
        case 3:
            TIM1-> CCER1 |= CC1N_POLARITY_HIGH;
            TIM1-> CCER2 &= CC3N_POLARITY_LOW;
            break;
        case 4:
            TIM1-> CCMR2 &= ~TIM1_OCMODE_MASK;
            TIM1-> CCMR2 |= TIM1_FORCE_INACTIVE;
            TIM1-> CCMR3 &= ~TIM1_OCMODE_MASK;
            TIM1-> CCMR3 |= TIM1_OCMODE_PWMB;
            break;
        case 5:
            TIM1-> CCER1 &= CC1N_POLARITY_LOW;
            TIM1-> CCER1 |= CC2N_POLARITY_HIGH;
            break;
        }
        HA++;
    }

    if(Motor_sta == RUN)
    {
        TR0=0;
        switch(RD_HALL())
        {
        case 3:
            TIM1-> CCMR3 &= ~TIM1_OCMODE_MASK;
            TIM1-> CCMR3 |= TIM1_FORCE_INACTIVE;
            TIM1-> CCMR1 &= ~TIM1_OCMODE_MASK;
            TIM1-> CCMR1 |= TIM1_OCMODE_PWMB;
            break;
        case 1:
            TIM1-> CCER1 &= CC2N_POLARITY_LOW;
            TIM1-> CCER2 |= CC3N_POLARITY_HIGH;
            break;
        case 5:
            TIM1-> CCMR1 &= ~TIM1_OCMODE_MASK;
            TIM1-> CCMR1 |= TIM1_FORCE_INACTIVE;
            TIM1-> CCMR2 &= ~TIM1_OCMODE_MASK;
            TIM1-> CCMR2 |= TIM1_OCMODE_PWMB;
            break;
        case 4:
            TIM1-> CCER1 |= CC1N_POLARITY_HIGH;
            TIM1-> CCER2 &= CC3N_POLARITY_LOW;
            break;
        case 6:
            TIM1-> CCMR2 &= ~TIM1_OCMODE_MASK;
            TIM1-> CCMR2 |= TIM1_FORCE_INACTIVE;
            TIM1-> CCMR3 &= ~TIM1_OCMODE_MASK;
            TIM1-> CCMR3 |= TIM1_OCMODE_PWMB;
            break;
        case 2:
            TIM1-> CCER1 &= CC1N_POLARITY_LOW;
            TIM1-> CCER1 |= CC2N_POLARITY_HIGH;
            break;
        }
    }
}

void PWMA_ISR() interrupt 26
{
    if((TIM1->SR1 & 0x20))
    {
        P00=0;
        CAP1_sum += TIM2_CAP1_v;
        CAP1_cnt++;
        if(CAP1_cnt==128)
        {
            CAP1_cnt=0;
            CAP1_avg = (CAP1_sum>>7);
            CAP1_sum = 0;
            Motor_speed = 5000000/CAP1_avg;
        }
        TIM1->SR1 &=~0x20;                      //清零
    }
    if((TIM1->SR1 & 0x80))                      //BRK
    {
        BRK_occur = TRUE;
        TIM1->SR1 &=~0x80;                      //清零
    }
}

void PWMB_ISR() interrupt 27
{
    unsigned char ccr_tmp=0;

    if((TIM2->SR1 & 0X02))
    {
        ccr_tmp = TIM2-> CCR1H;
        if(ccr_tmp>1)                           //软件滤波
        {
            TIM2_CAP1_v = ccr_tmp;
            TIM2_CAP1_v = (TIM2_CAP1_v<<8) + TIM2->CCR1L;
            if(Motor_sta == RUN)                //换向delay计时
            {
                TR0=1;
                TH0 = 256-(TIM2_CAP1_v>>9);
            }
        }
        TIM2->SR1 &=~0X02;
    }
}

void UART_INIT()
{
    SCON = 0x50;                                //8位可变波特率
    AUXR = 0x40;                                //定时器1为1T模式
    TMOD = 0x20;                                //定时器1为模式0(16位自动重载)

    TL1 = 254;
    TH1 = 254;
//  ET1 = 0;
    TR1 = 1;
}

void DelayXus(unsigned char delayTime)
{
    int i = 0;
    while( delayTime--)
    {
        for( i = 0 ; i < 1 ; i++);
    }
}

void DelayXms( unsigned char delayTime )
{
    int i = 0;
    while( delayTime--)
    {
        for( i = 0 ; i < 2 ; i++)
        {
            DelayXus(100);
        }
    }
}

unsigned int ADC_Convert(u8 ch)
{
    u16 res=0;

    ADC_CONTR &= ~0x0f;
    ADC_CONTR |= ch;
    ADC_CONTR |= 0x40;
    DelayXus(1);
    while (!(ADC_CONTR & 0x20));
    ADC_CONTR &= ~0x20;

    res = ADC_RES;
    res = (res<<2)+(ADC_RESL>>6);

    if (res < 360) res=360;
    if (res > 900) res=900;

    return res;
}

void SPEED_ADJ()
{
    u16 ADC_result;

    ADC_result = (ADC_Convert(RV09_CH)/4);      //调速旋钮ADC采样
    TIM1-> CCR1H = (u8)(ADC_result >> 8);       //计数器比较值
    TIM1-> CCR1L = (u8)(ADC_result);
    TIM1-> CCR2H = (u8)(ADC_result >> 8);
    TIM1-> CCR2L = (u8)(ADC_result);
    TIM1-> CCR3H = (u8)(ADC_result >> 8);
    TIM1-> CCR3L = (u8)(ADC_result);
}

unsigned char RD_HALL()                         //读霍尔传感器
{
    unsigned char Hall_sta = 0;

    DelayXus(40);
    (P17)? (Hall_sta|=0x01) : (Hall_sta&=~0x01);
    (P54)? (Hall_sta|=0x02) : (Hall_sta&=~0x02);
    (P33)? (Hall_sta|=0x04) : (Hall_sta&=~0x04);

    return Hall_sta;
}

void MOTOR_START()
{
    TIM1-> CCR1H = (u8)(TIM1_STPulse >> 8);     //计数器比较值
    TIM1-> CCR1L = (u8)(TIM1_STPulse);
    TIM1-> CCR2H = (u8)(TIM1_STPulse >> 8);
    TIM1-> CCR2L = (u8)(TIM1_STPulse);
    TIM1-> CCR3H = (u8)(TIM1_STPulse >> 8);
    TIM1-> CCR3L = (u8)(TIM1_STPulse);
    TIM1-> BKR |= 0x80;                         //主输出使能相当于总开关
    TIM1-> IER = 0x00;                          //使能中断
    TR0 = 1;

    while (HA < 6*20);

    TIM1-> IER = 0xa0;                          //使能中断
}

void MOTOR_STOP()
{
    TIM1-> BKR &= ~0x80;
    TIM1-> IER &= ~0x20;
}

unsigned char KEY_detect()
{
    if(!P37)
    {
        DelayXms(10);
        if(!P37)
        {
            return 1;
        }
        else return 0;
    }
    else if(!P03)
    {
        DelayXms(10);
        if(!P03)
        {
            return 2;
        }
        else return 0;
    }
    else return 0;
}

  • 📋编译信息
    在这里插入图片描述

  知否,知否?应是绿肥红瘦。——李清照《如梦令·昨夜雨疏风骤》。
### 使用STC8H1单片机控制无刷直流电机BLDC) #### 控制原理 在使用STC8H系列单片机驱动三相无刷直流电机的过程中,主要依赖于PWM信号的生成和霍尔传感器反馈的位置信息来进行精确的速度和位置控制[^1]。通过调整PWM波形的不同占空比,可以改变施加给电机线圈电压的时间比例,从而达到调节转速的效果。 对于具体的实现方式,在停机状态下允许进入配置模式以设定不同的运行参数如转向与速度调节策略等[^2]。此外,还需要注意的是并非所有引脚都能被充分利用;某些情况下为了简化电路设计或节省空间而不得不做出妥协。 #### 示例代码结构 下面给出一段用于演示目的的基础框架Python伪代码,实际应用时应转换成适合目标平台的语言: ```python import time def setup(): # 初始化GPIO口及定时器中断服务函数 pass def loop(): while True: read_hall_sensors() # 获取当前转子位置数据 calculate_pwm_duty_cycle() apply_pwm_to_motors() def read_hall_sensors(): global rotor_position # 实现读取三个霍尔效应传感器的状态,并据此更新rotor_position变量 pass def calculate_pwm_duty_cycle(): global pwm_value # 根据期望速度计算新的PWM占空比值pwm_value pass def apply_pwm_to_motors(): # 将新计算得到的PWM应用于相应的电机绕组上 pass ``` 请注意上述仅为概念性的描述,并未提供完整的可执行源码。真实环境中还需考虑更多细节因素比如异常处理机制、安全保护措施等方面的设计。
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值