我已经获取了足够的信息来编写完整的六步换相范例程序。现在我可以开始编写代码了。
根据手册关键信息:
- STC32G12K128版芯片的普通I/O口下降沿中断和上升沿中断暂时不要使用,所以采用低电平中断方式
- I/O口中断向量大于31(P3口中断入口地址=0143H),必须借用13号中断入口地址(006BH)
- 需要配合ISR.ASM汇编跳转文件
- 需要设置
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.c 和 ISR.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.c 和 ISR.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中断 无刷电机"
📌 相关论坛讨论
- 探索STC32G12K128在BLDC电机控制中的I/O中断应用
⏱️ 查找用时 20.5s | 总回答用时 65.2s
🔍 搜索 "STC32G12K128 普通IO中断触发六步换相写一段范例"
📌 相关论坛讨论
- BLDC电机控制-万能实验板-V1.0@STCAI.com,原理图/PCB, 全开源
- BLDC, 三相无刷直流电机驱动-STC32G-无 HALL 或 带 HALL,例子打板测试已OK
- FOC-有感@Ai8051U,7万5千转的电机!系统成本6元, 5/26更新,磁编码器,低速重载启动
⏱️ 查找用时 5.6s | 总回答用时 36.9s