Arduino Uno PWM引脚冲突

bin*_*nar 13 avr atmega timer arduino pwm

我基于L298N芯片制造了这个电机屏蔽,以控制一个水箱的两个电机.它将引脚5和6用于一个电机,而引脚10和11用于另一个电机.

在尝试添加TSOP 4838以便使用IR遥控器控制油箱时,我注意到在10/11引脚上反向移动电机只能在全速运行 - 即引脚11上的HIGH(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);
}
Run Code Online (Sandbox Code Playgroud)

现在,我在这里发现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()和使用millis(),所以当它搞乱它时会有后果
  • Timer1是一个16位定时器,最多可以保存65535(无符号16位整数).Arduino Servo库使用此计时器
  • Timer2是Arduino tone()函数使用的8位定时器

当然,IRremote库使用TIMER_RESET,因此根据它使用的计时器,它可能与相关的引脚冲突.

use*_*391 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; 
Run Code Online (Sandbox Code Playgroud)

它似乎每次中断时都会重置计时器计数.这可能是您的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);
    }
Run Code Online (Sandbox Code Playgroud)

因此,通过写入255,analogWrite代码忽略了整个PWM和输出比较的东西,只需将引脚写入高电平.

最后,为了解决您的问题,我个人会采用不使用引脚11和3(timer2)的路线.是的,它需要一个小的重新布线,但这样你可以释放timer2供IR库使用.

或者,您可以在IR库周围寻找并尝试使其工作而不重置计数.