PWM 波输出实验1
实验1:输出指定频率和占空比的PWM波。
脉冲宽度调制,简称PWM。
PWM有两种应用:一种是将单片机内部的数字量转换为模拟电压输出,一种应用主要是针对一些产品需要PWM信号进行控制,比如直流无刷电机的调速,通常需要外部提供PWM信号。
PWM可用于调整输出直流平均电压。
对于矩形波,平均电压=峰值电压*占空比。占空比是一个脉冲周期内高电平时间与周期的比值。
例如上图,占空比=高电平时间Tp/脉冲周期T
输出平均电压=峰值电压*占空比
假设占空比为50%,峰值电压为5V,则平均电压=5*50%=2.5V,也就是万用表直流档得到的电压。
15W4K58S4有6路PWM波形发生器,都是以一个15位的PWM计数器为基准的。其中,6路PWM各自独立,有单独的寄存器对反转门限和工作方式进行设置。
注意,在STCPWM管脚中,在6路PWM中,它的起始标号是2,末尾标号是7,共6路。
与PWM波形发生器有关的寄存器
PWM波形发生器引脚切换:
PWM | PWM2 | PWM3 | PWM4 | PWM5 | PWM6 | PWM7 |
第一输出引脚 | P3.7 | P2.1 | P2.2 | P2.3 | P1.6 | P1.7 |
第二输出引脚 | P2.7 | P4.5 | P4.4 | P4.2 | P0.7 | P0.6 |
PWMn控制寄存器PWMnCR:
复位值:xxxx0000
位 | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 |
名字 | - | - | - | - | PWMn_PS | EPWMnI | EC2T2SI | EC2T1SI |
■PWMn_PS:PWM输出引脚选择位
0:第一输出引脚
1:第二输出引脚
■EPWMnI:PWMn中断使能控制位。
0:关闭PWM2中断。
1:使能PWM2中断。
当CnIF(PWMn中断标志位)被硬件设置为1时,程序将跳转到相应中断服务程序入口执行中断服务程序
■ECnT2sI :PWMn的T2匹配发生波形翻转时的中断控制位。
0:关闭T2翻转时的中断
1:使能T2翻转时的中断,当PWMn波形发生器内部计数值与T2计数器所设置的值相匹配时,PWM的波形发生翻转,同时硬件将CnIF置1。
■ECnT1SI:PWMn的T1匹配发生波形翻转时的中断控制位。
0:关闭T1翻转时的中断;
1:使能T1翻转时的中断。当PWMn波形发生器内部计数值与T1计数器所设置的值相匹配时,PWM的波形发生翻转,同时硬件将CnIF置1。
端口配置寄存器 P_SW2:
地 址:0xBA 复位值:000x0000
位 | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 |
名字 | EAXSFR | 0 | 0 | 0 | - | S4_S | S3_S | S2_S |
STC15W4K系列单片机有些特殊功能寄存器位于外部RAM区(XRAM),EAXSFR位用来控制是访问XRAM存储区,还是XRAM特殊功能寄存器区。
■EAXSFR:为访问扩展SFR使能控制位。
0:访问XRAM存储区
1:访问XRAM特殊功能寄存器区
PWM配置寄存器PWMCFG:
地址:0xF1 复位值:x0000000
位 | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 |
名字 | - | CBTADC | C7INI | C6INI | C5INI | C4INI | C3INI | C2INI |
■CBTADC:PWM计数器归零触发ADC转换控制位。
0:PWM计数器归零不触发ADC转换
1:PWM计数器归零触发ADC转换
■C7INI:设置PWM7输出端口初始电平
0:初始电平为低
1:初始电平为高
其它位类似
PWM控制寄存器:PWMCR
地址:0xF5 复位值:00000000
位 | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 |
名字 | ENPWM | ECBI | ENC7O | ENC6O | ENC5O | ENC4O | ENC3O | ENC2O |
■ENPWM:使能PWM发生器
0:关闭PWM发生器
1:开启PWM发生器,PWM计数器开始计数
■ECBI: PWM计数器归零中断使能位。
0:关闭PWM计数器归零中断,(CBIF依然会被硬件置位)
1:使能PWM计数器归零中断。
■ENC7O :PwM7输岀使能位。
0:PwM通道7的端口为GPIO
1:PWM通道7的端口为PWM输出口,受PWM波形发生器控制
其它位类似
PWM中断标志寄存器:
地址:0xF6 复位值:x0000000
位 | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 |
名字 | - | CBIF | C7IF | C6IF | C5IF | C4IF | C3IF | C2IF |
■CBIF:PWM计数器归零中断标志位。当PWM计数器归零时,硬件将此位置为1。当ECBI=1时,程序会跳转到响应的中断入口执行中断服务程序。
■CTIF
第7通道的PWM中断标志位,可设置在翻转点1和翻转点2触发C7IF。
当PWM发生翻转时,硬件自动将该位置1。当EPWM7位为1时,程序会跳转到相应中断入口执行中断服务程序。
其它位类似
当达到设置的翻转门限时,该位置1,如果PWM中断设置位允许,则CPU响应中断。
(这位类似定时器里的定时器中断标志位。EPWMnI就相当于定时器中断允许位。 )
PWM外部异常控制寄存器PWMFDCR
地址:0xF7 复位值:x0000000
位 | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 |
名字 | - | - | ENFD | FLTFLIO | EEDI | FDCMP | FDIO | FDIF |
■ENFD:PWM外部异常检测功能控制位。
0:关闭PWM外部异常检测功能
1:使能PWM外部异常检测功能
■ FLTFLIO:发生PWM外部异常时,对PWM输出口控制位。
0:发生PWM外部异常时;PWM的输出口不作任何改变;
1:发生PWM外部异常时,PWM的输出口立即被设置为高阻输入模式。
■EFDI:PWM异常检测中断使能位。
0:关闭PWM异常检测中断(FDIF仍然会被硬件置位);
1:使能PWM异常检测中断
■EDCMP设定PWM异常检测源为比较器的输出。
0时,比较器与PWM无关。
1时,当比较器正极P5.5/CMP+的电平比比较器负极P5.4/CMP-的电平高或者比较器正极P5.5/CMP+的电平比内部参考电压源1.28V高时,触发PWM异常。
■FDIO设定PWM异常检测源为端口P24的状态。
0时,P2.4的状态与PWM无关;
1时,P24的电平为高时,触发PWM异常。
■FDIF:PWM异常检测中断标志位。
当发生PWM异常,即:比较器正极P5.5/CMP+的电平比比较器负极P5.4/CMP-的电平高。
或者比较器正极P5.5/CMP+的电平比内部参考电压源1.28V高,或者P2.4的电平为高时,硬件自动将该位置1。
当EFDI为1时,程序会跳转到中断入口执行中断服务程序
PWM计数器
包含PWM计数器高字节寄存器 PWMCH和PWM计数器低字节寄存器 PWMCL。是一个15位的寄存器,计数范围为1~32768之间的任意值都可以作为PWM的周期。
PWM波形发生器内部的计数器从0开始计数,每个PWM时钟周期递增1
当内部计数器的计数值达到[ PWMCH, PWMCL]设置的PWM周期时,PWM波形发生器内部的计数器将从0开始重新计数。硬件会自动将PWM归零中断标志位CBF置为1,如果ECB为1序将跳转到相应中断入口执行中断服务程序。
PWMCH寄存器:
地址: 0xFFF0 复位值:x0000000
位 | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 |
名字 | - | PWMCH[14:8] |
PWMCL寄存器:
地址: 0xFFF1 复位值:00000000
位 | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 |
名字 | PWMCL[7:0] |
低8位和高7位组合为15位计数值,计数范围是0---32767
PWM时钟选择寄存器 PWMCKS
地址:0xFFF2 复位值:XXX00000
位 | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 |
名字 | - | - | - | SELT2 | PS[3:0] |
■SELT2:PWM时钟源选择。
0: PWM时钟源为系统时钟经过分频器之后的时钟;
1时,PWM时钟源为定时器2的溢出脉冲
■PS[3:0]:系统时钟分频参数。
当SELT2位为0时,PWM时钟频率=系统时钟频率/(PS[3:0]+1)
PWM2第一次翻转高字节寄存器PWM2T1H
地址:0xFF00的位置 复位值:x0000000
位 | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 |
名字 | - | PWM2T1H[14:8] |
每个PWM通道都有两个翻转寄存器:第一次翻转寄存器和第二次翻转寄存器,每个寄存器有高位和低位两个字节。
有高位7字节,低位8字节,构成15位值,就是翻转的计数门限。
PWM2第一次翻转低字节寄存器PWM2T1L
地址:0xFF01的位置 复位值:00000000
位 | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 |
名字 | PWM2T1L[7:0] |
PWM中断优先级控制寄存器IP2
地址:0xB5 复位值: xxxx0000
位 | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 |
名字 | - | - | - | PX4 | PPWMFD | PPWM | PSPI | PS2 |
PWM寄存器使用的是扩展内存区的SFR,无法使用51的sfr指令去声明地址。需要这样定义指针:
(在STC15W4K.H中,厂家已经定义好了,也可以自己定义)
厂家头文件是这样定义的:
#define PWMC (*(unsigned int volatile xdata *)0xFFF0)
其中(unsigned int volatile xdata *)0xFFF0) 是将一个常量转换为指针,这个指针存储的就是扩展特殊功能寄存器的地址。
*(unsigned int volatile xdata *)0xFFF0就是对这个地址的引用,也就是可以对地址中的存储单元进行赋值操作。
#define PWMC *(unsigned int volatile xdata *)0xFFF0就是将这个引用的表达式简写
PWM波形发生实例:
要求用IAP 15W4K58S4芯片做一个PWM输出,占空比为50.8% 频率为13.57KHZ
问题解答:
假设单片机使用内部RC振荡器,为12MHz,没有进行系统时钟分频,那么系统时钟sysclk就等于12MHz
PWM时钟源设置为分频后的系统时钟,那么PWM计数一次的时间是:1/12MHz=1/12微秒
如果PWM波的频率为13.57KHz,那么它的周期是1/13.57KHz=73.692微秒
73.692/(1/12)=884个PWM计数
占空比884*50.8%=450
也就是设置 CYCLE=884-1; WIDE=450-1;
就可得到 13.57KHz 占空比50.8% 的PWM波
使用PWM6输出
如图所示,由于起始电平设置为低电平,而T2的翻转门限是0,那么在每个周期的开始,有一次翻转。所以T1翻转门限值就是高电平所占的时间。也就是T2=0; T1=WIDE;
其实,T1,T2这两个翻转点没有先后顺序之分,它只是提供了一个周期中两次翻转的机会,T1,T2只是这两次翻转的门限计数寄存器的名字,并不代表第一次翻转必须设置在T1,第二次翻转必须设置在T2,翻转的先后顺序是由计数值决定的。所以,如果设置T1=0,T2=WIDE,产生的波形结果也是一样的。
#include "STC15W4K.H"
#define uchar unsigned char
#define CYCLE 884-1 //定义PWM周期(最大值为32767)
#define WIDE 450-1 //定义高电平时间
sbit P1_6=P1^6; //PWM6第一输出
void port_mode() // 端口模式 将所有端口设置为准双向弱上拉
{
P0M1=0x00; P0M0=0x00;P1M1=0x00; P1M0=0x00;P2M1=0x00; P2M0=0x00;P3M1=0x00; P3M0=0x00;
P4M1=0x00; P4M0=0x00;P5M1=0x00; P5M0=0x00;P6M1=0x00; P6M0=0x00;P7M1=0x00; P7M0=0x00;
}
void main()
{
//经过设置后,端口工作模式为 准双向弱上拉
//根据实际需要,设置为强推挽也可以输出PWM波,只是一定要串上电阻
port_mode();//将所有端口初始化为准双向弱上拉
//将P_SW2寄存器的最高位置1,
//也就是使能访问外部扩展特殊功能寄存器XSFR,而不是访问外部数据寄存器XRAM
P_SW2|=0x80;
//设置PWM配置寄存器
//其他各位都为1,只有C6INI=0,也就是设置PWM6的初始输出电平为低电平
PWMCFG&=0xEF;
//设置PWM计数器的时钟源为 系统时钟分频,而不是定时器T2溢出,设置为系统时钟的0+1=1分频
PWMCKS=0x00;
//PWM计数器设置计数值
PWMC=CYCLE;
//T1翻转的计数值
PWM6T1=WIDE;
//T2翻转的计数值
PWM6T2=0;
//注意这个寄存器与PWMCR不同
//PWM6第一引脚输出,即P1.6输出
//关闭PWM6中断
//关闭T1匹配翻转中断
//关闭T2匹配翻转中断
PWM6CR=0;
//由于前面已经设置完XSFR,这里设置为禁止访问XSFR
//也就是设置为对外部数据存储器XRAM的访问
P_SW2&=0x0F;
//开启总PWM 波形发生器功能,开启PWM6输出,或者说是使能也可以
PWMCR|=0x90;
while(1);
}
实验结果: