arduino(mega2560)配置寄存器输出自定义频率pwm
1.快速脉宽调制
在最简单的 PWM 模式下,定时器从 0 到 255 重复计数。当定时器为 0 时输出打开,当定时器与输出比较寄存器匹配时关闭。输出比较寄存器中的值越高,占空比越高。这种模式称为快速 PWM 模式。下图显示了 OCRnA 和 OCRnB 的两个特定值的输出。请注意,两个输出具有相同的频率,与整个定时器周期的频率相匹配。
(最大重载值为255,输出比较寄存器OCRnA 和 OCRnB ,控制输出比较值)
2.mega2560定时器
我使用的是使用atmega2560芯片的arduino mega2560 开发板。PWM波是通过timer/counter产生。该单片机有timer0、timer1、timer2、timer3、timer4、timer5共六个定时/计数器。
timer0、timer2为8位的定时/计数器,每个定时/计数器又有A、B两个通道。
timer1、timer3、timer4、timer5为16位的定时/计数器,每个又有A、B、C三个通道。
引脚对应表:
-
第一行 为定时器对应通道,OCRnA/B/C表示定时器n的通道对应通道A/B/C,举例OCR4C:表示timer4的通道C
-
第二行 为芯片对应io端口
-
第三行 开发板对应输出口
配置输出端口(以16位定时器timer3为例)
//定时器3:三个输出通道 pinMode(5, OUTPUT); //OC3A pinMode(2, OUTPUT); //OC3B pinMode(3, OUTPUT); //OC3C
3.定时器寄存器
定时器/计数器控制寄存器 TCCRnA 和 TCCRnB 保存定时器的主要控制位(请注意,TCCRnA 和 TCCRnB 不对应于输出 A 和 B。)
- 波形生成模式位 (WGM):这些位控制定时器的整体模式。(这些位分在 TCCRnA 和 TCCRnB。)
我们要通过这四个位来控制我们想要的模式。
根据数据手册,我们需要设置成可调频率的fast pwm模式,此时四个位应为 1111 对应模式15,该模式下为TOP(即重装载值)为OCRnA(输出比较寄存器),即timer n的通道A,这个寄存器的值由我们自己控制。以16位定时器timer3为例OCRnA的取值范围就是0-65535。
pwm频率的计算公式:
f=16Mhz(mega2560时钟源)/(预分频系数)/(重装载值)
注意,此模式下之所以可调频率是因为重装载值在可调范围内是由我们设置的,即原本用来的输出pwm的通道A,被我们设置成输出通道B的最大重装载值,所以频率可调的只有通道B,而通道A可以通过对设置输出模式让他输出一个%50占空比的pwm。
配置代码(以16位定时器timer3为例):
TCCR3A = _BV(WGM31) | _BV(WGM30);
TCCR3B = _BV(WGM33) |_BV(WGM32) ;
_BV即bit value(位对应的值)
WGM33:3 表示定时器3,3表示将1左移3位,此时对应的值就是1000
WGM32:3 表示定时器3,2表示将1左移2位,此时对应的值就是0100
WGM31:3 表示定时器3,1 表示将1左移1位,此时对应的值就是0010
WGM30:3 表示定时器3,0表示将1左移0位,此时对应的值就是0001
将 以上 位值 进行 或运算就可以配置成我们想要的模式15:
_BV(WGM31) | _BV(WGM30)|_BV(WGM33) |_BV(WGM32)=1111
- 时钟选择位 (CS):这些控制时钟预分频器
同样我们根据数据手册提供的图表进行配置
我想要配置成8分频,cs位就需要配置成010(以16位定时器timer3为例):
TCCR3B = _BV(CS31); //10设置预分频系数为8
CS31:3 表示定时器3,1表示将1左移1位,此时对应的值就是010
- 比较匹配输出通道 A 模式位 (COMnA):这些启用/禁用/反转输出 A
- 比较匹配输出通道 B 模式位 (COMnB):这些启用/禁用/反转输出 B
根据数据手册配置输出通道A/B的模式
配置代码(以16位定时器timer3为例):
TCCR3A = _BV(COM3A0) | _BV(COM3B1)
前面说的50%的占空比就是将OCR2A 的模式设置为“Toggle on Compare Match”得到的。
至此配置完毕:
void setup()
{
//定时器3:三个输出通道
pinMode(5, OUTPUT); //OC3A
pinMode(2, OUTPUT); //OC3B
pinMode(3, OUTPUT); //OC3C
TCCR3A = _BV(COM3A0) | _BV(COM3B1) | _BV(WGM31) | _BV(WGM30);
TCCR3B = _BV(WGM33) |_BV(WGM32) | _BV(CS31); //10设置预分频系数为8
OCR3A = 40000; //重装载值为40000 pwm频率为16Mhz/8预分频系数/40000重装载值=50hz :T=20ms
OCR3B = 20000; //输出比较值,即控制占空比,如20000/40000=50%
void loop() {
// put your main code here, to run repeatedly:
}
你可能想知道为什么有些位配置在TCCR3A上,有些在TCCR3B上,那么你可以再看看下面两张图(来自数据手册)。
本文用作记录学习,其中大多为个人理解,如有误请指出。
(如有侵权请联系我删除)
参考链接(建议都去看看,会理解的更透彻一点):
arduino官方文档
https://docs.arduino.cc/tutorials/generic/secrets-of-arduino-pwm
动力老男孩
http://www.diy-robots.com/?p=852
arduino中文社区
https://www.arduino.cn/thread-19799-1-1.html