14

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

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

对于遥控器,我使用这个库IR接收器连接在引脚 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);
}

现在,我在这里发现Arduino 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 会else在第 68 行使用分支,尽管那里只有 timer1 和 timer2。我想知道为什么 timer0 不能用于 Uno。

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

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

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

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

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

4

3 回答 3

14
  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 处起作用,我们可以看一下 AnalogWrite 代码:

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 库并尝试在不重置计数的情况下使其工作。

于 2013-09-09T20:11:31.330 回答
1

注意使用的板子,如果你使用 Arduino Uno,那么负责的代码是: // Arduino Duemilanove、Diecimila、LilyPad、Mini、Fio 等 //define IR_USE_TIMER1 // tx = pin 9 define IR_USE_TIMER2 // tx = 引脚 3 endif

于 2014-03-25T20:31:22.897 回答
0

我对预装的L298 V2电机护罩也有同样的问题。

护罩上的引脚标记如下:

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

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

于 2014-03-15T14:31:00.577 回答