在基于Leonardo电路板的Arduino Esplora上,引脚5的PWM支持驱动RGB LED的红色分量,看起来它与tone
功能共享一个定时器。这有一个意想不到的后果,即在播放音调后使红色组件无效,因为它的行为变得无法预测。
这是一个简单的setup
例程,用于说明问题:
void setup()
{
//analogWrite(5, 255);
//delay(1000);
analogWrite(5, 1);
delay(2000);
Esplora.tone(440);
delay(1000);
Esplora.noTone();
}
这会将LED的红色通道设置为最低设置并保持2秒钟,然后播放440 HZ音调1/4秒,但一旦音调开始,而不是保持低亮度, LED完全关闭。
如果取消注释前两行,此时音调开始,而不是像以前那样(错误地)关闭,它现在(同样不正确)会变回全亮度。
在调用tone
后,我无法弄清楚如何恢复Red组件的正常功能(或更具体地说是引脚5上的PWM)。
我的猜测是为声音生成适当的HZ,tone
更改定时器的设置,然后影响PWM功能。如果我能找到如何手动重置定时器以再次正确支持LED的PWM,这可能是解决方案。不过我是Arduino的新手,计时器之类的,所以这是纯粹的推测,我对这种方法或我对它的理解可能完全错误,但从我所读到的,这似乎是领先的在正确的方向。
所以任何人都知道如何在该引脚上恢复正确的PWM功能?
标记
答案 0 :(得分:1)
您对tone()
重新配置计时器的怀疑是正确的。在' 32U4上,定时器3用于tone()
,但在Esplora上,OC3A用于红色分量(OC1B和OC1A分别用于绿色和蓝色分量)。这意味着每次在Esplora上调用tone()
时,定时器3将重新配置为CTC(WGM3 [3:0] = 0b0100),而红色分量需要PWM以便正确使用(和{{1具体使用8位相位校正PWM [WGM [3:0] = 0b0001])。并且由于需要定时器直到音调停止,因此无法在模式之间来回切换它。
通常,解决此问题的最简单方法是告诉analogWrite()
使用其他计时器。不幸的是,在Esplora上没有它可以使用的定时器:tone()
等人使用定时器0,绿色和蓝色组件使用定时器1,定时器4完全不同地使用 比Arduino库编程的更多,而计时器2甚至不存在于' 32U4上。
然而,  32U4上的OC3A引脚与nOC4A的引脚相同。这意味着我们可以使用计时器4来控制红色组件。当你检查它们时,TCCR4 *的值不是0,但这可能是因为引导加载程序与它们混在一起;我无法在Arduino核心或Esplora库中找到修改它们的任何内容。
使用计时器4有两个问题:
引脚13连接到OC4A。这意味着引脚13必须始终配置为输入,因为它的输出将是与红色分量相反的PWM信号。
Arduino库未编程为处理定时器4.这意味着我们需要以低级别访问定时器4来配置和使用它。
所以:
delay()
答案 1 :(得分:1)
我研究了32U4文档并从Arduino库中获取了Esplora特定逻辑,用于在启动时初始化PWM资源。下面生成的timerFix()例程可用于将事物恢复到正确的设置。
void loop()
{
Esplora.writeRGB(127,0,0);
delay(1000);
Esplora.tone(311);
delay(1000);
timerFix();
Esplora.writeRGB(32,0,0);
delay(1000);
}
void timerFix()
{
#define sbi(sfr,b) (_SFR_BYTE(sfr) |= _BV(b))
//Tone will have hijacked the timer used for the
//RGB led RED channel so once we're done we need
//to restore it. First shutdown the tone internals
//if not done already...
Esplora.noTone();
//Now clear the Timer Count Control Registers to
//have them in a known state.
TCCR3A = 0;
TCCR3B = 0;
//Setup the clock source - clk/64
sbi(TCCR3B, CS31);
sbi(TCCR3B, CS30);
//Set the wave form generator for 10-bit PWM
sbi(TCCR3A, WGM30);
//re-link the PWM timer to output channel
//by passing something other than 0 and 255
//so that the analogWrite function is forced to
//recompute the correct value for either the
//OCR3A or OCR3B register (output control register)
//as appropriate
analogWrite(5, 1);
//turn the LED channel off
analogWrite(5, 0);
}