Урок 61. Аппаратная реализация интерфейса RS-485. Объединение плат Ардуино в локальную сеть RS-485.

Связь Ардуино через RS485

В уроке расскажу об аппаратной реализации интерфейса RS-485. Разработаем распределенную систему аналогичную системе из  предыдущего урока, только с использованием сети RS-485.

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

Для подключения к линии связи RS-485 применяются дифференциальные передатчики и приемники.

 

Передатчик должен формировать два противофазных сигнала.

Сигналы RS485

При этом стандарт RS-485 предъявляет к нему довольно жесткие требования:

  • высокое быстродействие;
  • работа на низкоомную и емкостную нагрузку;
  • защита от коротких замыканий;
  • отключение от линии (перевод в 3 состояние).

Дифференциальные приемники должны выделять разность между сигналами линий. И это при значительном уровне синфазных помех (-7 … +12 В) и высоком быстродействии.

Реализовать такие функции на дискретных элементах крайне сложно. Проще использовать интегральные приемопередатчики.

 

Приемопередатчики (драйверы) интерфейса RS-485.

Существует большое количество различных типов приемопередатчиков (драйверов) RS-485. Я предпочитаю использовать микросхемы ADM485, SP485, MAX485. Это однотипные микросхемы разных производителей. Функциональные возможности, параметры, назначение выводов у них совершенно одинаковые.

Драйвер RS-484 Производитель Ссылка на документация
MAX485 Maxim Integrated Products MAX481-MAX1487.pdf
ADM485 Analog Devices ADM485.pdf
SP485 Sipex SP485.pdf

Микросхемы выполнены в 8 выводном корпусе и имеют низкую цену.

По моей партнерской ссылке на момент написания статьи:

  • микросхема MAX485ESA стоит всего 8 руб;
  • микросхема MAX485SPA стоит 15 руб;
  • модуль конвертера TTL в RS-485 можно купить за 45 руб.

Купить драйверы RS485

В 8 выводном корпусе драйвера реализованы приемник и передатчик с параметрами, полностью соответствующими стандарту RS-485. Выходы передатчика и входы приемника объединены в микросхеме.

Драйверы RS485

Для преобразования интерфейса UART в RS-485 достаточно одной такой микросхемы.

Схема преобразования интерфейса UART в RS485

Если необходима гальваническая развязка, приходится использовать оптроны. Например, по этой схеме.

Схема преобразования интерфейса UART в RS485 с гальванической развязкой

Питание драйвера (+5 V INT) в этом случае должно быть гальванически развязано.

 

Объединение нескольких плат Ардуино в локальную сеть RS-485.

В качестве примера практической реализации сети RS-485 переработаем распределенную систему из урока 59 на сеть RS-485.

Новая схема локального контроллера будет выглядеть так.

Схема

Пояснять особенно нечего. Я добавил драйвер RS-485 по стандартной схеме включения.

Внешний вид

Такие же преобразования произошли со схемой центрального контроллера.

Схема

Все контроллеры подключены параллельно двухпроводной линии связи. Локальные контроллеры получают питание 5 В от центрального контроллера.

Линия у меня не длинная, скорость передачи низкая (9600 бит/сек). Поэтому в терминаторах нет необходимости. Для устранения неопределенности состояния линии при отключенных всех передатчиках к схеме центрального контроллера добавлены 3 резистора.

Схема смещения

Вся система теперь выглядит так.

Общий вид системы

 

Программное обеспечение.

Резидентное программное обеспечение центрального и локального контроллера осталось прежним:

  • sketch_59_2.ino - центральный контроллер:

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

  • sketch_59_1.ino  - локальный контроллер:

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

Загрузить программы в платы Ардуино необходимо до запайки драйверов RS-485. Иначе они будут блокировать сигналы RxD и мешать загрузке из Arduino IDE.

Обмен данными по сети происходит под управлением библиотек Tiny_ModBusRTU_Master и Tiny_ModBusRTU_Slave.

В программах, которые мы использовали в уроке 59, для организации сети через интерфейсы UART объекты ModBus создаются следующим конструктором:

Tiny_ModBusRTU_Slave slave(1, 8, regTable, 6, 13); // создаем объект ModBus

Последний параметр задает номер вывода для управления передатчиком RS-485 (сигнал DE). Для интерфейса UART этот вывод не нужен. Можно было параметр не задавать и сэкономить один вывод микроконтроллера. Но я его задал с номером 13 – светодиод общего назначения. Светодиод светился, когда в контроллере происходила передача данных.

Теперь мы подключили сигнал разрешения работы передатчика (DE) к 13 выводу. Поэтому программное обеспечение осталось прежним. В реальных разработках лучше использовать другой вывод.

 

Проверка работы системы.

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

Дисплей системы

Имитировал ошибки обмена – нажал кнопку сброса локального контроллера.

Сообщение об ошибках

Посыпались ошибки на дисплее для данных обоих контроллеров.

В системе-прообразе на интерфейсе UART при нажатии сброса были ошибки только одного локального контроллера. Второй работал нормально. Происходит это, потому что при состоянии сброса микроконтроллер переводит все свои выводы в плавающее состояние (бросает в воздухе). Сигнал разрешения работы передатчика RS-485 за счет светодиод с резистором (вывод 13) переходит в состояние лог. 1. Для передатчика это разрешающий уровень. В результате выход драйвера блокирует линию связи.

Если необходимо, чтобы при отключении микроконтроллера сигналом сброса линия связи не блокировалась необходимо использовать для сигнала DE другой вывод. Также надо подключить его к земле через резистор сопротивлением 5…10 кОм.

Помехоустойчивость сети.

Все, что было написано по поводу сети RS-485 в предыдущем уроке в полной мере справедливо по отношению к нашей системе.

Длина линии связи теперь может достигать 1200 м. Скорость обмена можно увеличить. По сравнению с сетью через интерфейс UART схема незначительно усложнилась, но помехоустойчивость и все остальные параметры повысились. Получилась сеть совершенно другого качественного уровня.

 

В следующем уроке продолжу тему обмена данными между платами Ардуино.

 

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

0

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

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

Эдуард

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

94 комментария на «Урок 61. Аппаратная реализация интерфейса RS-485. Объединение плат Ардуино в локальную сеть RS-485.»

  1. Здравствуйте! Спасибо за статью! Скажите пожалуйста, нужно-ли защищать приемопередатчик MAX495 от наводок в линии супрессором?

    0
    • Здравствуйте!
      Да конечно. Если линия длинная и есть опасность высоковольтных импульсных помех то надо защищать. Поставить 3 пробивных стабилитрона (супрессора) между линиями A B, A C, B C.

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

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

      0
      • Здравствуйте! У меня все получилось. Сперва не мог понять что делает 2 в (regTable+2), и что надо было ставить для третьего датчика температуры( поставил +4). Но пока не увеличил регистры хранения с 6 до 8 ничего не получалось. Тему открою чуть попозже. Сперва определюсь сколько данных мне надо передавать в проекте. Большое спасибо за уроки.

        0
  3. Эдуард, спасибо за уроки.
    Библиотеки
    Tiny_ModBusRTU_Slave и
    Tiny_ModBusRTU_Master
    не работают с программным UART..??

    0
      • Спасибо за ответ, думал что я что-то не то делаю, хотел использовать уно для опроса нескольких разных веток.
        Придется использовать отдельный контроллер на каждую ветку, или «Мегу».

        0
  4. Здравствуйте Эдуард !
    Спасибо за уроки. Очень хорошие статьи.
    Вопрос: Будет ли работать сеть RS-485 с тремя ведомыми платами Ардуино, если к ней подключить через стандартный преобразователь RS-485 USB компьютер в качестве ведущего с программой для обмена данными, используя на Ардуино Вашу библиотеку Tiny_ModBusRTU_Slave ?

    С уважением Геннадий.

    0
  5. Здравствуйте Эдуард !
    1. Правильно ли я понял, что с помощью переключателей SW1, SW2 и SW3 устанавливается адрес платы с Ардуино ?
    2. Будет ли работать покупной модуль RS-485 TTL, использующий микросхему МАХ 485, с Вашей библиотекой Tiny_ModBusRTU_Slave ?
    С уважением Геннадий.

    0
    • Здравствуйте!
      1. Кнопки SW1 — SW3 используются для демонстрации передачи информации на локальные контроллеры. При нажатии кнопки должен загораться светодиод на соответствующем локальном контроллере.
      2. Да, конечно. Библиотека будет работать с модулем на микросхеме MAX485. У меня в уроке схема ничем не отличается от схемы этого модуля.

      0
  6. Здравствуйте, Эдуард! Огромное спасибо за великолепные уроки! Повсюду в интернете лежат лишь монструозные скетчи, собранные из стандартных примеров, напичканные delay’ями. В крайнем случае встречаются псевдопланировщики на базе функции millis, но все библиотеки опроса датчиков типа DHT22 или того же 18B20 все равно используют все те же delay’и, так что о параллельном выполнении задач вообще речи нет. Ваш же сайт, похоже, единственный в рунете, где показана нормальная реализация многозадачности для всего сразу. Правда придется переделывать все стандартные библиотеки, но это даже хорошо — опыт прокачивается. 🙂
    З.Ы, Присоединяюсь к ждущим с нетерпением следующих уроков. Панели Nextion HMI очень удобны (правда, дороги), с удовольствием почитаю про Ваш опыт общения с ними.

    0
  7. Здравствуйте Эдуард !
    1. У меня Ардуино Мега 2650 и имеется три канала: RX0-TX0, RX1-TX1 и RX2-TX2. Я подключил конвертер RS-485 TTL к каналу RX1-TX1. Скажите, у Вас в библиотеке Tiny_ModBusRTU_Slave для Ардуино определяется по какому каналу вести прием-передачу? Если нет, то подскажите, что надо сделать?
    2. Из каких условий выбран интервал прерываний в 500 мксек ? Можно ли его изменить ?
    С уважением Геннадий.

    0
    • Здравствуйте!
      Библиотека работает только на аппаратном порту 0. Она была создана для урока, хотя по моим тестам и отзывам других работает безупречно. Я проверял ее только на Arduino UNO, Arduino Nano и Arduino PRO Mini. Мне писали, что были проблемы с функционированием на Mega 2560 на Serial, но нашлась причина. Давайте лучше я сейчас на форуме сайта (http://mypractic-forum.ru) опубликую переписку по этому поводу в разделе «Уроки Ардуино». Там же можете задавать вопросы на эту тему.

      0
  8. Здравствуйте Эдуард !
    1. Ардуино Мега 2650 имеет 4 порта: RX0-TX0, RX1-TX1, RX2-TX2, RX3-TX3. У меня подключено к порту RX1-TX1. Есть ли в Вашей библиотеке Tiny_ModBusRTU_Slave возможность указывать по какому порту работать ? Если нет, то как запрограммировать Ардуино, чтобы он работал через этот порт ?
    2. Как выбирался интервал прерывания в 500 мксек и можно ли его изменять ?
    С уважением Геннадий.

    0
  9. Здравствуйте Эдуард !
    Arduino UNO по ModBus_RTU пытаюсь прочитать регистр (ватметр dds238-2 zn) адрес 40015 функции 3. (реверсная энергия)
    Не работает! Чем может отличаться режим раба ардуино от ватметр dds238??
    Вот сам Ваттметр https://ru.aliexpress.com/item/5-65-A-230V-50HZ-voltage-current-DDS238-2-ZN-S-single-phase-Din-rail/32812065998.html?spm=2114.13010708.0.0.8Z8w4V

    0
    • Здравствуйте!
      Может у вас устройство медленно отвечает. Попробуйте увеличить время тайм-аута. На форуме сайта пишут, что даже потребовалось изменить тип переменной для тайм-аута.
      http://mypractic-forum.ru/viewtopic.php?t=87

      0
  10. Здравствуйте!
    А какой допуск на длину импульса при приеме в библиотеках?
    Например,если использовать RS485 для DMX512 — не все устройства передают импульсы-паузы длиной строго 4мс.

    0
    • Здравствуйте!
      Драйверы RS-485 осуществляют только преобразование уровней сигнала. Формированием сигналов занимается контроллер. Длительность импульсов 4 мкс драйверы RS-485 передадут без проблем.

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

    Одна надежда на Вас осталась! 3 недели бьюсь с настройкой передачи данных через китайские модули на MAX485. Приходит -1, а должны придти данные от 0 до 1023 (от потенциометра). Буду очень признателен, если подскажите что не так я сделал. Вот ссылки на мои скетчи, он отличаются от Ваших, но вполне простые.

    https://drive.google.com/file/d/1cXvEr3OWzMjULIxX35F1GlH_MONWMe2w/view?usp=sharing

    https://drive.google.com/file/d/1MpAj73tsTZZhRGMR_XG4dn2zv00eFrfC/view?usp=sharing

    0
    • Здравствуйте!
      Прежде всего, если у вас чисто практическая задача, то возьмите библиотеку для ModBus из последующих уроков и реализуйте задачу через нее. Будет проще, надежнее.
      Теперь про ваше творение.
      Я правильно понял, что для обмена по RS-485 используется аппаратный порт Serial?
      Что вы передаете. Команда Serial.println(pot); передает несколько байтов: символы, соответствующие числу pot в десятичном виде, управляющие символы возврат каретки (код 13) и перевод строки (код 10).
      Это от 3 до 6 байтов. Например, если у вас значение pot= 356, то будет передан код символа 3, символа 5, символа 6 и управляющие коды. И вы добавляете паузу между пакетами 150 мс.
      Что вы принимаете.
      Командой Serial.read(); вы считываете первый попавшийся байт и загружаете его в переменную pot, с которой дальше работаете, полагая, что это число, полученное от передатчика.
      В pot у вас будет, что попало. Если вы попадете на момент, когда буфер Serial пуст, вы получите -1. Еще из буфера вы можете получить код одного символа числа в текстовом виде.
      Посмотрите урок 12 о последовательном порте. Обратите внимание на передачу данных в двоичном и символьном виде. И еще просмотрите урок 31 о текстовых протоколах.
      Если вы хотите принять, то что вы сейчас передаете, т.е. число в текстовом виде, то вы должны:
      1. Ожидать паузу в передаче. Проверять функцией available, что в течении какого-то времени, например 10 мс, не пришло ни одно данное.
      2. Ожидать прихода первого данного.
      3. Записать в текстовый массив все пришедшие коды символов, без управляющих символов.
      4. Преобразовать полученное число из текстового вида в двоичное число и записать его в переменную pot.
      Только так.
      Более простой вариант передавать переменную pot в двоичном виде. Надо передать 2 байта функцией write.
      Тогда всегда будут передаваться только 2 байта и нет необходимости преобразовывать их в двоичный формат. Все остальное, вычислять паузу между передачами и т.п., делать надо.
      И еще я не понял, зачем вы принятое число передаете назад.
      Serial.println(pot);

      0
      • Эдуард, добрый день! Благодарю за внимание и совет! ModBus еще сложно для меня, не разобрался.Serial.println(pot); использовал, чтобы увидеть что передаю. Иначе не получилось. Решил передавать через write, но ничего не получается.В мониторах передатчика и приемника пусто. Паузу ставил, не помогает. Вот отредактированный код:

        #include

        SoftwareSerial RS485 (7,6); // Инициализируем порты RX и TX
        #define DIR 13 // Задаем константу для порта управления
        //int pot;

        void setup () {

        Serial.begin(9600); // Инициализируем последовательное соединение
        RS485.begin(4800); // Инициализируем программный сериал

        pinMode(DIR,OUTPUT); // Устанавливаем режим работы для цифрового вывода как Выход
        digitalWrite(DIR, HIGH); // включаем режим передачи
        }

        void loop () {
        if( Serial.available() > 0 ) {
        int pot = analogRead(0);
        Serial.write(pot);
        }
        }

        Что я упустил, подскажите, пожалуйста.

        0
        • Здравствуйте!
          Так вы какой порт используете для обмена по RS-485?
          Если программный, то почему вы передаете данные через аппаратный.
          В любом случае вы проверяете наличие данных в приемном буфере и, если он пуст, то передаете. Зачем?
          Но давайте с портом определимся.

          0
  12. Вот тут провал в понимании и терминалогии. Насмотрелся полупохожих примеров и запутался. Я пытаюсь получить данные с потенциометра и отправить их через програмный сериал с пинов 6 и 7. Я пробовал задавать RS485.write(pot) вместо Serial.write(pot), но толку не было. Почему я передаю при пустом буфере?

    0
    • Начните с того, что передавайте в цикле один байт.
      RS485.write(50);
      delay(200);
      Если нет осциллографа, то подключите светодиод через резистор к выводу 6 и убедитесь, что он мигает примерно 5 раз в секунду.
      Потом подключите приемную плату, подключите светодиод на выход MAX485 приемной платы и убедитесь, что данные приходят.

      0
  13. Поправил:

    void loop () {
    int pot = analogRead(0);
    RS485.write(pot);
    delay(500);
    }

    На МАХ485 передатчика диод работает как надо. На выходе МАХ 485 приемника тоже работает.

    Но приемник команды не выполняет…

    0
    • Верните передатчик к передаче одного фиксированного байта и проверьте приемник.
      if( RS485. available() != 0 ) {
      RS485.read();
      digitalWrite(13, ! digitalRead(13));
      }
      Программа должна инвертировать состояние светодиода на приход каждого байта.
      Только задайте 13 вывод на выход.

      1
    • Значит прием идет.
      Теперь надо передавать переменную pot. Она типа int, поэтому надо передавать 2 байта. Сначала младший, потом старший.
      int pot = analogRead(0);
      RS485.write((byte)pot);
      RS485.write((byte)(pot>>8));
      delay(500);

      Светодиод перестанет мигать, потому что прием одного байта будет инвертировать вывод 13, и тут же прием следующего байта инвертировать еще раз.
      Дальше надо выделять паузу. между принятыми данными.
      И принимать данные.
      while( RS485.available == 0 ) {}
      pot= (unsigned int)RS485.read();
      while( RS485.available == 0 ) {}
      pot |= ((unsigned int)RS485.read()) < < 8 ; Надо отрабатывать тайм-аут, вдруг обмен зависнет и т.п. Посмотрите в моих программах.

      1
  14. Эдуард, добрый день!

    Проблемы с строчкой «pot |= ((unsigned int)RS485.read()) < < 8" Пишет "expected primary-expression before 'unsigned'"
    Не нашел решения. Что же делать?

    0
  15. Ура, это исправил! Теперь в мониторе порта приемника приходит «1». Но как же мне теперь получить данные от 0 до 1023?

    0
    • Сейчас данные должны приниматься. Только не выделяется первый байт, поэтому может быть путаница. Может приниматься сначала второй, а потом первый байт. Но в принципе данные с АЦП должны изменяться.

      0
      • На потенциометр не реагирует и постоянно 1 мониторе.

        Вот такой код получается:

        void loop () {

        while( RS485.available() == 0 ) {}
        pot= (unsigned int)RS485.read();
        delay(10);
        while( RS485.available() == 0 ) {}
        pot |= ((unsigned int)RS485.read()) << 8;
        delay(10);
        Serial.println(RS485);

        Тогда как же избавиться от путаницы?

        0
          • Эдуард, разве в данной программе не выводится два байта?

            #include

            SoftwareSerial RS485 (7,6); // Инициализируем порты RX и TX
            #define DIR 13 // Задаем константу для порта управления
            int pot;
            int a;
            int s;
            void setup () {

            Serial.begin(9600); // Инициализируем последовательное соединение
            RS485.begin(4800); // Инициализируем программный сериал

            pinMode(DIR,OUTPUT); // Устанавливаем режим работы для цифрового вывода как Выход
            digitalWrite(DIR, HIGH); // включаем режим передачи
            }

            void loop () {
            int pot = analogRead(0);
            RS485.write((byte)pot);
            RS485.write((byte)(pot>>8));
            delay(500);

            }

            0
          • Еще вопрос analogRead(0);. Надо analogRead(A0);

            Добейтесь, чтобы у вас с одним байтом работало. На передающей стороне сделайте в цикле:
            RS485.write((byte)analogRead(A0));
            delay(500);

            На приемной стороне:
            if( RS485.available() != 0 ) Serial.println(RS485.read());

            0
          • Так как я вывожу в сериал с приемника, поэтому Serial.println(pot);

            Вот скетч. Мне нужно передать показания потенциометра, конвертировать их в ШИМ для управления моторами.

            #include

            SoftwareSerial RS485 (8,7); // Инициализируем порты RX и TX
            //#define DIR 12 // Задаем константу для порта управления
            #define LED 13 // Задаем константу для порта управления

            //Motor Pins
            int EN_A = 11; //Enable pin for first motor. было 11
            int IN1 = 9; //control pin for first motor было 9
            int IN2 = 6; //control pin for first motor было 8
            int IN3 = 5; //control pin for second motor было 7
            int IN4 = 3; //control pin for second motor было 6
            int EN_B = 10; //Enable pin for second motor было 10
            //Initializing variables to store data
            int X;
            int pot;
            int a;

            void setup ( ) {
            Serial.begin (9600); //Starting the serial communication at 9600 baud rate
            RS485.begin(4800); // Инициализируем программный сериал
            pinMode(DIR,OUTPUT); // Устанавливаем режим работы для цифрового вывода как Выход
            digitalWrite(DIR, LOW); // Задаем логически 0, что переводит модуль в режим приемника
            pinMode(LED,OUTPUT);

            pinMode(EN_A, OUTPUT);
            pinMode(IN1, OUTPUT);
            pinMode(IN2, OUTPUT);
            pinMode(IN3, OUTPUT);
            pinMode(IN4, OUTPUT);
            pinMode(EN_B, OUTPUT);

            }

            void loop () {

            while( RS485.available() == 0 ) {}
            pot= (unsigned int)RS485.read();
            delay(10);
            while( RS485.available() == 0 ) {}
            pot |= ((unsigned int)RS485.read()) << 8;
            delay(100);
            Serial.println(RS485);

            int X = map(pot, 0, 1023, 0, 255); //Mapping the values to 0-255 to move the motor

            digitalWrite(IN1, LOW);
            digitalWrite(IN2, HIGH);
            analogWrite(EN_A, X);

            digitalWrite(IN3, LOW);
            digitalWrite(IN4, HIGH);
            analogWrite(EN_B, X);
            }

            0
  16. С одним байтом приходят разные числа. Добавляю второй байт:

    void loop () {

    //if( RS485.available() != 0 ) Serial.println(RS485.read());
    while( RS485.available() == 0 ) {}
    pot= (unsigned int)RS485.read();
    delay(10);
    while( RS485.available() == 0 ) {}
    pot |= ((unsigned int)RS485.read()) << 8;
    delay(100);
    Serial.println(RS485);

    В результате — опять приходит только "1". Эдуард, а правильно ли введено "pot |" ? Символ в виде палки не помеха?

    0
    • А правильные?
      Когда вы повышает напряжение от 0 до максимума должны приходить 0…255, затем опять 0…255, и еще 2 раза так.

      0
      • Если все правильно с одним байтом, то надо включить 2 байта только на передатчике. И вручную пересчитать код.
        код = мл. байт + ( ст.байт * 256 )
        Если все правильно, только тогда делать приемник на 2 байта.

        0
        • С одним приходит через единицу, в виде:

          1
          35
          1
          35
          1
          35
          1
          35
          1
          Да, максимальное число 255. Единица это и есть младший байт?

          0
          • Кстати, может лучше на передатчике показания потенциометра конвертировать в диапазон 0-255 и передать, а полученные сигнал использовать для ШИМ ?

            0
          • Конечно, 1 байт передавать проще. Передавать так:
            RS485.write((byte)(analogRead(A0) >> 2));
            delay(500);

            0
          • Старший байт не может быть боле 3. Сейчас код 291, т.е. напряжение 1,42 В. Так?

            0
  17. Не могу сказать на счет кода и напряжения, но добился передачи от 0 до 255.

    Передатчик

    void loop () {
    pot=analogRead(A0);
    int X = map(pot, 0, 1023, 0, 255); //Mapping the values to 0-255 to move the motor
    RS485.write(X);

    Приемник

    oid loop () {

    if( RS485.available() != 0 ) Serial.println(RS485.read());
    while( RS485.available() == 0 ) {}
    pot= (unsigned int)RS485.read();
    delay(500);
    Serial.println(RS485);

    В результате при крайнем положении потенциометра:

    1
    255
    1
    255
    1
    255
    1
    255
    1

    ЧТо же делать с единицей?

    0
  18. Добрый день. Можете посоветовать, как прикрутить библиотеку Tiny_ModBusRTU_Master к ESP8266

    0
      • Спасибо за оперативные ответы. Вот разбираюсь с алгоритмом библиотеки Tiny_ModBusRTU_Master и такие вот вопросы:
        1. Почему выбор режима _mode реализовали через if/else, а не switch/case?
        2. Команда if( (UCSR0A & 64) != 0 ) очень уж специфичная для AVR. Можно ли заменить на if(!Serial.available())? Если я правильно понимаю UCSR0A с маской по пятому биту проверяет флаг опустошения регистра данных UDR0 последовательного интерфейса USART0.
        Дело в том, что я пока плохо знаю тонкости Си, потому и такие вопросы.

        0
        • Здравствуйте!
          1. Какая разница?
          2. Нет, нельзя. Функция available() проверяет наличие принятых данных в буфере Serial. Цель конструкции if( (UCSR0A & 64) != 0 ) — проверить, что закончилась передача данных из сдвигового регистра. Есть буферный регистр передатчика. Если он пуст, то это значит, что новые данные можно загружать, но это не означает, что передача данных на выходе TX закончилась. А нам надо убедиться, что передача данных закончилась и можно разворачивать шину на прием. Посмотрите последний урок по STM32. Там этот момент обсуждается.

          0
          • Спасибо огромное. Ну про if/else я просто уточнил. Было предположение, что конструкция switch/case больше памяти съедает.
            Касаемо UCSR0A & 64 пока думаю как организовать проверку окончания передачи данных в ESP8266. С этим зверем я только начинаю дружить.
            Еще раз огромное спасибо!!!

            0
  19. Чтобы использовать систему, описанную в качестве системы мониторинга температуры в 6-ти разных помещениях сауны (Расстояние от мастера до слейвов от 15 до 25 метров), нужно просто добавить нужное количество модулей slave с разными адресами и убрать ненужное- кнопки и переменные резисторы?
    Можно так использовать?

    0
  20. Добрый день! Хочу на master контроллере принимать данные о температуре
    от 6-ти устройств slave по протоколу ModBus RTU. В качестве исходников
    для slave взял ваш пример из урока. В slave прошивке мне менять ничего наверное не нужно.
    Я подключу термопару и в регистр буду сохранять значения одной переменной float.
    А вот ваш пример скетча устройства master переделал для опроса 6-ти устройств slave.
    Так же, master устройством я отправляю через каждые 3 минуты данные о значениях 6-ти температур на веб сервер.
    Меня интересует следующий вопрос- не нужно ли увеличивать на ведущем (master) устройстве
    время прерывания таймера 500 мкс на большее, если я использую не 2 устройства slave а 6?
    И нужно ли менять это время на slave? Прилагаю скетч master контроллера.

    #include
    #include
    #include
    #include

    #define ADR_CONTR_1 1 // адрес контроллера 1
    #define ADR_CONTR_2 2 // адрес контроллера 2
    #define ADR_CONTR_3 3 // адрес контроллера 3
    #define ADR_CONTR_4 4 // адрес контроллера 4
    #define ADR_CONTR_5 5 // адрес контроллера 5
    #define ADR_CONTR_6 6 // адрес контроллера 6

    float v1 = 0;
    float v2 = 0;
    float v3 = 0;
    float v4 = 0;
    float v5 = 0;
    float v6 = 0;

    byte mac[] = { 0x44, 0xe6, 0x4a, 0x3A, 0x30, 0x39 }; //MAC Arduino
    #define postingInterval 180000 // период отправки данных (в мс)
    const char* host = «mywebserver.net»;// адрес сервера

    EthernetClient client;

    unsigned long lastConnectionTime = 0;
    boolean lastConnected = false;
    String outJson;

    Tiny_ModBusRTU_Master master(8, 30, 13);

    unsigned int regTable[2]; // таблица регистров
    unsigned int cyclCount= 0; // счетчик циклов
    unsigned int errorCount= 0; // счетчик ошибок
    byte mode=0; // режим
    int timeCount=0; // счетчик времени

    void setup() {
    Timer1.initialize(500); // инициализация таймера 1, период 500 мкс
    Timer1.attachInterrupt(timerInterrupt, 500); // задаем обработчик прерываний
    Serial.begin(9600);

    do
    {
    delay(1000);
    } while (Ethernet.begin(mac) == 0);
    lastConnectionTime = millis()-postingInterval+15000; //перва отправка данных через 15 сек после включения

    }

    void loop() {

    if(mode == 0) {
    if(timeCount > 1000) {
    timeCount=0;
    // вывод счетчиков на дисплей
    cyclCount++; // счетчик циклов

    mode=1;
    master.read(ADR_CONTR_1, regTable, 0, 2); // чтение регистров контроллера 1
    }
    }

    if(mode == 1) {
    // ожидание данных контроллера 1
    if(master.state != 1) {

    if(master.state == 0) {
    // данные получены

    v1 = (* ((float *)regTable),1); //Выводим переменную

    }
    else {
    // ошибка обмена
    errorCount++;

    }
    mode=2;
    master.read(ADR_CONTR_2, regTable, 0, 2); // чтение регистров контроллера 2
    }
    }

    if(mode == 2) {
    // ожидание данных контроллера 2
    if(master.state != 1) {

    if(master.state == 0) {
    // данные получены

    v2 = (* ((float *)regTable),1); //Выводим переменную

    }
    else {
    // ошибка обмена
    errorCount++;

    }
    mode=3;
    master.read(ADR_CONTR_3, regTable, 0, 2); // чтение регистров контроллера 3
    }
    }

    if(mode == 3) {
    // ожидание данных контроллера 3
    if(master.state != 1) {

    if(master.state == 0) {
    // данные получены

    v3 = (* ((float *)regTable),1); //Выводим переменную

    }
    else {
    // ошибка обмена
    errorCount++;

    }
    mode=4;
    master.read(ADR_CONTR_4, regTable, 0, 2); // чтение регистров контроллера 4
    }
    }

    if(mode == 4) {
    // ожидание данных контроллера 4
    if(master.state != 1) {

    if(master.state == 0) {
    // данные получены

    v4 = (* ((float *)regTable),1); //Выводим переменную

    }
    else {
    // ошибка обмена
    errorCount++;

    }
    mode=5;
    master.read(ADR_CONTR_5, regTable, 0, 2); // чтение регистров контроллера 5
    }
    }

    if(mode == 5) {
    // ожидание данных контроллера 5
    if(master.state != 1) {

    if(master.state == 0) {
    // данные получены

    v5 = (* ((float *)regTable),1); //Выводим переменную

    }
    else {
    // ошибка обмена
    errorCount++;

    }
    mode=6;
    master.read(ADR_CONTR_6, regTable, 0, 2); // чтение регистров контроллера 6
    }
    }

    if(mode == 6) {
    // ожидание данных контроллера 6
    if(master.state != 1) {

    if(master.state == 0) {
    // данные получены

    v6 = (* ((float *)regTable),1); //Выводим переменную

    }
    else {
    // ошибка обмена
    errorCount++;

    }
    mode=0;

    }
    }
    //——————————————————————————————————-

    if (client.available())
    {
    client.read();
    }
    if (!client.connected() && lastConnected)
    {
    client.stop();
    }
    if (!client.connected() && (millis() — lastConnectionTime > postingInterval))
    {

    int sensorIDs[6] = {1,2,3,4,5,6};
    float values[6] = {v1,v2,v3,v4,v5,v6};

    struct result
    {
    int id;
    float v;
    };

    result allResult[6];

    for (int i = 0; i < 6; i++){
    result oneResult;
    oneResult.id = sensorIDs[i];
    oneResult.v = values[i];
    allResult[i] = oneResult;
    }

    int allResultlength = sizeof(allResult)/sizeof(allResult[0]);

    outJson = String("[");
    for (int i = 0; i 1 && i < allResultlength — 1) {
    suboutJson += String(",");
    }
    outJson += suboutJson;
    }
    outJson += String("]");

    // отправляем запрос
    httpRequest();
    }

    lastConnected = client.connected();
    }

    //————————— обработчик прерывания 500 мкс
    void timerInterrupt() {
    master.update(); // проверка данных обмена
    timeCount++;
    }

    //функция POST запроса
    void httpRequest()
    {
    if (client.connect(host, 80)) //
    {
    client.println("POST /api/Thermo/?key=aede75a76aea8ea7 HTTP/1.1");
    client.print( "Host:" );
    client.println(host);
    client.println("Content-Type: application/json");
    client.print("Content-Length: ");
    client.println(outJson.length());
    client.println();
    client.print(outJson);
    client.println();

    lastConnectionTime = millis();//

    while (client.available())
    {
    char c = client.read();
    }
    client.stop();
    client.flush();
    delay(100);
    }
    else
    {
    client.stop();
    client.flush();
    }
    }

    0
  21. Не авторизировался. Еще забыл сказать, между устройствами планирую использовать обмен на аппаратных UART по RS485 на китайских модулях.

    0
  22. Добрый день! Скажите, именно для ваших библиотек и примеров скетчей, есть ли ограничение на колличество устройств slave? Можно ли опрашивать таким образом например десять устройств slave? Благодарю!

    0
  23. Добрый день! Почему вы используете подтяжку входа RE микросхемы RS485 на землю, а не объединяете RE и DE ?
    У меня пока работает часть с библиотекой Slave при проверке с компьютером, а при попытке работы с другим модулем Мастер — не работает. Я использую модули RS485, объединив входы RE и DE, может в этом проблема?

    0
    • Здравствуйте!
      Нет, можно объединить эти входы, можно включить по моей схеме. В библиотеке при переходе на прием сбрасывается UART, тем самым удаляется принятое в ходе передачи данное. Попробуйте мои скетчи из уроков без изменений.

      0
  24. Еще отдельный вопрос: мне друг помог изменить вашу библиотеку для master, чтобы она работала с Mega. С Мегой работает, но я хочу иметь обе библиотеки доработанную и вашу. Как можно сохранить доработанную библиотеку под другим именем? Простое переименование папки и файлов не помогло

    0
  25. Убрал переделанную библиотеку, переустановил среду, поставил Вашу библиотеку — заработало! Но все же хочется сохранить и библиотеку для меги.
    #ifdef ARDUINO_AVR_NANO
    Tiny_ModBusRTU_Master::Tiny_ModBusRTU_Master(byte timeOutTransmit, byte timeOutRecieve, byte directPin) {

    _timeOutTransmit = timeOutTransmit;
    _timeOutRecieve = timeOutRecieve;
    _directPin = directPin;

    // вывод направления
    _noDirectPin = false;
    pinMode(_directPin, OUTPUT);
    digitalWrite(_directPin,LOW);
    _mode= 0;

    }
    #endif

    #ifdef ARDUINO_AVR_MEGA
    Tiny_ModBusRTU_Master::Tiny_ModBusRTU_Master(int port, int speedRort, byte directPin, byte timeOutTransmit, byte timeOutRecieve) {

    _timeOutTransmit = timeOutTransmit;
    _timeOutRecieve = timeOutRecieve;
    _directPin = directPin;

    // вывод направления
    _noDirectPin = false;
    pinMode(_directPin, OUTPUT);
    digitalWrite(_directPin,LOW);
    _mode= 0;

    if(port==0){
    _port=&Serial;
    _register=&UCSR0A;
    }else if(port==1){
    _port=&Serial1;
    _register=&UCSR1A;
    }else if(port==2){
    _port=&Serial2;
    _register=&UCSR2A;
    }else if(port==3){
    _port=&Serial3;
    _register=&UCSR3A;
    }
    _port->begin(speedRort);

    }
    #endif

    0
  26. Эдуард, здравствуйте
    Совсем запутался, подскажите плиз.
    Вот вы в этом уроке запитываете локальные контроллеры от главного контроллера. А если предположить что локальные контроллеры находятся весьма далеко и запитаны от собственных блоков питания 7-12В, которые включены в отдельные розетки 220В. Тогда нужно объединять земли у локальных и главного контроллера? Или что у них нужно объединять в этом случае?
    Ну или поставлю вопрос по-другому. Скольки-жильный провод мне тянуть к каждому локальному контроллеру, если они (локальные), питаются от собственного блока питания, включенного в собственную розетку?
    Заранее спасибо.

    0
    • Здравствуйте!
      Интерфейс RS485 — дифференциальный. Сигнал данных преобразуется в 2 противофазных сигнала и выделяется на приемной стороне как разность напряжений между ними. Разность напряжения сигналов измеряется относительно общего провода. Поэтому он необходим.
      Необходимо 3 сигнала: 2 дифференциальных и общий провод. Если используется гальванически развязанный RS485, то по общему проводу объединяются не земли устройств, а земли приемо-передатчиков RS485.

      1
  27. Здравствуйте. На основе ваших программ я сделал три скетча: первый для контроллера с кнопкой, второй со светодиодом, третий мастер, который считывает состояние кнопки из первого и подает сигнал на включение светодиода второму. Они соединены друг с другом через конвертер TTL-RS485. После их соединения схема не заработала. Тогда я проверил работу первых двух по отдельности через конвертер USB-RS485, оба выполняют свои функции правильно, получается проблема в мастере. Прошу проверить скетч мастера на ошибки:
    // центральный контроллер с протоколом ModBus

    #include
    #include

    Tiny_ModBusRTU_Master master(8, 30, 12); //время паузы (тишины) между фреймами 8, время тайм-аута ответа ведомого устройства 30, номер вывода разрешения передатчика ведущего устройства 12

    unsigned int regTable[1]; // таблица регистров

    void setup()
    {
    Timer1.initialize(500); // инициализация таймера 1, период 500 мкс
    Timer1.attachInterrupt(timerInterrupt, 500); // задаем обработчик прерываний
    Serial.begin(9600);
    }

    void loop()
    {
    // чтение регистров контроллера 1
    master.read(1, regTable, 0, 1); //адрес ведомого устройства 1, массив для прочитанных данных, начальный адрес регистров хранения 0, количество регистров хранения 1

    // запись регистров контроллера 2
    master.writeMultiple(2, regTable, 0, 1); //адрес ведомого устройства 2, данные — начальная ячейка массива, начальный адрес регистров хранения 0, количество регистров хранения 1

    }

    //————————— обработчик прерывания 500 мкс
    void timerInterrupt()
    {
    master.update(); // проверка данных обмена
    }

    0
    • в строках include, почему-то не отобразились строки с TimerOne.h и Tiny_ModBusRTU_Master.h.
      Скетч компилируется без ошибок.

      0
    • Здравствуйте!
      Ваша ошибка в следующем.
      Библиотека выполняет свои функции параллельным процессом. Когда вы вызвали функцию, например read() вы только запустили процесс. Он еще выполняется, а вы вызываете другую функцию. Необходимо дождаться окончания выполнения предыдущей. Посмотрите про переменную state.
      while(master.state == 1) {} // ожидание данных

      0
      • Переделал программу, но она все равно не работает.

        void loop()
        {
        // чтение регистров контроллера 1
        master.read(1, regTable, 0, 1); //адрес ведомого устройства 1, массив для прочитанных данных, начальный адрес регистров хранения 0, количество регистров хранения 1
        while(master.state == 1) {} // ожидание данных
        // запись регистров контроллера 2
        master.writeMultiple(2, regTable, 0, 1); //адрес ведомого устройства 2, данные — начальная ячейка массива, начальный адрес регистров хранения 0, количество регистров хранения 1
        while(master.state == 1) {} // ожидание данных
        }

        0
        • Здравствуйте!
          Посмотрите внимательно программу из урока 58. Там объект master объявляется с квалификатором volatile. Лучше сделать, чтобы программа при ожидании окончания передачи через loop() проходила.

          0
          • Здравствуйте. Изменил скетч следующим образом:

            // центральный контроллер с протоколом ModBus
            #include
            #include
            volatile Tiny_ModBusRTU_Master master(8, 30, 12);
            unsigned int regTable[1];
            void setup()
            {
            Timer1.initialize(500);
            Timer1.attachInterrupt(timerInterrupt, 500);
            Serial.begin(9600);
            }
            void loop()
            {
            // чтение регистров контроллера 1
            master.read(1, regTable, 0, 1);
            while(master.state == 1) {}
            // запись регистров контроллера 2
            master.writeMultiple(2, regTable, 0, 1);
            while(master.state == 1) {}
            delay(50);
            }

            //————————— обработчик прерывания 500 мкс
            void timerInterrupt()
            {
            master.update(); // проверка данных обмена
            }

            Компилятор выдал предупреждение:
            warning: passing ‘volatile Tiny_ModBusRTU_Master’ as ‘this’ argument discards qualifiers [-fpermissive]

            Система по прежнему не работает. на центральном контроллере горит ТХ, на других не горит ничего.

            0
          • Здравствуйте!
            Попробуйте по принципу программы 2 из урока 58. Программа проходит через цикл loop при ожидании.

            // центральный контроллер с протоколом ModBus
            #include
            #include

            Tiny_ModBusRTU_Master master(8, 30, 12);

            unsigned int regTable[6]; // таблица регистров
            byte mode=0;

            void setup() {
            Timer1.initialize(500); // инициализация таймера 1, период 500 мкс
            Timer1.attachInterrupt(timerInterrupt, 500); // задаем обработчик прерываний
            Serial.begin(9600);
            master.read(1, regTable, 0, 1);
            }

            void loop() {
            if( (mode & 1) == 0 ) {
            // чтение регистров хранения
            if(master.state != 1) {
            // операция завершена
            master.writeMultiple(2, regTable, 0, 1);
            mode++;
            }
            }
            else {
            // запись регистра хранения
            if(master.state != 1) {
            // операция завершена
            master.read(1, regTable, 0, 1);
            mode++;
            }
            }
            delay(500);
            }

            //————————— обработчик прерывания 500 мкс
            void timerInterrupt() {
            master.update(); // проверка данных обмена
            }

            0

          • Спасибо. С этим скетчем схема частично заработала — начали мигать ТХы на всех трех платах, но светодиод от кнопки почему-то не загорается. Ну с этим я буду разбираться дополнительно.

            Правда остались вопросы по вашему скетчу:
            1) Я так и не понял, что вы имели ввиду — «Лучше сделать, чтобы программа при ожидании окончания передачи через loop() проходила.
            2) Зачем вы поместили чтение первого контроллера в сетап?
            3 И Зачем нужен mode? Что с ним происходит — понятно, но зачем это надо — непонятно.

            0
          • Здравствуйте!
            Это как раз вариант, при котором программа постоянно проходит через цикл loop, не зависая в программных блоках.
            Переменная mode определяет по какой ветке идти в loop ожидание окончания чтения данных или окончания записи.

            0
          • Здравствуйте. Извините за беспокойство, но моя схема так и не заработала. Я максимально ее упростил, чтобы просто передать с первого контроллера на второй через мастера единицу, чтобы при ее получении зажегся светодиод. Причем если просто передавать с мастера единицу — светодиод загорается. Вот все три скетча:
            // локальный контроллер 1, UART, ModBus
            #include
            #include
            unsigned int regTable[6]; // таблица регистров
            Tiny_ModBusRTU_Slave slave(1, 8, regTable, 6, 12); // создаем объект ModBus, адрес 1, таймаут 8 мс, массив regTable, размер 6, контакт уаправления передачей 12
            void setup()
            {
            Timer1.initialize(500); // инициализация таймера 1, период 500 мкс
            Timer1.attachInterrupt(timerInterrupt, 500); // задаем обработчик прерываний
            Serial.begin(9600);
            // инициализируем пин, подключенный к кнопке, как вход
            pinMode(buttonPin, INPUT);
            regTable[0] = 1;
            }
            void loop()
            {
            }
            //————————— обработчик прерывания 500 мкс
            void timerInterrupt()
            {
            slave.update(); // проверка данных обмена
            }

            // локальный контроллер 2, UART, ModBus
            #include
            #include
            unsigned int regTable[6]; // таблица регистров
            Tiny_ModBusRTU_Slave slave(2, 8, regTable, 6, 12); // создаем объект ModBus, адрес 2, таймаут 8 мс, массив regTable, размер 6, контакт уаправления передачей 12
            const int ledPin = 3; // номер выхода светодиода
            bool ledOn = false; // текущее состояние светодиода
            void setup()
            {
            Timer1.initialize(500); // инициализация таймера 1, период 500 мкс
            Timer1.attachInterrupt(timerInterrupt, 500); // задаем обработчик прерываний
            Serial.begin(9600);
            // инициализируем пин, подключенный к светодиоду, как выход
            pinMode(ledPin, OUTPUT);
            regTable[0] = 0;
            }
            void loop()
            {
            // перегрузка состояния кнопки из таблицы регистров
            noInterrupts();
            if (regTable[0] == 1)
            {
            ledOn = true;
            }
            else ledOn = false;
            interrupts();
            digitalWrite(ledPin, ledOn); // Включаем или выключаем светодиот (смотря что пришло после инверсии)
            }
            //————————— обработчик прерывания 500 мкс
            void timerInterrupt()
            {
            slave.update(); // проверка данных обмена
            }

            // центральный контроллер с протоколом ModBus
            #include
            #include
            Tiny_ModBusRTU_Master master(8, 30, 12);
            unsigned int regTable[6]; // таблица регистров
            byte mode=0;
            void setup() {
            Timer1.initialize(500); // инициализация таймера 1, период 500 мкс
            Timer1.attachInterrupt(timerInterrupt, 500); // задаем обработчик прерываний
            Serial.begin(9600);
            master.read(1, regTable, 0, 1);
            }
            void loop() {
            if( (mode & 1) == 0 )
            {
            // запись регистров хранения
            if(master.state != 1)
            {
            // операция завершена
            master.writeMultiple(2, regTable, 0, 1);
            mode++;
            }
            }
            else {
            // чтение регистра хранения
            if(master.state != 1) {
            // операция завершена
            master.read(1, regTable, 0, 1);
            mode++;
            }
            }
            delay(500);
            }
            //————————— обработчик прерывания 500 мкс
            void timerInterrupt() {
            master.update(); // проверка данных обмена
            }

            Компилируются скетчи без ошибок, на всех контроллерах мигают ТХы.

            0
          • Здравствуйте!
            Скорее всего, не смогу уделить много времени до понедельника.
            Пока. Локализуйте проблему. Если у вас не работает прием данных, то отладьте именно этот режим. Пускай мастер только принимает данные и выводит результат на светодиод.
            Возможно, необходимо выдерживать паузу между командами. Попробуйте для проверки в мастере после каждого mode++ вставьте delay(10);
            Если не заработает, напомните мне в понедельник.

            0
          • Сделал как вы сказали — подключил к мастеру светодиод и считывал единицу с первого контроллера, но это не сработало, значит проблема в чтении. Посмотрите пожалуйста скетчи из прошлого сообщения.

            0
          • Да, сейчас скетчи выглядят так:
            // центральный контроллер с протоколом ModBus
            #include
            #include
            Tiny_ModBusRTU_Master master(8, 30, 12);
            unsigned int regTable[6];
            byte mode=0;
            const int ledPin = 3;
            bool ledOn = false;
            void setup() {
            Timer1.initialize(500);
            Timer1.attachInterrupt(timerInterrupt, 500);
            Serial.begin(9600);
            master.read(1, regTable, 0, 1);
            }
            void loop() {
            if( (mode & 1) == 0 ) {
            if(master.state != 1)
            {
            mode++;
            delay(200);
            }
            }
            else {
            if(master.state != 1) {
            master.read(1, regTable, 0, 1);
            mode++;
            delay(200);
            }
            }
            delay(200);
            noInterrupts();
            if (regTable[0] == 1) {
            ledOn = true;
            }
            else ledOn = false;
            interrupts();
            digitalWrite(ledPin, ledOn);
            }
            void timerInterrupt() {
            master.update();
            }

            // локальный контроллер 1, UART, ModBus
            #include
            #include
            unsigned int regTable[6];
            Tiny_ModBusRTU_Slave slave(1, 8, regTable, 6, 12);
            void setup()
            {
            Timer1.initialize(500);
            Timer1.attachInterrupt(timerInterrupt, 500);
            Serial.begin(9600);
            pinMode(buttonPin, INPUT);
            regTable[0] = 1;
            }
            void loop() {}
            void timerInterrupt() {
            slave.update();
            }

            0
          • Здравствуйте!
            Без проверки ошибок обмена должно быть как-то так.

            #include
            #include

            Tiny_ModBusRTU_Master master(8, 30, 12);
            unsigned int regTable[6];
            byte mode=0;
            const int ledPin = 3;
            bool ledOn = false;
            void setup() {
            Timer1.initialize(500);
            Timer1.attachInterrupt(timerInterrupt, 500);
            Serial.begin(9600);
            master.read(1, regTable, 0, 1);
            }
            void loop() {
            if( (mode & 1) == 0 ) {
            // ожидание окончания чтения
            if(master.state != 1)
            {
            if (regTable[0] == 1) digitalWrite(ledPin, HIGH);
            else digitalWrite(ledPin, LOW);
            mode++;
            delay(10);
            master.writeMultiple(2, regTable, 0, 1);
            }
            }
            else {
            // ожидание окончания записи
            if(master.state != 1) {
            master.read(1, regTable, 0, 1);
            mode++;
            delay(10);
            }
            }
            }
            void timerInterrupt() {
            master.update();
            }

            2

          • Спасибо. В этом варианте все заработало. Правильно ли я понял, что рабочий код программы мне надо помещать в блок:
            if( (mode & 1) == 0 ) {
            // ожидание окончания чтения
            if(master.state != 1) {
            master.writeMultiple(2, regTable, 0, 1);
            mode++;
            delay(10);
            }
            }
            иначе он может быть пропущен при прерывании?

            0
          • Здравствуйте!
            Надо, чтобы программа не зависала на ожидании какого-либо события, а всегда проходила цикл loop до конца. Проблема в том, что компилятор оптимизирует код и не понимает, что данные изменяются в прерывании.

            0
  28. Здравствуйте! Скажите, как вместо аппаратного Serial использовать SoftwareSerial ? Нужно переделывать библиотеку?

    0

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

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

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