0

在基于 Leonardo 板的 Arduino Esplora 上,驱动 RGB LED 的红色组件的引脚 5 的 PWM 支持看起来与该tone功能共享一个定时器。这会产生意想不到的后果,即在播放音调后使 Red 组件变得无用,因为它的行为变得不可预测。

这是一个演示问题的简单setup例程:

void setup()
{
    //analogWrite(5, 255);
    //delay(1000);
    analogWrite(5, 1);
    delay(2000);
    Esplora.tone(440);
    delay(1000);
    Esplora.noTone();
}

这会将 LED 的红色通道打开到其最低设置并保持两秒钟,然后播放 440 HZ 音调 1/4 秒,但一旦音调开始,LED 不会保持低亮度,而是打开完全关闭。

如果您取消注释前两行,这一次当音调开始时,而不是像以前那样(不正确地)关闭,它现在(同样不正确地)恢复为全亮度。

在调用tone.

我的猜测是为声音生成适当的 HZ,tone更改定时器的设置,然后影响 PWM 功能。如果我能找到如何手动重置计时器以再次正确支持 LED 的 PWM,那可能就是解决方案。但是我是 Arduino、计时器等的新手,所以这纯粹是猜测,我可能对这种方法或我对它的理解完全错误,但从我读过的内容来看,这似乎是朝着正确的方向发展.

那么有人知道如何在该引脚上恢复正确的 PWM 功能吗?

标记

4

2 回答 2

2

您对重新配置计时器的怀疑tone()是正确的。在 '32U4 上,定时器 3 用于tone(),但在 Esplora 上,OC3A 用于红色分量(OC1B 和 OC1A 分别用于绿色和蓝色分量)。这意味着每次tone()在 Esplora 上调用时,定时器 3 都会重新配置为 CTC(WGM3[3:0]=0b0100),而红色组件需要 PWM 才能正确使用(analogWrite()特别是使用 8 位相位校正脉宽调制 [WGM[3:0]=0b0001])。而且由于在音调停止之前需要计时器,因此没有理智的方法可以在模式之间来回切换。

通常,解决此问题的最简单方法是告诉tone()使用不同的计时器。不幸的是,在 Esplora 上没有可以使用的计时器:计时器 0 由delay()等人使用,计时器 1 由绿色和蓝色组件使用,计时器 4 的工作方式与 Arduino 库的编程完全不同,计时器 2 没有'32U4 上甚至都不存在。

但是,'32U4 上 OC3A 的引脚与 nOC4A 的引脚相同。这意味着我们可以使用定时器 4 来控制红色组件。当您检查 TCCR4* 时,它们的值不是 0,但这可能是因为引导加载程序对它们进行了摆弄;我在 Arduino 核心或 Esplora 库中找不到任何修改它们的东西。

使用定时器 4 有 2 个问题:

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

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

所以:

pinMode(13, INPUT);
// disable timer 4 interrupts
TIMSK4 = 0;
// reset TCCR4C
TCCR4C = 0;
// set OCR4C to maximum
OCR4C=0xff;
// clear dead time register
DT4 = 0;
// enable PWM based on OCR4A and connect nOC4A (and OC4A)
TCCR4A = _BV(PWM4A) | _BV(COM4A0);
// match analogWrite() prescaling
TCCR4B = _BV(CS42) | _BV(CS41) | _BV(CS40);
// enable fast PWM
TCCR4D = 0;
// set minimum brightness
OCR4A = 0xff;

delay(1000);
OCR4A = 0xbf; // low brightness
delay(1000);
OCR4A = 0x3f; // high brightness
delay(1000);
OCR4A = 0x7f; // mid brightness
delay(1000);
OCR4A = 0x00; // max brightness
于 2014-04-26T17:58:30.753 回答
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);
}
于 2014-04-29T00:45:54.580 回答