Библиотека Serial27b для радиомоделизма и не только

Тема в разделе "Глядите, что я сделал", создана пользователем issaom, 27 авг 2019.

Метки:
  1. parovoZZ

    parovoZZ Гуру

    Про то, что данные трансиверы не умеют кодировать пакет помехоустойчивым кодом. Это умеет лора. В принципе можно и самому сделать, но гораздо проще передавать мелкими пакетами.
     
  2. issaom

    issaom Гик

    Если верить статье по которой я делал расчет контрольной суммы в своей библе на 256 кривых отправленных пакетов из 8 байт, только один пройдет проверку контрольной суммы, остальные будут отброшены как не валидные ну и существовать он там будет не более 250-300мс - данные ведь постоянно обновляются ;-) надо протестировать конечно, но я не настолько маньяк ))) по факту валидация должна быть выше - это связано с реализацией самого протокола - один косяк и мозайка из передаваемых бит обратно не соберется что тут-же будет выявлено и пущено "мимо ушей" с выдачей соответсвующего предупреждения в виде погасшего светодиода )))
     
    Daniil нравится это.
  3. Daniil

    Daniil Гуру

    Вот оно что! Как-то я не рассматривал (недооценивал) такой метод передачи данных.
    Я то хочу, чтобы было гибко, так гибко, что аж реализовывать сложно) но тут дубово (в хорошем смысле) - не припечатало с 1-го раза, так со 2-го дойдёт)
    Спасибо, каждый день что-то новое.
     
  4. issaom

    issaom Гик

    В целом идея очень простая: у Вас и Вашего друга есть часы которые ходят синхронно. Вы говорите когда у Вас на часах четное количество минут - Ваш друг говорит когда у него на часах нечетное количество минут. Войну и мир за одну минуту вы прочитать не успеете - а вот сказать несколько предложений вполне. При такой методе никогда не возникнет ситуации когда вы заговорите одновременно. Объем информации который вы сообщаете друг-другу маленький - за то обмениваться ей вы сможете часто. Я реализовывал эту модель в своих различных р/у поделках - но если выносить этот код в основной скетч получается очень громоздко - поэтому и вынес в отдельный файл :). По принципу: реализовал, оттестировал и забыл. Передаваемые туда сюда пакеты не просто обрабатываются и отдаются пользователю, а еще и синхронизируют эти виртуальные часы - поэтому в этой схеме и не реализована "передача по запросу" - она разрушает саму концепцию того для чего это писалось ;)
     
    Daniil нравится это.
  5. Daniil

    Daniil Гуру

    Воо...
    Для общения двух равноправных устройств я читал про частотное разделение прд/прм (устройства общаются на разных частотах, нужны пары антенн/цепей обработки). Про разные методы передачи данных (modbus, но тут, обычно, не делают 2ух мастеров) и..та-дам..про временное разделение - когда устройства говорят только в свое время.
    И вот первый пример увидел)
    Есть нюанс, у меня шестеренка в часах может быть с дефектом, который приведет через некоторое время к тому, что мои часы скажут говорить тогда же когда и у моего друга. У вас есть синхронизация (сбросить таймер при приёме данных)? Хотя, при сотнях мс это будет ой как не скоро и можно оставить на волю случая.
     
  6. issaom

    issaom Гик

    Не совсем так.... на Ваших часах 1 минута вы кричите своему другу, а в ответ тишина. На Ваших часах 3 минуты Вы снова кричите. А в ответ тишина. Все это время часы у Вашего друга просто стоят ))), а отсчитывать время они у него начнут только тогда он Вас услышит ))) и как только он снова перестанет Ваш слышать часы снова остановятся. Строго говоря одна из плат является мастером, вторая слайвом ))). Вторая плата никогда не отвечает в пустоту не услышав голос первой - она лишь отзывается. На приемнике - происходит запуск таймера как только он услышит голос первой и проверит что ей не наплели какой-нибудь фигни ))). Передатчик же отправляет пакеты строго по расписанию, но если он не дождется ответа на свой крик в установленное время это событие также обрабатывается. т.е. пока платы успешно укладываются в отведенное время светодиод на 13-м пине горит сообщая что проблем в общении не возникает.
     
    Daniil нравится это.
  7. issaom

    issaom Гик

    Вы уж так захотели докопаться до истины :)
    Передатчик:
    Проходит одна минута - кричим
    Ждем ответ не дольше одной минуты (если в течении одной минуты никто не ответил значит есть проблема ждем еще одну минуту и кричим снова).
    Приемник:
    Отвечает сразу как только обработал всю посылку до конца. и запускает свои часы ожидая следующую посылку не позднее чем через 2 минуты.
    Как только передатчик получил адекватный ответ он не будет ждать до окончания 2-й минуты таймер сбрасывается отсчитывается одна минута и кричит снова.
    т.е. отправка пакета с передатчика происходит с частотой 1 минута + время на обработку ответа
     
  8. Daniil

    Daniil Гуру

    Да. Теперь стало ясно.
    Любопытный способ, надо будет прокрутить его в голове на досуге ещё раз.
    Как я понял, никто не мешает поменяться ролями (условные master/slave) в любой момент времени т.к. оба знают состояния друг друга?
     
  9. issaom

    issaom Гик

    Ну.... с точки зрения конечного пользователя особой разницы, что является приемником, а что передатчиком вообщем-то нет ни какой. Ему просто необходимо наполнять массивы данными и читать их от туда. Но внутренние алгоритмы передатчика и приемника разумеется сильно отличаются.... Если например пользователь будет пользоваться только одним массивом (например передатчика) - то ответ то от приемника все равно будет приходить - 2 служебных байта символизирующих начало и окончание пакета чтобы таймеры тикали и обрабатывалось событие "потеря связи".
     
    Daniil нравится это.
  10. parovoZZ

    parovoZZ Гуру

    В модбасе ровно все тоже самое, только привязано к длительности одного символа.
     
  11. issaom

    issaom Гик

    Подпилил код библиотеки на совместимость с разными Ардуинами
    Гарантировано будет компилироваться и работать на Arduino Mega, Arduino Leonardo, Arduino UNO(Nano), Iskra Nano Pro. Других плат у меня в наличии нет - тестировать не на чем. Файлик обновил в первом посте - кому захочется можно(и даже нужно) скачать и покритиковать. Константы вытащил в отдельный блок описаний.

    Беспроводная клава для ПК (для управления проигрывателем Windows Media или чем-нибудь подобным)

    Код клавиатуры:
    Код (C++):
    #define Serial_2     // Arduino MEGA - клавиатура
    byte transm_arr[27];  // Массив который отправляется на приемник
    byte receiv_arr[27];   // Массив который приходит с приемника
    #include <Serial27bTransmitter.h>   // Подключаем библиотеку передатчика

    void setup() {
      startTransmitter(9600, 100);        // старт передатчика
      pinMode(36 , INPUT_PULLUP);    // кнопка плей/пауза                    
      pinMode(37 , INPUT_PULLUP);    // кнопка следующий трек                          
      pinMode(38 , INPUT_PULLUP);    // кнопка предыдущий трек  
      pinMode(39 , INPUT_PULLUP);    // кнопка громкость ++
      pinMode(40 , INPUT_PULLUP);    // кнопка громкость --
    }

    void loop() {
      bitWrite(transm_arr[0], 0, !digitalRead(36));
      bitWrite(transm_arr[0], 1, !digitalRead(37));
      bitWrite(transm_arr[0], 2, !digitalRead(38));
      bitWrite(transm_arr[0], 3, !digitalRead(39));
      bitWrite(transm_arr[0], 4, !digitalRead(40));
    }
    Код для ответной части
    Код (C++):
    #include <Keyboard.h>   // подключаем библиотеку клавиатуры
    #define Serial_1     // Arduino LEONARDO - приемник беспроводной клавиатуры
    byte transm_arr[27];      // Массив который приходит с передатчика
    byte receiv_arr[27];       // Массив который отправляется передатчику
    #include <Serial27bReceiver.h>  // Подключаем библиотеку приемника

    boolean playState = true;
    boolean nextState = true;
    boolean previousState = true;
    boolean volumeUpState = true;
    boolean volumeDownState = true;

    void setup() {
      startReceiver(9600, 200);    // старт передатчика
      Keyboard.begin();             // старт клавиатуры
    }

    void loop() {
      // кнопка плей/пауза CTRL + p
      if (bitRead(transm_arr[0], 0) && (playState == true)) {
        Keyboard.press(KEY_LEFT_CTRL);
        Keyboard.press('p');
        Keyboard.releaseAll();
        playState = false;
      }
      // кнопка следующий трек CTRL + f
      if (bitRead(transm_arr[0], 1) && (nextState == true)) {
        Keyboard.press(KEY_LEFT_CTRL);
        Keyboard.press('f');
        Keyboard.releaseAll();
        nextState = false;
      }
      // кнопка предыдущий трек CTRL + b
      if (bitRead(transm_arr[0], 2) && (previousState == true)) {
        Keyboard.press(KEY_LEFT_CTRL);
        Keyboard.press('b');
        Keyboard.releaseAll();
        previousState  = false;
      }
      //кнопка громкость ++ F9
      if (bitRead(transm_arr[0], 3) && (volumeUpState == true)) {
        Keyboard.press(KEY_F9);
        Keyboard.releaseAll();
        volumeUpState = false;
      }
      //кнопка громкость -- F8
      if (bitRead(transm_arr[0], 4) && (volumeDownState == true)) {
        Keyboard.press(KEY_F8);
        Keyboard.releaseAll();
        volumeDownState = false;
      }

      if (!bitRead(transm_arr[0], 0)) playState = true;
      if (!bitRead(transm_arr[0], 1)) nextState = true;
      if (!bitRead(transm_arr[0], 2)) previousState = true;
      if (!bitRead(transm_arr[0], 3)) volumeUpState = true;
      if (!bitRead(transm_arr[0], 4)) volumeDownState = true;

    }
    Маленькое видео (презентация работы)

     
    lepidot и Daniil нравится это.
  12. Daniil

    Daniil Гуру

    Классно получилось!
    Код очень даже читабельный, если разобраться как оно работает во внутрях.
    Я извиняюсь за вопрос новичка (мало на ардуинке работаю) (и уж точно не в ваш огород) - получается, что при использовании разных библиотек, нужно знать какие они аппаратные ресурсы требуют, чтобы не нарваться на использование одного таймера двумя библиотеками?
    Тут я мучал парня и в итоге выжал из себя код почти-модбас. Думаю, Вы и так его знаете, но пояснит о чём я говорил ранее.