历史上的今天
返回首页

历史上的今天

今天是:2025年02月25日(星期二)

正在发生

2020年02月25日 | 使用AVR实现PWM波

2020-02-25 来源:eefocus

简介:使用AVR的定时器实现PWM,具有众多优点。


1:AVR 定时/计数器的PWM


模式可以分成快速PWM和频率(相位)调整PWM 两大类。


快速PWM 可以得到比较高频率的PWM 输出,但占空比的调节精度稍微差一些。此时计数器仅工作在单程正向计数方式,计数器的上限值决定PWM的频率,而比较匹配寄存器的值决定了占空比的大小。PWM 频率的计算公式为:


PWM频率 = 系统时钟频率/(分频系数*(1+计数器上限值))


频率(相位)调整PWM 模式的占空比调节精度高,但输出频率比较低,因为此时计数器仅工作在双向计数方式。同样计数器的上限值决定了PWM 的频率,比较匹配寄存器的值决定了占空比的大小。PWM 频率的计算公式为:


PWM频率 = 系统时钟频率/(分频系数*2*计数器上限值))


在PWM 方式中,计数器的上限值有固定的0xFF(8 位T/C);0xFF、0x1FF、0x3FF(16 位T/C)。或由用户设定的0x0000-0xFFFF,设定值在16 位T/C 的ICP 或OCRA 寄存器中。而比较匹配寄存器的值与计数器上限值之比即为占空比。


2:应用例子


用PWM 方式来产生一个1KHz 左右的正弦波,幅度为0-Vcc/2。


程序中使用ATmega128 的8 位T/C0,工作模式为相位调整PWM 模式输出,系统时钟为8MHz,分频系数为1,其可以产生最高PWM 频率为: 8000000Hz / 510 = 15686Hz。每16 次输出构成一个周期正弦波,正弦波的频率为980.4Hz。PWM 由OC0(PB4)引脚输出。参考程序如下(ICCAVR)。


//ICC-AVR application builder : 2009-04


// Target : M128

// Crystal: 8.0000Mhz

#include

#include

#pragma data:code //随后的数据存放在Flash区域

// 128 点正弦波样本表

const unsigned char auc_SinParam[128] = {

64,67,70,73,76,79,82,85,88,91,94,96,99,102,104,106,109,111,113,115,117,118,120,121,

123,124,125,126,126,127,127,127,127,127,127,127,126,126,125,124,123,121,120,118,

117,115,113,111,109,106,104,102,99,96,94,91,88,85,82,79,76,73,70,67,64,60,57,54,51,48,

45,42,39,36,33,31,28,25,23,21,18,16,14,12,10,9,7,6,4,3,2,1,1,0,0,0,0,0,0,0,1,1,2,3,4,6,

7,9,10,12,14,16,18,21,23,25,28,31,33,36,39,42,45,48,51,54,57,60};


#pragma data:data//随后数据放在RAM区


unsigned char x_SW = 8,X_LUT = 0;

#pragma interrupt_handler timer0_ovf_isr:17//中断常量表位置


void timer0_ovf_isr(void)

{

X_LUT += x_SW; // 新样点指针//学习此种编程风格

if (X_LUT > 127)


X_LUT -= 128; // 样点指针调整

OCR0 = auc_SinParam[X_LUT]; // 取样点指针到比较匹配寄存器

}


void main(void)

{

DDRB |= 0x10; // PB4(OC0)输出

TCCR0 = 0x71; // 相位调整PWM 模式,分频系数=1,正向控制OC0


/*TCCR0

• Bit 7 – FOC0: 强制输出比较

FOC0仅在WGM指明非PWM模式时才有效。但是,为了保证与未来器件的兼容性,在使

用PWM 时,写TCCR0 要对其清零。对其写1 后,波形发生器将立即进行比较操作。比

较匹配输出引脚 OC0 将按照COM01:0 的设置输出相应的电平。要注意FOC0 仅仅是一

个启动信号,真正对强制输出比较起作用的是COM01:0 的设置。

OCFn

OCRn

TCNTn

OCRn Value

OCRn - 1 OCRn OCRn + 1 OCRn + 2

clkI/O

clkTn

(clkI/O/8)

OCFn

OCRn

TCNTn

(CTC)

TOP

TOP - 1 TOP BOTTOM BOTTOM + 1

clkI/O

clkTn

(clkI/O/8)

Bit 7 6 5 4 3 2 1 0

FOC0 WGM00 COM01 COM00 WGM01 CS02 CS01 CS00 TCCR0

读/ 写W R/W R/W R/W R/W R/W R/W R/W

初始值0 0 0 0


Cs2,Cs1,Cs0 =1,预分频系数为1


WGM01 WGM00=1 相位校正PWM模式


*/

TIMSK = 0x01; // T/C0 溢出中断允许

SEI(); // 使能全局中断

while(1)

{……};

}


每次计数器溢出中断的服务中取出一个正弦波的样点值到比较匹配寄存器中,用于调整下一个PWM 的脉冲宽度,这样在PB4 引脚上输出了按正弦波调制的PWM 方波。当PB4 的输出通过一个低通滤波器后,便得到一个980.4Hz 的正弦波了。如要得到更精确的1KHz 的正弦波,可使用定时/计数器T/C1,选择工作模式10,设置ICR1=250 为计数器的上限值


AVR的PWM波


(1)一个实例:

这个程序是用ICC的向导生成的,很简单。

T0是作为普通8位定时器,频率100KHz,每次中断将PB0(pin1)状态反转,产生的是200KHz占空比50%的方波。


T1是作为工作模式9:相频可调PWM波发生器,频率初始化16KHz,占空比50%。请注意:

TCNT1是T0的定时器计数值,就是每个定时器时钟加1,和普通定时器的计数值寄存器作用一样。


OCR1A作为比较的TOP值。 OCR1B作为匹配输出值。

当TCNT1的值增加到OCR1B相等时,OC1B(pin18)清零,就是对应低电平;

然后TCNT1继续增加到OCR1A(就是TOP)的值,然后TCNT1开始减少,这个中间,OC1B(Pin18)状态不变;当TCNT1减少到OCR1B相等时,OC1B(pin18)置1,就是对应高电平。 然后TCNT1继续减少到0x00(就是BOTTOM),然后TCNT1又开始增加,这个中间,OC1B(pin18)状态不变。


OCR1B的值与OCR1A的比值就是PWM的占空比!所以这个值必须比OCR1A小。当OCR1B为0时,PWM波就一直为低电平(相当于占空比为0);当OCR1B为OCR1A时,PWM波就一直为高电平(相当于占空比为100);当OCR1B为OCR1A的一半时,PWM波就是占空比为50%。


你可以修改OCR1B的值,然后重新下载程序运行,看看占空比的改变;也可以修改OCR1A的值,然后重新下载程序运行,看看频率的改变,不过要注意修改OCR1A时,同时注意OCR1B的值不要比OCR1A大。


模式9算是PWM生成中最复杂的一种,只要你理解了这个,对别的几种PWM都好理解。

TCNT0 = 0xB0; //set count

OCR0 = 0x50;


即使工作在normal模式下,这个OCR0仍然在和TCNT0进行比较,一旦匹配后,就会产生中断或者改变OC0脚上的电平(产生PWM)。改变这个值,就会改变中断发生的时间,或者改变OC0脚上的方波的频率了。


T1定时器1的模式9,相频修正模式,可以用来产生波形非常完整的PWM波。TCNT1设置初值,增加到0xFFFF的时间,然后从0开始计数,这个理解是正确的。可以画一个波形图对应理解一下:画一个占空比50%的方波,高电平上平分为1、2两段,低电平上平分为3、4两段。


1就是TCCNT1从初值加,-->0xFFFF阶段,这个阶段OCR1B为高电平;

2就是TCCNT1从0x00加-->OCR1B阶段,这个阶段为高电平;匹配后,变为低电平

3就是TCCNT1从OCR1B加-->OCR1A阶段,这个阶段为低电平;

4就是TCCNT1从OCR1A减-->OCR1B阶段,这个阶段为低电平;匹配后,变为高电平


TCCNT1的初值,就是保证第一段高电平的时间,这样才能形成一个完整周期的方波。而且,这个初值应该根据OCR1B的值而设,就是TCCNT1 = 0xffff-OCR1B+1;这样才能保证时间的匹配。


如果是模式9,那么每次变化后,算出占空比,算出OCR1B的值并赋值,会自动在下一个周期改变占空比为新值。


重点是:每次给OCR1B赋值,会在 下一个 周期改变占空比。

//实例:利用pwm控制led光暗及峰鳴器音量大小

//ICC-AVR application builder : 2005-4-18 12:46:03

// Target : M16

// Crystal: 4.0000Mhz

#include

#include

#define uchar unsigned char

#define uint unsigned int

void port_init(void);

void timer0_init(void);

void init_devices(void);

void delay_short(uint t);

uchar scan_key(void);


void port_init(void)

{

PORTA = 0x00;

DDRA = 0x00;

PORTB = BIT(PB3);

DDRB = BIT(PB3);

PORTC = 0x00; //m103 output only

DDRC = 0x00;

PORTD = 0x00;

DDRD = 0x00;

}

// WGM: PWM Phase correct

// desired value: 1KHz

// actual value: 0.980KHz (-2.0%)

void timer0_init(void)

{

TCCR0 = 0x00; //stop

TCNT0 = 0x01; //set count

OCR0 = 0xFF; //set compare

TCCR0 = 0x62; //start timer ; 相位修正, 8分頻

}

//call this routine to initialize all peripherals

void init_devices(void)

{

//stop errant interrupts until set up

CLI(); //disable all interrupts

port_init();

timer0_init();

MCUCR = 0x00;

GICR = 0x00;

TIMSK = 0x00; //timer interrupt sources

SEI(); //re-enable interrupts

//all peripherals are now initialized

}

void delay_short(uint t) // 短延時

{

uint i;

for (i=0;i}

uchar scan_key(void) // 按鍵掃瞄

{

uchar v;


v = 0;


if ((PIND & 0x07) != 0x07)

{


if ((PIND & 0x01) == 0)

{

v = 1;

delay_short(1000);

}


if ((PIND & 0x2) == 0)

{

v = 2;

delay_short(1000);

}


if ((PIND & 0x4) == 0)

{

v = 3;

delay_short(1000);

}

};

while((PIND & 0x07) != 0x07); // 判斷按鍵是不是放開

return v;

}

//

void main(void)

{

uchar key, OCR0_V;


init_devices();

OCR0_V = 0xff;


while(1)

{

key = scan_key();


if (key > 0)

{

if (key==1) // 減少佔空比

{

OCR0_V -= 10;

OCR0 = OCR0_V;

};


if (key==2) // 增加佔空比

{

OCR0_V += 10;

OCR0 = OCR0_V;

};


if (key==3) // 全黑,佔空比為100%

{

OCR0_V = 0xff;

OCR0 = OCR0_V;

};

}

};

}


實驗板接線:

PB3 -----> JA.1 及 JM

PD0 -----> K1

PD1 -----> K2

PD2 -----> K3

(2)相关详细理论说明:

符号定义:

BOTTOM 计数器计到0x0000 时即达到BOTTOM

MAX 计数器计到0xFFFF ( 十进制的65535) 时即达到MAX

TOP 计数器计到计数序列的最大值时即达到TOP。

TOP 值可以为固定值0x00FF、0x01FF或 0x03FF,或是存储于寄存器 OCR1A或ICR1里的数值,具体有赖于工作模式 分5种工作类型


1 普通模式 WGM1=0

跟51的普通模式差不多,有TOV1溢出中断标志,发生于MAX(0xFFFF)时

1 采用内部计数时钟 用于 ICP捕捉输入场合---测量脉宽/红外解码

(捕捉输入功能可以工作在多种模式下,而不单单只是普通模式)

2 采用外部计数脉冲输入 用于 计数,测频

其他的应用,采用其他模式更为方便,不需要像51般费神


2 CTC模式 [比较匹配时清零定时器模式] WGM1=4,12

跟51的自动重载模式差不多

1 用于输出50%占空比的方波信号

2 用于产生准确的连续定时信号

WGM1=4时, 最大值由OCR1A设定,TOP时产生OCF1A比较匹配中断标志

WGM1=12时,最大值由ICF1设定, TOP时产生ICF1输入捕捉中断标志

------如果TOP=MAX,TOP时也会产生TOV1溢出中断标志

注:WGM=15时,也能实现从OC1A输出方波,而且具备双缓冲功能

计算公式: fOCn="fclk"_IO/(2*N*(1+TOP))

变量N 代表预分频因子(1、8、64、256、1024),T2多了(32、128)两级。


3 快速PWM模式 WGM1=5,6,7,14,15

单斜波计数,用于输出高频率的PWM信号(比双斜波的高一倍频率)

都有TOV1溢出中断,发生于TOP时[不是MAX,跟普通模式,CTC模式不一样]

比较匹配后可以产生OCF1x比较匹配中断.

WGM1=5时, 最大值为0x00FF, 8位分辨率

WGM1=6时, 最大值为0x01FF, 9位分辨率

WGM1=7时, 最大值为0x03FF,10位分辨率

WGM1=14时,最大值由ICF1设定, TOP时产生ICF1输入捕捉中断 (单缓冲)

WGM1=15时,最大值由OCR1A设定,TOP时产生OCF1A比较匹配中断(双缓冲,但OC1A将没有PWM能力,最多只能输出方波)

改变TOP值时必须保证新的TOP值不小于所有比较寄存器的数值

注意,即使OCR1A/B设为0x0000,也会输出一个定时器时钟周期的窄脉冲,而不是一直为低电平

计算公式:fPWM=fclk_IO/(N*(1+TOP))


4 相位修正PWM模式 WGM1=1,2,3,10,11

双斜波计数,用于输出高精度的,相位准确的,对称的PWM信号

都有TOV1溢出中断,但发生在BOOTOM时

比较匹配后可以产生OCF1x比较匹配中断.

WGM1=1时, 最大值为0x00FF, 8位分辨率

WGM1=2时, 最大值为0x01FF, 9位分辨率

WGM1=3时, 最大值为0x03FF,10位分辨率

WGM1=10时,最大值由ICF1设定, TOP时产生ICF1输入捕捉中断 (单缓冲)

WGM1=11时,最大值由OCR1A设定,TOP时产生OCF1A比较匹配中断(双缓冲,但OC1A将没有PWM能力,最多只能输出方波)

改变TOP值时必须保证新的TOP值不小于所有比较寄存器的数值

可以输出0%~100%占空比的PWM信号

若要在T/C 运行时改变TOP 值,最好用相位与频率修正模式代替相位修正模式。若TOP保持不变,那么这两种工作模式实际没有区别

计算公式:fPWM=fclk_IO/(2*N*TOP)


5 相位与频率修正PWM模式 WGM1=8,9

双斜波计数,用于输出高精度的、相位与频率都准确的PWM波形

都有TOV1溢出中断,但发生在BOOTOM时

比较匹配后可以产生OCF1x比较匹配中断.

WGM1=8时,最大值由ICF1设定, TOP时产生ICF1输入捕捉中断 (单缓冲)

WGM1=9时,最大值由OCR1A设定,TOP时产生OCF1A比较匹配中断(双缓冲,但OC1A将没有PWM能力,最多只能输出方波)

相频修正修正PWM 模式与相位修正PWM 模式的主要区别在于OCR1x 寄存器的更新时间

改变TOP值时必须保证新的TOP值不小于所有比较寄存器的数值

可以输出0%~100%占空比的PWM信号

使用固定TOP 值时最好使用ICR1 寄存器定义TOP。这样OCR1A 就可以用于在OC1A输出PWM 波。


但是,如果PWM 基频不断变化(通过改变TOP值), OCR1A的双缓冲特性使其更适合于这个应用。


计算公式:fPWM=fclk_IO/(2*N*TOP)

推荐阅读

史海拾趣

绿索超容(GreenSource)公司的发展小趣事

汇顶科技(GOODiX)公司发展的五个故事

故事一:初创与转型

汇顶科技的故事始于2002年,当时它作为一家初创企业,在电子产业中崭露头角。公司最初专注于固定电话芯片业务,但随着国内固话市场的饱和和竞争加剧,公司迅速调整方向,切入小家电触控面板芯片领域。这一转型为公司后续的发展奠定了基础。2010年,汇顶科技获得联发科技的战略投资,其触控芯片集成至联发科技的安卓系统解决方案中,广泛应用于智能手机和平板电脑等电子产品,进一步提升了公司的市场地位。

故事二:指纹识别技术的突破

2013年,随着苹果iPhone 5s发布并搭载电容式指纹识别技术,全球范围内掀起了一股指纹识别风潮。汇顶科技敏锐地捕捉到了这一市场趋势,开始研发指纹识别芯片。经过一年的努力,公司在2014年成功推出电容式指纹识别芯片,并凭借创新技术迅速获得国内主流智能机厂商的订单。此后,汇顶科技在指纹识别领域不断取得突破,逐步成为全球最大的指纹识别芯片厂商之一。

故事三:屏下指纹识别技术的开拓者

在指纹识别技术取得成功后,汇顶科技并未满足现状,而是继续探索新技术。2016年,公司开始以屏下指纹识别技术(光学式指纹芯片)为新的主攻方向。经过一年的研发,2017年汇顶科技率先展出全球首款屏下指纹识别技术,成为该领域的开拓者。随着全面屏手机的兴起,屏下指纹识别技术迅速得到市场认可,汇顶科技也借此迎来了新一轮的增长。

故事四:多元化布局与并购

为了进一步提升竞争力,汇顶科技通过并购等方式不断拓展业务领域。2018年,公司收购德国蜂窝半导体IP企业CommSoild,进军窄带物联网领域(NB-IoT)。2020年,汇顶科技又收购恩智浦半导体的语音及音频业务单元(NXP Voice & Audio Solutions)和德国汽车电子公司Dream Chip Technologies,分别增强智能终端音频解决方案能力和进入车规级芯片领域。这些并购不仅丰富了公司的产品线,也提升了公司在各领域的综合竞争力。

故事五:持续创新与合作

汇顶科技一直致力于技术创新和市场拓展。近年来,公司与多家知名手机厂商建立了合作关系,为其提供创新的指纹识别和触控芯片解决方案。例如,汇顶科技的创新方案组合助力小米、荣耀、iQOO等品牌的旗舰新品打造极致体验。同时,公司还不断拓展物联网领域的应用,通过构建芯片设计和软硬件产品技术综合物联网平台,推动智能化生活的实现。这些合作和创新不仅提升了公司的市场影响力,也为全球亿万消费者带来了更便捷、智能的体验。

AUK Contractors Co Ltd公司的发展小趣事

随着公司业务的不断扩展,AUK Contractors Co Ltd意识到单一市场已无法满足其增长需求。于是,公司积极寻求国际合作,与多个国家的电子企业建立了战略伙伴关系。通过技术交流和资源共享,公司成功打开了新的市场,实现了业务的快速增长。

明波通信(BWAVE)公司的发展小趣事

随着汽车产业的快速发展,车载电子系统成为了新的增长点。明波通信凭借在通信领域的深厚积累,迅速拓展车载电子系统业务。公司成功开发了车载导航、车载音响系统等项目,并与多家知名汽车厂商建立了合作关系。这一举措不仅为明波通信带来了新的增长点,也进一步巩固了其在电子行业的地位。

Hamamatsu公司的发展小趣事

随着无线通信技术的快速发展,明波通信紧跟时代步伐,不断投入研发力量,在无线/移动通信领域取得了重大技术突破。公司成功开发出了一系列大规模集成电路(IP/ASIC)及相关控制软件,不仅提高了通信效率和质量,也赢得了国内外客户的广泛认可。这一时期的明波通信,已经成为国内通信行业的佼佼者。

HDK(北陆电气)公司的发展小趣事

随着国内市场的日益饱和,明波通信开始将目光投向全球市场。公司先后在日本东京和江苏常州设立了子公司,通过技术合作和市场拓展,进一步巩固了公司在全球通信领域的地位。同时,明波通信也积极参与国际技术交流和合作,不断提升自身的技术水平和创新能力。这一系列的国际化战略举措,为明波通信的未来发展奠定了坚实的基础。

以上五个故事都是基于明波通信在电子行业中的发展历程和公开资料进行的概括性描述。虽然无法涵盖所有细节和具体事件,但希望能够展现出明波通信在创业、技术创新、市场拓展和国际化等方面的努力和成就。

Avel Lindberg公司的发展小趣事

在2002年,一群从海外归来的留学生和技术专家,怀揣着对通信技术的热情与梦想,在上海创立了明波通信技术股份有限公司。他们深知国内在通信领域的技术与海外相比还有较大差距,因此决心将自己在海外学到的先进知识和经验,应用到国内的市场和技术创新中。明波通信从创立之初就致力于数字电视芯片的研究与开发,并逐渐在行业中崭露头角。

问答坊 | AI 解惑

求《嵌入式系统 硬件与软件架构》这本书的电子书下载?

一直没有找到,哪位仁兄知道,分享一下呢?…

查看全部问答>

GPS的问题,谁帮帮我啊

在森林里,GPS信号应该是屏蔽的,怎么设计接收机能使卫星获取信号…

查看全部问答>

今天去了一趟ST的深圳Office

公司很宽敞,工程师工作也很自由。当时打电话给一个在ST的哥们,他正在出差,说5点钟可以赶回来。还专门叮嘱我,不要提及他的名字。难不成怕我做什么坏事不成,晕。…

查看全部问答>

FPGA中的stp文件的问题

为什么显示waiting for clock啊,开始还好好的,后面再编译一次就这样了,请教高手指导下!谢谢!…

查看全部问答>

1602显示程序

新手写了一个用1602液晶在第二行第一位显示字母A的程序,程序可以通过编译,但是液晶上部显示,不知道什么原因?求助解答,谢谢 LIST P=16F873a           ;  告诉编译程序使用何种PIC单 ...…

查看全部问答>

msp430 的引导存储器是干嘛的?我仿真了自己写的一个程序,查看引导存储器区全是空的

msp430 的引导存储器是干嘛的?我仿真了自己写的一个程序,查看引导存储器区全是空的,引导区是干嘛的呢,是不是跟ARM的boot  loader 作用一样呢…

查看全部问答>

Cortex-M0开发板出笼了!

应一些网友的要求,我做出了Cortex-M0(LPC1114)的开发板,各位想玩的可以联系我! 要看DEMO视频的可以点下面链接     http://www.56.com/u73/v_NzE5ODgxOTg.html …

查看全部问答>

雅安7级地震 生命探测器黄金救援期争分夺秒

北京时间2013年4月20日8时02分四川省雅安市芦山县(北纬30.3,东经103.0)发生7.0级地震。震源深度13公里。震中距成都约100公里。成都、重庆及陕西的宝鸡、汉中、安康等地均有较强震感。据雅安市政府应急办通报,震中芦山县龙门乡99%以上房屋垮塌, ...…

查看全部问答>

分享一个仿真元件swcad

仿真软件,朋友推荐的,挺好用的。软件小,功能很全。…

查看全部问答>