Урок 10. Прерывание по таймеру в Ардуино. Библиотека MsTimer2. Параллельные процессы.

Arduino UNO R3

Узнаем, как работать с прерываниями по таймеру. Напишем простую программу с параллельными процессами.

Предыдущий урок     Список уроков     Следующий урок

В реальной программе надо одновременно совершать много действий. Во введении я приводил пример программы контроллера холодильника на модуле Пельтье. Перечислю, какие действия она совершает:

Операция

Время цикла
Опрашивает 3 кнопки, обрабатывает сигналы с них для устранения дребезга 2 мс
Регенерирует данные семисегментных светодиодных индикаторов 2 мс
Вырабатывает сигналы управления для 2 датчиков температуры DS18B20 и считывает данные с них. Датчики имеют последовательный интерфейс  1-wire. 100 мкс для каждого бита,
1 сек общий цикл чтения
Чтение аналоговых значений тока и напряжения на элементе Пельтье, напряжения питания 100 мкс
Цифровая фильтрация аналоговых значений тока и напряжения 10 мс
Вычисление мощности на элементе Пельтье 10 мс
ПИД (пропорционально интегрально дифференциальный) регулятор стабилизации тока и напряжения 100 мкс
Регулятор мощности 10 мс
Регулятор температуры 1 сек
Защитные функции, контроль целостности данных 1 сек
Управление, общая логика работы системы 10 мс

Все эти операции выполняются циклически, у всех разные периоды циклов. Ни какую из них нельзя приостановить. Любое, даже кратковременное, изменение времени периода операции приведет к неприятностям: значительной погрешности измерения, неправильной работе стабилизаторов, мерцанию индикаторов, неустойчивой реакции нажатий на кнопки и т.п.

 

В программе контроллера холодильника существует несколько параллельных процессов, которые и совершают все эти действия, каждое в цикле со своим временем периода. Параллельные процессы - это процессы, действия которых выполняются одновременно.

В предыдущих уроках мы создали класс для объекта кнопка. Мы сказали, что это класс для обработки сигнала в параллельном процессе. Что для его нормальной работы необходимо вызывать функцию (метод) обработки сигнала в цикле с регулярным периодом (мы выбрали время 2 мс). И тогда в любом месте программы доступны признаки, показывающие текущее  состояние кнопки или сигнала.

В одном цикле мы поместили код обработки состояния кнопок и управление светодиодами. А в конце цикла поставили функцию задержки delay(2).  Но, время на выполнение программы в цикле меняет общее время цикла. И период цикла явно не равен 2 мс. К тому же, во время выполнения функции delay() программа зависает и не может производить других действий. На сложной программе получится полный хаос.

Выход  - вызывать функцию обработки состояния кнопки по прерыванию от аппаратного таймера. Каждые 2 мс основной цикл программы должен прерываться, происходить обработка сигнала кнопки и управление возвращаться в основной цикл на код, где он был прерван. Короткое время на обработку сигнала кнопки не будет значительно влиять на выполнение основного цикла. Т.е. обработка кнопки будет происходить параллельно, незаметно для основной программы.

Аппаратное прерывание от таймера.

Аппаратное прерывание это сигнал, сообщающий о каком-то событии. По его приходу выполнение программы приостанавливается, и управление переходит на обработчик прерываний. После обработки управление возвращается в прерванный код программы.

С точки зрения программы прерывание это вызов функции по внешнему, не связанному напрямую с программным кодом, событию.

Сигнал прерывания от таймера вырабатывается циклически, с заданным временем периода. Формирует его аппаратный таймер – счетчик с логикой, сбрасывающий его код при достижении определенного значения. Программно установив код для логики сброса, мы можем задать время периода прерывания от таймера.

Установка режима и времени периода таймера Ардуино производится через аппаратные регистры микроконтроллера. При желании можете разобраться, как это делается. Но я  предлагаю более простой вариант – использование библиотеки MsTimer2. Тем более, что установка режима таймера происходит редко, а значит, использование библиотечных функций не приведет к замедлению работы программы.

 

Библиотека MsTimer2.

Библиотека предназначена для конфигурирования аппаратного прерывания от Таймера 2 микроконтроллера. Она имеет всего три функции:

  • MsTimer2::set(unsigned long ms, void (*f)())

Эта функция устанавливает время периода прерывания в мс. С таким периодом будет вызываться обработчик прерывания f. Он должен быть объявлен как void (не возвращает ничего) и не иметь аргументов. * f – это указатель на функцию. Вместо него надо написать имя функции.

  • MsTimer2::start()

Функция разрешает прерывания от таймера.

  • MsTimer2::stop()

Функция запрещает прерывания от таймера.

Перед именем функций надо писать MsTimer2::, т.к. библиотека написана с использованием директивы пространства имен namespace.

Для установки библиотеки скопируйте каталог MsTimer2 в папку libraries в рабочей папке Arduino IDE. За тем запустите программу Arduino IDE, откройте Скетч -> Подключить библиотеку и посмотрите, что в списке библиотек присутствует библиотека MsTimer2.

Загрузить библиотеку MsTimer2 в zip-архиве можно здесь. Для установки его надо распаковать.

Простая программа с параллельной обработкой сигнала кнопки.

Теперь напишем простую программу с одной кнопкой и светодиодом из урока 6. К плате Ардуино подключена одна кнопка по схеме:Схема подключения

Выглядит это так:

Подключение к плате

На каждое нажатие кнопки светодиод на плате Ардуино меняет свое состояние. Необходимо чтобы были установлены библиотеки MsTimer2 и Button:

 MsTimer2  загрузить 

Зарегистрируйтесь и оплатитеВсего 60 руб. в месяц за доступ ко всем ресурсам сайта!

 

// sketch_10_1 урока 10
// Нажатие на кнопку меняет состояние светодиода

#include <MsTimer2.h>
#include <Button.h>

#define LED_1_PIN 13     // светодиод подключен к выводу 13
#define BUTTON_1_PIN 12  // кнопка подключена к выводу 12

Button button1(BUTTON_1_PIN, 15);  // создание объекта - кнопка

void setup() {
  pinMode(LED_1_PIN, OUTPUT);      // определяем вывод светодиода как выход
  MsTimer2::set(2, timerInterupt); // задаем период прерывания по таймеру 2 мс
  MsTimer2::start();              // разрешаем прерывание по таймеру
}

void loop() {

// управление светодиодом
  if ( button1.flagClick == true ) {
    // был клик кнопки
    button1.flagClick= false;         // сброс признака
    digitalWrite(LED_1_PIN, ! digitalRead(LED_1_PIN));  // инверсия состояния светодиода
   
  }   
}

// обработчик прерывания
void  timerInterupt() {
  button1.scanState();  // вызов метода ожидания стабильного состояния для кнопки 
}

В функции setup() задаем время цикла прерывания по таймеру 2 мс и указываем имя обработчика прерывания timerInterrupt. Функция обработки сигнала кнопки button1.scanState() вызывается в обработчике прерывания таймера каждые 2 мс.

Таким образом, состояние кнопки мы обрабатываем параллельным процессом. А в основном цикле программы проверяем признак клика кнопки и меняем состояние светодиода.

 

Квалификатор volatile.

Давайте изменим цикл loop() в предыдущей программе.

void loop() {

  while(true) {
    if ( button1.flagClick == true ) break;   
  }

    // был клик кнопки
    button1.flagClick= false;         // сброс признака
    digitalWrite(LED_1_PIN, ! digitalRead(LED_1_PIN));  // инверсия светодиода       
}

Логически ничего не поменялось.

  • В первом варианте программа проходила цикл loop до конца и в нем анализировала флаг button1.flagClick.
  • Во втором варианте программа анализирует флаг  button1.flagClick в бесконечном цикле while. Когда флаг становится активным, то выходит из цикла while по break и инвертирует состояние светодиода.

Разница только в том, в каком цикле крутится программа в loop или в while.

Но если мы запустим последний вариант программы, то увидим, что светодиод не реагирует на нажатие кнопки. Давайте уберем класс, упростим программу.

#include <MsTimer2.h>
#define LED_1_PIN 13     // светодиод подключен к выводу 13
int count=0;

void setup() {
  pinMode(LED_1_PIN, OUTPUT);      // определяем вывод светодиода как выход
  MsTimer2::set(500, timerInterupt); // задаем период прерывания по таймеру 500 мс
  MsTimer2::start();              // разрешаем прерывание по таймеру
}

void loop() {

  while (true) {
    if ( count != 0 ) break;
  }

  count= 0; 
  digitalWrite(LED_1_PIN, ! digitalRead(LED_1_PIN));  // инверсия состояния светодиода       
}

// обработчик прерывания
void  timerInterupt() {
  count++; 
}

В этой программе счетчик count увеличивается на 1 в обработчике прерывания каждые 500 мс. В цикле while он анализируется, по break выходим из цикла и инвертируем состояние светодиода. Проще программы не придумаешь, но она тоже не работает.

Дело в том, что компилятор языка C++ по мере своего интеллекта оптимизирует программу. Иногда это не идет на пользу. Компилятор видит, что в цикле while никакие операции с переменной count не производятся. Поэтому он считает, что достаточно проверить состояние count только один раз. Зачем в цикле проверять, то, что никогда не может измениться. Компилятор  корректирует код, оптимизируя его по времени исполнения. Проще говоря убирает из цикла код проверки переменной.  Понять, что переменная count меняет свое состояние в обработчике прерывания, компилятор не может. В результате мы зависаем в цикле while.

В вариантах программы с выполнением цикла loop до конца компилятор считает, что все переменные могут измениться и оставляет код проверки. Если в цикл while вставить вызов любой системной функции, то компилятор также решит, что переменные могут измениться.

Если, например, добавить в цикл while вызов функции delay(), то программа заработает.

  while (true) {
    if ( count != 0 ) break;
    delay(1);
  }

Хороший стиль – разрабатывать программы, в которых цикл loop выполняется до конца и программа нигде не подвисает. В следующем уроке будет единственный код с анализом флагов в бесконечных циклах while. Дальше я планирую во всех программах выполнять loop до конца.

Иногда это сделать непросто или не так эффективно. Тогда надо использовать квалификатор volatile. Он указывается при объявлении переменной и сообщает компилятору, что не надо пытаться оптимизировать ее использование. Он запрещает компилятору делать предположения по поводу значения переменной, так как переменная может быть изменена в другом программном блоке, например, в параллельном процессе. Также компилятор размещает переменную в ОЗУ, а не в регистрах общего назначения.

Достаточно в программе при объявлении count написать

volatile int count=0;

и все варианты будут работать.

Для программы с управлением кнопкой надо объявить, что свойства экземпляра класса Button могут измениться.

volatile Button button1(BUTTON_1_PIN, 15);  // создание объекта - кнопка

По моим наблюдениям применение квалификатора  volatile никак не увеличивает длину кода программы.

 

Сравнение метода обработки сигнала кнопки с библиотекой Bounce.

Существует готовая библиотека для устранения дребезга кнопок Bounce. Проверка состояния кнопки происходит при вызове функции update(). В этой функции:

  • считывается сигнал кнопки;
  • сравнивается с состоянием во время предыдущего вызова update();
  • проверяется, сколько прошло времени с предыдущего вызова с помощью функции millis();
  • принимается решение о том, изменилось ли состояние кнопки.

Далее надо еще считать состояние кнопки функцией read().

  • Но это не параллельная обработка сигнала. Функцию update() обычно вызывают в основном, асинхронном цикле программы. Если ее не вызывать дольше определенного времени, то информация о сигнале кнопки будет потеряна. Нерегулярные вызовы приводят к неправильной работе алгоритма.
  • Сама функция имеет достаточно большой код и выполняется намного дольше функций библиотеки Button (уроки 7, 8, 9).
  • Цифровой фильтрации сигналов по среднему значению там вообще нет.

В сложных программах эту библиотеку лучше не использовать.

 

В следующем уроке напишем более сложную программу с параллельными процессами. Узнаем, как реализовывать выполнение блоков программы в циклах с различными временными интервалами от одного прерывания по таймеру.

 

Предыдущий урок     Список уроков     Следующий урок

4

Автор публикации

не в сети 16 часов

Эдуард

280
Комментарии: 1936Публикации: 197Регистрация: 13-12-2015

110 комментариев на «Урок 10. Прерывание по таймеру в Ардуино. Библиотека MsTimer2. Параллельные процессы.»

    • Создать 3 объекта Button, для каждого вызывать метод scanState() в прерывании и сделать в цикле loop() 3 проверки для каждой кнопки и светодиода.

      0
  1. Правильно ли прерывание по таймеру называть параллельным процессом?
    Ведь loop() во время выполнения timerInterupt() прерывается?

    0
    • Наверное, зависит от времени реакции программы и от задачи. Вы нажимаете на кнопку и программа тут же что-то делает. Вы не замечаете, что она прервалась на другую задачу. Для вас как пользователя это процессы, которые выполняются одновременно.
      Если рассуждать с вашей точки зрения, то параллельное выполнение задач возможно только в мультипроцессорной системе.

      0
  2. А как насчет использования функции millis(), что-то типа:
    TS=millis();
    if ((TS-TSo) >= 1000)
    {
    TSo=TS;

    }
    пробовал…, вроде бы работает…

    0
    • Эту проверку надо все время вызывать и чем чаще тем лучше. Если программа задержится в какой-то задаче, то не вовремя отработает такое псевдо прерывание.

      0
    • Если вы хотите использовать эту функцию как синхронизатор точных отрезков времени, то ее надо изменить на:

      TS=millis();
      if ((TS-TSo) >= 1000)
      {
      TSo=TSo+1000;

      }

      0
  3. Такая ситуация…
    В Ардуину передаю строку (например дату-время) периодически (каждую секунду)…
    В случае аппаратного прерывания строка «порвется»?
    Если да, то как с этим бороться?

    0
    • Что значит строка порвется?
      Если имеется в виду передача по последовательному порту, то это происходит так. Строка функцией класса Serial загружается в буфер. От туда по прерыванию аппаратного последовательного порта после передачи каждого байта загружается новый байт. На загрузку нового байта есть время передачи предыдущего байта. Даже если произойдет задержка, то ничего страшного не будет. Передача или прием это тоже параллельные процессы, реализованные встроенным классом Serial.

      0
  4. Когда-то давно изучал бейсик и 386 комп был чудом техники, Теперь жизнь заставляет учить все с нуля. Спасибо очень помогают Ваши уроки, но никак не могу понять для чего нужны классы? Объем кода меньше не становиться.

    0
  5. А если мне надо одновременно контролировать несколько кнопок, причем контролировать длительность из нажатия.
    К примеру, короткое нажатие- считываю соответствующее кнопке значение ПЗУ и выполняю какое-то действие, длинное- считываю усредненное значение АЦП, и очень длинное- какое-то другое значение, пусть будет какая-нибудь калибровка. Тут как быть? случай без dalay, т.е. с прерываниями. В прерывании опрашивать кнопки или считать тики? я тут не зря упоминаю усредненное значение АЦП. )))) Старый стал))) Не соображу))

    0
    • Много вариантов решения. Например, в уроке 42 в программе контроллера элемента Пельтье при удержании кнопок «+» или «-» значение параметра меняется автоматически. Посмотрите как там реализовано.

      0
  6. а если так:
    кнопки на пин1, пин2, пин3, пин4
    входы подтянуты к плюсу
    примем А=!пин1*8, В=!пин2*4, С=!пин3*2, D=!пин4,
    ПОРТ=A+B+C+D
    Это, типа порт с маской
    Запускаем «тикалку»

    Введем некую переменную ПортХ

    если ПортХ=ПОРТ && ПортХ !=0, то считаем тики ТИК++
    если ПортХ !=ПОРТ && ПортХ !=0, тогда

    смотрим, сколько у нас натикало
    если ТИК<10 считаем, что дребезжит и сбрасываем счетчик

    если ТИК <20, сбрасываем счетчик тикалки, считаем, что на кнопку наступили и делаем, что-то первое

    если ТИК<40, сбрасываем счетчик тикалки, считаем, что на кнопку наступили и делаем, что-то второе

    если ТИК<80, сбрасываем счетчик тикалки, считаем, что на кнопку конкретно наступили и делаем, что-то третье

    если натикало больше 80, считаем, что кот спит на клаве, сбрасываем счетчик тикалки и ничего не делаем, вернее, всё остальное по порядку

    В прерывании по тикалке читаем состояние ПОРТ

    Так пойдет? Тут получается, что мы можем отслеживать несколько длительностей (тут отслеживаем 5 состояний нажатий кнопок
    1- кнопки никому не нужны и давить их никто не собирался, ну, может, импульсы вокруг летают, или кот проскочил, наступив на клаву, до 10 тиков

    2- нормально наступили, ненадолго, от 10 до 20 тиков,

    3- конкретно надавили, чуток подержали и отпустили от 20 до 40 тиков

    4- давили от души, но вовремя одумались от 40 до 80 тиков

    5- больше 80- либо тарелку с салатом и клаву перепутали, либо кот-подлец нашел себе новую лёжку
    Вроде, должно работать
    Число тиков, конечно, условно

    1
  7. чуть не забыл, помимо отслеживания времени нажатия, что-то делать можем по любому сочетанию кнопок

    0
  8. Не совсем понимаю… А можно ли сделать так (кнопки не нужны мне), чтобы три управляющих выхода на плате мигали светодиодами с разной задержкой, но одновременно? То есть пин1 = 100 мс, пин2 = 500 мс, пин3 = 1000мс. А то они работают друг за другом…

    0
  9. Написал программу по включению/выключению подсветки кнопкой (ИК датчик) и автоматическому её выключению через час (на случай, если ушел и забыл выключить либо ложное срабатывание датчика — чтобы свет не горел целый день).

    int ledPin = 13;
    int keyPin = 2; // кнопка
    bool keyState, oldKeyState; // состояние кнопки
    long on = 3600000; // время свечения, мс
    unsigned long ms, ms1 = 0;
    unsigned long timer = 0;

    void setup() {
    pinMode(ledPin, OUTPUT);
    }

    void loop() {
    // кнопка ВКЛ/ВЫКЛ и убираем дребезг контактов
    ms = millis();
    if ((digitalRead(keyPin)==HIGH)&&(ms-ms1>1000)) {
    ms1 = ms;
    if(keyState==oldKeyState) {
    keyState=!keyState;
    digitalWrite(ledPin, keyState);
    timer = millis(); // запоминаем момент времени, нужно для отсчета прошедшего времени
    }
    }
    else oldKeyState=keyState;

    // если светодиод включен и светится больше чем надо
    if ((keyState==HIGH)&&(millis()-timer >= on)) {
    keyState=LOW; //выключаем
    digitalWrite(ledPin,keyState); // реализуем новое состояние
    }
    }

    Сомневаюсь в правильности работы программы и не дает покоя момент переполнения счетчика millis().
    Нужен ли здесь сторожевой таймер?

    0
      • Спасибо.
        1. Если вместо millis использовать библиотеку mstimer2, нужно ли будет в этом случае отслеживать переполнение счетчика?
        2. Можно ли как-то еще упростить программу?

        0
        • Если для счетчика времени выбрать достаточную разрядность (на 1 час), то переполнение отслеживать не надо. По нажатию кнопки или по достижению счетчиком нужного времени он должен сбрасываться в 0.
          Мне кажется с mstimer программа будет проще.

          0
  10. Наверное стоит упомянуть в тексте урока что указанная библиотека MsTimer2 не будет работать Mega2650. Я уж думал что начал косячить от бессоницы, полез искать оригинальные библиотеки — а там оказывается есть варианты. Для Atmega2560 или Teensy надо использовать FlexiTimer2. Скачать можно здесь: http://playground.arduino.cc/Main/FlexiTimer2 Но все равно уроки отличные.

    2
    • Спасибо за подсказку… А то уже час не могу понять в чем дело… Готовый пример с таймером не работает… а на delay работает… Оказывается из-за Меги

      0
    • для меги 2650 , подключить бибилиотеку
      http://playground.arduino.cc/Main/FlexiTimer2

      и переписать инициализацию

      FlexiTimer2::set(2,1/1000, timerInterupt); // задаем период прерывания по таймеру 2 мс
      FlexiTimer2::start();

      0
  11. Здравствуйте, при компиляции первого примера при расположении в конце программы блока

    void timerInterupt()
    {
    button1.scanState(); // вызов метода ожидания стабильного состояния для кнопки
    }
    Arduino выдает сообщение:
    ‘timerInterupt’ was not declared in this scope
    при переносе блока перед void setup() компилируется нормально, но не работает. Cветодиод (на плате, не 13й) светит постоянно?

    0
  12. Со светодиодом разобрался, перепутал кнопку и светодиод, извините стормозил. А вот с остальным не понятно. Если оставляю void timerInterupt()
    {
    button1.scanState(); // вызов метода ожидания стабильного состояния для кнопки
    }
    то не компилируется, а если переношу перед void setup, все ок?

    0
  13. Да, Вы правы нашел в пути одну русскую папку, спасибо. А порядок в этом случае получается не важен? Меняется что нибудь если переместить этот блок перед void loop()

    0
    • в версиях IDE выше 1.6.12 функции надо объявлять до setup иначе компилируется с ошибкой о не объявленной функции

      0
  14. У меня не совпадает интервал вызова обработчика прерывания с установленным мною.

    Указываю:

    MsTimer2::set(2000, timerInterupt);

    А в обработчике делаю Serial.println(«interupt»). По выводу сообщений вижу, что обработчик вызывается не каждые 2 секунду, а каждую секунду, то есть ровно в два раза чаще.

    Любое число, какое бы не задал — обработчик вызывается ровно в 2 раза чаще.

    Не могу этого понять.

    Arduino NANO 3 ATmega328

    0
    • У меня все совпадает. Специально проверил на такой программе.

      #include
      void setup() {
      Serial.begin(9600);
      MsTimer2::set(2000, timerInterupt);
      MsTimer2::start();
      }

      void loop() {
      }

      // обработчик прерывания
      void timerInterupt() {
      Serial.println(«interupt»);
      }

      Проверьте у себя этот скетч. Библиотека устанавливает делитель таймера в зависимости от частоты тактирования микроконтроллера. Может у вас этот параметр неправильно определяется.

      0

  15. У меня леонардо.Упорно не хочет переходить на программу обработки прерывания по вашей библиотеке.(MsTimer2.h) Перепробовал все примеры.И еще
    Компилятор не воспринимает
    volatile Button button1(BUTTON_1_PIN, 15);

    0
    • Может та же проблема, что и у меня была с мегой? Сейчас эксперементирую с FlexiTimer2.h

      0
    • Здравствуйте!
      Может быть У вас дважды определяется библиотека Button.
      Одну библиотеку надо удалить. У меня вылетала ошибка этой библиотеки при обновлении Arduino IDE. Дело в том, что появилась еще одна библиотека с тем же именем Button.h. Проверьте внимательно и лишнюю удалите.

      0
      • Спасибо за совет. Похоже и правда две библиотеки.
        Большое спасибо за уроки.Обещаю дойти до элемента Пельтье. Началось с того ,что купил LCD wh1602b1 оказалось это индикатор с SPI -интерфейсом кое как нашел инфу. Но оказалось библиотек-то нет на него.Потому он такой дешевый 🙂 . Вот решил изучить предмет детально.

        0
  16. У меня вообще заморочки!!! После дельфи не могу переключиться… то := пишу, то не могу понять, почему if не работает… (забываю, что == надо ставить) 🙂

    0
  17. Все равно прерывания по таймеру не происходит. Может это только Леонардовский проц так себя ведет.Даже инверсия светодиода в обработке не работает в последнем скетче.

    0
    • Может у вас та же проблема. Повторяю комментарий выше.

      Наверное стоит упомянуть в тексте урока что указанная библиотека MsTimer2 не будет работать Mega2650. Я уж думал что начал косячить от бессоницы, полез искать оригинальные библиотеки — а там оказывается есть варианты. Для Atmega2560 или Teensy надо использовать FlexiTimer2. Скачать можно здесь: http://playground.arduino.cc/Main/FlexiTimer2

      0
  18. Здравствуйте, а не подскажите что может произойти, если в обработчике прерывания выполняется большое количество операций и затем происходит новое прерывание?
    Программа зациклится?

    0
    • Здравствуйте!
      Я уже отвечал на этот вопрос на форуме сайта. Посмотрите по этой ссылке в конце форума http://mypractic-forum.ru/viewtopic.php?t=23

      0
  19. Добрый день.

    По мотивам урока решил поправить свой проект. Сразу споткнулся на проблеме. Следующий код:

    #include «DHT.h»
    #include «MsTimer2.h»
    #define DHTPIN 9
    DHT dht(DHTPIN, DHT11);

    int currTemp;
    int currHum;

    void setup() {
    dht.begin();
    Serial.begin(9600);
    MsTimer2::set(1000, getCurrentSensorData);
    MsTimer2::start();
    }

    void loop() {
    Serial.print(«From Loop: T=»);
    Serial.print(currTemp);
    Serial.print(» H=»);
    Serial.println(currHum);
    delay(1000);

    }

    // Считывание показателей датчиков
    void getCurrentSensorData() {
    currTemp = dht.readTemperature();
    currHum = dht.readHumidity();

    Serial.print(«From Interrupt: T=»);
    Serial.print(currTemp);
    Serial.print(» H=»);
    Serial.println(currHum);
    }

    В порт постоянно выдаёт нули. Если вместо прерывания по таймеру вызвать в loop функцию getCurrentSensorData(), то всё работает. Подскажите, в чём может быть проблема.

    0
    • Здравствуйте!
      Скорее всего, дело в том, что библиотека DHT.h использует функцию millis() для отработки временных интервалов. А вы вызываете функции dht.read в прерывании. При входе в обработчик прерывания прерывания запрещаются и millis() не работает.
      Вообще вы поступаете не корректно. В прерывании должны отрабатываться короткие процессы, а вы подвешиваете систему.

      0
  20. Здравствуйте, Эдуард!
    Написал скетч для обработки сигналов 5 радиокнопок.
    Использовал библиотеку RCswitch.
    На принятую радиопосылку Нано включает звуковой сигнал на 2сек. и светодиод на 30 сек.Проблема в невозможности работы всех пяти каналов одновременно.Как должен выглядеть фрагмент кода в обработчике прерываний если нельзя использовать delay ? Спасибо.

    #include
    #include
    #include

    RCSwitch mySwitch = RCSwitch();

    volatile int relePin2 = 3;
    volatile int relePin3 = 4;
    volatile int relePin4 = 5;
    volatile int relePin5 = 6;
    volatile int relePin6 = 7;
    volatile int buzPin = 11; // пьезо

    void setup() {

    Serial.begin(9600);

    mySwitch.enableReceive(0); // приемник на pin 2 (DATA)

    pinMode(relePin2,OUTPUT);
    pinMode(relePin3,OUTPUT);
    pinMode(relePin4,OUTPUT);
    pinMode(relePin5,OUTPUT);
    pinMode(relePin6,OUTPUT);
    pinMode(buzPin,OUTPUT);

    digitalWrite(relePin2,HIGH);
    digitalWrite(relePin3,HIGH);
    digitalWrite(relePin4,HIGH);
    digitalWrite(relePin5,HIGH);
    digitalWrite(relePin6,HIGH);

    MsTimer2::set(2, timerInterupt); // задаем период прерывания по таймеру 2 мс
    MsTimer2::start(); // разрешаем прерывание по таймеру

    }

    void loop()

    {

    if (mySwitch.available())
    {
    volatile int value = mySwitch.getReceivedValue();
    Serial.print( mySwitch.getReceivedValue() );

    switch (value)
    {

    case 3328511:
    digitalWrite(relePin2,LOW);
    delay(500);
    digitalWrite(buzPin,HIGH);
    delay(2000);
    digitalWrite(buzPin,LOW);
    delay(20000);
    digitalWrite(relePin2,HIGH);
    break;

    case 1256703:
    digitalWrite(relePin3,LOW);
    delay(500);
    digitalWrite(buzPin,HIGH);
    delay(2000);
    digitalWrite(buzPin,LOW);
    delay(20000);
    digitalWrite(relePin3,HIGH);
    break;

    case 5369087:
    digitalWrite(relePin4,LOW);
    delay(500);
    digitalWrite(buzPin,HIGH);
    delay(2000);
    digitalWrite(buzPin,LOW);
    delay(20000);
    digitalWrite(relePin4,HIGH);
    break;

    case 11769343:
    digitalWrite(relePin5,LOW);
    delay(500);
    digitalWrite(buzPin,HIGH);
    delay(2000);
    digitalWrite(buzPin,LOW);
    delay(20000);
    digitalWrite(relePin5,HIGH);
    break;

    case 12305919:
    digitalWrite(relePin6,LOW);
    delay(500);
    digitalWrite(buzPin,HIGH);
    delay(2000);
    digitalWrite(buzPin,LOW);
    delay(20000);
    digitalWrite(relePin6,HIGH);
    break;

    }
    mySwitch.resetAvailable();
    }
    }
    // обработчик прерывания
    void timerInterupt() {

    ????????????????????????
    }

    0
  21. Извините не пропечатались библиотеки:

    #include
    #include
    #include

    и в void setup()

    digitalWrite(buzPin,LOW);

    0
  22. Здравствуйте!

    Написал скетч для приема сигнала от 5 радиокнопок и включения
    по сигналам пьезоэлемента и реле нагрузок на 22сек. Для радио передачи использовал библиотеку RCswitch.Требуется паралельная работа всех пяти каналов. Помогите пожалуйста с фрагментом кода, который надо писать в обработчике прерываний для обработки радиосигнала и выполнении команд процессора без delay.

    Спасибо.

    #include
    #include
    #include

    RCSwitch mySwitch = RCSwitch();

    int relePin2 = 3; // реле будет тут
    int relePin3 = 4; // реле будет тут
    int relePin4 = 5; // реле будет тут
    int relePin5 = 6; // реле будет тут
    int relePin6 = 7; // реле будет тут
    int buzPin = 11; // пьезо

    void setup() {

    Serial.begin(9600);

    //mySwitch.enableTransmit(10);
    mySwitch.enableReceive(0); // приемник на pin 2 (DATA)

    pinMode(relePin2,OUTPUT);
    pinMode(relePin3,OUTPUT);
    pinMode(relePin4,OUTPUT);
    pinMode(relePin5,OUTPUT);
    pinMode(relePin6,OUTPUT);
    pinMode(buzPin,OUTPUT);

    digitalWrite(relePin2,HIGH);
    digitalWrite(relePin3,HIGH);
    digitalWrite(relePin4,HIGH);
    digitalWrite(relePin5,HIGH);
    digitalWrite(relePin6,HIGH);
    digitalWrite(buzPin,LOW);

    MsTimer2::set(2, timerInterupt); // задаем период прерывания по таймеру 2 мс
    MsTimer2::start(); // разрешаем прерывание по таймеру

    }

    void loop()

    {

    if (mySwitch.available())
    {
    volatile int value = mySwitch.getReceivedValue();
    Serial.print( mySwitch.getReceivedValue() );

    switch (value)
    {

    case 3328511:
    digitalWrite(relePin2,LOW);
    delay(500);
    digitalWrite(buzPin,HIGH);
    delay(2000);
    digitalWrite(buzPin,LOW);
    delay(20000);
    digitalWrite(relePin2,HIGH);
    break;

    case 1256703:
    digitalWrite(relePin3,LOW);
    delay(500);
    digitalWrite(buzPin,HIGH);
    delay(2000);
    digitalWrite(buzPin,LOW);
    delay(20000);
    digitalWrite(relePin3,HIGH);
    break;

    case 5369087:
    digitalWrite(relePin4,LOW);
    delay(500);
    digitalWrite(buzPin,HIGH);
    delay(2000);
    digitalWrite(buzPin,LOW);
    delay(20000);
    digitalWrite(relePin4,HIGH);
    break;

    case 11769343:
    digitalWrite(relePin5,LOW);
    delay(500);
    digitalWrite(buzPin,HIGH);
    delay(2000);
    digitalWrite(buzPin,LOW);
    delay(20000);
    digitalWrite(relePin5,HIGH);
    break;

    case 12305919:
    digitalWrite(relePin6,LOW);
    delay(500);
    digitalWrite(buzPin,HIGH);
    delay(2000);
    digitalWrite(buzPin,LOW);
    delay(20000);
    digitalWrite(relePin6,HIGH);
    break;

    }
    mySwitch.resetAvailable();
    }
    }

    // обработчик прерывания
    void timerInterupt()

    {
    ??????????????????
    }

    0
  23. Почему stop выделяется цветом,а start нет?
    После stop таймер не запускается start-ом !!!

    0
  24. Здравствуйте. Пытаюсь использовать ваш таймер в часах для мигания точками. Ваша библиотека работает совместно с библиотекой часов #include . Loop совсем простой:
    void loop() {
    time.gettime();
    hourNew = time.Hours;
    minNew = time.minutes;
    if ((minNew != minOld) || (hourNew != hourOld)) {
    outNormal(hourNew, minNew);
    }
    }
    Но точки пытаются мигать только при выводе времени на матричный индикатор (функция outNormal(hourNew, minNew);).
    Секунды у меня не отображаются. И пока часы не нуждаются в смене индикации (в течение минуты) точки не мигают.
    Может ли библиотека часов мешать работе вашей библиотеки?

    0
    • Здравствуйте!
      Я не понял, о какой моей библиотеке идет речь? В уроке 10 я описываю библиотеку MsTimer2. Это не моя библиотека.
      Проверьте отдельно чтение времени с выводом через последовательный порт и вывод чисел на индикатор.

      0
      • Спасибо за внимание. Разобрался. Как всегда дело было не в бобине… Ещё раз прошу пардону, MsTimer2 работает правильно — это я неправильно выводил точки.

        0
  25. На Arduino Mega 2560 библиотека MsTimer2 не работает. Помогло пройтись по коду поиском с зменой:
    Этого:
    || defined(__AVR_ATmega1280__)
    На это:
    || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)

    0
    • проверил не помогло . там надо регистры выставлять для меги . гораздо быстрее просто установить счетчик для меги FlexiTimer2 , с ним работает

      0
  26. Эдуард, добрый день.
    Бьюсь вот уже целый день. Подскажите куда копать.
    Кратко о работе программы ,при нажатии на кнопку 1 загорается светодиод и так далее до 5 загораются все по цепочке. При нажатие на кн.2 нужно чтобы светодиод из цепочки гас который текущий. Но при нажатие на 2 кнопку происходит зацикливание на текущем значении счетчика i
    Скейтч вот, плата мега 2560:

    #include
    #include

    #define BUTTON_1_PIN 8 // кнопка подключена к выводу 8
    #define BUTTON_2_PIN 10 // кнопка подключена к выводу 9
    volatile Button button1(BUTTON_1_PIN, 40); // создание объекта — кнопка
    volatile Button button2(BUTTON_2_PIN, 40); // создание объекта — кнопка
    volatile int i = 0;

    void setup() {
    Serial.begin(9600); // инициализируем порт, скорость 9600
    pinMode(1, OUTPUT);
    pinMode(2, OUTPUT);
    pinMode(3, OUTPUT);
    pinMode(4, OUTPUT);
    pinMode(5, OUTPUT);
    // определяем вывод светодиода как выход
    FlexiTimer2::set(2, 1 / 1000, timerInterupt); // задаем период прерывания по таймеру 2 мс
    FlexiTimer2::start(); // разрешаем прерывание по таймеру
    }

    void loop() {

    // управление светодиодом
    if ( button1.flagClick == true ) {
    // был клик кнопки
    button1.flagClick = false; // сброс признака
    i ++ ;
    if ( i > 5 ) {
    i = 0;
    digitalWrite (1, LOW);
    digitalWrite (2, LOW);
    digitalWrite (3, LOW);
    digitalWrite (4, LOW);
    digitalWrite (5, LOW);
    Serial.println(i, DEC);
    }

    else {

    digitalWrite (i, HIGH);
    Serial.println(i, DEC);
    }
    }//end button1.flagClick

    // управление светодиодом
    if ( button2.flagClick == true ) {
    // был клик кнопки
    button1.flagClick = false; // сброс признака
    digitalWrite (i, LOW);
    // i—;
    Serial.println(i, DEC);

    }

    } //end loop

    // обработчик прерывания
    void timerInterupt() {
    button1.scanState(); // вызов метода ожидания стабильного состояния для кнопки
    button2.scanState();
    }

    0
  27. В прерывании поставил счётчик, а подпрограмме сравнение в в цикле while (переменная счетчика<переменная задержки), не работает, стоит добавить в цикле serial.print не важно какой все начинает работать почему когда не смотришь не работает

    0
  28. Эдуард, здравствуйте!

    Первое: огромный Вам «решпект» за Ваши уроки — они доступны для понимания начинающим. А я, имея неплохой опыт в конструировании электроники (в т. ч. цифровой) на дискретных элементах, только начинаю постигать азы программирования.

    Второе: очень надеюсь на Ваши подсказки. Встала задача изготовить реверсивный 6-разрядный десятичный счётчик. На дискретных элементах сделать можно, но будет громоздко. К тому же я намерен освоить программирование. А что может быть для этого лучше, чем практическая задача?
    Проблема в том, что я не знаю, с какой стороны подступиться.

    Вот предварительные прикидки:

    ( период счётных импульсов ок. 3,5mS)

    1. Назначаем:
    переменную unsigned long x=0;
    PinA -счётные импульсы;
    PinB — направление счёта.

    2. PinA запускает прерывание (1mS?) по RISING.
    При изменении состояния счётчика прерываний:
    если PinB=HIGH,то х=х+1
    если PinB=LOW, то х=х-1

    3. Отображение х на дисплее.

    Пока буду использовать LCD1602, со временем (если сумею переделать Вашу Led4Digit в Led6Digit)
    — семисегментники.

    Если найдёте возможность ответить — буду очень признателен.

    PS: и пожалуйста — как для блондинки, по буквам!

    0
    • Михаил, здравствуйте!
      В комментариях вести проект неудобно. Откройте тему на форуме сайта. Я с удовольствием помогу.

      0
  29. Здравствуйте! Попытался с помощью прерывания сделать часы с выводом результата в СОМ-порт каждую секунду. на 7 секунде начал выдавать одинаковые значения. Не подскажите, пожалуйста, с чем это связано и как можно это устранить?

    #include
    byte h=0;
    byte m=0;
    byte s=0;
    int days=0;

    void setup() {
    Serial.begin(9600);
    MsTimer2::set(1000, timerInterupt); // задаем период прерывания по таймеру 1000 мс
    MsTimer2::start(); // разрешаем прерывание по таймеру
    }

    void loop() {
    if(s==60){
    s=0;
    m=m++;
    }
    if(m==60)
    {
    m=0;
    h=h++;
    }
    if(h==24)
    {
    h=0;
    days=days++;
    }

    }
    // обработчик прерывания
    void timerInterupt(){
    s++;
    Serial.print(«days: «);
    Serial.print(days);
    Serial.print(» hours: «);
    Serial.print(h);
    Serial.print(» minutes: «);
    Serial.print(m);
    Serial.print(» seconds: «);
    Serial.println(s);
    }

    0
    • Здравствуйте!
      В обработчике прерывания нельзя использовать функции Serial. Только для вывода одного байта.
      При входе в обработчик прерывания запрещаются все прерывания микроконтроллера. Разрешаются только при выходе из обработчика. А функции Serial используют прерывания. Поэтому их работа блокируется.
      Сделайте взвод флага в обработчике. В основном цикле анализируйте этот флаг. Если он активен, то сбрасывайте его и выводите данные в Serial.
      Обработчики прерывания должны быть минимальные по времени выполнения. Они подвешивают всю работу системы.

      0
  30. Здравствуйте
    Прошу прощения но я не понял!
    допустим есть светодиод пауза интервала меж миганием составляет допустим 5 секунд
    с deley это примерно так:
    digitalWrite(4,HIGH);
    delay(5000);
    digitalWrite(4,LOW);
    здесь всё понятно, а как ето зделать через прерывание ????
    буду очень благодарен за ответ.

    P.S. если не сложно напишыте на мой адрес электронной почты: kvitko1304@gmail.com

    0
  31. не понял!!!!!
    допустим есть светодиод пауза интервала меж миганием составляет допустим 5 секунд
    с deley это примерно так:
    digitalWrite(4,HIGH);
    delay(5000);
    digitalWrite(4,LOW);
    здесь всё понятно, а как ето зделать через прерывание ????
    буду очень благодарен за ответ.

    P.S. если не сложно напишыте на мой адрес электронной почты: kvitko1304@gmail.com

    0
    • Здравствуйте!
      Например, так.
      #include
      #define LED_1_PIN 13 // светодиод подключен к выводу 13
      int count=0;

      void setup() {
      pinMode(LED_1_PIN, OUTPUT); // определяем вывод светодиода как выход
      MsTimer2::set(1, timerInterrupt); // задаем период прерывания по таймеру 1 мс
      MsTimer2::start(); // разрешаем прерывание по таймеру
      }

      void loop() {
      }

      // обработчик прерывания 1 мс
      void timerInterrupt() {
      count++;
      if( count > 5000 ) {
      count=0;
      digitalWrite(LED_1_PIN, ! digitalRead(LED_1_PIN)); // инверсия состояния светодиода
      }
      }

      0

      • Здравствуйте, Эдуард! Огромное вам спасибо за столь замечательные и глубокие уроки!
        Вопрос у меня по данному коду: при его использовании компилятор выдает ошибку — функция timerInterrupt ему неизвестна. Решилась проблема перемещением блока реализации данной функции перед блоком setup.
        Подскажите, пожалуйста, почему так происходит, что я делаю неправильно?

        0
  32. Ардуино немного кривой.
    Нужны были короткие импульсы на выходе, сделал вставку на ассемблере.
    asm volatile
    (//внешний цикл на несколько тысяч
    …..
    //внутренний цикл на 8,в нем вывод
    ROR %5
    : …
    : …
    : ….
    );
    На выход поступала какая-то ерунда.Посмотрел ассемблерный код ардуино.Счетчики внешнего и внутреннего циклов были организованы нормально,но информацию для сдвига помещал в регистр R24,потом сдвигал ее один раз,после во внутреннем цикле R24 использовал для своих целей(в мой асм вставил свой!!!) в результате чего и передавалась фигня! Пришлось написать «ROR r24» и указать R24 в списке экранирования.
    Т.е. при написании даже на ассемблере и volatile ардуино переделывает код.

    0
  33. Здравствуйте Эдуард,
    Спасибо за уроки!

    Скажите пожалуйста работает ли прерывание по таймеру с PWM и analogWrite()?

    У меня примерно такой код, но никак не могу уменьшить свет диода:

    #include
    #include

    #define GREEN_PIN 3
    #define BUTTON 11

    Button buttonOne(BUTTON, 15);

    void setup() {
    pinMode(GREEN_PIN, OUTPUT);

    MsTimer2::set(2, timerInterupt);
    MsTimer2::start();
    }

    void loop() {
    if (buttonOne.flagClick == true) {
    buttonOne.flagClick = false;
    analogWrite(GREEN_PIN, 55);
    delay (10000);
    analogWrite(GREEN_PIN, 0);
    }
    }
    void timerInterupt() {
    buttonOne.scanState();
    }

    Arduino NANO.
    Ищу, но ни как не могу найти решение проблема.

    0
    • Здравствуйте!
      Посмотрите в уроке 37.
      » Если таймер используется для других целей, например для прерывания, то параметры ШИМ соответствующих выводов могут не соответствовать указанным выше.
      Таймер 2 выводы 3 и 11 »

      Надо или изменить вывод для ШИМ, либо использовать прерывание по другому таймеру, не второму. Например, библиотеку TimerOne.

      0
  34. Эдуард, здравствуйте
    Подскажите плиз, а как быть если второй аппаратный таймер уже используется какой-либо подключенной библиотекой. Например библиотека Servo использует (как я понимаю) второй таймер в своих целях. А первый таймер занят библиотекой IRRemote… И что мне остается?

    0
      • Задача такая же, которую вы поставили в этом уроке — устранение дребезга кнопки путем опроса состояния кнопки в параллельном процессе. Ну или более обобщенно — организация этого самого параллельного процесса для чего-нибудь. Вопрос — как его организовать, если и первый и второй аппаратный таймер заняты сторонними библиотеками ( в моем примере Servo и IRRemote)? Вы упомянули про millis — объясните плиз в двух словах, чем она тут может помочь?

        0
        • Здравствуйте!
          Я имел в виду стандартное решение. В цикле loop вы создаете программный блок, в который программа переходит с определенным периодом времени. А реализуется это чтением текущего системного времени в цикле loop и вычислением не пора ли заходить в блок. Конечно, таким способом можно реализовать только процессы с периодом вызова несколько мс.

          0
  35. Добрый день Эдуард подскажите как работает эта строка: while(true) { код }; с чем происходит сравнение в циклe while? Как я понимаю что здесь происходит сравнение со значением указанного в круглых скобках и если оно верно то выполняется код из фигурных скобок, а в кр скобках просто true без описания сравнения с чем либо, поправьте меня пожалуйста если не правильно размышляю.

    0
  36. Снова я попал в сети невнимательности спасибо за пояснение, т. е. этой строкой мы создаём условие в цикле который выполняется вечно по команде true и производит сравнение нажатия.

    0
  37. теперь понял почему некоторые не любят функцию while() , но если придать переменным внутри неё тип volatile то всё идет нормально .наверно они не знают о признаке volatile . пытался сделать библиотеку используя arduino ide но как вы и говорили ничего не вышло так как ардуино ide все файлы упорно переводит только в один формат ino . вернулся к ноутпаду тем более у него много приятных мелочей . понял что если хотим программу часто использовать и для этого сделать её библиотечной то недолго думая описываем в классе все переменные и функции для этой программы и загоняем класс в файл типа (.h) . затем описываем все работающие в этой программе функции и методы и загоняем их в файл типа (.cpp). и всё библиотека готова .

    0
  38. но если у нас не нужна скорость и быстрота программы то можно обойтись и без прерывания и вместо него воткнуть delay(2) на те же 2мс .

    0
  39. Эдуард, позвольте вопрос.
    Вносит ли Ваша библиотека MsTimer2 изменения в выполнение команды millis()?
    В программе требуется измерение времени, можно ли одновременно с Вашим таймером
    применять команду millis()?
    Будет ли время измеряться корректно?

    0
    • Здравствуйте!
      MsTimer2 не моя библиотека. На функцию millis она никак не влияет. Функция millis работает по системному времени Ардуино и использует таймер 0.

      0
      • Большое Вам спасибо. Можно было бы, конечно, приспособить MsTimer2 и для измерения времени, но для большого промежутка времени команда millis гораздо удобнее.

        0
      • Всё-таки Ардуино кроме Timer0 для исчисления системного времени использует ещё какой-то счётчик. Timer0 восьмиразрядный, его никак не хватит на 57 дней работы до переполнения, если считаются и миллисекунды, и даже микросекунды.

        0
  40. Добрый день!

    Подскажите пожалуйста, если в какой то используемой в моем скетче библиотеке уже используется прерывание по таймеру и я воспользуюсь библиотекой MsTimer2 для своей функции, возможны какие то конфликты, ошибки в прерываниях и т.д.?

    0
    • Здравствуйте!
      Конечно. Таймер — аппаратное устройство и он не может одновременно использоваться в различных библиотеках.

      0
      • Спасибо.
        Получается, прежде чем задействовать какие то аппаратные возможности, нужно проанализировать используемые библиотеки в скетче… (учусь, прошу прощения за глупые вопросы)

        0
        • В принципе да. Обычно в описании библиотек есть информация, какие они используют таймеры и другие аппаратные ресурсы.

          0
  41. Здравствуйте. Предположим что цикл прерывания вызывается каждые 2мс, при этом функция в прерывании выполняется за 4мс. Значит ли это что цикл прерывания дойдет только до половины, прервет сам себя и начнется сначала? Либо что произойдет в данном случае? спасибо

    0
    • Здравствуйте!
      Конечно, так программа работать не должна. Заданный алгоритм не будет выполняться правильно.
      Произойдет следующее. При вызове прерывания микроконтроллер перейдет по адресу обработки прерывания и сбросит глобальный флаг разрешения прерываний. Теперь, пока прерывание не обработается, все остальные вызовы будут запрещены. По окончанию обработки флаг разрешения установится и тут же вызовется пропущенное прерывание.

      1
  42. Здравствуйте, Эдуард! Большое спасибо за уроки! Я в этом деле еще очень начинающий, и возник вот какой вопрос. При использовании Вашего кода с библиотекой msTimer2, для светодиода на плате все работало хорошо, но если поменять пин и подключить светодиод на макетке, то нормальная работа нарушалась: могло работать несколько нажатий нормально, потом светодиод «зависал» во включенном состоянии и на кнопку реакции не было или «зависал» сразу. Пробовал на двух платах, на обеих AtMega 328p. Результат одинаковый. Пробовал библиотеку flexiTimer2. Ничего не поменялось.
    Помогло только введения переменной для состояния светодиода, тогда заработало без косяков.
    Т.е. вместо
    if ( button1.flagClick == true ) {
    button1.flagClick= false;
    digitalWrite(LED_1_PIN, ! digitalRead(LED_1_PIN));

    Так
    if ( button1.flagClick == true ) {
    button1.flagClick= false;
    ledState = ! ledState;
    digitalWrite(LED_1_PIN, ! ledState );
    Был бы очень Вам признателен если бы Вы данный феномен объяснили)

    0
    • Здравствуйте!
      Как вы подключили светодиод?
      Проблема может быть вот в чем.
      Когда вы инвертируете состояние вывода микроконтроллера установленного на выход, он считывает состояние вывода, инвертирует его и загружает новое значение. Но уровень сигнала на выходе не всегда соответствует заданному в программе значению. Например, вы подключили к нему слишком низкое сопротивление. Микроконтроллер не способен поднять уровень до логической 1. Возможно, вы подключили светодиод без ограничительного резистора. Тогда напряжение на выходе не будет превышать 1,5 В. Микроконтроллер считает его как лог. 0, инвертирует и опять запишет на выход 1.
      Измерьте напряжение на выходе микроконтроллера в состояниях лог. 1 и 0. Оно должно быть близко к 5 В и 0.

      1
      • Спасибо Вам большое! Я осознал свою глупость. Действительно светодиод включил без ограничительного резистора. Сила тока большая — падение напряжения большое и при считывании контроллер видит логический ноль. Понятно почему код с переменной состояния диода работал)
        Все встало на свои места)

        0
  43. while(true) {
    тут ясно что если внутрь скобок while попадёт ноль или false то он застрянет там навеки вечные то есть программа зависнет . судя по всему volatile применяют при некорректном написании программ .

    0
  44. наверно while (true) можно перевести с английского так — всё приехали программа не будет работать . достаточно чтобы внутри стало true то есть отличным от нуля и всё будет крутиться внутри while и не выходить из нее .

    0
  45. while (true) {
    if ( count != 0 ) break;
    delay(1);
    }
    тут наверно дело не в компиляторе . возможно при выполнении любой функции или delay процессору приходится покидать насиженные берега while и проходить вынужденно цикл заново и таким образом программа начинает оживать .

    0
  46. надо отметить что MsTimer2 на плате ардуино мега не работает и там вместо него применяют счётчик flexTimer2-master или просто FlexTimer . всё дело в том что у уно и меги разное устройство портов и регистров . например порт B2 на уно является выводом 10 а на меге это уже вывод 53 . для того чтобы MsTimer2 заработало на меге надо залезть в библиотеку таймера и внести изменения в нумерациях портов и в регистрах . проще использовать FlexTimer и не заниматься садомазохизмом .

    0
  47. Спасибо за урок. Если время опроса датчика DS18B20 длится 1 сек, а аппаратные прерывание происходят каждые 2 мск, с учетом того , что нельзя прерывать поток данных от DS18B20 , иначе не будут правильно считаны данные, то как строится программа?

    0
    • Здравствуйте!
      В 26 уроке есть пример? в котором программа не подвисает при измерении температуры. И в серии уроков (начиная с урока 36) по разработке контроллера элемента Пельтье используются 2 датчика DS18B20.

      0
  48. Здравствуйте, Эдуард! Я выполнял все установки из данного урока, все совпадало с описанным Вами, до того момента как экземпляру класса Button я не объявил квалификатор volatile. Компилятор начал выдавать ошибку exit status 1
    passing ‘volatile Button’ as ‘this’ argument of ‘void Button::scanState()’ discards qualifiers [-fpermissive]
    Выделяет button1.scanState в обработчике прерываний.
    Помогите пожалуйста)

    0
    • Здравствуйте!
      Я попробовал, у меня компилирует, ошибок не выдает.
      volatile Button button1(BUTTON_1_PIN, 15); // создание объекта — кнопка
      Не используйте volatile. Если проверка флагов происходит в основном цикле loop, который после каждой проверки доходит до конца, то volatile не нужен. Вашему компилятору не нравится, что в библиотеке класс не объявлен как volatile.

      1
  49. Спасибо Вам за ответ. Пробовал сам класс объявить как volatile — не помогло. У меня была старая версия IDE, решил обновить до последней — помогло. Видимо компиляторы чуть разные.

    0

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Нажимая кнопку "Отправить" Вы даёте свое согласие на обработку введенной персональной информации в соответствии с Федеральным Законом №152-ФЗ от 27.07.2006 "О персональных данных".