你如何阻止Arduino Esplora的音调功能干扰RGB LED

时间:2014-04-25 02:04:06

标签: arduino pwm

在基于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功能?

标记

2 个答案:

答案 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有两个问题:

  1. 引脚13连接到OC4A。这意味着引脚13必须始终配置为输入,因为它的输出将是与红色分量相反的PWM信号。

  2. Arduino库未编程为处理定时器4.这意味着我们需要以低级别访问定时器4来配置和使用它。

  3. 所以:

    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);
}