利用STC15输出两路互补SPWM波形
-
🎞逻辑分析仪信号采集演示:
-
🔖本案例使用的是
IAP15W4K61S4
验证。 -
📍相关篇《STC15系列PWM相关功能寄存器介绍》
-
📌相关开源PCB《【PCB开源分享】STC/IAP15W4K61S4开发板》
-
🎈相关参考来源于STC官方资料。
📋STC15W4K32S4系列新增6通道高精度PWM (带死区控制的增强型PWM波形发生器)简介
STC15W4K32S4系列的单片机集成了一组(各自独立6路)增强型的PWM波形发生器。PWM波形发生器内部有一个15位的PWM计数器供6路PWM使用,用户可以设置每路PWM的初始电平。另外,PWM波形发生器为每路PWM又设计了两个用于控制波形翻转的计数器T1/T2,可以非常灵活的每路PWM的高低电平宽度,从而达到对PWM的占空比以及PWM的输出延迟进行控制的目的。由于6路PWM是各自独立的,且每路PWM的初始状态可以进行设定,所以用户可以将其中的任意两路配合起来使用,即可实现互补对称输出以及死区控制等特殊应用。
📑SPWM实现原理介绍
SPWM是使用PWM来获得正弦波输出效果的一种技术。像STCI5W4KxS4系列MCU内带6通道15位PWM,各路PWM周期 (频率) 相同,输出的占空比独立可调,并且输出始终保持同步,输出相位可设置。这些特性使得设计SPWM成为可能并且可方便设置死区时间,对于驱动桥式电路,死区时间至关重要。不过本MCU没有专门的死区控制寄存器,通讨查表法设置PWM占空比参数来达到。
内部15位的PWM计数器一旦运行,就会从0开始在每个PWM时钟到来时加1,其值线性上升,当计数到与15位的周期设置寄存器[
PWMCH
,PWMCL
]相等时(图中斜线A到B),内部PWM计数器归0,并产生中断,称为“归0中断
”。本例周期设置为2400,内部计数器计到2400就归0,即2399,下一个时钟就归0.
STC15W4K32S4 PWM输出端口定义和切换
STC15W4K32S4系列增强型PWM输出端口定义如下:[PWM2:P3.7, PWM3:P2.1, PWM4:P2.2, PWM5:P2.3, PWM6:P1.6, PWM7:P1.7],每路PWM的输出端口都可使用特殊功能寄存器位CnPINSEL分别独立的切换到第二组:[PWM2_2:P2.7, PWM3_2:P4.5, PWM4_2:P4.4, PWM5_2:P4.2, PWM6_2:P0.7, PWM7_2:P0.6]。
所有与PWM相关的端口,在上电后均为高阻输入态,必须在程序中将这些口设置为双向口或强推挽模式才可正常输出波形。
🌼双路PWM产生互补或同相的SPWM示例程序代码
- 🎉本示例程序来源于STC15实验箱中的案例。
- ✨使用的是PWM3(P21)和PWM4(P22)两路。
- 📢在使用STC-ISP烧录时,注意选择24MHz,不然波形频率就不对了。
当内部计数器的值与某个翻转寄存器的值相等时,就对对应的输出IO取反,本例中,PWM3从P2.1输出
并且PWM3输出的P2.1初始电平为0,PWM4输出的P2.2初始电平为1,则,当内部PWM计数器计到等于PWM4T1=53时,P2.2 由高输出低,计到等于PWM3T1=65时,P2.1由低输出高,计到等于PWM3T2-800时,P2.1由高输出低,计到等于PWM4T2-812时,P22由低输出高
两路输出是互补的,用于驱动一些MOSFET的半桥式驱动IC。可以看到这两路PWM的翻转时刻有一点差别,相差12个时钟,为什么要这样设计呢?这就是传说中的死区。为了方便说明,把这两路PWM放大如图2:
-
P22输出低电平后,再过12个时钟在24MHZ时,对应0.Sus),P2.1输出高电平。
-
P2.1输出低电平后,再过12个时钟在24MHZ时,对应0.5us),P2.2输出高电平。
这个12个时钟就是死区时间,本例PWM时钟为IT模式,对应0.5ws。假设P2.1驱动的是半桥的下臂,P22驱动的是上臂,则P2.2输出低电平后,上臂开始关闭,经过05us,上臂关闭完毕,P2.1输出高电平,下臂打开。P2.1输出低电平后,下臂开始关闭,经过0.5us,下臂关闭完毕,P2.2输出高电平,上臂打开。这样,死区时间的设置,可以避免上下臂同时打开造成烧毁MOSFET。
有人会说,一路输出关闭的同时,另一路大开,不会烧管子啊?
错啦,MOSFET打开快,关闭慢相关知识请翻翻书),所以需要一段时间关闭
P2.1或P2.2如果直接用示波器观察,会看到比我们的思绪还凌乱的波形,因为PWM一直在变化,但
是通过RC (1K+1uF) 低通滤波再观察的话,就会看到两个反相的正弦波,神奇吧,呵呵! -
RC低通滤波器,截止频率计算公式:
-
经过RC低通滤波器后,使用示波器采集的2路波形:
本例伸用24MHz时钟,PWM时钟为1T模式,PWM周期2400,正收表幅度为2300,往上偏移60
个时钟方便过0中断重装数据)。正弦采样为200点,则输出正弦波频率 =240000002400/200=50HZ。
/*------------------------------------------------------------------*/
/* --- STC MCU International Limited -------------------------------*/
/* --- STC 1T Series MCU RC Demo -----------------------------------*/
/* --- Mobile: (86)13922805190 -------------------------------------*/
/* --- Fax: 86-0513-55012956,55012947,55012969 ---------------------*/
/* --- Tel: 86-0513-55012928,55012929,55012966 ---------------------*/
/* --- Web: www.GXWMCU.com -----------------------------------------*/
/* --- QQ: 800003751 ----------------------------------------------*/
/* If you want to use the program or the program referenced in the */
/* article, please specify in which data and procedures from STC */
/*------------------------------------------------------------------*/
#include "config.h"
#include "PWM.h"
/************* 功能说明 **************
演示使用2路PWM产生互补或同相的SPWM.
主时钟选择24MHZ, PWM时钟选择1T, PWM周期2400, 死区12个时钟(0.5us).正弦波表用200点.
输出正弦波频率 = 24000000 / 2400 / 200 = 50 HZ.
本程序仅仅是一个SPWM的演示程序, 用户可以通过上面的计算方法修改PWM周期和正弦波的点数和幅度.
本程序输出频率固定, 如果需要变频, 请用户自己设计变频方案.
本程序从P2.1(PWM3)输出正相脉冲, 从P2.2(PWM4)输出反相脉冲(互补).
如果需要P2.2输出同相的, 请在初始化配置中"Start_IO_Level"项选择0(设置PWM输出端口的初始电平, 0或1).
工程文件:
delay.c
pwm.c
main.c
******************************************/
/************* 本地常量声明 **************/
/************* 本地变量声明 **************/
/************* 本地函数声明 **************/
/************* 外部函数和变量声明 *****************/
//========================================================================
// 函数: void PWM_config(void)
// 描述: PWM配置函数。
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2014-8-15
// 备注:
//========================================================================
void PWM_config(void)
{
PWMx_InitDefine PWMx_InitStructure; //结构定义
PWMx_InitStructure.PWMx_IO_Select = PWM3_P21; //PWM输出IO选择. PWM2_P37,PWM2_P27,PWM3_P21,PWM3_P45,PWM4_P22,PWM4_P44,PWM5_P23,PWM5_P42,PWM6_P16,PWM6_P07,PWM7_P17,PWM7_P06
PWMx_InitStructure.Start_IO_Level = 0; //设置PWM输出端口的初始电平, 0或1
PWMx_InitStructure.PWMx_Interrupt = DISABLE; //中断允许, ENABLE或DISABLE
PWMx_InitStructure.FirstEdge_Interrupt = DISABLE; //第一个翻转中断允许, ENABLE或DISABLE
PWMx_InitStructure.SecondEdge_Interrupt = DISABLE; //第二个翻转中断允许, ENABLE或DISABLE
PWMx_InitStructure.FirstEdge = 65; //第一个翻转计数, 1~32767
PWMx_InitStructure.SecondEdge = 1220; //第二个翻转计数, 1~32767
PWMx_Configuration(PWM3_ID, &PWMx_InitStructure); //初始化PWM, PWM2_ID,PWM3_ID,PWM4_ID,PWM5_ID,PWM6_ID,PWM7_ID
P21 = 0;
P2n_push_pull(1<<1); //IO初始化, 上电时为高阻
PWMx_InitStructure.PWMx_IO_Select = PWM4_P22; //PWM输出IO选择. PWM2_P37,PWM2_P27,PWM3_P21,PWM3_P45,PWM4_P22,PWM4_P44,PWM5_P23,PWM5_P42,PWM6_P16,PWM6_P07,PWM7_P17,PWM7_P06
PWMx_InitStructure.Start_IO_Level = 1; //设置PWM输出端口的初始电平, 0或1
PWMx_InitStructure.PWMx_Interrupt = DISABLE; //中断允许, ENABLE或DISABLE
PWMx_InitStructure.FirstEdge_Interrupt = DISABLE; //第一个翻转中断允许, ENABLE或DISABLE
PWMx_InitStructure.SecondEdge_Interrupt = DISABLE; //第二个翻转中断允许, ENABLE或DISABLE
PWMx_InitStructure.FirstEdge = 65-PWM_DeadZone; //第一个翻转计数, 1~32767
PWMx_InitStructure.SecondEdge = 1220+PWM_DeadZone;//第二个翻转计数, 1~32767
PWMx_Configuration(PWM4_ID, &PWMx_InitStructure); //初始化PWM, PWM2_ID,PWM3_ID,PWM4_ID,PWM5_ID,PWM6_ID,PWM7_ID
P22 = 1;
P2n_push_pull(1<<2); //IO初始化, 上电时为高阻
PWM_SourceClk_Duty(PwmClk_1T, 2400); //时钟源: PwmClk_1T,PwmClk_2T, ... PwmClk_16T, PwmClk_Timer2, PWM周期: 1~32767
PWMCR |= ENPWM; // 使能PWM波形发生器,PWM计数器开始计数
// PWMCR &= ~ECBI; //禁止PWM计数器归零中断
PWMCR |= ECBI; //允许PWM计数器归零中断
// PWMFDCR = ENFD | FLTFLIO | FDIO; //PWM失效中断控制, ENFD | FLTFLIO | EFDI | FDCMP | FDIO
}
/**********************************************/
void main(void)
{
PWM_config(); //初始化PWM
EA = 1; //允许全局中断
while (1)
{
}
}
📚完整工程代码
链接: https://pan.baidu.com/s/1PlF8HmJgXOgMTSa48lodcg
提取码: 8h6k