Конфликт контактов ШИМ Arduino Uno

Я построил этот моторный щиток на базе микросхемы L298N для управления двумя моторами танка. Он использует контакты 5 и 6 для одного двигателя и контакты 10 и 11 для другого.

Пытаясь добавить TSOP 4838 для управления резервуаром с помощью ИК-пульта, я заметил что движение двигателя на контактах 10/11 в обратном направлении работает только на полной скорости, то есть при ВЫСОКОМ (255) значении на контакте 11. Все, что ниже этого значения, ничего не выводит на контакт 11 (измеренное напряжение на этих контактах равно 0 V).

Для пульта дистанционного управления я использую эту библиотеку. Приемник IR подключен к контакту 2 (но контакт не имеет значения). Проблема в самом коде библиотеки. Линия, которая включает ИК-прослушивание irrecv.enableIRIn();, является причиной проблемы. Я узнал, что существует конфликт внутренних таймеров Arduino и контактов, используемых щитом для ШИМ.

Это код для включения двигателя в обратном направлении:

#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 для ШИМ? Они соответствуют 2 разным таймерам. Почему не 9 и 10?

  2. Какой таймер мне нужно настроить в библиотеке IR, чтобы использовать ИК вместе с моторным щитом?

  3. Если ответ - 2, следует раскомментировать строку в IRremoteInt.h. Я предполагаю, что Uno возьмет ветку else в строке 68, хотя там есть только timer1 и timer2. Интересно, почему timer0 нельзя было использовать для Uno.

Хотя я хотел бы оставить следы резки и пайку в качестве последнего варианта, другой возможностью было бы изменить контакты, используемые щитом, но какие? И я предполагаю, что это также будет связано с настройкой таймеров на ШИМ на других выводах, кроме по умолчанию, но я ничего не знаю о таймерах / прерываниях, а мои знания об Arduino и C ограничены.

Я задал этот длинный вопрос, потому что хочу научиться, а не просто решать проблему, поэтому не стесняйтесь объяснять больше, чем то, о чем просят.

В поисках решения я также обнаружил другие конфликты, о которых следует помнить при использовании PWM или таймеры:

  • Timer0 - это 8-битный таймер, он может содержать максимальное значение 255. Он используется delay() и millis(), поэтому есть последствия, если с ним возиться.
  • Timer1 - это 16-разрядный таймер, он может содержать максимум 65535 (16-разрядное целое число без знака). Библиотека Arduino Servo использует этот таймер
  • Timer2 - это 8-битный таймер, используемый функцией Arduino tone().

И, конечно же, библиотека IRremote использует TIMER_RESET, поэтому в зависимости от того, какой таймер он использует, он может конфликтовать с соответствующими контактами.


person binar    schedule 09.09.2013    source источник
comment
+1. Образцовый вопрос.   -  person Peter Mortensen    schedule 20.04.2014


Ответы (3)


  1. Не все оборудование спроектировано наилучшим образом. Использование 10 и 11 действительно расточительно, поскольку требует двух таймеров.

2/3. В идеале вы должны использовать таймер, отличный от Timer0. Вот еще несколько подробностей о таймерах / прерываниях:

Чип Arduino (328P) имеет три таймера. Каждый таймер можно использовать для нескольких целей, однако важно отметить, что для каждого таймера можно включить только одно прерывание от таймера.

Возьмем, к примеру, Timer0. Он прерывает, чтобы генерировать правильные задержки для методов delay () и delay_us (). Он также используется для выходов PWM на контактах 5 и 6. Это может произойти, потому что выходы PWM не используют прерывание таймера, они используют отдельные модули сравнения выходов.

Теперь, глядя конкретно на вашу проблему, она должна работать нормально, даже если у вас есть выход PWM с использованием timer2, 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 игнорирует весь ШИМ и сравнение вывода и просто записывает высокий вывод.

Наконец, что касается решения вашей проблемы, я бы лично пошел по пути отказа от контактов 11 и 3 (timer2). Да, потребуется небольшая переустановка, но таким образом вы можете освободить таймер 2 для использования ИК-библиотекой.

В качестве альтернативы вы можете покопаться в библиотеке IR и попытаться заставить ее работать, не сбрасывая счетчик.

person user2461391    schedule 09.09.2013
comment
Отличный ответ, спасибо! Я пойду по пути изменения проводки и переместу контакты 10 на 9 и контакты 11 на 10 (просто для сохранения логического порядка). Таким образом, будет использоваться только Timer1. - person binar; 10.09.2013
comment
Я также видел код для analogWrite(), но в то время я не подозревал, что проблема в таймерах. Теперь, глядя на это, я также вижу, что pinMode(pin, OUTPUT); в setup является избыточным, поскольку analogWrite уже делает это. - person binar; 10.09.2013
comment
@talereader Да, вы заметите много избыточного раздутого кода, встроенного в функции Arduino. Это хорошая идея, чтобы помнить об этом, поэтому позже, если вам понадобится больше скорости, вы можете напрямую использовать команды нижнего уровня C. (Например, вместо digitalWrite можно использовать более быструю DDRB | = 0x01, она менее читаема, но намного быстрее). - person user2461391; 10.09.2013

Обратите внимание на используемую плату, если вы используете Arduino Uno, тогда ответственный код будет: // Arduino Duemilanove, Diecimila, LilyPad, Mini, Fio и т. Д. Else // определить IR_USE_TIMER1 // tx = pin 9 определить IR_USE_TIMER2 // tx = контакт 3 endif

person sky10    schedule 25.03.2014
comment
Вы правы, проект, над которым я сейчас работаю, относится к Mega 2560, и я посмотрел не на тот код. Итак, комментарий в библиотеке предупредил меня о выводе 9, но тогда я не понял, что с частью TX. - person binar; 26.03.2014
comment
Просто чтобы прояснить для тех, кто прочитает это в будущем, ваш ответ - на вопрос, который я задал в комментарии ниже, а не непосредственно на опубликованный вопрос. - person binar; 26.03.2014

У меня была такая же проблема с предварительно созданным моторным щитом L298 V2.

Штифты были обозначены на щите так:

Motor1: контакты 3 и 5 Motor2: контакты 6 и 9

Я использую PIN10 вместо 3 и использую небольшой обходной путь: я помещаю провод от PIN10 к PIN3 на SHIELD. Мой проект состоял в том, чтобы управлять своим роботом с помощью пульта дистанционного управления SAMSUNG TV.

person sky10    schedule 15.03.2014
comment
Добро пожаловать в ТАК румынский брат! RoboFun - это весело, но создавать собственные - еще веселее :) Моя цель - учиться, поэтому я предпочитаю сборки своими руками. Но это также вызвало у меня головную боль. В любом случае, после проекта танка я перешел к другому проекту, используя 2 шаговых двигателя, а также ИК-управление. Я немного изменил библиотеку IRremote для своих целей. Но у меня все еще есть один вопрос по этой библиотеке: вы поняли, что означают комментарии в IRremoteInt.h, те, в которых определяется использование таймера? Например, #define IR_USE_TIMER1 // tx = pin 11. Какое отношение имеет контакт 11 к TIMER1? - person binar; 19.03.2014
comment
Также я столкнулся с этой проблемой: мне нужно управлять шаговыми двигателями в реальном времени, держать шаговый двигатель в движении, пока нажата кнопка ИК. Однако текущий пульт, который у меня есть (sparkfun.com/products/retired/10280) отправляет один и тот же сигнал в 3 разных форматах, что требует времени и создает проблемы с задержкой (вызывая остановку шаговых двигателей). Вот почему я перехожу к этому: sparkfun.com/products/11759. Только что заказал, еще не пришел. Но, тем не менее, одна ИК-команда имеет 8 байтов, и требуется некоторое время, чтобы она была отправлена ​​и полностью прочитана ИК-приемником. Как себя ведет пульт от телевизора Самсунг? - person binar; 19.03.2014
comment
Вы точно возненавидите это. Он имеет прерывистый ИК-луч. Не подходит для точного управления двигателем. - person sky10; 26.03.2014