查看: 4637|回复: 8

关于如何修改ATMEGA328P的PWM频率

[复制链接]

该用户从未签到

发表于 2018-12-4 13:38 | 显示全部楼层 |阅读模式
在arduino开发中用到最多的就是atmega328p这个avr芯片了,常用的Nano, Uno开发板都是用的这款芯片。但是在做某些开发时可能会用到高低不等的PWM频率,比如,我在用PWM控制TEC制冷片工作时需要给MOSFAT比较大的频率以保证TEC的效率,但光靠arduino自身设定的976Hz的PWM频率远远是不够的。

现在插播一条关于arduino的知识:328p芯片有6个可以输出PWM的pin,D5和D6是一组,它们的频率是976hz;D9和D10是一组,它们的频率是490hz;D3和D11是一组,它们的频率也是490hz。为什么第一组和二三两组的频率不一样呢?这又要说到硬件计时器了——timer。D5D6两个pin的PWM是由timer0控制的,D9D10是由timer1控制的,D3D11是由timer2控制的。关键就是这三个timer的运行模式不一样,timer0是运行在“快速PWM模式”下,而timer1和timer2是运行在“相位修正PWM”模式下,(关于快速PWM和相位修正PWM我就不再详述了,本质区别就是前者是从0数到255,而后者是从0数到255后再从255数回0)。所以快速PWM的频率要比相位修正PWM的频率快一倍(这是因为它要数一个来回,当然是多走一倍路喽 ……)。
好了,回到正题。arduino其实在代码初始化时已经设好了每个PWM引脚的频率,代码在cores\arduino\wiring.c的init()中。

init.jpg

代码中涉及到多个AVR寄存器比如TCCR0A,TCCR0B之类,下面会慢慢讲。这个init()脚本会在setup()之前运行,并将PWM设置为上面所讲的频率并关联到每个PWM引脚上,以便之后用analogWrite(pin, value)来输出PWM波。
到目前为止我们已经知道了arduino是如何设定PWM频率的,所以只要修改掉一些寄存器的值就能修改PWM的频率了,关于哪些寄存器里设置什么样的值那就要来看万能的DATASHEET了。
控制计时器的寄存器大致有两个TCCRxA和TCCRxB,(其中的“x”代表哪个timer的寄存器,比如timer0的就是TCCR0A,TCCR0B)。每个寄存器有8个位,先以timer1为例:
tccr1a.JPG
tccr1a_3.JPG

按照上面两个图所给出的配置选项来说,当在8位快速PWM模式下(因为timer1是16位的,所以可以选8位PWM,9位PWM,10位PWM。而对于timer0和timer2是8位的,所以只有8位PWM),也就是当WGM13,WGM12,WGM11,WGM10这4位为0101时(看下图,那WGM13,WGM12在哪里?别急,它们在TCCR1B寄存器里,所以先要把TCCR1A的WGM11,WGM10设为01,再去TCCR1B把WGM13,WGM12设为01)还要把COM1A1/COM1B1和COM1A0/COM1B0分别设置为10时(这个A和B是什么意思?就是A通道和B通道,它们分别控制着OC1A和OC1B,而OC1A则与D10引脚相连,OC1B则与D9引脚相连,这样一来你就知道为什么D9,D10能输出PWM波了吧!
注:arduino初始化是把timer1设置为"相位修正PWM",而上面我们设置的是"8位快速PWM"。我这样设是因为我要把频率再提高一倍。


tccr1a_2_fuben.JPG
这样一来,TCCR1A的值就是10 10 00 01。
下面就来设置TCCR1B的值(下图),上面说到WGM13,WGM12是 01。ICNC1和ICES1先不管,在这用不到,设为00即可
tccr1b.JPG
接下来本文的重点来了,就是设置除频值,(如下图),arduino默认设置的除频值是64,以16MHz的主频来说:
16000000 / 256 / 64 = 976.5625Hz  (快速PWM,D5, D6 引脚PWM)
16000000 /255 / 2 / 64 = 490.196Hz  (相位修正PWM,D3, D11, D9, D10 引脚PWM)
这就是arduinoPWM引脚的频率。(第一个除以256是因为到了255后还要加1才会回到0,而第二个是因为到了255后不直接跳回0,而是要从255再回来到254,253...再到0,所以后面还要除2,如果不明白可以去看一下快速PWM和相位修正PWM的区别)。
于是乎,要让频率变快就要减小除频值,反之加大除频值。 所以安照上面TCCR1A的配置,再把TCCR1B的除频设为1(CS12,CS11,CS10 = 001)。

tccr1b_2_fuben.JPG
于是就有了以下配置值:
TCCR1A = 10100001
TCCR1B = 00001001
然后就有了这些代码:(代码申明,loop()中没有代码,因为什么都不用做,所以配置代码写在setup()里)
void setup()
{
// 禁止中断
cli();
// set timer1 fast pwm, f = 62.5kHz
// D9 = OCR1A; D10 = OCR1B
pinMode(9, OUTPUT);
pinMode(10, OUTPUT);
TCCR1A = 0;
TCCR1B = 0;
// 比较匹配时清零 OC1A/OC1B
TCCR1A |= _BV(COM1A1) | _BV(COM1B1);
// 配置8位快速PWM, TOP = 0xFF
TCCR1A |= _BV(WGM10);
TCCR1B |= _BV(WGM12);
// 时钟无分频
TCCR1B |= _BV(CS10);
OCR1A = 127;    // 占空比50%
OCR1B = 51;    // 占空比20%

// 允许中断
sei();
}

关于以上代码需要注意的是,配置前最好先关闭系统中断,设完后再打开。_BV()是一个宏定义,意思是置位(即将某一位设为1),OCR1A,OCR1B是设占空比的,即timer1数到多少再把OC1A,OC1B拉低,看了下图可能更容易理解
ocr1_fuben.jpg

综上所述,timer0和timer2也是一样修改,但要注意的是arduino的millis(), delay()函数依赖于timer0计时器,所以每到万不得已不要去改timer0的除频,否则函数时间会变化。

最后上两张通过上面设置产生的PWM
IMG_20181204_131041.jpg

freq=62.5khz  duty=50%

IMG_20181204_131107_1.jpg

freq=62.5khz  duty=20%


该用户从未签到

发表于 2019-9-28 11:07 | 显示全部楼层
请问楼主,设置了62.5KHZ后,PWM的分辨率是多少?

该用户从未签到

 楼主| 发表于 2019-10-10 16:10 | 显示全部楼层
请问楼主,设置了62.5KHZ后,PWM的分辨率是多少?


还是8位

该用户从未签到

发表于 2020-11-25 17:22 | 显示全部楼层
ATmega 328 的哪几个IO 用来做PWM ? datasheet 上没有写清楚。。

该用户从未签到

 楼主| 发表于 2020-11-26 11:48 | 显示全部楼层
Samhuang8204 发表于 2020-11-25 17:22
ATmega 328 的哪几个IO 用来做PWM ? datasheet 上没有写清楚。。
ATmega 328 的哪几个IO 用来做PWM ?

D3,D5,D6,D9,D10,D11

该用户从未签到

发表于 2020-11-26 19:15 | 显示全部楼层
几天才看到,这个写的好,很仔细,谢谢,学习了!

该用户从未签到

发表于 2021-4-24 20:58 | 显示全部楼层
感谢楼主 ,可以多增加几个输出引脚吗?

该用户从未签到

发表于 2021-4-24 21:00 | 显示全部楼层
WT..#/#/..WT 发表于 2021-4-24 20:58
感谢楼主 ,可以多增加几个输出引脚吗?

我想要6个PWM ,英语的数据手册是道硬伤,请楼主指点一下

该用户从未签到

 楼主| 发表于 2021-4-29 19:21 | 显示全部楼层
WT..#/#/..WT 发表于 2021-4-24 21:00
我想要6个PWM ,英语的数据手册是道硬伤,请楼主指点一下

uno,nano用的是atmega328p芯片,总共才3个timer,最多也就6路了。除非用mega2560
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

arduino程序设计基础 blinker物联网解决方案

热门推荐

小爱同学控制不了ESP8266-01s
小爱同学控制不了ESP8266-
电灯科技可以控制ESP8266-01s继电器吸合,添加到米家APP后唤醒小爱同学控制不了#defin
合肥机器人创新公开赛
合肥机器人创新公开赛
合肥市第一次举办这种开源的比赛,意义还是挺好的,小学组比赛比较简答,直接上高中的
arduino麦轮重型运载车
arduino麦轮重型运载车
功能:可以装载货物,猫等没有采用PID调制,这样能减轻自重,而且对走直线要求没那么高
一文教你选择Arduino开发板,小白进
一文教你选择Arduino开发
笔者在2016年接触了Arduino,跳了万条坑,行了千里弯,到今天也算是Arduino的一
【干货分享】mega2560原理图PCB图纸altium designer18
【干货分享】mega2560原理
分享一下mega2560的板子 AD版本 **** 本内容被作者隐藏 **** ergo
Copyright   ©2015-2016  Arduino中文社区  Powered by©Discuz!   
快速回复 返回顶部 返回列表