ARM裸机 - PWM定时器

1.什么是PWM

 PWM波形是一个周期性波形,周期为T,在每个周期内波形是完全相同的。每个周期内由一个高电平和一个低电平组成

PWM波形有2个重要参数:一个是周期T,另一个是占空比duty(占空比就是一个周期内高电平的时间除以周期时间的商),高电平时间为Tduty,低电平时间为T(1-duty)。

2..PWM波形的生成原理

先将GPIO引脚电平拉高、同时启动定时器定T*duty时间,时间到了在isr中将电平拉低,然后定时T*(1-duty)后再次启动定时器,然后时间到了后在isr中将电平拉高,然后再定时T*duty时间再次启动定时器····如此循环即可得到周期为T,占空比为duty的PWM波形。

后来因为定时器经常和PWM产生纠结一起,所以设计SoC的时候就直接把定时器和一个GPIO引脚内部绑定起来了,然后在定时器内部给我们设置了PWM产生的机制,可以更方便的利用定时器产生PWM波形

PWM波形产生有2个寄存器很关键一个是TCNTB、一个是TCMPB。其中,TCNTB决定了PWM波形的周期,TCMPB决定了PWM波形的占空比

ARM裸机 - PWM定时器

3.输出电平翻转器 

PWM定时器可以规定:当TCNT>TCMPB时为高电平当TCNT<TCMPB时为低电平

当电平改变时,TCMPB寄存器中的值就要改,210的PWM定时器帮我们提供了一个友好的工具叫做电平翻转器

电平翻转器在电路上的实质就是一个电平取反的部件,在编程上反映为一个寄存器位写0就关闭输出电平反转,写1就开启输出电平反转

ARM裸机 - PWM定时器

 

4.蜂鸣器和PWM定时器编程实战 

-> 蜂鸣器的工作原理:

蜂鸣器里面有2个金属片,离的很紧但没挨着没电的时候两个片在弹簧本身张力作用下分开彼此平行有电的时候两边分别充电,在异性电荷的吸力作用下两个片挨着

我们只要以快速的频率给蜂鸣器的正负极:供电、断电。进行这样的循环,蜂鸣器的两个弹簧片就会挨着分开挨着分开···形成敲击,发出声音

-> 硬件原理图:

ARM裸机 - PWM定时器

ARM裸机 - PWM定时器

-> 主要寄存器:

预分频器TCFG0:预分频器的值设置为65,使得分频后等于1MHZ。

分频器TCFG1:分频后的时钟周期为500KHZ。

CON:

ARM裸机 - PWM定时器

TCNTB2、TCMPB2的计算:
我们的时钟频率是500KHz,对应的时钟周期是2us。也就是说每隔2us 计一次数。如果要定的时间是x,则TCNTB中应该写入
rTCNTB2 = 250; // 0.5ms/2us = 500us/2us = 250
rTCMPB2 = 125; // duty = 50%
 

代码实现:

pwm.c:

#define 	GPD0CON		(0xE02000A0)
#define 	TCFG0		(0xE2500000)
#define 	TCFG1		(0xE2500004)
#define 	CON			(0xE2500008)
#define 	TCNTB2		(0xE2500024)
#define 	TCMPB2		(0xE2500028)

#define 	rGPD0CON	(*(volatile unsigned int *)GPD0CON)
#define 	rTCFG0		(*(volatile unsigned int *)TCFG0)
#define 	rTCFG1		(*(volatile unsigned int *)TCFG1)
#define 	rCON		(*(volatile unsigned int *)CON)
#define 	rTCNTB2		(*(volatile unsigned int *)TCNTB2)
#define 	rTCMPB2		(*(volatile unsigned int *)TCMPB2)


// 初始化PWM timer2,使其输出PWM波形:频率是2KHz、duty为50%
void timer2_pwm_init(void)
{
	// 设置GPD0_2引脚,将其配置为XpwmTOUT_2
	rGPD0CON &= ~(0xf<<8);
	rGPD0CON |= (2<<8);
	
	// 设置PWM定时器的一干寄存器,使其工作
	rTCFG0 &= ~(0xff<<8);
	rTCFG0 |= (65<<8);			// prescaler1 = 65, 预分频后频率为1MHz
	
	rTCFG1 &= ~(0x0f<<8);
	rTCFG1 |= (1<<8);			// MUX2设置为1/2,分频后时钟周期为500KHz
	// 时钟设置好,我们的时钟频率是500KHz,对应的时钟周期是2us。也就是说每隔2us
	// 计一次数。如果要定的时间是x,则TCNTB中应该写入x/2us
	
	rCON |= (1<<15);		// 使能auto-reload,反复定时才能发出PWM波形
	//rTCNTB2 = 250;			// 0.5ms/2us = 500us/2us = 250
	//rTCMPB2 = 125;			// duty = 50%
	
	rTCNTB2 = 50;			
	rTCMPB2 = 25;	
	
	// 第一次需要手工将TCNTB中的值刷新到TCNT中去,以后就可以auto-reload了
	rCON |= (1<<13);		// 打开自动刷新功能
	rCON &= ~(1<<13);		// 关闭自动刷新功能
	
	rCON |= (1<<12);		// 开timer2定时器。要先把其他都设置好才能开定时器
}

main.c:

#include "stdio.h"

void uart_init(void);
void timer2_pwm_init(void);

int main(void)
{
	uart_init();
	
	timer2_pwm_init();
	
	while(1)
	{
		putc('a');
		delay();
	}
	
	return 0;
}

上一篇:直播预告|4月1日与你相约腾讯云共探TcaplusDB


下一篇:【CF1528B】Kavi on Pairing Duty