找回密码
 立即注册
查看: 79|回复: 6

STC32G 无刷电机控制有IO中断换相的例程吗

[复制链接]

6

主题

13

回帖

64

积分

注册会员

积分
64
发表于 2026-9-1 15:14:21 | 显示全部楼层 |阅读模式
目前从论坛上只能找到,HALL接口采用PWM输入捕获触发六部换相方波控制的程序;
请问有普通IO中断触发六步换相的程序吗?
回复

使用道具 举报 送花

39

主题

590

回帖

3512

积分

超级版主

积分
3512
发表于 2026-9-1 16:32:40 | 显示全部楼层

我已经获取了足够的信息来编写完整的六步换相范例程序。现在我可以开始编写代码了。

根据手册关键信息:

  1. STC32G12K128版芯片的普通I/O口下降沿中断和上升沿中断暂时不要使用,所以采用低电平中断方式
  2. I/O口中断向量大于31(P3口中断入口地址=0143H),必须借用13号中断入口地址(006BH)
  3. 需要配合ISR.ASM汇编跳转文件
  4. 需要设置 EAXFR=1 使能访问XFR寄存器

六步换相原理(基于霍尔传感器):

  • BLDC电机三相六步换相,霍尔传感器输出3位编码(HA/HB/HC)
  • 每60°电角度换相一次,共6个状态
  • 根据霍尔编码查表确定当前应导通的两相MOS管

引脚规划:

  • P3.0~P3.2:霍尔信号输入(HA/HB/HC),配置为准双向口
  • P1.0~P1.5:6路MOSFET驱动输出(AH/AL/BH/BL/CH/CL),配置为推挽输出

由于代码较长,我将分两部分输出:main.cISR.ASM。先输出 main.c 完整内容。

由于篇幅限制,我先输出完整的 main.c 文件。


我已查阅了STC32G12K128的普通I/O口均可中断章节和I/O口章节资料。下面给出基于霍尔传感器反馈的低电平中断触发六步换相范例程序。

⚠️ 重要说明(请先阅读)

根据手册"普通I/O口均可中断,不是传统外部中断"章节的说明:

STC32G12K128版芯片的普通I/O口下降沿中断和上升沿中断暂时不要使用

因此本范例采用低电平中断方式触发换相。同时由于I/O口中断向量大于31(P3口中断入口地址为0143H),在Keil中无法直接编译,必须借用13号中断入口地址,配合一个 ISR.ASM 汇编文件实现跳转。

程序文件结构

文件 说明
main.c 主程序:初始化、霍尔检测换相、主循环
ISR.ASM 汇编跳转文件:将P3口中断入口跳转到13号中断

一、main.c(主程序)

/******************************************************************************
 * 文件名 : main.c
 * 芯片   : STC32G12K128
 * 编译器 : Keil C251 (使用C251编译器, 32位8051)
 * 功能   : 基于普通I/O口中低电平中断触发的无刷直流电机(BLDC)
 *          六步换相控制范例程序
 *
 * 六步换相原理:
 *   BLDC电机定子三相(A/B/C)绕组, 转子装有3个霍尔传感器(HA/HB/HC),
 *   每60°电角度霍尔编码变化一次, 共6种状态, 每个状态对应一种
 *   绕组通电方式(两两导通), 按顺序循环即实现电机连续旋转。
 *
 * 引脚分配:
 *   P1.0 : AH  A相上管驱动 (PWM/高低控制)
 *   P1.1 : AL  A相下管驱动
 *   P1.2 : BH  B相上管驱动
 *   P1.3 : BL  B相下管驱动
 *   P1.4 : CH  C相上管驱动
 *   P1.5 : CL  C相下管驱动
 *   P3.0 : HA  霍尔A信号输入
 *   P3.1 : HB  霍尔B信号输入
 *   P3.2 : HC  霍尔C信号输入
 *
 * 注意: 因STC32G12K128版芯片下降沿/上升沿中断暂不可用,
 *       故霍尔信号触发采用"低电平中断"方式,
 *       在中断中读取PORTA电平, 判断状态并查表换相。
 *
 * 编译环境: Keil C251, 需配合 ISR.ASM 文件加入工程
 *****************************************************************************/

#include "stc32g.h"     // STC32G系列头文件
#include "intrins.h"

/*--------------------- 引脚定义 ---------------------*/
sbit AH = P1^0;     // A相上管
sbit AL = P1^1;     // A相下管
sbit BH = P1^2;     // B相上管
sbit BL = P1^3;     // B相下管
sbit CH = P1^4;     // C相上管
sbit CL = P1^5;     // C相下管

/* 霍尔信号引脚(P3.0/P3.1/P3.2), 使用P3口整体读取 */

/*--------------------- 六步换相表 ---------------------*/
/* 六步换相通电逻辑表 (AH/BH/CH为上管, AL/BL/CL为下管)
 * 索引 = 霍尔编码(HA<<2 | HB<<1 | HC)
 * 值   = 6位MOS驱动输出 (bit5=AH, bit4=AL, bit3=BH, bit2=BL, bit1=CH, bit0=CL)
 *
 *  霍尔编码  通电相      驱动字节(bit5..bit0 = AH AL BH BL CH CL)
 *  101      A+ C-      0b100001  -> 0x21
 *  100      A+ B-      0b100010  -> 0x22
 *  110      B+ A-      0b011000  -> 0x18
 *  010      B+ C-      0b010100  -> 0x14
 *  011      C+ A-      0b001001  -> 0x09
 *  001      C+ B-      0b001010  -> 0x0A
 */
unsigned char code commutation_table[8] = {
    0x00,   // 000: 无效状态, 关断
    0x0A,   // 001: C+ B-
    0x14,   // 010: B+ C-
    0x09,   // 011: C+ A-
    0x22,   // 100: A+ B-
    0x21,   // 101: A+ C-
    0x18,   // 110: B+ A-
    0x00    // 111: 无效状态, 关断
};

/*--------------------- 全局变量 ---------------------*/
volatile unsigned char g_hall_state;   // 当前霍尔编码
volatile unsigned char g_comm_step;    // 当前换相步序号(0~5)
volatile unsigned char g_comm_flag;    // 换相触发标志(中断置1, 主循环处理)

/*--------------------- 函数声明 ---------------------*/
void delay_ms(unsigned int ms);
void gpio_init(void);
void port_int_init(void);
void update_commutation(void);

/*--------------------- 延时函数 ---------------------*/
void delay_ms(unsigned int ms)
{
    unsigned int i, j;
    for (i = 0; i < ms; i++)
    {
        for (j = 0; j < 3000; j++)
        {
            _nop_();
        }
    }
}

/*--------------------- I/O口初始化 ---------------------*/
void gpio_init(void)
{
    /* P1.0~P1.5 用作MOS驱动输出, 配置为推挽输出 */
    P1M0 |= 0x3F;       // P1.0~P1.5置1 => 推挽输出
    P1M1 &= ~0x3F;      // P1M1对应位置0

    /* P3.0~P3.2 用作霍尔信号输入, 配置为准双向口(内部上拉) */
    P3M0 &= ~0x07;      // P3.0~P3.2置0
    P3M1 &= ~0x07;      // P3M1对应位置0

    /* 上电时关断所有MOS管(输出全为0) */
    P1 = 0x00;
}

/*--------------------- 端口中断初始化 ---------------------*/
void port_int_init(void)
{
    EAXFR = 1;              // 使能访问XFR寄存器区

    /* P3口中断模式配置: 低电平中断
     * P3IM0.x = 0, P3IM1.x = 1 => 低电平中断 */
    P3IM0 = 0x00;           // 全部置0
    P3IM1 = 0x07;           // P3.0~P3.2置1 => 低电平中断

    /* 使能P3口中断: P3.0~P3.2 */
    P3INTE = 0x07;          // 使能P3.0/P3.1/P3.2端口中断

    /* 清除P3口中断标志 */
    P3INTF = 0x00;
}

/*--------------------- 换相状态更新函数 ---------------------*/
void update_commutation(void)
{
    unsigned char hall;
    unsigned char drive;

    /* 读取当前霍尔编码: HA=P3.0, HB=P3.1, HC=P3.2 */
    hall = (P3 & 0x07);      // 取P3.0~P3.2
    g_hall_state = hall;

    /* 查表获取对应驱动字节 */
    drive = commutation_table[hall];

    /* 输出到P1口(仅P1.0~P1.5有效) */
    P1 = (P1 & 0xC0) | drive;   // 保留P1.6/P1.7原有状态

    /* 记录换相步(有效状态时记录) */
    if (drive != 0x00)
    {
        g_comm_step++;
        if (g_comm_step >= 6)
        {
            g_comm_step = 0;
        }
    }
}

/*--------------------- 主函数 ---------------------*/
void main(void)
{
    /* 初始化 */
    gpio_init();            // I/O口模式配置
    port_int_init();        // P3口低电平中断配置

    /* 初始霍尔状态读取, 上电即进行一次换相 */
    update_commutation();

    EA = 1;                 // 打开总中断

    while (1)
    {
        /* 若中断触发了换相标志, 在主循环中处理 */
        if (g_comm_flag)
        {
            g_comm_flag = 0;    // 清除标志
            update_commutation();  // 根据最新霍尔状态换相
        }

        /* 此处可加入其他控制逻辑(如转速调节PWM占空比等) */
    }
}

/*--------------------- 公共中断服务函数 ---------------------*/
/* 由于I/O口中断向量大于31, 在Keil中无法直接编译,
 * 必须借用13号中断入口地址(006BH)。
 * 汇编ISR.ASM将P3口中断入口(0143H)跳转到此处。 */
void common_isr(void) interrupt 13
{
    unsigned char intf;

    intf = P3INTF;      // 读取P3口中断标志

    if (intf)
    {
        P3INTF = 0x00;  // 清除中断标志(软件清零)

        /* 判断是哪个引脚触发中断 */
        if (intf & 0x01)
        {
            // P3.0 (HA) 触发中断
            g_comm_flag = 1;    // 置换相标志, 主循环处理
        }
        if (intf & 0x02)
        {
            // P3.1 (HB) 触发中断
            g_comm_flag = 1;
        }
        if (intf & 0x04)
        {
            // P3.2 (HC) 触发中断
            g_comm_flag = 1;
        }
    }
}

二、ISR.ASM(汇编跳转文件)

; 文件名 : ISR.ASM
; 功能   : 将P3口中断入口地址(0143H)跳转到13号中断入口(006BH)
; 说明   : 由于Keil C251不支持直接声明大于31的中断向量,
;          必须使用此汇编文件将P3口中断入口跳转到13号中断
; 使用方法: 将本文件加入Keil工程中, 与main.c一起编译

CSEG AT 0143H      ; P3口中断入口地址
JMP P3INT_ISR

P3INT_ISR:
JMP 006BH          ; 跳转到13号中断入口地址(common_isr)

END

三、使用说明与注意事项

1. 编译环境

  • 使用 Keil C251 编译器(STC32G为32位8051内核)
  • 需在Keil工程中加入 main.cISR.ASM 两个文件

2. 关键配置说明(依据手册)

  • EAXFR = 1:使能访问XFR扩展寄存器区(P3INTE/P3INTF/P3IM0/P3IM1等寄存器位于7EFDxxH扩展地址)
  • 低电平中断配置:P3IM0.x=0, P3IM1.x=1
  • 中断标志需软件清零P3INTF = 0x00
  • 中断使能:P3INTE = 0x07(使能P3.0/P3.1/P3.2)

3. 关于中断模式的说明

根据手册"普通I/O口均可中断"章节:

STC32G12K128版芯片的普通I/O口下降沿中断和上升沿中断暂时不要使用

因此本范例使用低电平中断。若要使用边沿触发(更精确的换相时刻),需使用支持该功能的芯片型号(如STC32G8K64等),或等待新版芯片固件修复后使用。

4. 换相逻辑说明

  • 霍尔编码读取:hall = P3 & 0x07(取P3.0~P3.2)
  • 通过查表 commutation_table[hall] 得到对应的6路MOS驱动输出
  • 中断触发时置 g_comm_flag=1,主循环中调用 update_commutation() 完成换相

5. 实际应用注意事项

  • 本范例为开环六步换相演示,实际应用中还需:
    • 加入换相消磁延时(防止上下管直通)
    • 加入PWM调速控制
    • 加入过流保护功能
    • 根据实际电机霍尔安装角度(60°或120°)调整换相表

如果你需要边沿触发版本的范例(需使用STC32G8K64等支持边沿中断的型号),或需要加入PWM调速功能,请告诉我,我可以进一步扩展程序。


🔍 搜索 "STC32G 六步换相 IO中断 无刷电机"

📌 相关论坛讨论

  1. 探索STC32G12K128在BLDC电机控制中的I/O中断应用

⏱️ 查找用时 20.5s | 总回答用时 65.2s


🔍 搜索 "STC32G12K128 普通IO中断触发六步换相写一段范例"

📌 相关论坛讨论

  1. BLDC电机控制-万能实验板-V1.0@STCAI.com,原理图/PCB, 全开源
  2. BLDC, 三相无刷直流电机驱动-STC32G-无 HALL 或 带 HALL,例子打板测试已OK
  3. FOC-有感@Ai8051U,7万5千转的电机!系统成本6元, 5/26更新,磁编码器,低速重载启动

⏱️ 查找用时 5.6s | 总回答用时 36.9s

电话:0513-55012946 QQ:2195591714  微信:  19952583740
回复

使用道具 举报 送花

83

主题

8216

回帖

1万

积分

超级版主

积分
17634
发表于 2026-9-1 23:04:13 | 显示全部楼层
由于STC32G12K128不支持普通IO的上升沿、下降沿中断,不能使用,STC32G8K64的可以使用。我的STC32G12K128的例子是使用PWMB的外部捕捉功能来代替外部中断的。

BLDC, 三相无刷直流电机驱动-STC32G-无HALL 或 带HALL,例子打板测试已OK
https://www.stcaimcu.com/thread-7291-1-1.html
(出处: 国芯人工智能技术交流网站)
回复

使用道具 举报 送花

已绑定手机

0

主题

72

回帖

895

积分

高级会员

积分
895
发表于 2026-9-6 14:27:00 | 显示全部楼层
回复

使用道具 举报 送花

6

主题

13

回帖

64

积分

注册会员

积分
64
 楼主| 发表于 2026-9-11 10:00:54 | 显示全部楼层
梁*** 发表于 2026-9-1 23:04
由于STC32G12K128不支持普通IO的上升沿、下降沿中断,不能使用,STC32G8K64的可以使用。我的STC32G12K128的 ...

请教一下梁工,STC32G144K246可以采用双边沿IO中断触发方式,对有感无刷电机换相吗?

点评

可以,每个边沿中断都读取霍尔信号作为换相指示。  详情 回复 发表于 2026-9-11 10:19
回复

使用道具 举报 送花

83

主题

8216

回帖

1万

积分

超级版主

积分
17634
发表于 2026-9-11 10:19:53 | 显示全部楼层
随*** 发表于 2026-9-11 10:00
请教一下梁工,STC32G144K246可以采用双边沿IO中断触发方式,对有感无刷电机换相吗? ...

可以,每个边沿中断都读取霍尔信号作为换相指示。
回复

使用道具 举报 送花

已绑定手机

6

主题

502

回帖

2465

积分

金牌会员

积分
2465
发表于 7 天前 | 显示全部楼层
又有新的学习资料了
学习
回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2026-9-22 10:39 , Processed in 0.072523 second(s), 75 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表