【问题标题】:Arduino Uno PWM pins conflictArduino Uno PWM 引脚冲突
【发布时间】:2013-09-09 19:18:36
【问题描述】:

我基于L298N芯片构建了this motor shield来控制一个坦克的两个电机。一个电机使用引脚 5 和 6,另一个电机使用引脚 10 和 11。

在尝试添加 TSOP 4838 以使用 IR 遥控器控制油箱时,我注意到反向移动引脚 10/11 上的电机只能在全速下工作 - 也就是说,高 (255) 值引脚 11。低于该值的任何值都不会在引脚 11 上输出任何内容(这些引脚上的测量电压为 0 V)。

对于遥控器,我使用this libraryIR 接收器连接在引脚 2 上(但引脚无关紧要)。问题是库代码本身。启用 IR 监听的行 irrecv.enableIRIn(); 是导致问题的原因。我了解到内部 Arduino 定时器和屏蔽用于 PWM 的引脚存在冲突。

这是给电机反向供电的代码:

#include <IRremote.h>

// IR receiver configuration
const int irPin = 2;
IRrecv irrecv(irPin);

// Motors configuration
const int mLeftPin1  = 10;
const int mLeftPin2  = 11;
const int mRightPin1 = 5;
const int mRightPin2 = 6;

void setup()
{
  // Start IR
  irrecv.enableIRIn();

  // Setup motors
  pinMode(mLeftPin1, OUTPUT);
  pinMode(mLeftPin2, OUTPUT);
  pinMode(mRightPin1, OUTPUT);
  pinMode(mRightPin2, OUTPUT);

  // Move left motor in reverse, slower speed
  analogWrite(mLeftPin2, 100); // This works only with 255 instead of 100
  digitalWrite(mLeftPin1, LOW);
}

现在,我发现hereArduino Uno 上的定时器使用的引脚是:

  • 引脚 5 和 6:由 Timer0 控制
  • 引脚 9 和 10:由 Timer1 控制
  • 引脚 11 和 3:由 Timer2 控制

所以我的问题是:

  1. 为什么指令中的屏蔽使用引脚 10 和 11 进行 PWM?它们对应于 2 个不同的计时器。为什么不是 9 和 10?

  2. 为了将 IR 与电机护罩一起使用,我应该配置 IR 库以使用什么计时器?

  3. 如果答案为 2,则应在 IRremoteInt.h 中取消注释一行。我猜 Uno 会在第 68 行采用else 分支,尽管那里只有 timer1 和 timer2。我想知道为什么 Timer0 不能用于 Uno。

虽然我想留下切割痕迹并重新焊接作为最后的选择,但另一种可能性是更改屏蔽使用的引脚,但是哪个?而且我猜这也将与将定时器配置为在其他引脚上进行 PWM 而非默认配置配对,但我对定时器/中断一无所知,而且我对 Arduino 和 C 的了解有限。

我提出了一个很长的问题,因为我想学习的不仅仅是解决问题,所以请随意解释而不是问什么。

在寻找解决方案时,我还发现在使用 PWM 或计时器时需要记住的其他冲突:

  • Timer0是一个8位定时器,最大值为255,被delay()millis()使用,乱用会有后果
  • Timer1 是一个 16 位定时器,它最多可以容纳 65535(一个无符号的 16 位整数)。 Arduino Servo 库使用此计时器
  • Timer2 是 Arduino tone() 函数使用的 8 位定时器

当然,IRremote 库使用TIMER_RESET,因此根据它使用的定时器,它可能会与关联的引脚发生冲突。

【问题讨论】:

  • +1。示例性问题。

标签: timer arduino avr atmega pwm


【解决方案1】:
  1. 并非所有硬件都以最佳方式设计。使用 10 和 11 确实很浪费,因为它需要两个计时器。

2/3。理想情况下,您将使用不是 Timer0 的计时器。以下是有关计时器/中断的更多详细信息:

Arduino 芯片 (328P) 有三个定时器。每个定时器可用于多种用途,但需要注意的是,您只能为每个定时器启用一个定时器中断。

以 Timer0 为例。它中断以便为 delay() 和 delay_us() 方法生成适当的延迟。它也用于引脚 5 和 6 上的 PWM 输出。这可能是因为 PWM 输出不使用定时器中断,它们使用单​​独的输出比较模块。

现在专门查看您的问题,它应该工作正常,即使您使用 timer2 有一个 PWM 输出,PWM 也不会在 timer2 上产生中断,因此 IR 库应该可以免费使用那个中断。然而,查看 IR 库代码,我们看到了这段代码:

ISR(TIMER_INTR_NAME)
{
   TIMER_RESET; 

似乎每次中断时,它都会重置计时器计数。这可能是您的 PWM 输出无法正常工作的原因。输出比较模块正在等待某个滴答计数,但它永远不会达到那个值。

至于为什么它在 255 处工作,我们可以看一下模拟写代码:

void analogWrite(uint8_t pin, int val)
{
    // We need to make sure the PWM output is enabled for those pins
    // that support it, as we turn it off when digitally reading or
    // writing with them.  Also, make sure the pin is in output mode
    // for consistenty with Wiring, which doesn't require a pinMode
    // call for the analog output pins.
    pinMode(pin, OUTPUT);
    if (val == 0)
    {
        digitalWrite(pin, LOW);
    }
    else if (val == 255)
    {
        digitalWrite(pin, HIGH);
    }

因此,通过写入 255,analogWrite 代码忽略了整个 PWM 和输出比较的事情,而只是将引脚写入高电平。

最后,至于解决您的问题,我个人会选择不使用引脚 11 和 3(timer2)的路线。是的,它需要重新布线,但这样您就可以腾出 timer2 供 IR 库使用。

或者,您可以在 IR 库中四处寻找,并尝试在不重置计数的情况下使其工作。

【讨论】:

  • 很好的答案,谢谢!我将走重新布线路线并将引脚 10 移动到 9 并将引脚 11 移动到 10(只是为了保持逻辑顺序)。所以这将只使用Timer1
  • 我还看到了analogWrite() 的代码,但当时我并不怀疑计时器可能是问题所在。现在看一下,我还看到setup 中的pinMode(pin, OUTPUT); 是多余的,因为analogWrite 已经这样做了。
  • @talereader 是的,您会注意到 Arduino 的函数中内置了许多冗余的臃肿代码。记住这些是个好主意,所以以后如果您需要更快的速度,可以直接使用较低级别的 C 命令。 (例如,您可以使用更快的 DDRB |= 0x01 代替 digitalWrite,它的可读性较差但速度更快)。
【解决方案2】:

注意使用的板子,如果你使用Arduino Uno,那么负责的代码是://Arduino Duemilanove, Diecimila, LilyPad, Mini, Fio, etc 别的 //定义 IR_USE_TIMER1 // tx = 引脚 9 定义 IR_USE_TIMER2 // tx = 引脚 3 结束

【讨论】:

  • 你说得对,我现在正在做的项目是在 Mega 2560 上,我查看了错误的代码。所以库中的评论警告了我关于 pin 9 的信息,但当时不明白 TX 部分是什么。
  • 只是为了澄清以后阅读本文的人,您的答案是我在下面的评论中提出的问题,而不是直接针对已发布的问题。
【解决方案3】:

我在使用预建的 L298 V2 电机护罩时遇到了同样的问题。

盾牌上的引脚是这样标记的:

电机 1:引脚 3 和 5 电机 2:引脚 6 和 9

我使用 PIN10 而不是 3,并使用了一个小解决方法:我在 SHIELD 上放置了一根从 PIN10 到 PIN3 的电线。 我的项目是用三星电视遥控器控制我的机器人。

【讨论】:

  • 欢迎罗马尼亚同胞! RoboFun 很有趣,但构建自己的游戏更有趣 :) 我的目的是学习,所以我更喜欢 DIY 构建。但这也让我有些头疼。无论如何,自从坦克项目以来,我现在已经转移到另一个项目,使用 2 个步进器和 IR 控制。我稍微修改了 IRremote 库以适应我的目的。但是我对这个库还有一个问题:你明白IRremoteInt.h 中的cmets 是什么意思吗,那些定义了定时器使用的地方?例如,#define IR_USE_TIMER1 // tx = pin 11。引脚 11 与 TIMER1 有什么关系?
  • 另外,我遇​​到了这个问题:我需要实时控制步进器,按住IR按钮时保持步进器移动。然而,我目前拥有的遥控器 (sparkfun.com/products/retired/10280) 以 3 种不同格式发送相同的信号,这需要时间并产生延迟问题(导致步进器停止)。这就是为什么我要转向这个:sparkfun.com/products/11759。刚下单,还没到。但是,一个 IR 命令仍然有 8 个字节,并且需要一些时间才能被 IR 接收器发送和完全读取。三星电视遥控器的表现如何?
  • 你肯定会讨厌它。它具有间歇性红外光束。不适合精细运动控制。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多