我已获取到足够的手册依据。需要先向您说明一个重要提示:
关于手册原文的适用范围:在"高级PWM-硬件移相"章节的"PWM硬件移相端口说明"原文中,明确指出"STC8H2K12U系列支持PWM硬件移相的端口为 P1.3(PWMAPS5)和 P1.5(PWMAPS6)"。手册中未单独列出 STC8H2K32U 的移相端口编号,但两者同属 2K 系列、封装管脚定义基本一致(P1.3、P1.5 均标注为 PWMAPS5/PWMAPS6),因此下面示例按 P1.3/P1.5 这两个移相端口来配置,请您在实测时以实际芯片验证为准。
STC8H2K32U 移相全桥驱动示例
一、方案依据(手册原文)
1. 芯片支持情况(来源:"16位高级PWM定时器,支持正交编码器"产品支持表)
- STC8H2K32U:高级PWM ●、高级PWM新增硬件移相功能 ●、高速高级PWM ●
- 特性表明确标注:"144MHz 16位高级PWM定时器 互补对称死区控制 硬件移相"
2. 移相原理(来源:"高级PWM-硬件移相" → "移相PWM输出模式" → "不对称PWM模式")
"在不对称模式下,生成的两个中心对齐PWM信号间允许存在可编程相移。频率由 PWMA_ARR 寄存器的值确定,而占空比和相移则由一对 PWMA_CCRx 寄存器确定……向 PWMA_CCMRx 寄存器的 OCxM 位写入'1110'(不对称PWM模式1)或'1111'(不对称PWM模式2)。"
"与死区发生器配合使用时,这可控制相移全桥直流到直流转换器。"
这就是移相全桥驱动的官方实现路径:不对称PWM模式(OCxM=1110)+ 死区发生器。
3. 输出脚(来源:"16位高级PWM定时器" → "高级PWM功能脚切换",PWMA_PS 寄存器)
- C1PS[1:0]=00 → PWM1P=P1.0,PWM1N=P1.1
- C2PS[1:0]=00 → PWM2P=P1.2,PWM2N=P1.3
4. I/O口模式(来源:"I/O口" → "配置I/O口")
二、移相全桥信号结构
移相全桥需要 4 个开关管(Q1~Q4),两组互补桥臂:
- 超前桥臂:Q1(PWM1P)、Q2(PWM1N)—— 固定 50% 占空比
- 滞后桥臂:Q3(PWM2P)、Q4(PWM2N)—— 固定 50% 占空比,但相对超前桥臂移相
而 OC1REFC 由 PWMA_CCR1 与 PWMA_CCR2 共同决定,OC2REFC 由 PWMA_CCR3 与 PWMA_CCR4 共同决定。因此本示例用通道1/通道2这一对,通过 CCR1 与 CCR2 的差值设定相移量。
说明:手册给出的通道-CCR 对应关系为"OC1REFC 由 PWMA_CCR1 和 PWMA_CCR2 控制",其中递增计数用 CCR1、递减计数用 CCR2。二者设置相同的 50% 值时输出即为标准中心对齐;两者之和偏离满量程时即产生相移。为便于工程调试,示例中将相移量参数化,您可通过串口在线调整。
三、示例代码(Keil C51,单文件可编译)
/* ============================================================
* STC8H2K32U 移相全桥驱动示例
* ------------------------------------------------------------
* 功能说明:
* 1. 使用 PWMA 的"不对称PWM模式1"输出一组相移PWM波
* 2. 通道1(PWM1P=P1.0 / PWM1N=P1.1) 作为超前桥臂,50%固定占空比
* 3. 通道2(PWM2P=P1.2 / PWM2N=P1.3) 作为滞后桥臂,相对超前臂移相
* 4. 开启死区发生器,防止上下管直通
* 5. 通过串口1可在线修改相移量(0~ARR),观察移相效果
*
* 硬件接线(以 LQFP32 为例):
* P1.0 -> 驱动芯片(超前桥臂上管)
* P1.1 -> 驱动芯片(超前桥臂下管)
* P1.2 -> 驱动芯片(滞后桥臂上管)
* P1.3 -> 驱动芯片(滞后桥臂下管)
* P3.0/P3.1 -> 串口1,连接PC,用于在线调相移量(115200,8,N,1)
*
* 操作说明:
* 编译下载后,串口发送形如 "PS:100" 的指令即可设置相移量,
* 单片机回传 "OK:100",相移量越大,滞后桥臂滞后越多。
* ============================================================ */
#include "stc8h.h"
#include "stdio.h"
#include "string.h"
/* ---------------- PWM 参数定义 ---------------- */
#define PWM_PERIOD 2400 /* PWMA_ARR 值,决定PWM频率 */
/* f_PWM = F_MASTER / (2 * PWM_PERIOD) */
/* 中心对齐模式下,一个完整周期 = 2*ARR 个计数 */
/* 相移量:0 ~ PWM_PERIOD,数值越大滞后桥臂相移越大 */
#define PHASE_DEFAULT 300
unsigned int g_Phase = PHASE_DEFAULT; /* 当前相移量 */
/* ---------------- 串口接收缓冲 ---------------- */
#define RX_BUF_LEN 32
unsigned char xdata g_RxBuf[RX_BUF_LEN];
unsigned char g_RxCnt = 0; /* 已接收字符数 */
bit g_RxFinish = 0; /* 一帧接收完成标志 */
unsigned char g_TxBuf[64]; /* 发送缓冲 */
/* ------------------------------------------------------------
* 函数:PWM_Init
* 说明:初始化PWMA,配置为不对称PWM模式1,输出4路互补信号
* ------------------------------------------------------------ */
void PWM_Init(void)
{
unsigned int cmp_lead; /* 超前桥臂比较值 */
unsigned int cmp_lag; /* 滞后桥臂比较值 */
P_SW2 |= 0x80; /* 使能访问XFR扩展寄存器 */
/* --- 1. 初始化PWM输出引脚为推挽输出 --- */
P1M1 &= ~0x0F; /* P1.0~P1.3 的M1位清0 */
P1M0 |= 0x0F; /* P1.0~P1.3 的M0位置1 -> 推挽输出 */
/* --- 2. 配置PWM时钟源与输出脚切换 --- */
PWMA_PS = 0x00; /* C1PS=00 -> PWM1P=P1.0,PWM1N=P1.1 */
/* C2PS=00 -> PWM2P=P1.2,PWM2N=P1.3 */
/* --- 3. 设置自动重装载值与预分频 --- */
PWMA_PSCRH = 0x00; /* 预分频高字节 */
PWMA_PSCRL = 0x00; /* 预分频=0,即不分频 */
PWMA_ARRH = (unsigned char)(PWM_PERIOD >> 8);
PWMA_ARRL = (unsigned char)(PWM_PERIOD & 0xFF);
/* --- 4. 配置通道1为不对称PWM模式1 --- */
/* OC1M[3:0] = 1110,其中OC1M[2:0]在CCMR1的B6~B4,
最高位OC1M[3]在CCMR1X的B0 */
PWMA_CCMR1 = (0x06 << 4); /* OC1M[2:0]=110 */
PWMA_CCMR1X = 0x01; /* OC1M[3]=1 -> 合起来OC1M[3:0]=1110 */
PWMA_CCMR1 |= 0x08; /* OC1PE=1,允许CCR1预装载 */
/* --- 5. 配置通道2为不对称PWM模式1 --- */
PWMA_CCMR2 = (0x06 << 4); /* OC2M[2:0]=110 */
PWMA_CCMR2X = 0x01; /* OC2M[3]=1 -> OC2M[3:0]=1110 */
PWMA_CCMR2 |= 0x08; /* OC2PE=1,允许CCR2预装载 */
/* --- 6. 设置比较值,决定占空比与相移 --- */
/* 不对称模式:UP计数到CCR1,DOWN计数到CCR2 */
/* 50%占空比中心对齐:CCR1+CCR2 = 2*ARR 时对称 */
cmp_lead = PWM_PERIOD; /* 超前臂50% */
cmp_lag = PWM_PERIOD - g_Phase; /* 滞后臂:相移 g_Phase */
PWMA_CCR1H = (unsigned char)(cmp_lead >> 8);
PWMA_CCR1L = (unsigned char)(cmp_lead & 0xFF);
PWMA_CCR2H = (unsigned char)(cmp_lag >> 8);
PWMA_CCR2L = (unsigned char)(cmp_lag & 0xFF);
/* --- 7. 使能输出通道及互补输出 --- */
PWMA_CCER1 = 0x55; /* CC1E=1,CC1NE=1,CC2E=1,CC2NE=1 */
/* 极性和死区由死区发生器配合 */
/* --- 8. 设置死区时间 --- */
/* 死区时间 = DTGA[7:0] x T_Master,单位视死区分频而定 */
PWMA_DTR = 0x10; /* 适当死区,需按驱动芯片调整 */
/* --- 9. 使能主输出 MOEA=1 --- */
PWMA_BKR = 0x80; /* MOEA=1使能PWM输出,OSSR/OSSI按需配置 */
/* --- 10. 使能PWM计数器,中心对齐模式 --- */
/* CMSA[1:0]=01 -> 中心对齐模式1,ARRPE=1自动重装载 */
PWMA_CR1 = 0x81; /* ARPEA=1, CMSA=01 -> 0b1000_0001 */
/* CENA=1启动计数 */
P_SW2 &= ~0x80; /* 关闭XFR访问(可选) */
}
/* ------------------------------------------------------------
* 函数:Uart_Init
* 说明:串口1初始化,115200,8,N,1
* ------------------------------------------------------------ */
void Uart_Init(void)
{
SCON = 0x50; /* 8位数据,可变波特率 */
/* 使用定时器2作为波特率发生器 */
AUXR |= 0x01; /* S1ST2=1,串口1用定时器2 */
AUXR |= 0x04; /* T2x12=1,定时器2 1T模式 */
/* 系统时钟24MHz时,115200对应的重载值约为 (65536-13) */
T2L = 0xF3;
T2H = 0xFF;
AUXR |= 0x10; /* T2R=1,启动定时器2 */
ES = 1; /* 使能串口1中断 */
EA = 1; /* 打开总中断 */
}
/* ------------------------------------------------------------
* 函数:Uart_SendString
* 说明:发送一个字符串
* ------------------------------------------------------------ */
void Uart_SendString(unsigned char *p)
{
while (*p)
{
SBUF = *p++;
while (!TI);
TI = 0;
}
}
/* ------------------------------------------------------------
* 函数:Uart1_Isr
* 说明:串口1接收中断,按'\n'或'\r'结束一帧
* ------------------------------------------------------------ */
void Uart1_Isr(void) interrupt 4
{
unsigned char c;
if (RI)
{
RI = 0;
c = SBUF;
if (c == '\n' || c == '\r')
{
g_RxBuf[g_RxCnt] = '\0';
g_RxFinish = 1; /* 通知主循环处理 */
}
else
{
if (g_RxCnt < RX_BUF_LEN - 1)
{
g_RxBuf[g_RxCnt++] = c;
}
}
}
}
/* ------------------------------------------------------------
* 函数:main
* ------------------------------------------------------------ */
void main(void)
{
unsigned int new_phase;
unsigned int cmp_lag;
PWM_Init();
Uart_Init();
Uart_SendString("STC8H2K32U Phase-Shift Full-Bridge Demo\r\n");
Uart_SendString("Send PS:xxx to set phase (0-2400)\r\n");
while (1)
{
if (g_RxFinish)
{
g_RxFinish = 0;
/* 解析 "PS:xxx" 格式指令 */
if (strncmp((char *)g_RxBuf, "PS:", 3) == 0)
{
if (sscanf((char *)g_RxBuf, "PS:%u", &new_phase) == 1)
{
if (new_phase > PWM_PERIOD)
{
new_phase = PWM_PERIOD;
}
g_Phase = new_phase;
/* 更新滞后桥臂比较值 */
cmp_lag = PWM_PERIOD - g_Phase;
P_SW2 |= 0x80; /* 使能XFR访问 */
/* 通过CCR2更新相移,ARRPE与OC2PE保证在更新事件生效 */
PWMA_CCR2H = (unsigned char)(cmp_lag >> 8);
PWMA_CCR2L = (unsigned char)(cmp_lag & 0xFF);
/* 产生更新事件,使CCR2立即生效 */
PWMA_EGR = 0x01; /* UGA=1,产生更新事件 */
P_SW2 &= ~0x80;
/* 回传结果 */
sprintf((char *)g_TxBuf, "OK:%u\r\n", g_Phase);
Uart_SendString(g_TxBuf);
}
}
else
{
Uart_SendString("ERR\r\n");
}
g_RxCnt = 0; /* 清接收计数,准备下一帧 */
}
}
}
四、关键配置说明与注意事项
| 项目 |
手册依据 |
说明 |
| OC1M[3:0]=1110 |
"高级PWM-硬件移相"章节 |
不对称PWM模式1,最高位OC1M[3]在CCMR1X,低3位在CCMR1 |
| OC1M 位域分两部分 |
章节注释:"出于兼容性原因,OCxM[3:0]位域分为两部分,最高有效位与最低有效的3位不相邻" |
所以必须分别写 CCMR1 和 CCMR1X |
| MOEA=1 |
"刹车寄存器(PWMx_BKR)" |
MOEA(B7)=1 才允许输出 |
| 死区 |
"死区寄存器(PWMx_DTR)" |
DTGA[7:0] |
| 推挽输出 |
"配置I/O口" |
PnM1.x=0, PnM0.x=1 |
⚠️ 需要您注意/确认的点:
- 系统时钟:示例按 24MHz 估算波特率重载值。若您使用 45MHz 或其他 IRC 频率,请相应修改
T2L/T2H。PWM 频率由 PWM_PERIOD 和主频共同决定,请按实际需求重新计算。
- 相移与占空比的耦合:在不对称PWM模式1中,CCR1、CCR2 共同决定占空比和相移。本示例将超前臂固定在 50%,仅调 CCR2 实现相移。实际移相全桥通常需要两臂都保持 50% 占空比、仅相位不同,若您追求严格的双50%相移,建议采用组合PWM模式(OCxM=1100/1101),手册原文说明该模式"生成的两个边沿或中心对齐PWM信号的各个脉冲间允许存在可编程延时和相移",更适合精确移相。是否需要我按组合PWM模式再给一版?
- 死区时间:
PWMA_DTR=0x10 仅为示例值,必须根据您选用的栅极驱动芯片和 MOS 管开关时间实际计算。
- 移相端口 P1.3/P1.5:手册明确写的是 STC8H2K12U 的移相端口,本型号请以实测为准。
需要我进一步为您提供以下哪一项?
- 按组合PWM模式重写一版(更贴合严格50%移相全桥)
- 增加刹车/过流保护(PWMFLT 外部异常检测)配置
- 帮您计算具体主频下的 PWM 频率、死区时间参数
请告诉我您的系统主频和目标 PWM 频率,我可给出精确的寄存器取值。
🔍 搜索 "STC8H2K32U 移相全桥驱动的例子"
📌 相关论坛讨论
- 求推荐一款合适的单片机,需要驱动一个移相全桥的转换器工作
- 关于8H12系列移相功能PWM芯片问题
- 请教各位大师 AI8H2K32U硬件PWM移相问题
⏱️ 查找用时 10.5s | 总回答用时 28.6s