【问题标题】:How do you stop Arduino Esplora's tone function interfering with RGB LED如何阻止 Arduino Esplora 的音调功能干扰 RGB LED
【发布时间】:2014-04-25 02:04:06
【问题描述】:

在基于 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 之后,我无法弄清楚如何恢复 Red 组件(或更具体地说是引脚 5 上的 PWM)的正常功能。

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

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

标记

【问题讨论】:

  • 故障前后的TCCR3A、TCCR3B、TCCR4A、TCCR4B、TCCR4C、TCCR4D、TCCR4E的值是多少(请用十六进制表示)?
  • Arduino 新手。我如何检查这些?任何草图代码将不胜感激。 (你是不是投票给我的人?如果是,请详细说明原因??)
  • 通过串口输出即可。
  • 使用这些名称调用 Serial.write(),我得到以下信息: 之前:TCCR3A:1 TCCR3B:3 TCCR4A:2 TCCR4B:7 TCCR4C:1 TCCR4D:1 TCCR4E:0 之后:TCCR3A: 0 TCCR3B: 9 TCCR4A: 2 TCCR4B: 7 TCCR4C: 1 TCCR4D: 1 TCCR4E: 0(你的意思是二进制吗?十六进制和十进制对于所有小于等于 9 的值都是相同的。)

标签: arduino pwm


【解决方案1】:

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

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

但是,'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

【讨论】:

  • 嗨,伊格纳西奥!对于问题所在,这是一篇非常棒的文章。你实际上已经超越了,并且超过了我需要的,这只是在播放音调后为 PWM 重新配置 Timer3。原因是当我在 Esplora 上进行原型设计时,我想屏蔽任何可能存在问题的电路板。但这对于更改/更新来说太好了,所以我可以麻烦你用一个简单的 sn-p 创建第二个关于如何重新配置​​计时器以返回支持 PWM 的问题吗?如果需要,我只会在音调和 RGB 之间切换,而不是在播放声音时使用 LED。
  • 另外,虽然这不能满足我的迫切需求,但我仍然有兴趣了解您在这里所做的事情。你能在 cmets 上扩展 OCR4A 之类的东西吗?我在谷歌上搜索,但似乎找不到关于计时器以及所有这些值之间关系的好的教程。
  • 另一件事......在您上面关于引脚 13 的“警告”中,这通常是默认的 LED 引脚。将其作为输出以查看红色的反转有什么害处吗?它会搞砸什么吗,还是你只是这样做所以你不会看到它?
  • 刚刚找到关于计时器和这些值的优秀文章! - engblaze.com/…
  • 您可以通过将 WGM3 和 CS3 位分别设置回 0b001 和 0b011 来重新配置时间。可以在制造商网站上的 MCU 数据表中找到有关各种外设、寄存器和位的文档。您可以将引脚 13 保留为输出;它不会干扰,只是看起来很奇怪。请注意,我将 '32U4 上的计时器 4 称为“完全不同”的评论并不夸张。这篇文章不会让你为它做好充分的准备,尽管它会给你一些基础知识。
【解决方案2】:

我稍微研究了 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);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-10-18
    • 2011-12-22
    • 2015-04-21
    • 1970-01-01
    • 2018-04-03
    • 1970-01-01
    • 1970-01-01
    • 2021-05-15
    相关资源
    最近更新 更多