PWM移相以及占空比可变(上)

本文阐述了STC8H如何通过高级定时器实现PWM输出的频率同步、相位差调节,并给出了实际编程代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文以 STC8H 芯片为例,输出两路相位可调以及占空比可调的PWM(CH1  CH2)。

一、PWM输出原理

我们所使用的是 STC8H 高级定时器的输出比较模式。

1.1、普通PWM输出

图1.1.1

图1.1.2

上两图展示的是普通的PWM输出模式,该模式下可以自己设定ARR和CCR,其中CCR用于控制占空比。

1.2、输出比较模式

输出比较模式通俗来说 是CNT = CCR时  电平会翻转。例如 你配置了 向上计数,ARR=100, CCR=30,初始电平为高电平,那么 CNT从0计数到30时, CNT =CCR =30,此时高电平就会跳变到低电平,CNT继续在30的基础上计数,直到计数到100并溢出,此时CNT会置0并重新开始计数。

值得注意的是,PWM模式与翻转模式下所输出的波形频率是相差 2倍的,即 PWM输出频率为10HZ,那么输出比较模式下的输出频率只有5HZ。

这是因为   输出比较模式下不关心CNT比 CCR值大还是小,只关心CNT和CCR值什么时候相等,两个值相等时,就翻转输出电平。在PWM模式下,CNT值从0增加到ARR一个周期内输出电平有两次变化,而在输出比较模式下时CNT值从0增加到ARR一个周期内输出电平只有一次变化。所以输出比较模式下,定时器输出方波的频率为PWM模式下定时器输出方波频率的一半。(该段内容源自--生成两路PWM波相位差90°的方法)

 要想 输出比较模式 下输出的PWM波的频率与普通PWM模式下输出的频率相等,则需要对输出比较模式下输出的PWM频率进行2分频。该点后续详解。

二、相位差原理

本文可调节的相位差在 0-180°范围 

CH1为普通PWM输出,其自动重装值为 ARR1=100,CH2为输出比较模式,其自动重装值为ARR2

2.1、频率相等

要实现CH1与CH2的输出频率相等,最重要的是两者的ARR的设置。其设置应为

ARR2=ARR1 / 2,且 CH2的 CCR应设置为0或50。

这是因为   输出比较模式下不关心CNT比 CCR值大还是小,只关心CNT和CCR值什么时候相等,两个值相等时,就翻转输出电平。在PWM模式下,CNT值从0增加到ARR一个周期内输出电平有两次变化,而在输出比较模式下时CNT值从0增加到ARR一个周期内输出电平只有一次变化。

我们设置 CH2 的ARR2 的值为50,其目的就是是为了 让  输出比较模式PWM模式下的一个 ARR1周期内,有两次电平跳变,从而达到2分频的效果。而CCR设置为0或50,只是让电平在最大量程临界点电平跳变。可参考下图理解。

2.2、移相原理

 想要得到0-180°范围内的相位差,最重要的是懂得如何调节输出通道CH1与输出通道2 CH2的 CCR关系。

首先我们理解 ARR 从0 --100这个范围对应着角度值的 0-- 360°。那么 0点对应的是 0°,25对应的就是90°,50 对应的就是 180°,  75对应的就是270°。那么想要实现移相的角度,无非是确定 输出比较模式 输出的 电平翻转点。

以180°移相为例。

要实现图中 CH1与CH2波形相位差为180°,我们要思考的是图中1 , 2 ,3点的电平该如何翻转。

仔细思考其实就可以知道,1点电平应该跳转为低电平,2点电平应跳转为高电平,3点应跳转为低电平。效果如下图所示。改图就是实现了180°移相,且占空比不改变的效果。

那么90°相位差呢? 

电平翻转点应该就是在CCR=25 这个点位。如下图所示

确定了 翻转点位为 CCR=25,那么为何在 CCR=75的时候还要翻转多一次?

这是因为前文所说的,需要保持与PWM输出频率相等。至于为什么一定是75这个点而不是其他的点,这是因为 CNT=CCR1=25 时,电平翻转后,CNT是继续计数到 CCR1 = 75 电平翻转,CNT继续计数到 CCR1 =100 并溢出后置零重新计数的。而在75  --- 100这个过程,CNT是走过了25个计数值,而 CNT重新从0 到 CNT=25这个过程,也走过了25个计数值,那合起来就一共是走了50个计数值,这与我们 设定的 ARR2是一致的,保持了PWM 与 输出比较模式下的频率相等。

所以,在0-180°范围内 想要得到任意的相位差x,只需要计算出该相位差x对应的 ARR1的值并将该值设置为 输出比较的CCR2的值即可。

计算公式 CCR2 = ARR1 /(360°/x)  

三、代码

u8	PWMA_ISR_En;	//每个通道可以单独允许中断处理, bit4:通道4, bit3:通道3, bit2:通道2, bit1:通道1.


u16		pwma1;		//PWMA1输出高电平时间
u16		pwma2;		//PWMA2输出高电平时间
u16   pwma2N;



void PWMA_config(void)
{
	u8	ccer1;
	u8	ccer2;
	u8	ps;
	u8	eno;

	P_SW2 |= 0x80;		//SFR enable   
	PWMA_ENO    = 0;	// IO输出禁止
	PWMA_IER    = 0;	// 禁止中断
	PWMA_SR1    = 0;	// 清除状态
	PWMA_SR2    = 0;	// 清除状态
	PWMA_CR1    = 0;	// 清除控制寄存器
	PWMA_CR2    = 0;	// 清除控制寄存器
	ccer1 = 0;
	ccer2 = 0;
	ps    = 0;
	eno   = 0;
	PWMA_ISR_En = 0;

	PWMA_PSCR = 100;	// 预分频寄存器, PWM时钟 = 12MHz/(11+1)=1MHz, 分频 Fck_cnt = Fck_psc/(PSCR[15:0}+1), 边沿对齐PWM频率 = SYSclk/((PSCR+1)*(AAR+1)), 中央对齐PWM频率 = SYSclk/((PSCR+1)*(AAR+1)*2).
	PWMA_DTR  = 12;	// 死区时间配置, n=0~127: DTR= n T,   0x80 ~(0x80+n), n=0~63: DTR=(64+n)*2T,  
						//				0xc0 ~(0xc0+n), n=0~31: DTR=(32+n)*8T,   0xE0 ~(0xE0+n), n=0~31: DTR=(32+n)*16T,
//	PWMA_ARR     = PWMA_DUTY-1;	// 自动重装载寄存器,  控制PWM周期

	PWMA_ARRH=((PWMA_DUTY-1) >> 8);
  PWMA_ARRL=((PWMA_DUTY-1) & 0xFF);
	
	
	PWMA_CCMR4 = 0x10;		// 通道模式配置, PWM模式1, 预装载允许
//	PWMA_CCR4  =pwma2; //PWMA_PHASE2+pwma2;	// 比较值, 控制占空比(高电平时钟数)
	ccer2 |= 0x50;			// 开启比较输出, 高电平有效
	ps    |= 0xC0;				// 选择IO, 0:选择P1.0 P1.1, 1:选择P2.0 P2.1, 2:选择P6.0 P6.1, 
	eno   |= 0xC0;			// IO输出允许,  bit7: ENO4N, bit6: ENO4P, bit5: ENO3N, bit4: ENO3P,  bit3: ENO2N,  bit2: ENO2P,  bit1: ENO1N,  bit0: ENO1P
	PWMA_ISR_En |= 0x10;	// 使能中断
	
	PWMA_CCMR1 = 0x68;		// 通道模式配置, PWM模式1, 预装载允许
	PWMA_CCR1  = pwma1;	// 比较值, 控制占空比(高电平时钟数)
	ccer1 |= 0x05;			// 开启比较输出, 高电平有效
	ps    |= 0;				// 选择IO, 0:选择P1.0 P1.1, 1:选择P2.0 P2.1, 2:选择P6.0 P6.1, 
	eno   |= 0x03;			// IO输出允许,  bit7: ENO4N, bit6: ENO4P, bit5: ENO3N, bit4: ENO3P,  bit3: ENO2N,  bit2: ENO2P,  bit1: ENO1N,  bit0: ENO1P
//	PWMA_ISR_En |= 0x02;	// 使能中断

	PWMA_CCER1  = ccer1;	// 捕获/比较使能寄存器1
	PWMA_CCER2  = ccer2;	// 捕获/比较使能寄存器2
	PWMA_PS     = ps;		// 选择IO
	PWMA_IER    = PWMA_ISR_En;	//设置允许通道1~4中断处理

	PWMA_BKR    = 0x80;		// 主输出使能 相当于总开关
	PWMA_CR1    = 0x81;		// 使能计数器, 允许自动重装载寄存器缓冲, 边沿对齐模式, 向上计数,  bit7=1:写自动重装载寄存器缓冲(本周期不会被打扰), =0:直接写自动重装载寄存器本(周期可能会乱掉)
	PWMA_EGR    = 0x01;		//产生一次更新事件, 清除计数器和预分频计数器, 装载预分频寄存器的值
	PWMA_ENO    = eno;		// 允许IO输出
}




void PWMA_ISR(void) interrupt PWMA_VECTOR
{
	u8	sr1;
//	u8	sr2;
	sr1 = PWMA_SR1;	//为了快速, 中断标志用一个局部变量处理
	PWMA_SR1 = 0;	//清除中断标志
//	sr2 = PWMA_SR2;	//为了快速, 中断标志用一个局部变量处理
	PWMA_SR2 = 0;	//清除中断标志
	sr1 &= PWMA_ISR_En;	//每个通道可以单独允许中断处理

	if(sr1 & 0x10)	//通道4匹配中断标志
	{
		if(!P34)	//当前输出低电平, 预装载的是输出高电平的匹配值, 则准备好输出低电平的匹配值
		{
			PWMA_CCR4 = pwma2;
//	pwma2; //PWMA_PHASE2;	// 通道2匹配值, 匹配时输出低
			PWMA_CCMR4 = 0x10;				// 通道模式配置, 匹配模式2, 禁止预装载, 匹配时输出低
		}
		else	//当前输出高电平, 预装载的是输出低电平的匹配值, 则准备好输出高电平的匹配值
		{
			PWMA_CCR4 =PWMA_PHASE2 + pwma2N;	// 通道2匹配值, 匹配时输出高
			PWMA_CCMR4 = 0x20;			// 通道模式配置, 匹配模式1, 禁止预装载, 匹配时输出高
		}
	}
}


void main(void)
{ 

	P_SW2  = 0x80;
	Tick_Init();
	Io_Init();
	
	pwma1 =200;
	pwma2 =50;
	pwma2N =850;

	PWMA_config(); 
	EA = 1;

	while (1) 
	{
		
	
		
		
	}
}

本文关于PWM移相逻辑有缺陷,无法实现0-180°任意移相。笔者已在最新文章PWM移相以及占空比可变 一文中做出最新逻辑说明,并已进行波形抓取,证明逻辑可行。

解释以下代码:#include "stc32g.h" #include "intrins.h " #define uchar unsigned char void main() { char CY1,CY2,CY3; EAXFR=1; CKCON=0x00; WTST=0x00; CKCON =0x00; WTST= 0x00; P0M0 = 0x00; P0M1 = 0x00; P1M0= 0x00; P1M1= 0x00; P2M0 = 0x00; P2M1 = 0x00; P3M0 = 0x00; P3M1 = 0x00; P4M0 = 0x00; P4M1 = 0x00; P5M0 = 0x00; P5M1= 0x00; while (1){ P33=1; _nop_(); _nop_(); CY1=P33; P14=1; _nop_(); _nop_(); CY2=P14; P15=1; _nop_(); _nop_(); CY3=P15; if(CY1==1&&CY2==0&&CY3==1){ PWMA_CCER1=0x00; PWMA_CCMR1 =0x60; PWMA_CCMR2 =0x60; PWMA_CCER1= 0x11; PWMA_CCR1H = 0x17; PWMA_CCR1L= 0x00; PWMA_CCR2H = 0x17; PWMA_CCR2L= 0x00; PWMA_ARRH= 0x6f; PWMA_ARRL= 0x00; PWMA_ENO=0x05; PWMA_PS=0x0A; PWMA_BKR= 0x80; PWMA_CR1=0x01; } if(CY1==0&&CY2==1&&CY3==1){ PWMA_CCER1=0x00; PWMA_CCMR1 =0x60; PWMA_CCMR2 =0x60; PWMA_CCER1= 0x11; PWMA_CCR1H = 0x10; PWMA_CCR1L= 0x00; PWMA_CCR2H = 0x17; PWMA_CCR2L= 0x00; PWMA_ARRH= 0x6f; PWMA_ARRL= 0x00; PWMA_ENO=0x05; PWMA_PS=0x0A; PWMA_BKR= 0x80; PWMA_CR1=0x01; } if(CY1==1&&CY2==1&&CY3==0){ PWMA_CCER1=0x00; PWMA_CCMR1 =0x60; PWMA_CCMR2 =0x60; PWMA_CCER1= 0x11; PWMA_CCR1H = 0x17; PWMA_CCR1L= 0x00; PWMA_CCR2H = 0x10; PWMA_CCR2L= 0x00; PWMA_ARRH= 0x6f; PWMA_ARRL= 0x00; PWMA_ENO=0x05; PWMA_PS=0x0A; PWMA_BKR= 0x80; PWMA_CR1=0x01; } if(CY1==0&&CY2==0&&CY3==0){ PWMA_CCER1=0x00; PWMA_CCMR1 =0x60; PWMA_CCMR2 =0x60; PWMA_CCER1= 0x11; PWMA_CCR1H = 0x00; PWMA_CCR1L= 0x00; PWMA_CCR2H = 0x00; PWMA_CCR2L= 0x00; PWMA_ARRH= 0x6f; PWMA_ARRL= 0x00; PWMA_ENO=0x05; PWMA_PS=0x0A; PWMA_BKR= 0x80; PWMA_CR1=0x01; } if(CY1==1&&CY2==1&&CY3==1){ PWMA_CCER1=0x00; PWMA_CCMR1 =0x60; PWMA_CCMR2 =0x60; PWMA_CCER1= 0x11; PWMA_CCR1H = 0x17; PWMA_CCR1L= 0x00; PWMA_CCR2H = 0x17; PWMA_CCR2L= 0x00; PWMA_ARRH= 0x6f; PWMA_ARRL= 0x00; PWMA_ENO=0x05; PWMA_PS=0x0A; PWMA_BKR= 0x80; PWMA_CR1=0x01; } }}
07-11
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

橘洲青年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值