前言
PWM(全称Pulse Width Modulation,定频调宽度调制技术),是近年来发展的一种电力电子技术,广泛应用于开关电源,电能变换领域,以及电机驱动等众多领域。PWM本质上是高频率,但占空比可能变化的脉冲波。
产生专门产生PWM信号的集成芯片,也可以使用MCU或者DSP进行配置产生PWM。数字控制器生成PWM具有灵活方便的优点,因此广泛使用控制器产生期望的PWM进行控制。
STC16F系列的单片机内部集成有PWMA,PWMB类高级PWM。PWMA有8个通道,PWMA1P,PWMA1N到PWMA4P,PWMA4N。
每一个PWMxP和对应的PWMxN互为一组PWM。可以输出带死区互补对称PWM。而PWMB只有4个通道,分别是PWM5,PWM6,PWM7,PWM8.
实际开发产品的过程中,基本上都有可能使用到互补对称的PWM波,并且STC16F系列的PWMA类的PWM通道完全够用。因此只需要掌握PWMA的配置方式以及使用方法即可。
PWM产生原理
TB(Time Base时基)模块
CK_PSC是主时钟,经预分频器分频后,作为16位计数器[PWM1_CNTRH:PWM1_CNTRL]的计数脉冲。 这个计数器有3种计数模式,向上计数,向下计数或中央对齐模式。 当16位计数器溢出之后,会重新装载重装值进行下一次计数。(类似于定时器的自动重装载模式)
重复计数寄存器PWM1_RCR用于设置多少次计数器溢出产生一次更新时间。
比较输出模块
比较输出模块的主要功能是将TB模块中的定时器与一个16位的寄存器[CCRxH:CCRxL]中的值作比较。 当PWMx_CNT<[CCRxH:CCRxL]以及PWMx_CNT>[CCRxH:CCRxL]时,PWM输出端口的极性。 一种PWM波形配置
代码配置
综上所述,只需要对PWMx的TB模块和输出比较模块进行相应的配置即可输出对应的PWM波。但是由于STC16F系列的PWM输出端口很灵活,可以根据软件配置在不同的IO口输出PWM。 编写pwm.c文件
#include "STC16f.h"
#include "pwm.h"
#include "led.h"
int PWM1_Duty = 0.1 * TBPRD;
int PWM2_Duty = 0.1 * TBPRD;
int PWM3_Duty = 0.5 * TBPRD;
int PWM4_Duty = 0.9 * TBPRD;
void Init_PWMA()
{
P_SW2 |= 0x80;
PWMA_CCER1 = 0x00;
PWMA_CCER2 = 0x00;
PWMA_PSCRH = (PreScale-1) >> 8;
PWMA_PSCRL = PreScale-1;
PWMA_CCMR1 = 0x60;
PWMA_CCMR2 = 0x60;
PWMA_CCMR3 = 0x60;
PWMA_CCMR4 = 0x60;
PWMA_CCER1 = 0x55;
PWMA_CCER2 = 0x55;
PWMA_ARRH = (TBPRD - 1) >> 8;
PWMA_ARRL = TBPRD - 1;
PWMA_ENO = 0x00;
PWMA_ENO |= ENO1P;
PWMA_ENO |= ENO2P;
PWMA_CCR1H = ((unsigned int)PWM1_Duty >> 8);
PWMA_CCR1L = ((unsigned int)PWM1_Duty);
PWMA_CCR2H = ((unsigned int)PWM2_Duty >> 8);
PWMA_CCR2L = ((unsigned int)PWM2_Duty);
PWMA_CCR3H = ((unsigned int)PWM3_Duty >> 8);
PWMA_CCR3L = ((unsigned int)PWM3_Duty);
PWMA_CCR4H = ((unsigned int)PWM4_Duty >> 8);
PWMA_CCR4L = ((unsigned int)PWM4_Duty);
PWMA_PS = 0x00;
PWMA_PS |= PWM1_2;
PWMA_PS |= PWM2_2;
PWMA_PS |= PWM3_2;
PWMA_PS |= PWM4_2;
PWMA_DTR = 50;
PWMA_BKR |= 0x80;
PWMA_CR1 |= 0x01;
P_SW2 &= 0x7f;
}
void Forward()
{
AIN1 = 0;
AIN2 = 1;
BIN1 = 0;
BIN2 = 1;
}
void Backward()
{
AIN1=1;
AIN2=0;
BIN1=1;
BIN2=0;
}
void PWM1_Duty_Update(unsigned int cmp)
{
P_SW2 |= 0x80;
if(cmp > 0.95 * TBPRD)
cmp = 0.95 * TBPRD;
else if(cmp < 0.05 * TBPRD)
cmp = 0.05 * TBPRD;
PWMA_CCR1H = ((unsigned int)cmp >> 8);
PWMA_CCR1L = ((unsigned int)cmp);
P_SW2 &= 0x7f;
}
void PWM2_Duty_Update(unsigned int cmp)
{
P_SW2 |= 0x80;
if(cmp > 0.95 * TBPRD)
cmp = 0.95 * TBPRD;
else if(cmp < 0.05 * TBPRD)
cmp = 0.05 * TBPRD;
PWMA_CCR2H = ((unsigned int)cmp >> 8);
PWMA_CCR2L = ((unsigned int)cmp);
P_SW2 &= 0x7f;
}
void PWM3_Duty_Update(unsigned int cmp)
{
P_SW2 |= 0x80;
if(cmp > 0.95 * TBPRD)
cmp = 0.95 * TBPRD;
else if(cmp < 0.05 * TBPRD)
cmp = 0.05 * TBPRD;
PWMA_CCR3H = ((unsigned int)cmp >> 8);
PWMA_CCR3L = ((unsigned int)cmp);
P_SW2 &= 0x7f;
}
void PWM4_Duty_Update(unsigned int cmp)
{
P_SW2 |= 0x80;
if(cmp > 0.95 * TBPRD)
cmp = 0.95 * TBPRD;
else if(cmp < 0.05 * TBPRD)
cmp = 0.05 * TBPRD;
PWMA_CCR4H = ((unsigned int)cmp >> 8);
PWMA_CCR4L = ((unsigned int)cmp);
P_SW2 &= 0x7f;
}
void PWMA_Routine(void) interrupt 7
{
static int i=0;
static int j=0;
i++;
if(i>=2000)
{
i=0;
j++;
if(j==500)
{
j=0;
}
}
}
编写pwm.h文件
#ifndef _PWM_H_
#define _PWM_H_
#define AIN1 P05
#define AIN2 P07
#define BIN1 P03
#define BIN2 P02
#define PreScale 24
#define TBPRD 100
#define PWM1_0 0x00
#define PWM1_1 0x01
#define PWM1_2 0x02
#define PWM2_0 0x00
#define PWM2_1 0x04
#define PWM2_2 0x08
#define PWM3_0 0x00
#define PWM3_1 0x10
#define PWM3_2 0x20
#define PWM4_0 0x00
#define PWM4_1 0x40
#define PWM4_2 0x80
#define PWM4_3 0xC0
#define ENO1P 0x01
#define ENO1N 0x02
#define ENO2P 0x04
#define ENO2N 0x08
#define ENO3P 0x10
#define ENO3N 0x20
#define ENO4P 0x40
#define ENO4N 0x80
extern int PWM1_Duty;
extern int PWM2_Duty;
extern int PWM3_Duty;
extern int PWM4_Duty;
void InitPWMA(void);
void Forward(void);
void Backward(void);
void PWM1_Duty_Update(unsigned int cmp);
void PWM2_Duty_Update(unsigned int cmp);
void PWM3_Duty_Update(unsigned int cmp);
void PWM4_Duty_Update(unsigned int cmp);
#endif
|