├── .gitattributes ├── .github └── workflows │ └── tg-send.yml ├── LICENSE ├── README.md ├── README_EN.md ├── examples ├── GBUSmini-GBUSmini │ ├── call response │ │ ├── simple_call_response_rx │ │ │ └── simple_call_response_rx.ino │ │ └── simple_call_response_tx │ │ │ └── simple_call_response_tx.ino │ ├── call response_ack │ │ ├── simple_call_response_rx │ │ │ └── simple_call_response_rx.ino │ │ └── simple_call_response_tx │ │ │ └── simple_call_response_tx.ino │ ├── data │ │ ├── read │ │ │ └── read.ino │ │ └── send │ │ │ └── send.ino │ ├── pack data │ │ ├── read │ │ │ └── read.ino │ │ └── send │ │ │ └── send.ino │ ├── raw │ │ ├── read │ │ │ └── read.ino │ │ └── send │ │ │ └── send.ino │ ├── request │ │ ├── read │ │ │ └── read.ino │ │ └── send │ │ │ └── send.ino │ └── общение ардуин через GBUSmini.txt ├── GBUSmini-softuart │ ├── data │ │ ├── rx-softuart │ │ │ └── rx-softuart.ino │ │ └── tx-gbusmini │ │ │ └── tx-gbusmini.ino │ └── общение ардуин через softuart и GBUSmini.txt ├── broadcast │ └── broadcast.ino ├── checkStatus │ └── checkStatus.ino ├── esp8266 to ardu (softserial) │ ├── read │ │ └── read.ino │ └── send │ │ └── send.ino ├── gyvertransfer-gyvertransfer │ ├── read_request │ │ └── read_request.ino │ ├── send_request │ │ └── send_request.ino │ ├── simple_call_response_rx │ │ └── simple_call_response_rx.ino │ ├── simple_call_response_tx │ │ └── simple_call_response_tx.ino │ └── общение ардуин через gyvertransfer.txt ├── softserial-serial │ ├── array │ │ ├── read_array │ │ │ └── read_array.ino │ │ └── send_array │ │ │ └── send_array.ino │ ├── request │ │ ├── read_request │ │ │ └── read_request.ino │ │ └── send_request │ │ │ └── send_request.ino │ ├── struct │ │ ├── read_struct │ │ │ └── read_struct.ino │ │ └── send_struct │ │ │ └── send_struct.ino │ └── общение ардуин через softserial и serial.txt ├── softserial-softserial │ ├── ack_RX │ │ └── ack_RX.ino │ ├── ack_TX │ │ └── ack_TX.ino │ └── общение ардуин через softserial.txt └── softuart-softuart │ ├── data │ ├── read │ │ └── read.ino │ └── send │ │ └── send.ino │ ├── raw │ ├── raw_RX │ │ └── raw_RX.ino │ └── raw_TX │ │ └── raw_TX.ino │ └── общение ардуин через встроенный softuart.txt ├── keywords.txt ├── library.properties └── src ├── GBUS.h ├── GBUSmini.cpp ├── GBUSmini.h ├── GyverBus.cpp ├── GyverBus.h └── softUART.h /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/workflows/tg-send.yml: -------------------------------------------------------------------------------- 1 | 2 | name: Telegram Message 3 | on: 4 | release: 5 | types: [published] 6 | jobs: 7 | build: 8 | name: Send Message 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: send telegram message on push 12 | uses: appleboy/telegram-action@master 13 | with: 14 | to: ${{ secrets.TELEGRAM_TO }} 15 | token: ${{ secrets.TELEGRAM_TOKEN }} 16 | disable_web_page_preview: true 17 | message: | 18 | ${{ github.event.repository.name }} v${{ github.event.release.tag_name }} 19 | ${{ github.event.release.body }} 20 | https://github.com/${{ github.repository }} 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 AlexGyver 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![latest](https://img.shields.io/github/v/release/GyverLibs/GyverBus.svg?color=brightgreen)](https://github.com/GyverLibs/GyverBus/releases/latest/download/GyverBus.zip) 2 | [![PIO](https://badges.registry.platformio.org/packages/gyverlibs/library/GyverBus.svg)](https://registry.platformio.org/libraries/gyverlibs/GyverBus) 3 | [![Foo](https://img.shields.io/badge/Website-AlexGyver.ru-blue.svg?style=flat-square)](https://alexgyver.ru/) 4 | [![Foo](https://img.shields.io/badge/%E2%82%BD%24%E2%82%AC%20%D0%9F%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B6%D0%B0%D1%82%D1%8C-%D0%B0%D0%B2%D1%82%D0%BE%D1%80%D0%B0-orange.svg?style=flat-square)](https://alexgyver.ru/support_alex/) 5 | [![Foo](https://img.shields.io/badge/README-ENGLISH-blueviolet.svg?style=flat-square)](https://github-com.translate.goog/GyverLibs/GyverBus?_x_tr_sl=ru&_x_tr_tl=en) 6 | 7 | [![Foo](https://img.shields.io/badge/ПОДПИСАТЬСЯ-НА%20ОБНОВЛЕНИЯ-brightgreen.svg?style=social&logo=telegram&color=blue)](https://t.me/GyverLibs) 8 | 9 | # GyverBus 10 | Библиотека для общения по протоколу GBUS 11 | - Очень простой, надёжный, устойчивый к помехам и задержкам, но медленный интерфейс связи на базе UART 12 | - Двухсторонняя связь по одному проводу 13 | - Асинхронная отправка и чтение (на базе millis()) 14 | - Двухсторонняя совместимость с аппаратным UART 15 | - Возможность принимать и отправлять данные внутри сети Ардуинок 16 | - Адресация до 254 устройств в сети (от 1 до 255) 17 | - Всеядная функция отправки и приёма (ест переменные, структуры, массивы) 18 | - Встроенная проверка CRC (контроль целостности) пакета данных 19 | - Возможность отправки и чтения короткого "запроса" 20 | - Поддерживаются все Arduino-совместимые платы 21 | - Сама библиотека предоставляет возможности по отладке (коды ошибок) 22 | - В примерах есть компактные варианты чтения и отправки данных, влезет даже в ATtiny 23 | 24 | ### Совместимость 25 | Совместима со всеми Arduino платформами (используются Arduino-функции) 26 | 27 | ### Документация 28 | К библиотеке есть [расширенная документация](https://alexgyver.ru/GyverBus/) 29 | 30 | ## Содержание 31 | - [Установка](#install) 32 | - [Инициализация](#init) 33 | - [Использование](#usage) 34 | - [Пример](#example) 35 | - [Версии](#versions) 36 | - [Баги и обратная связь](#feedback) 37 | 38 | 39 | ## Установка 40 | - Библиотеку можно найти по названию **GyverBus** и установить через менеджер библиотек в: 41 | - Arduino IDE 42 | - Arduino IDE v2 43 | - PlatformIO 44 | - [Скачать библиотеку](https://github.com/GyverLibs/GyverBus/archive/refs/heads/main.zip) .zip архивом для ручной установки: 45 | - Распаковать и положить в *C:\Program Files (x86)\Arduino\libraries* (Windows x64) 46 | - Распаковать и положить в *C:\Program Files\Arduino\libraries* (Windows x32) 47 | - Распаковать и положить в *Документы/Arduino/libraries/* 48 | - (Arduino IDE) автоматическая установка из .zip: *Скетч/Подключить библиотеку/Добавить .ZIP библиотеку…* и указать скачанный архив 49 | - Читай более подробную инструкцию по установке библиотек [здесь](https://alexgyver.ru/arduino-first/#%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA) 50 | ### Обновление 51 | - Рекомендую всегда обновлять библиотеку: в новых версиях исправляются ошибки и баги, а также проводится оптимизация и добавляются новые фичи 52 | - Через менеджер библиотек IDE: найти библиотеку как при установке и нажать "Обновить" 53 | - Вручную: **удалить папку со старой версией**, а затем положить на её место новую. "Замену" делать нельзя: иногда в новых версиях удаляются файлы, которые останутся при замене и могут привести к ошибкам! 54 | 55 | 56 | 57 | ## Инициализация 58 | См. [документацию](https://alexgyver.ru/GyverBus/) 59 | 60 | 61 | ## Использование 62 | См. [документацию](https://alexgyver.ru/GyverBus/) 63 | 64 | 65 | ## Пример 66 | См. [документацию](https://alexgyver.ru/GyverBus/) 67 | 68 | 69 | ## Версии 70 | - v1.1: добавлена waitAck() и исправлена ошибочка 71 | - v1.2: улучшена стабильность, функции оптимизированы, уменьшен вес 72 | - v1.3: добавлен CRC в запрос и ответ 73 | - v2.0: 74 | - Куча оптимизации 75 | - Логика работы переделана. Теперь GBUS работает для всех uart-библиотек 76 | - Однопроводной uart вынесен отдельным классом 77 | - Добавлена совместимость с esp8266 78 | - Переделана вся инициализация, смотри примеры! 79 | - Добавлены утилиты и примеры 80 | - v2.1: вернул getStatus 81 | - v2.2: небольшие багфиксы и оптимизация 82 | - v2.3: добавлена возможность отправки широковещательного сообщения (всем), отправлять на адрес 255 83 | - v2.4: исправлены ошибки, добавлена bool statusChanged() для GBUS 84 | - v2.5: добавил пример с GyverTransfer, добавил смену адреса 85 | - v2.6: мелкие фиксы 86 | 87 | 88 | ## Баги и обратная связь 89 | При нахождении багов создавайте **Issue**, а лучше сразу пишите на почту [alex@alexgyver.ru](mailto:alex@alexgyver.ru) 90 | Библиотека открыта для доработки и ваших **Pull Request**'ов! 91 | 92 | 93 | При сообщении о багах или некорректной работе библиотеки нужно обязательно указывать: 94 | - Версия библиотеки 95 | - Какой используется МК 96 | - Версия SDK (для ESP) 97 | - Версия Arduino IDE 98 | - Корректно ли работают ли встроенные примеры, в которых используются функции и конструкции, приводящие к багу в вашем коде 99 | - Какой код загружался, какая работа от него ожидалась и как он работает в реальности 100 | - В идеале приложить минимальный код, в котором наблюдается баг. Не полотно из тысячи строк, а минимальный код 101 | -------------------------------------------------------------------------------- /README_EN.md: -------------------------------------------------------------------------------- 1 | This is an automatic translation, may be incorrect in some places. See sources and examples! 2 | 3 | # Gyverbus 4 | Library for communication on the GBUS protocol 5 | - very simple, reliable, resistant to interference and delays, but a slow communication interface based on UART 6 | - bilateral communication one wire 7 | - asynchronous sending and reading (based on Millis ()) 8 | - double -sided compatibility with hardware UART 9 | - the ability to accept and send data inside the arduni network 10 | - Addressing up to 254 devices on the network (from 1 to 255) 11 | - omnivorous function of sending and reception (eats variables, structures, arrays) 12 | - Built -in CRC check (integrity control) data package 13 | - The possibility of sending and reading a short "request" 14 | - all Arduino-compatible boards are supported 15 | - The library itself provides debugging opportunities (error codes) 16 | - In the examples there are compact options for reading and sending data, it will even fit into Attiny 17 | 18 | ## compatibility 19 | Compatible with all arduino platforms (used arduino functions) 20 | 21 | ### Documentation 22 | There is [extended documentation] to the library (https://alexgyver.ru/gyverbus/) 23 | 24 | ## Content 25 | - [installation] (# Install) 26 | - [initialization] (#init) 27 | - [use] (#usage) 28 | - [Example] (# Example) 29 | - [versions] (#varsions) 30 | - [bugs and feedback] (#fedback) 31 | 32 | 33 | ## Installation 34 | - The library can be found by the name ** gyverbus ** and installed through the library manager in: 35 | - Arduino ide 36 | - Arduino ide v2 37 | - Platformio 38 | - [download the library] (https://github.com/gyverlibs/gyverbus/archive/refs/heads/main.zip) .Zip archive for manual installation: 39 | - unpack and put in * C: \ Program Files (X86) \ Arduino \ Libraries * (Windows X64) 40 | - unpack and put in * C: \ Program Files \ Arduino \ Libraries * (Windows X32) 41 | - unpack and put in *documents/arduino/libraries/ * 42 | - (Arduino id) Automatic installation from. Zip: * sketch/connect the library/add .Zip library ... * and specify downloaded archive 43 | - Read more detailed instructions for installing libraries [here] (https://alexgyver.ru/arduino-first/#%D0%A3%D1%81%D1%82%D0%B0%BD%D0%BE%BE%BE%BED0%B2%D0%BA%D0%B0_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA) 44 | ### Update 45 | - I recommend always updating the library: errors and bugs are corrected in the new versions, as well as optimization and new features are added 46 | - through the IDE library manager: find the library how to install and click "update" 47 | - Manually: ** remove the folder with the old version **, and then put a new one in its place.“Replacement” cannot be done: sometimes in new versions, files that remain when replacing are deleted and can lead to errors! 48 | 49 | 50 | 51 | ## initialization 52 | See [documentation] (https://alexgyver.ru/gyverbus/) 53 | 54 | 55 | ## Usage 56 | See [documentation] (https://alexgyver.ru/gyverbus/) 57 | 58 | 59 | ## Example 60 | See [documentation] (https://alexgyver.ru/gyverbus/) 61 | 62 | 63 | ## versions 64 | - v1.1: added Waitack () and a mistake is fixed 65 | - V1.2: Improved stability, the functions are optimized, the weight is reduced 66 | - V1.3: Added CRC to the request and answer 67 | - V2.0: 68 | - A bunch of optimization 69 | - The logic of work has been converted.Now GBUS is working for all UART Bibliotek 70 | - one -wire UART is carried out by a separate class 71 | - Added compatibility with ESP8266 72 | - All initialization has been redone, see examples!- Added utilities and examples 73 | - V2.1: Returned Getstatus 74 | - V2.2: Small Bagfixes and Optimization 75 | - V2.3: added the possibility of sending a broadcast message (to all), send to the address 255 76 | - V2.4: Fixed errors, added Bool Statuschand () for GBUS 77 | - V2.5: added an example with Gyvertransfer, added address change 78 | - V2.6: Small fixes 79 | 80 | 81 | ## bugs and feedback 82 | Create ** Issue ** when you find the bugs, and better immediately write to the mail [alex@alexgyver.ru] (mailto: alex@alexgyver.ru) 83 | The library is open for refinement and your ** pull Request ** 'ow! 84 | 85 | 86 | When reporting about bugs or incorrect work of the library, it is necessary to indicate: 87 | - The version of the library 88 | - What is MK used 89 | - SDK version (for ESP) 90 | - version of Arduino ide 91 | - whether the built -in examples work correctly, in which the functions and designs are used, leading to a bug in your code 92 | - what code has been loaded, what work was expected from it and how it works in reality 93 | - Ideally, attach the minimum code in which the bug is observed.Not a canvas of a thousand lines, but a minimum code -------------------------------------------------------------------------------- /examples/GBUSmini-GBUSmini/call response/simple_call_response_rx/simple_call_response_rx.ino: -------------------------------------------------------------------------------- 1 | // принимаем запрос и отправляем в ответ данные с АЦП 2 | 3 | #define RX_PIN 4 // пин 4 | #define RX_ADDR 3 // наш адрес 5 | #include "GBUSmini.h" // мини-библиотека с лёгкими функциями 6 | 7 | void setup() { 8 | Serial.begin(9600); 9 | } 10 | 11 | void loop() { 12 | // ждём приём на адрес RX_ADDR, т.е. наш адрес RX_ADDR 13 | byte txaddr = GBUS_read_request(RX_PIN, RX_ADDR); 14 | if (txaddr) { 15 | // если успешно приняли 16 | // например читаем АЦП 17 | int val = analogRead(0); 18 | 19 | Serial.print("sending "); 20 | Serial.println(val); 21 | 22 | // разбиваем на байты 23 | byte b1 = lowByte(val); 24 | byte b2 = highByte(val); 25 | byte buf[] = {b1, b2}; 26 | 27 | // отправляем обратно (по txaddr) 28 | // с нашего адреса (RX_ADDR) 29 | // c контролем целостности данных 30 | GBUS_send(RX_PIN, txaddr, RX_ADDR, buf, sizeof(buf)); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examples/GBUSmini-GBUSmini/call response/simple_call_response_tx/simple_call_response_tx.ino: -------------------------------------------------------------------------------- 1 | // отправляем запрос и в ответ ждём данные с АЦП 2 | 3 | #define TX_PIN 4 // пин 4 | #define RX_ADDR 3 // адрес приёмника 5 | #define TX_ADDR 5 // наш адрес 6 | #include "GBUSmini.h" // мини-библиотека с лёгкими функциями 7 | 8 | byte buf[2]; 9 | 10 | void setup() { 11 | Serial.begin(9600); 12 | } 13 | 14 | void loop() { 15 | // отправляем запрос каждые три секунды 16 | static uint32_t tmr; 17 | if (millis() - tmr > 3000) { 18 | tmr = millis(); 19 | GBUS_send_request(TX_PIN, RX_ADDR, TX_ADDR); 20 | } 21 | 22 | if (GBUS_read(TX_PIN, TX_ADDR, buf, sizeof(buf))) { 23 | // склеиваем байты обратно в инт 24 | int val = buf[0] | (buf[1] << 8); 25 | Serial.print("received "); 26 | Serial.println(val); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /examples/GBUSmini-GBUSmini/call response_ack/simple_call_response_rx/simple_call_response_rx.ino: -------------------------------------------------------------------------------- 1 | // принимаем запрос и отправляем в ответ данные с АЦП 2 | 3 | #define RX_PIN 4 // пин 4 | #define RX_ADDR 3 // наш адрес 5 | #include "GBUSmini.h" // мини-библиотека с лёгкими функциями 6 | 7 | void setup() { 8 | Serial.begin(9600); 9 | } 10 | 11 | void loop() { 12 | // ждём приём на адрес RX_ADDR, т.е. наш адрес RX_ADDR 13 | byte txaddr = GBUS_read_request(RX_PIN, RX_ADDR); 14 | if (txaddr) { 15 | Serial.print("got request from "); 16 | Serial.println(txaddr); 17 | GBUS_send_ack(RX_PIN, txaddr, RX_ADDR); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/GBUSmini-GBUSmini/call response_ack/simple_call_response_tx/simple_call_response_tx.ino: -------------------------------------------------------------------------------- 1 | // отправляем запрос с подтверждением 2 | 3 | #define TX_PIN 4 // пин 4 | #define RX_ADDR 3 // адрес приёмника 5 | #define TX_ADDR 5 // наш адрес 6 | #include "GBUSmini.h" // мини-библиотека с лёгкими функциями 7 | 8 | void setup() { 9 | Serial.begin(9600); 10 | } 11 | 12 | void loop() { 13 | // отправляем запрос каждые три секунды 14 | static uint32_t tmr; 15 | if (millis() - tmr > 3000) { 16 | tmr = millis(); 17 | // отправлять запросы и ждать подтверждения приёма, т.е. пытаться достучаться 18 | // (пин, адрес получателя, адрес отправителя, кол-во попыток, таймаут между попытками) 19 | if (GBUS_send_request_ack(TX_PIN, RX_ADDR, TX_ADDR, 3, 500)) { 20 | Serial.println("got ack"); 21 | } else { 22 | Serial.println("error"); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/GBUSmini-GBUSmini/data/read/read.ino: -------------------------------------------------------------------------------- 1 | // простой пример приёма данных 2 | #include "GBUSmini.h" // мини-библиотека с лёгкими функциями 3 | 4 | #define RX_PIN 4 // пин 5 | #define RX_ADDR 3 // наш адрес 6 | byte data[6]; // приёмный буфер (байты) 7 | 8 | void setup() { 9 | Serial.begin(9600); 10 | 11 | // ПИН ОБЯЗАТЕЛЬНО PULLUP!!!111 12 | pinMode(RX_PIN, INPUT_PULLUP); 13 | } 14 | 15 | void loop() { 16 | // ждём приём, если функция вернула отличное от 0 значение 17 | if (GBUS_read(RX_PIN, RX_ADDR, data, sizeof(data))) { 18 | // если успешно приняли 19 | for (byte i = 0; i < sizeof(data); i++) { 20 | Serial.print(data[i]); 21 | Serial.print(", "); 22 | } 23 | Serial.println(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/GBUSmini-GBUSmini/data/send/send.ino: -------------------------------------------------------------------------------- 1 | // простая функция отправки по GBUS 2 | #include "GBUSmini.h" // мини-библиотека с лёгкими функциями 3 | 4 | #define TX_PIN 4 // пин 5 | #define RX_ADDR 3 // адрес приёмника 6 | #define TX_ADDR 5 // наш адрес 7 | 8 | void setup() { 9 | // ПИН ОБЯЗАТЕЛЬНО PULLUP!!!111 10 | pinMode(TX_PIN, INPUT_PULLUP); 11 | } 12 | 13 | // отправляемая дата (байты) 14 | byte data[] = {12, 34, 56}; 15 | 16 | void loop() { 17 | // пин, адрес получателя, адрес отправителя, дата, размер 18 | GBUS_send(TX_PIN, RX_ADDR, TX_ADDR, data, sizeof(data)); 19 | delay(1000); 20 | } 21 | -------------------------------------------------------------------------------- /examples/GBUSmini-GBUSmini/pack data/read/read.ino: -------------------------------------------------------------------------------- 1 | // принимаем и распаковываем отправленные в примере packData_mini_send данные 2 | 3 | #include "GBUSmini.h" // мини-библиотека с лёгкими функциями 4 | 5 | #define RX_PIN 4 // пин 6 | #define RX_ADDR 3 // наш адрес 7 | 8 | // структура для приёма 9 | struct myStruct { 10 | byte val_b; 11 | int val_i; 12 | float val_f; 13 | }; 14 | myStruct rxData; // приёмная структура 15 | byte buffer[sizeof(rxData)]; // приёмный буфер 16 | 17 | void setup() { 18 | Serial.begin(9600); 19 | 20 | // ПИН ОБЯЗАТЕЛЬНО PULLUP!!!111 21 | pinMode(RX_PIN, INPUT_PULLUP); 22 | } 23 | 24 | void loop() { 25 | if (GBUS_read(RX_PIN, RX_ADDR, buffer, sizeof(buffer))) { 26 | // если успешно приняли, распаковываем 27 | unpackDataBytes(buffer, rxData); 28 | 29 | // выводим проверяем 30 | Serial.println(rxData.val_b); 31 | Serial.println(rxData.val_i); 32 | Serial.println(rxData.val_f); 33 | Serial.println(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /examples/GBUSmini-GBUSmini/pack data/send/send.ino: -------------------------------------------------------------------------------- 1 | // пакуем данные любого типа (например, структура) в буфер и отправляем 2 | // принимаем и распаковываем в примере packData_mini_read 3 | 4 | #include "GBUSmini.h" // мини-библиотека с лёгкими функциями 5 | 6 | #define TX_PIN 4 // пин 7 | #define RX_ADDR 3 // адрес приёмника 8 | #define TX_ADDR 5 // наш адрес 9 | 10 | // структура для отправки 11 | struct myStruct { 12 | byte val_b; 13 | int val_i; 14 | float val_f; 15 | }; 16 | myStruct txData; // отправная структура 17 | byte buffer[sizeof(txData)]; // отправной буфер 18 | 19 | void setup() { 20 | // ПИН ОБЯЗАТЕЛЬНО PULLUP!!!111 21 | pinMode(TX_PIN, INPUT_PULLUP); 22 | 23 | // заполняем структуру 24 | txData.val_b = 123; 25 | txData.val_i = -23456; 26 | txData.val_f = 3.14; 27 | 28 | // пакуем структуру в буфер 29 | packDataBytes(buffer, txData); 30 | } 31 | 32 | void loop() { 33 | // пин, адрес получателя, адрес отправителя, дата, размер 34 | GBUS_send(TX_PIN, RX_ADDR, TX_ADDR, buffer, sizeof(buffer)); 35 | delay(2000); 36 | } 37 | -------------------------------------------------------------------------------- /examples/GBUSmini-GBUSmini/raw/read/read.ino: -------------------------------------------------------------------------------- 1 | // простой пример приёма сырых данных и их разбор вручную 2 | #include "GBUSmini.h" // мини-библиотека с лёгкими функциями 3 | 4 | #define RX_PIN 4 // пин 5 | byte data[10]; // приёмный буфер (байты) 6 | // МИНИМУМ НА 4 БАЙТА БОЛЬШЕ, ЧЕМ ОЖИДАЕМАЯ ДАТА 7 | 8 | void setup() { 9 | Serial.begin(9600); 10 | 11 | // ПИН ОБЯЗАТЕЛЬНО PULLUP!!!111 12 | pinMode(RX_PIN, INPUT_PULLUP); 13 | } 14 | 15 | void loop() { 16 | // ждём приём 17 | if (GBUS_read_raw(RX_PIN, data, sizeof(data))) { 18 | // если успешно приняли, выводим 19 | for (byte i = 0; i < sizeof(data); i++) { 20 | Serial.print(data[i]); 21 | Serial.print(", "); 22 | } 23 | Serial.println(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/GBUSmini-GBUSmini/raw/send/send.ino: -------------------------------------------------------------------------------- 1 | // простая функция отправки по GBUS с контролем целостности данных 2 | #include "GBUSmini.h" // мини-библиотека с лёгкими функциями 3 | 4 | #define TX_PIN 4 // пин 5 | 6 | void setup() { 7 | // ПИН ОБЯЗАТЕЛЬНО PULLUP!!!111 8 | pinMode(TX_PIN, INPUT_PULLUP); 9 | } 10 | 11 | // отправляемая дата (байты) 12 | byte data[] = {12, 34, 56}; 13 | 14 | void loop() { 15 | GBUS_send_raw(TX_PIN, data, sizeof(data)); 16 | delay(1000); 17 | } 18 | -------------------------------------------------------------------------------- /examples/GBUSmini-GBUSmini/request/read/read.ino: -------------------------------------------------------------------------------- 1 | // принимаем реквест 2 | #include "GBUSmini.h" // мини-библиотека с лёгкими функциями 3 | 4 | #define RX_PIN 4 // пин 5 | #define RX_ADDR 3 // наш адрес 6 | 7 | void setup() { 8 | Serial.begin(9600); 9 | 10 | // ПИН ОБЯЗАТЕЛЬНО PULLUP!!!111 11 | pinMode(RX_PIN, INPUT_PULLUP); 12 | } 13 | 14 | void loop() { 15 | // ждём приём, ловим адрес 16 | byte txaddr = GBUS_read_request(RX_PIN, RX_ADDR); 17 | if (txaddr) { 18 | Serial.print("Request from "); 19 | Serial.println(txaddr); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /examples/GBUSmini-GBUSmini/request/send/send.ino: -------------------------------------------------------------------------------- 1 | // отправляем реквест 2 | #include "GBUSmini.h" // мини-библиотека с лёгкими функциями 3 | 4 | #define TX_PIN 4 // пин 5 | #define RX_ADDR 3 // адрес приёмника 6 | #define TX_ADDR 5 // наш адрес 7 | 8 | void setup() { 9 | // ПИН ОБЯЗАТЕЛЬНО PULLUP!!!111 10 | pinMode(TX_PIN, INPUT_PULLUP); 11 | } 12 | 13 | void loop() { 14 | // пин, адрес получателя, адрес отправителя, дата, размер 15 | GBUS_send_request(TX_PIN, RX_ADDR, TX_ADDR); 16 | delay(1000); 17 | } 18 | -------------------------------------------------------------------------------- /examples/GBUSmini-GBUSmini/общение ардуин через GBUSmini.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GyverLibs/GyverBus/31816306d5a7b5e1fcb97faa955a35de80b359b9/examples/GBUSmini-GBUSmini/общение ардуин через GBUSmini.txt -------------------------------------------------------------------------------- /examples/GBUSmini-softuart/data/rx-softuart/rx-softuart.ino: -------------------------------------------------------------------------------- 1 | // принимаем данные от gbus mini 2 | 3 | // подключаем софт юарт 4 | #include "softUART.h" 5 | softUART<4> UART(1000); // пин 4, скорость 1000 6 | 7 | // подключаем GBUS 8 | #include "GBUS.h" 9 | GBUS bus(&UART, 3, 20); // обработчик UART, адрес 3, буфер 20 байт 10 | 11 | // структура для приёма 12 | struct myStruct { 13 | byte val_b; 14 | int val_i; 15 | float val_f; 16 | }; 17 | 18 | void setup() { 19 | Serial.begin(9600); // сериал для отладки (вывод в монитор) 20 | } 21 | 22 | void loop() { 23 | // в тике сидит отправка и приём 24 | bus.tick(); 25 | 26 | if (bus.gotData()) { 27 | myStruct rxData; 28 | bus.readData(rxData); 29 | Serial.println(rxData.val_b); 30 | Serial.println(rxData.val_i); 31 | Serial.println(rxData.val_f); 32 | Serial.println(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /examples/GBUSmini-softuart/data/tx-gbusmini/tx-gbusmini.ino: -------------------------------------------------------------------------------- 1 | // пакуем данные любого типа (например, структура) в буфер и отправляем 2 | // принимаем на softuart (под GBUS) и распаковываем 3 | #define GBUS_SPEED 1000 4 | #include "GBUSmini.h" // мини-библиотека с лёгкими функциями 5 | 6 | #define TX_PIN 4 // пин 7 | #define RX_ADDR 3 // адрес приёмника 8 | #define TX_ADDR 5 // наш адрес 9 | 10 | // структура для отправки 11 | struct myStruct { 12 | byte val_b; 13 | int val_i; 14 | float val_f; 15 | }; 16 | myStruct txData; // отправная структура 17 | byte buffer[sizeof(txData)]; // отправной буфер 18 | 19 | void setup() { 20 | // ПИН ОБЯЗАТЕЛЬНО PULLUP!!!111 21 | pinMode(TX_PIN, INPUT_PULLUP); 22 | 23 | // заполняем структуру 24 | txData.val_b = 123; 25 | txData.val_i = -23456; 26 | txData.val_f = 3.14; 27 | 28 | // пакуем структуру в буфер 29 | packDataBytes(buffer, txData); 30 | } 31 | 32 | void loop() { 33 | // пин, адрес получателя, адрес отправителя, дата, размер 34 | GBUS_send(TX_PIN, RX_ADDR, TX_ADDR, buffer, sizeof(buffer)); 35 | delay(2000); 36 | } 37 | -------------------------------------------------------------------------------- /examples/GBUSmini-softuart/общение ардуин через softuart и GBUSmini.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GyverLibs/GyverBus/31816306d5a7b5e1fcb97faa955a35de80b359b9/examples/GBUSmini-softuart/общение ардуин через softuart и GBUSmini.txt -------------------------------------------------------------------------------- /examples/broadcast/broadcast.ino: -------------------------------------------------------------------------------- 1 | // отправка данных всем устройствам на шине 2 | 3 | // подключаем софт юарт 4 | #include "softUART.h" 5 | // делаем только отправителем (экономит память) 6 | softUART<4, GBUS_TX> UART(1000); // пин 4, скорость 1000 7 | 8 | // подключаем GBUS 9 | #include "GBUS.h" 10 | GBUS bus(&UART, 3, 20); // обработчик UART, адрес 3, буфер 20 байт 11 | 12 | struct myStruct { 13 | byte val_b; 14 | int val_i; 15 | long val_l; 16 | float val_f; 17 | }; 18 | 19 | void setup() { 20 | } 21 | 22 | void loop() { 23 | // в тике сидит отправка и приём 24 | bus.tick(); 25 | 26 | static uint32_t tmr; 27 | if (millis() - tmr >= 2000) { 28 | tmr = millis(); 29 | // отправляем каждые 2 секунды 30 | myStruct data; 31 | data.val_b = 12; 32 | data.val_i = 1234; 33 | data.val_l = 123456; 34 | data.val_f = 123.45678; 35 | // просто отправляем на адрес 255 (константа GBUS_BROADCAST) 36 | bus.sendData(GBUS_BROADCAST, data); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /examples/checkStatus/checkStatus.ino: -------------------------------------------------------------------------------- 1 | // приём сырых данных по однопроводному юарту 2 | 3 | // подключаем софт юарт 4 | #include "softUART.h" 5 | softUART<4> UART(1000); // пин 4, скорость 1000 6 | 7 | // подключаем GBUS 8 | #include "GBUS.h" 9 | GBUS bus(&UART, 5, 20); // обработчик UART, адрес 5, буфер 20 байт 10 | 11 | void setup() { 12 | Serial.begin(9600); // сериал для отладки (вывод в монитор) 13 | } 14 | 15 | void loop() { 16 | bus.tick(); // тикаем 17 | if (bus.statusChanged()) { // если статус изменился 18 | Serial.println(bus.getStatus()); // выводим код 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /examples/esp8266 to ardu (softserial)/read/read.ino: -------------------------------------------------------------------------------- 1 | // принимаем структуру через SoftwareSerial 2 | // отправляет esp8266, принимает Ардуина (этот скетч) 3 | // здесь провод подключен к ноге RX софт сериала 4 | // Провод подключен к D2 ноды и D10 Ардуины 5 | 6 | #include 7 | SoftwareSerial mySerial(10, 11); // RX, TX 8 | // сначала объявляем обработчик 9 | // это может почти быть любая интерфейсная либа, 10 | // например софтСериал на любой другой платформе 11 | 12 | #include "GBUS.h" 13 | GBUS bus(&mySerial, 3, 25); // адрес 3, буфер 25 байт 14 | 15 | // приёмная структура 16 | // структура структур должна быть одинаковая 17 | struct myStruct { 18 | float val_f; 19 | float val_f2; 20 | long val_i; // а тут long, иначе всё сломается 21 | long val_l; 22 | byte val_b; 23 | }; 24 | 25 | void setup() { 26 | // родной сериал открываю для наблюдения за процессом 27 | Serial.begin(9600); 28 | 29 | // этот сериал будет принимать данные 30 | // мы указали его как обработчик 31 | mySerial.begin(9600); 32 | } 33 | 34 | void loop() { 35 | // здесь принимаются данные 36 | // если это аппаратный сериал - слишком часто его опрашивать даже не нужно 37 | bus.tick(); 38 | 39 | // приняли данные 40 | if (bus.gotData()) { 41 | myStruct data; 42 | bus.readData(data); 43 | 44 | // выводим 45 | Serial.println(data.val_f); 46 | Serial.println(data.val_f2); 47 | Serial.println(data.val_i); 48 | Serial.println(data.val_l); 49 | Serial.println(data.val_b); 50 | Serial.println(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /examples/esp8266 to ardu (softserial)/send/send.ino: -------------------------------------------------------------------------------- 1 | // отправляем структуру через SoftwareSerial 2 | // отправляет esp8266 (этот скетч), принимает Ардуина 3 | // Провод подключен к D2 ноды и D10 Ардуины 4 | 5 | #include 6 | SoftwareSerial mySerial(5, 4); // RX, TX 7 | // ВНИМАНИЕ! Нужно указывать номера GPIO, а не D-пины 8 | // на Node получается RX-D1, TX-D2 9 | 10 | #include "GBUS.h" 11 | 12 | // адрес 5, буфер 20 байт 13 | GBUS bus(&mySerial, 5, 20); 14 | 15 | // структура для отправки 16 | // БУДЬ ВНИМАТЕЛЕН, ЛЮБИТЕЛЬ ESP8266!! 17 | // Тут данные кодируются хрен пойми как, компилятор "не смог" 18 | // сначала располагай тяжёлые типы данных (float, int, long) 19 | // РАСПОЛАГАЙ БАЙТЫ В КОНЦЕ СТРУКТУРЫ! 20 | // int тут занимает 4 байта, так что на Arduino его нужно принимать как long!!! 21 | // структура структур должна быть одинаковая 22 | struct myStruct { 23 | float val_f; 24 | float val_f2; 25 | int val_i; 26 | long val_l; 27 | byte val_b; 28 | }; 29 | 30 | void setup() { 31 | // родной сериал открываю для наблюдения за процессом 32 | Serial.begin(9600); 33 | // этот сериал будет принимать данные 34 | // мы указали его как обработчик 35 | mySerial.begin(9600); 36 | } 37 | 38 | void loop() { 39 | Serial.println("transmitting"); 40 | myStruct data; 41 | // забиваем данные 42 | data.val_f = 12.34; 43 | data.val_f2 = 56.78; 44 | data.val_i = 1234; 45 | data.val_l = 123456; 46 | data.val_b = 12; 47 | // отправляем на адрес 3 48 | bus.sendData(3, data); 49 | delay(2000); 50 | 51 | // tick() тут не нужен! Он занимается только приёмом данных 52 | // отправка делается так, как реализовано в используемой либе интерфейса 53 | } 54 | -------------------------------------------------------------------------------- /examples/gyvertransfer-gyvertransfer/read_request/read_request.ino: -------------------------------------------------------------------------------- 1 | // принимаем запрос через GyverTransfer 2 | #define GT_STREAM_MODE // STREAM_MODE нужен для работы GBUS 3 | #include 4 | GyverTransfer<2, GT_TRX> trans; 5 | 6 | #include "GBUS.h" 7 | GBUS bus(&trans, 3, 20); // адрес 3, буфер 20 байт 8 | 9 | void setup() { 10 | Serial.begin(9600); 11 | // прерывания по CHANGE для приёма 12 | attachInterrupt(0, isr, CHANGE); 13 | } 14 | 15 | // GyverTransfer читает в прерывании 16 | void isr() { 17 | trans.tickISR(); 18 | } 19 | 20 | void loop() { 21 | bus.tick(); 22 | 23 | // приняли данные 24 | if (bus.gotRequest()) { 25 | Serial.print("request from: "); 26 | Serial.println(bus.getTXaddress()); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /examples/gyvertransfer-gyvertransfer/send_request/send_request.ino: -------------------------------------------------------------------------------- 1 | // отправляем запрос через GyverTransfer 2 | #define GT_STREAM_MODE // STREAM_MODE нужен для работы GBUS 3 | #include 4 | GyverTransfer<2, GT_TRX> trans; 5 | 6 | #include "GBUS.h" 7 | GBUS bus(&trans, 5, 20); // адрес 5, буфер 20 байт 8 | 9 | void setup() { 10 | Serial.begin(9600); 11 | } 12 | 13 | void loop() { 14 | // отправляем на адрес 3 15 | Serial.print("request to: "); 16 | Serial.println(3); 17 | bus.sendRequest(3); 18 | delay(2000); 19 | 20 | // tick() тут не нужен! Он занимается только приёмом данных 21 | // отправка делается так, как реализовано в используемой либе интерфейса 22 | } 23 | -------------------------------------------------------------------------------- /examples/gyvertransfer-gyvertransfer/simple_call_response_rx/simple_call_response_rx.ino: -------------------------------------------------------------------------------- 1 | // принимаем запрос и отправляем в ответ данные с АЦП 2 | 3 | #define GT_STREAM_MODE // STREAM_MODE нужен для работы GBUS 4 | #include 5 | GyverTransfer<2, GT_TRX> trans; 6 | 7 | #include "GBUS.h" 8 | GBUS bus(&trans, 3, 20); // адрес 3, буфер 20 байт 9 | 10 | void setup() { 11 | Serial.begin(9600); 12 | // прерывания по CHANGE для приёма 13 | attachInterrupt(0, isr, CHANGE); 14 | } 15 | 16 | // GyverTransfer читает в прерывании 17 | void isr() { 18 | trans.tickISR(); 19 | } 20 | 21 | void loop() { 22 | // здесь принимаются данные 23 | // если это аппаратный сериал - слишком часто его опрашивать даже не нужно 24 | bus.tick(); 25 | 26 | // приняли данные 27 | if (bus.gotRequest()) { 28 | Serial.print("request from: "); 29 | Serial.println(bus.getTXaddress()); 30 | 31 | // ответили 32 | //bus.sendAck(bus.getTXaddress()); 33 | 34 | // ИЛИ отправили дату (случайный байт) в ответ 35 | byte data = random(255); 36 | Serial.print("sending: "); 37 | Serial.println(data); 38 | bus.sendData(bus.getTXaddress(), data); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /examples/gyvertransfer-gyvertransfer/simple_call_response_tx/simple_call_response_tx.ino: -------------------------------------------------------------------------------- 1 | // отправляем запрос с подтверждением 2 | 3 | #define GT_STREAM_MODE // STREAM_MODE нужен для работы GBUS 4 | #include 5 | GyverTransfer<2, GT_TRX> trans; 6 | 7 | #include "GBUS.h" 8 | GBUS bus(&trans, 5, 20); // адрес 5, буфер 20 байт 9 | 10 | void setup() { 11 | Serial.begin(9600); 12 | // прерывания по CHANGE для приёма 13 | attachInterrupt(0, isr, CHANGE); 14 | } 15 | 16 | // GyverTransfer читает в прерывании 17 | void isr() { 18 | trans.tickISR(); 19 | } 20 | 21 | void loop() { 22 | // здесь принимаются данные 23 | // если это аппаратный сериал - слишком часто его опрашивать даже не нужно 24 | bus.tick(); 25 | 26 | // отправляем запрос на адрес 3 каждые 5 секунд 27 | static uint32_t tmr; 28 | if (millis() - tmr > 5000) { 29 | tmr = millis(); 30 | Serial.println("send request"); 31 | bus.sendRequest(3); 32 | } 33 | 34 | // ждём ответа от 3 35 | // пытаемся достучаться через таймаут 500мс 3 раза 36 | byte state = bus.waitAck(3, 3, 500); 37 | switch (state) { 38 | case ACK_IDLE: //Serial.println("idle"); 39 | break; 40 | case ACK_WAIT: //Serial.println("wait"); 41 | break; 42 | case ACK_ERROR: Serial.println("ack error"); 43 | break; 44 | case ACK_ONLY: Serial.println("got ack"); 45 | break; 46 | case ACK_DATA: Serial.print("got data: "); 47 | // читаем и выводим 48 | byte val; 49 | bus.readData(val); 50 | Serial.println(val); 51 | break; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /examples/gyvertransfer-gyvertransfer/общение ардуин через gyvertransfer.txt: -------------------------------------------------------------------------------- 1 | GyverTransfer - ещё один Stream интерфейс, через который можно общаться по GBUS 2 | - Однопроводной интерфейс связи 3 | - Самосинхронизирующийся 4 | - Полностью асинхронный приём в прерывании по CHANGE 5 | - Лёгкий и надёжный 6 | https://github.com/GyverLibs/GyverTransfer -------------------------------------------------------------------------------- /examples/softserial-serial/array/read_array/read_array.ino: -------------------------------------------------------------------------------- 1 | // принимаем массив байт через SoftwareSerial 2 | // здесь провод подключен к ноге RX софт сериала 3 | // у меня настроено на D10 4 | 5 | #include 6 | SoftwareSerial mySerial(10, 11); // RX, TX 7 | // сначала объявляем обработчик 8 | // это может почти быть любая интерфейсная либа, 9 | // например софтСериал на любой другой платформе 10 | 11 | #include "GBUS.h" 12 | GBUS bus(&mySerial, 3, 20); // адрес 3, буфер 20 байт 13 | 14 | void setup() { 15 | // родной сериал открываю для наблюдения за процессом 16 | Serial.begin(9600); 17 | 18 | // этот сериал будет принимать данные 19 | mySerial.begin(9600); 20 | } 21 | 22 | void loop() { 23 | // здесь принимаются данные 24 | // если это аппаратный сериал - слишком часто его опрашивать даже не нужно 25 | bus.tick(); 26 | 27 | // приняли данные 28 | if (bus.gotData()) { 29 | byte data[11]; 30 | // читаем в свой массив 31 | bus.readData(data); 32 | 33 | // выводим смотрим 34 | for (byte i = 0; i < sizeof(data); i++) { 35 | Serial.print(data[i]); 36 | Serial.print(','); 37 | } 38 | Serial.println(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /examples/softserial-serial/array/send_array/send_array.ino: -------------------------------------------------------------------------------- 1 | // отправляем массив байт через Serial 2 | // здесь провод подключен к ноге TX (D1) 3 | 4 | #include "GBUS.h" 5 | 6 | // адрес 5, буфер 20 байт 7 | GBUS bus(&Serial, 5, 20); 8 | 9 | void setup() { 10 | // запускаем интерфейс 11 | Serial.begin(9600); 12 | } 13 | 14 | void loop() { 15 | // отправляем на адрес 3 16 | byte data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; 17 | bus.sendData(3, data); 18 | delay(2000); 19 | 20 | // tick() тут не нужен! Он занимается только приёмом данных 21 | // отправка делается так, как реализовано в используемой либе интерфейса 22 | } 23 | -------------------------------------------------------------------------------- /examples/softserial-serial/request/read_request/read_request.ino: -------------------------------------------------------------------------------- 1 | // принимаем запрос через SoftwareSerial 2 | // здесь провод подключен к ноге RX софт сериала 3 | // у меня настроено на D10 4 | 5 | #include 6 | SoftwareSerial mySerial(10, 11); // RX, TX 7 | // сначала объявляем обработчик 8 | // это может почти быть любая интерфейсная либа, 9 | // например софтСериал на любой другой платформе 10 | 11 | #include "GBUS.h" 12 | GBUS bus(&mySerial, 3, 20); // адрес 3, буфер 10 байт 13 | 14 | void setup() { 15 | // родной сериал открываю для наблюдения за процессом 16 | Serial.begin(9600); 17 | 18 | // этот сериал будет принимать данные 19 | mySerial.begin(9600); 20 | } 21 | 22 | void loop() { 23 | // здесь принимаются данные 24 | // если это аппаратный сериал - слишком часто его опрашивать даже не нужно 25 | bus.tick(); 26 | 27 | // приняли данные 28 | if (bus.gotRequest()) { 29 | Serial.print("request from: "); 30 | Serial.println(bus.getTXaddress()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examples/softserial-serial/request/send_request/send_request.ino: -------------------------------------------------------------------------------- 1 | // отправляем запрос через Serial 2 | // здесь провод подключен к ноге TX (D1) 3 | 4 | #include "GBUS.h" 5 | 6 | // адрес 5, буфер 20 байт 7 | GBUS bus(&Serial, 5, 20); 8 | 9 | void setup() { 10 | // запускаем интерфейс 11 | Serial.begin(9600); 12 | } 13 | 14 | void loop() { 15 | // отправляем на адрес 3 16 | bus.sendRequest(3); 17 | delay(2000); 18 | 19 | // tick() тут не нужен! Он занимается только приёмом данных 20 | // отправка делается так, как реализовано в используемой либе интерфейса 21 | } 22 | -------------------------------------------------------------------------------- /examples/softserial-serial/struct/read_struct/read_struct.ino: -------------------------------------------------------------------------------- 1 | // принимаем структуру через SoftwareSerial 2 | // здесь провод подключен к ноге RX софт сериала 3 | // у меня настроено на D10 4 | 5 | #include 6 | SoftwareSerial mySerial(10, 11); // RX, TX 7 | // сначала объявляем обработчик 8 | // это может почти быть любая интерфейсная либа, 9 | // например софтСериал на любой другой платформе 10 | 11 | #include "GBUS.h" 12 | 13 | GBUS bus(&mySerial, 3, 20); // адрес 3, буфер 10 байт 14 | 15 | // приёмная структура 16 | struct myStruct { 17 | byte val_b; 18 | int val_i; 19 | long val_l; 20 | float val_f; 21 | }; 22 | 23 | void setup() { 24 | // родной сериал открываю для наблюдения за процессом 25 | Serial.begin(9600); 26 | 27 | // этот сериал будет принимать данные 28 | // мы указали его как обработчик 29 | mySerial.begin(9600); 30 | } 31 | 32 | void loop() { 33 | // здесь принимаются данные 34 | // если это аппаратный сериал - слишком часто его опрашивать даже не нужно 35 | bus.tick(); 36 | 37 | // приняли данные 38 | if (bus.gotData()) { 39 | myStruct data; 40 | bus.readData(data); 41 | 42 | // выводим 43 | Serial.println(data.val_b); 44 | Serial.println(data.val_i); 45 | Serial.println(data.val_l); 46 | Serial.println(data.val_f); 47 | Serial.println(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /examples/softserial-serial/struct/send_struct/send_struct.ino: -------------------------------------------------------------------------------- 1 | // отправляем структуру через Serial 2 | // здесь провод подключен к ноге TX (D1) 3 | 4 | #include "GBUS.h" 5 | // адрес 5, буфер 20 байт 6 | GBUS bus(&Serial, 5, 20); 7 | 8 | // структура для отправки 9 | struct myStruct { 10 | byte val_b; 11 | int val_i; 12 | long val_l; 13 | float val_f; 14 | }; 15 | 16 | void setup() { 17 | // запускаем интерфейс 18 | Serial.begin(9600); 19 | } 20 | 21 | void loop() { 22 | myStruct data; 23 | data.val_b = 12; 24 | data.val_i = 1234; 25 | data.val_l = 123456; 26 | data.val_f = 123.45678; 27 | 28 | // отправляем на адрес 3 29 | bus.sendData(3, data); 30 | delay(2000); 31 | 32 | // tick() тут не нужен! Он занимается только приёмом данных 33 | // отправка делается так, как реализовано в используемой либе интерфейса 34 | } 35 | -------------------------------------------------------------------------------- /examples/softserial-serial/общение ардуин через softserial и serial.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GyverLibs/GyverBus/31816306d5a7b5e1fcb97faa955a35de80b359b9/examples/softserial-serial/общение ардуин через softserial и serial.txt -------------------------------------------------------------------------------- /examples/softserial-softserial/ack_RX/ack_RX.ino: -------------------------------------------------------------------------------- 1 | // принимаем запрос через SoftwareSerial 2 | // отвечаем на запрос 3 | // связь двухсторонняя!!!! Это скетч ПРИЁМНИКА 4 | // TX передатчика подключен к RX приёмника 5 | // RX передатчика подключен к TX приёмника 6 | 7 | #include 8 | SoftwareSerial mySerial(10, 11); // RX, TX 9 | // сначала объявляем обработчик 10 | // это может почти быть любая интерфейсная либа, 11 | // например софтСериал на любой другой платформе 12 | 13 | // указываем "обработчик" интерфейса перед подключением библиотеки 14 | #include "GBUS.h" 15 | 16 | GBUS bus(&mySerial, 3, 5); // адрес 3, буфер 5 байт 17 | 18 | void setup() { 19 | // родной сериал открываю для наблюдения за процессом 20 | Serial.begin(9600); 21 | 22 | // этот сериал будет принимать и отправлять данные 23 | mySerial.begin(9600); 24 | } 25 | 26 | void loop() { 27 | // здесь принимаются данные 28 | // если это аппаратный сериал - слишком часто его опрашивать даже не нужно 29 | bus.tick(); 30 | 31 | // приняли данные 32 | if (bus.gotRequest()) { 33 | Serial.print("request from: "); 34 | Serial.println(bus.getTXaddress()); 35 | 36 | // ответили 37 | //bus.sendAck(bus.getTXaddress()); 38 | 39 | // ИЛИ отправили дату (случайный байт) в ответ 40 | byte data = random(255); 41 | Serial.print("sending: "); 42 | Serial.println(data); 43 | bus.sendData(bus.getTXaddress(), data); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /examples/softserial-softserial/ack_TX/ack_TX.ino: -------------------------------------------------------------------------------- 1 | // отправляем запрос через SoftwareSerial 2 | // ожидаем ответа 3 | // связь двухсторонняя!!!! Это скетч ПЕРЕДАТЧИКА 4 | // TX передатчика подключен к RX приёмника 5 | // RX передатчика подключен к TX приёмника 6 | 7 | #include 8 | SoftwareSerial mySerial(10, 11); // RX, TX 9 | // сначала объявляем обработчик 10 | // это может почти быть любая интерфейсная либа, 11 | // например софтСериал на любой другой платформе 12 | 13 | // указываем "обработчик" интерфейса перед подключением библиотеки 14 | #include "GBUS.h" 15 | 16 | // адрес 5, буфер 5 байт, скорость 9600 бод 17 | GBUS bus(&mySerial, 5, 5); 18 | 19 | void setup() { 20 | // родной сериал открываю для наблюдения за процессом 21 | Serial.begin(9600); 22 | 23 | // этот сериал будет принимать и отправлять данные 24 | mySerial.begin(9600); 25 | } 26 | 27 | void loop() { 28 | // здесь принимаются данные 29 | // если это аппаратный сериал - слишком часто его опрашивать даже не нужно 30 | bus.tick(); 31 | 32 | // отправляем запрос на адрес 3 каждые 5 секунд 33 | static uint32_t tmr; 34 | if (millis() - tmr > 5000) { 35 | tmr = millis(); 36 | Serial.println("send request"); 37 | bus.sendRequest(3); 38 | } 39 | 40 | // ждём ответа от 3 41 | // пытаемся достучаться через таймаут 500мс 3 раза 42 | byte state = bus.waitAck(3, 3, 500); 43 | switch (state) { 44 | case ACK_IDLE: //Serial.println("idle"); 45 | break; 46 | case ACK_WAIT: //Serial.println("wait"); 47 | break; 48 | case ACK_ERROR: Serial.println("ack error"); 49 | break; 50 | case ACK_ONLY: Serial.println("got ack"); 51 | break; 52 | case ACK_DATA: Serial.print("got data: "); 53 | // читаем и выводим 54 | byte val; 55 | bus.readData(val); 56 | Serial.println(val); 57 | break; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /examples/softserial-softserial/общение ардуин через softserial.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GyverLibs/GyverBus/31816306d5a7b5e1fcb97faa955a35de80b359b9/examples/softserial-softserial/общение ардуин через softserial.txt -------------------------------------------------------------------------------- /examples/softuart-softuart/data/read/read.ino: -------------------------------------------------------------------------------- 1 | // приём данных по однопроводному юарту 2 | 3 | // подключаем софт юарт 4 | #include "softUART.h" 5 | // делаем только приёмником (экономит память) 6 | softUART<4, GBUS_RX> UART(1000); // пин 4, скорость 1000 7 | 8 | // подключаем GBUS 9 | #include "GBUS.h" 10 | GBUS bus(&UART, 5, 20); // обработчик UART, адрес 5, буфер 20 байт 11 | 12 | struct myStruct { 13 | byte val_b; 14 | int val_i; 15 | long val_l; 16 | float val_f; 17 | }; 18 | 19 | void setup() { 20 | Serial.begin(9600); // сериал для отладки (вывод в монитор) 21 | } 22 | 23 | void loop() { 24 | // в тике сидит отправка и приём 25 | bus.tick(); 26 | 27 | if (bus.gotData()) { 28 | // выводим данные 29 | myStruct data; 30 | bus.readData(data); 31 | 32 | Serial.println(data.val_b); 33 | Serial.println(data.val_i); 34 | Serial.println(data.val_l); 35 | Serial.println(data.val_f); 36 | Serial.println(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /examples/softuart-softuart/data/send/send.ino: -------------------------------------------------------------------------------- 1 | // отправка данных по однопроводному юарту 2 | 3 | // подключаем софт юарт 4 | #include "softUART.h" 5 | // делаем только отправителем (экономит память) 6 | softUART<4, GBUS_TX> UART(1000); // пин 4, скорость 1000 7 | 8 | // подключаем GBUS 9 | #include "GBUS.h" 10 | GBUS bus(&UART, 3, 20); // обработчик UART, адрес 3, буфер 20 байт 11 | 12 | struct myStruct { 13 | byte val_b; 14 | int val_i; 15 | long val_l; 16 | float val_f; 17 | }; 18 | 19 | void setup() { 20 | } 21 | 22 | 23 | void loop() { 24 | // в тике сидит отправка и приём 25 | bus.tick(); 26 | 27 | static uint32_t tmr; 28 | if (millis() - tmr >= 2000) { 29 | tmr = millis(); 30 | // отправляем каждые 2 секунды 31 | myStruct data; 32 | data.val_b = 12; 33 | data.val_i = 1234; 34 | data.val_l = 123456; 35 | data.val_f = 123.45678; 36 | bus.sendData(5, data); // на адрес 5 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /examples/softuart-softuart/raw/raw_RX/raw_RX.ino: -------------------------------------------------------------------------------- 1 | // приём сырых данных по однопроводному юарту 2 | 3 | // подключаем софт юарт 4 | #include "softUART.h" 5 | softUART<4> UART(1000); // пин 4, скорость 1000 6 | 7 | // подключаем GBUS 8 | #include "GBUS.h" 9 | GBUS bus(&UART, 5, 20); // обработчик UART, адрес 5, буфер 20 байт 10 | 11 | void setup() { 12 | Serial.begin(9600); // сериал для отладки (вывод в монитор) 13 | } 14 | 15 | void loop() { 16 | // в тике сидит отправка и приём 17 | bus.tick(); 18 | 19 | if (bus.gotRaw()) { 20 | // выводим сырые данные 21 | for (byte i = 0; i < bus.rawSize(); i++) { 22 | byte val = bus.buffer[i]; 23 | Serial.print(bus.buffer[i]); 24 | Serial.print(','); 25 | } 26 | Serial.println(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /examples/softuart-softuart/raw/raw_TX/raw_TX.ino: -------------------------------------------------------------------------------- 1 | // отправка сырых данных по однопроводному юарту 2 | 3 | // подключаем софт юарт 4 | #include "softUART.h" 5 | softUART<4> UART(1000); // пин 4, скорость 1000 6 | 7 | // подключаем GBUS 8 | #include "GBUS.h" 9 | GBUS bus(&UART, 3, 20); // обработчик UART, адрес 3, буфер 20 байт 10 | 11 | void setup() { 12 | 13 | } 14 | 15 | 16 | void loop() { 17 | // в тике сидит отправка и приём 18 | bus.tick(); 19 | 20 | static uint32_t tmr; 21 | if (millis() - tmr >= 2000) { 22 | tmr = millis(); 23 | // отправляем массив каждые 2 секунды 24 | byte buf[] = {1, 2, 3, 4, 5}; 25 | bus.sendRaw(buf, sizeof(buf)); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /examples/softuart-softuart/общение ардуин через встроенный softuart.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GyverLibs/GyverBus/31816306d5a7b5e1fcb97faa955a35de80b359b9/examples/softuart-softuart/общение ардуин через встроенный softuart.txt -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For GyverBus 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | GBUS KEYWORD1 9 | GyverBus KEYWORD1 10 | softUART KEYWORD1 11 | 12 | ####################################### 13 | # Methods and Functions (KEYWORD2) 14 | ####################################### 15 | begin KEYWORD2 16 | end KEYWORD2 17 | setAddress KEYWORD2 18 | tick KEYWORD2 19 | getStatus KEYWORD2 20 | gotData KEYWORD2 21 | getTXaddress KEYWORD2 22 | isBusy KEYWORD2 23 | sendData KEYWORD2 24 | readData KEYWORD2 25 | sendRaw KEYWORD2 26 | sendRequest KEYWORD2 27 | gotRequest KEYWORD2 28 | gotRaw KEYWORD2 29 | rawSize KEYWORD2 30 | waitAck KEYWORD2 31 | sendAck KEYWORD2 32 | gotAck KEYWORD2 33 | sendRequestAck KEYWORD2 34 | statusChanged KEYWORD2 35 | 36 | GBUS_is_busy KEYWORD2 37 | GBUS_send KEYWORD2 38 | GBUS_read KEYWORD2 39 | GBUS_send_raw KEYWORD2 40 | GBUS_read_raw KEYWORD2 41 | GBUS_send_request KEYWORD2 42 | GBUS_read_request KEYWORD2 43 | GBUS_send_ack KEYWORD2 44 | GBUS_read_ack KEYWORD2 45 | GBUS_send_request_ack KEYWORD2 46 | 47 | GBUS_crc_update KEYWORD2 48 | GBUS_crc_bytes KEYWORD2 49 | packDataBytes KEYWORD2 50 | unpackDataBytes KEYWORD2 51 | checkGBUS KEYWORD2 52 | packGBUSdata KEYWORD2 53 | unpackGBUSdata KEYWORD2 54 | packGBUScmd KEYWORD2 55 | 56 | ####################################### 57 | # Constants (LITERAL1) 58 | ####################################### 59 | GBUS_IDLE LITERAL1 60 | TRANSMITTING LITERAL1 61 | TX_OVERFLOW LITERAL1 62 | TX_COMPLETE LITERAL1 63 | RECEIVING LITERAL1 64 | RX_ERROR LITERAL1 65 | RX_ABORT LITERAL1 66 | RX_OVERFLOW LITERAL1 67 | RX_ADDRESS_ERROR LITERAL1 68 | RX_CRC_ERROR LITERAL1 69 | RX_REQUEST LITERAL1 70 | RX_DATA LITERAL1 71 | RX_ACK LITERAL1 72 | 73 | ACK_IDLE LITERAL1 74 | ACK_WAIT LITERAL1 75 | ACK_ERROR LITERAL1 76 | ACK_ONLY LITERAL1 77 | ACK_DATA LITERAL1 78 | 79 | GBUS_RX LITERAL1 80 | GBUS_TX LITERAL1 81 | GBUS_FULL LITERAL1 82 | GBUS_CRC LITERAL1 83 | 84 | GBUS_SPEED LITERAL1 85 | GBUS_OFFSET_WRITE LITERAL1 86 | GBUS_OFFSET_READ LITERAL1 87 | 88 | GBUS_BROADCAST LITERAL1 -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=GyverBus 2 | version=2.6.1 3 | author=AlexGyver 4 | maintainer=AlexGyver 5 | sentence=Communicating by GBUS interface 6 | paragraph=Communicating by GBUS interface 7 | category=Communication 8 | url=https://github.com/GyverLibs/GyverBus 9 | architectures=* 10 | -------------------------------------------------------------------------------- /src/GBUS.h: -------------------------------------------------------------------------------- 1 | #ifndef _GBUS_h 2 | #define _GBUS_h 3 | #include "GyverBus.h" 4 | // Это оболочка протокола GBUS на любой интерфейс связи Stream (Serial, программный Serial) 5 | // Обеспечивает асинхронный приём данных по Serial (в отличие от readBytes()) 6 | // Полностью совместима на приём-передачу с остальными способами общения по GBUS 7 | // Можно использовать родной аппаратный UART с библиотеками Serial (+Serial1 Serial2...) или любой другой встроенной в ядро 8 | // Можно работать с аппаратным Serial и SoftwareSerial на любой платформе в пределах "экосистемы" Ардуино 9 | 10 | /* 11 | Коды статусов и ошибок (tick() и getStatus()): 12 | 0 [GBUS_IDLE] - ожидание (холостой режим) 13 | 1 [TRANSMITTING] - передача 14 | 2 [TX_OVERFLOW] - буфер переполнен 15 | 3 [TX_COMPLETE] - передача завершена 16 | 4 [RECEIVING] - приём 17 | 5 [RX_ERROR] - ошибка приёма 18 | 6 [RX_ABORT] - ошибка. Приём прерван 19 | 7 [RX_OVERFLOW] - ошибка. Буфер или пакет переполнен 20 | 8 [RX_ADDRESS_ERROR] - ошибка. Не наш адрес 21 | 9 [RX_CRC_ERROR] - ошибка. Не совпадает CRC 22 | 10 [RX_REQUEST] - успешное получение запроса 23 | 11 [RX_DATA] - успешный приём данных 24 | 12 [RX_ACK] - успешное получение подтверждения 25 | */ 26 | 27 | /* 28 | Инициализация: 29 | GBUS объект(обработчик, адрес, размер буфера) 30 | - обработчик: адрес объекта-обработчика интерфейса (например &Serial, &mySerial) 31 | - адрес: адрес этого устрйоства в сети 32 | - размер буфера: размер буфера 33 | 34 | Список методов: 35 | tick() - отправляет и принимает данные. Вызывать хотя бы каждую миллисекунду. Возвращает коды статусов, тип GBUSstatus (enum) 36 | getStatus() - возвращает коды статусов (такие же как tick()), тип GBUSstatus (enum) 37 | 38 | sendData(адрес, дата) - вводит данные на отправку по адресу получателя. Принимает любй тип данных (переменные, массивы, структуры). Отправка начнётся автоматически после "освобождения" линии 39 | gotData() - вернёт true, если новый пакет данных принят без ошибок. Сам сбрасывается в false 40 | readData(дата) - выводит данные из внутреннего буфера в указанную "переменную" (переменные, массивы, структуры) 41 | 42 | sendRequest(адрес) - отправить "запрос" по адресу получателя 43 | gotRequest() - вернёт true, если на наш адрес пришёл запрос. Сам сбрасывается в false. Адрес отправителя можно узнать в getTXaddress() 44 | 45 | getTXaddress() - возвращает адрес отправителя с последнего успешного получения данных или запроса 46 | isBusy() - возвращает true, если линия занята. Возвращает false, если с момента последнего общения по линии прошло GBUS_BUSY_TIMEOUT миллисекунд 47 | 48 | sendAck(адрес) - отправляет ack (ответ на запрос) по адресу 49 | gotAck() - вернёт true, если на наш адрес пришёл ack (ответ на запрос). Сам сбрасывается в false. Адрес отправителя можно узнать в getTXaddress() 50 | 51 | waitAck(адрес, кол-во попыток, таймаут) - ждёт ответа с указанного адреса. Если не дожидается за таймаут - отправляет ещё реквест 52 | И так далее пока не выйдет количество попыток. 53 | ФУНКЦИЯ НЕ БЛОКИРУЮЩАЯ 54 | Коды возврата: 55 | 0 [ACK_IDLE] - функция работает вхолостую 56 | 1 [ACK_WAIT] - ждём ответа 57 | 2 [ACK_ERROR] - не дождались ответа 58 | 3 [ACK_ONLY] - получен ack 59 | 4 [ACK_DATA] - получена дата 60 | Смотри примеры wait_ack 61 | 62 | sendRequestAck(адрес, кол-во попыток, таймаут) - отправляет реквест на адрес. 63 | Ждёт ответ (ack или data), если не дожидается в теч. таймаута - отправляет ещё раз. 64 | Коды возврата: 65 | 2 [ACK_ERROR] - не дождались ответа 66 | 3 [ACK_ONLY] - получен ack 67 | 4 [ACK_DATA] - получена дата 68 | ФУНКЦИЯ БЛОКИРУЮЩАЯ 69 | Смотри примеры call_response_ack 70 | 71 | sendRaw(байтовый массив, размер) - отправит сырые байты (без протокола) по шине. Смотри примеры в папке raw 72 | gotRaw() - вернёт true, были приняты какие-то данные (приём завершён успешно). Сам сбрасывается в false. 73 | rawSize() - вернёт количество принятых байт (последний успешный приём). Иначе вернёт 0 74 | 75 | setAddress(addr) - сменить адрес 76 | buffer - можно обращаться как к массиву. Встроенный буфер библиотеки 77 | 78 | Протокол: 79 | Дата [суммарное количество байт, адрес получателя, адрес отправителя, ...байты даты..., CRC] 80 | Запрос (request) [0, адрес получателя, адрес отправителя, CRC] 81 | Подтверждение (ack) [1, адрес получателя, адрес отправителя, CRC] 82 | CRC опционален 83 | */ 84 | 85 | // ============================ НАСТРОЙКИ ================================ 86 | // таймаут отправки после предыдущей активности на линии, мкс 87 | // он же МАКСИМАЛЬНЫЙ таймаут приёма (в процессе работы пересчитывается) 88 | #define GBUS_BUSY_TIMEOUT 50000 89 | 90 | // ======================================================================= 91 | 92 | class GBUS { 93 | public: 94 | GBUS(Stream* serial, uint8_t addr, uint8_t bufSize) : _bufSize(bufSize + GBUS_OFFSET) { 95 | buffer = (uint8_t *)malloc(_bufSize); 96 | memset(buffer, 0, _bufSize); 97 | port = serial; 98 | _addr = addr; 99 | } 100 | 101 | ~GBUS() { 102 | free(buffer); 103 | } 104 | 105 | // ==== ШИНА ==== 106 | bool isBusy() { 107 | return !(micros() - _tmr > GBUS_BUSY_TIMEOUT); 108 | } 109 | 110 | // сменить адрес 111 | void setAddress(uint8_t addr) { 112 | _addr = addr; 113 | } 114 | 115 | // в данной реализации это только функция ПАРСИНГА данных 116 | GBUSstatus tick() { 117 | int state = readBytesAsync(buffer, _bufSize); 118 | if (state <= 0) { 119 | switch (state) { 120 | case -2: _status = GBUS_IDLE; break; 121 | case -1: _status = RX_OVERFLOW; break; 122 | case 0: _status = RECEIVING; break; 123 | } 124 | } else { 125 | // если принят пакет 126 | _status = checkGBUS(buffer, _bufSize, state, _addr); 127 | switch (_status) { 128 | case RX_REQUEST: _requestFlag = true; break; 129 | case RX_ACK: _ackFlag = true; break; 130 | case RX_DATA: _dataFlag = true; break; 131 | } 132 | _rawFlag = true; 133 | _rawSize = state; 134 | _txAddress = buffer[2]; 135 | } 136 | return _status; 137 | } 138 | 139 | GBUSstatus getStatus() {return _status;} 140 | bool statusChanged() { 141 | if (_prevStatus != _status) { 142 | _prevStatus = _status; 143 | return true; 144 | } 145 | return false; 146 | } 147 | uint8_t getTXaddress() {return _txAddress;} 148 | 149 | // асинхронное чтение потока байтов. Возвращает: 150 | // -2: приём не идёт 151 | // -1: буфер переполнен 152 | // 0: приём идёт 153 | // кол-во байт: передача завершена 154 | int readBytesAsync(uint8_t* buffer, uint8_t size) { 155 | while (port->available()) { // пока есть данные в буфере сериал 156 | if (!_parseFlag) { // начало приёма 157 | _parseFlag = true; // ключ на старт 158 | _byteCount = 0; // сбросили счетчик 159 | _timeout = GBUS_BUSY_TIMEOUT; // сбросили таймаут 160 | } 161 | buffer[_byteCount++] = port->read();// читаем 162 | if (_byteCount == 2) _timeout = (micros() - _tmr) * 10; // таймаут как время передачи 10 бит 163 | if (_byteCount > size) { // буфер переполнен 164 | _parseFlag = false; 165 | return -1; 166 | } 167 | _tmr = micros(); // сброс таймера (идёт приём) 168 | return 0; 169 | } 170 | 171 | // таймаут ожидания приёма 172 | if (_parseFlag && micros() - _tmr >= _timeout) { 173 | _parseFlag = false; // приём окончен 174 | return _byteCount; 175 | } 176 | return -2; 177 | } 178 | 179 | // ===== REQUEST ===== 180 | // отправить 181 | void sendRequest(uint8_t to) { 182 | _txSize = packGBUScmd(buffer, 0, to, _addr); 183 | sendRaw(buffer, _txSize); 184 | if (_ackStage == ACK_IDLE) { 185 | _ackTimer = millis(); 186 | _ackTries = 0; 187 | _ackStage = ACK_WAIT; 188 | } 189 | } 190 | 191 | // принять 192 | bool gotRequest() { 193 | bool temp = _requestFlag; 194 | _requestFlag = false; 195 | return temp; 196 | } 197 | 198 | // ждать ответа асинхронно 199 | uint8_t waitAck(uint8_t to, uint8_t tries, int timeout) { 200 | switch (_ackStage) { 201 | case ACK_IDLE: 202 | break; 203 | 204 | case ACK_WAIT: 205 | if (gotData()) { 206 | _ackStage = ACK_IDLE; 207 | return ACK_DATA; 208 | } 209 | if (gotAck()) { 210 | _ackStage = ACK_IDLE; 211 | return ACK_ONLY; 212 | } 213 | if (millis() - _ackTimer >= timeout) { 214 | _ackTimer = millis(); 215 | _ackTries++; 216 | if (_ackTries >= tries) { 217 | _ackStage = ACK_IDLE; 218 | return ACK_ERROR; 219 | } 220 | sendRequest(to); 221 | } 222 | break; 223 | } 224 | return _ackStage; 225 | } 226 | 227 | // ждать ответа (блокирующая функция) 228 | uint8_t sendRequestAck(uint8_t to, uint8_t tries, int timeout) { 229 | sendRequest(to); 230 | while (tick() == GBUS_IDLE); // ждём таймаут 231 | while (tick() != TX_COMPLETE); // ждём отправку 232 | uint8_t thisTry = 0; 233 | uint32_t tmr = millis(); 234 | while (1) { 235 | tick(); // принимаем или отправляем 236 | if (gotData()) return ACK_DATA; // приняли дату 237 | if (gotAck()) return ACK_ONLY; // приняли ответ 238 | if (millis() - tmr >= timeout) { // таймаут 239 | tmr = millis(); 240 | thisTry++; 241 | if (thisTry >= tries) return ACK_ERROR; // превышено количество попыток 242 | sendRequest(to); // снова шлём запрос 243 | } 244 | } 245 | return ACK_ERROR; // не дождались 246 | } 247 | 248 | 249 | // ===== ACK ===== 250 | // отправить 251 | void sendAck(uint8_t to) { 252 | _txSize = packGBUScmd(buffer, 1, to, _addr); 253 | sendRaw(buffer, _txSize); 254 | } 255 | 256 | // принять 257 | bool gotAck() { 258 | bool temp = _ackFlag; 259 | _ackFlag = false; 260 | return temp; 261 | } 262 | 263 | // ===== RAW ===== 264 | void sendRaw(uint8_t* data, uint8_t size) { 265 | for (uint8_t i = 0; i < size; i++) port->write(data[i]); 266 | _status = TX_COMPLETE; 267 | } 268 | 269 | bool gotRaw() { 270 | bool temp = _rawFlag; 271 | _rawFlag = false; 272 | return temp; 273 | } 274 | 275 | uint8_t rawSize() {return _rawSize;} 276 | 277 | // ===== DATA ===== 278 | // принять 279 | bool gotData() { 280 | bool temp = _dataFlag; 281 | _dataFlag = false; 282 | return temp; 283 | } 284 | 285 | // отправить 286 | template 287 | bool sendData(uint8_t to, T &data) { 288 | _txSize = packGBUSdata(buffer, _bufSize, data, to, _addr); 289 | if (_txSize == 0) { 290 | _status = TX_OVERFLOW; 291 | return false; 292 | } 293 | sendRaw(buffer, _txSize); 294 | return true; 295 | } 296 | 297 | // прочитать 298 | template 299 | bool readData(T &data) { 300 | return unpackGBUSdata(buffer, _bufSize, data); 301 | } 302 | 303 | // ===== БУФЕР ===== 304 | uint8_t *buffer; 305 | 306 | private: 307 | const int _bufSize; 308 | uint32_t _tmr; 309 | uint32_t _ackTimer; 310 | uint32_t _timeout = GBUS_BUSY_TIMEOUT; 311 | uint8_t _txAddress; 312 | uint8_t _txSize = 0; 313 | uint8_t _byteCount = 0; 314 | uint8_t _addr; 315 | uint8_t _rawSize = 0; 316 | bool _parseFlag = false; 317 | bool _dataFlag = false; 318 | bool _requestFlag = false; 319 | bool _ackFlag = false; 320 | bool _rawFlag = false; 321 | uint8_t _ackTries = 0; 322 | uint8_t _ackStage = 0; 323 | GBUSstatus _status = GBUS_IDLE, _prevStatus = GBUS_IDLE; 324 | Stream* port; 325 | }; 326 | #endif -------------------------------------------------------------------------------- /src/GBUSmini.cpp: -------------------------------------------------------------------------------- 1 | #include "GBUSmini.h" 2 | 3 | uint8_t GBUS_send_request_ack(uint8_t pin, uint8_t to, uint8_t from, uint8_t tries, int timeout) { 4 | GBUS_send_request(pin, to, from); 5 | uint8_t thisTry = 0; 6 | uint32_t tmr = millis(); 7 | while (1) { 8 | uint8_t addr = GBUS_read_ack(pin, from); 9 | if (addr == to) return ACK_ONLY; 10 | if (millis() - tmr >= timeout) { 11 | tmr = millis(); 12 | thisTry++; 13 | if (thisTry >= tries) return ACK_ERROR; 14 | GBUS_send_request(pin, to, from); 15 | } 16 | } 17 | return ACK_ERROR; 18 | } 19 | 20 | // ******************************************************* 21 | bool GBUS_is_busy(uint8_t pin) { 22 | static uint32_t tmr; 23 | if (digitalRead(pin)) { 24 | if (millis() - tmr >= GBUSMINI_BUSY_TIMEOUT) return false; 25 | else return true; 26 | } else { 27 | tmr = millis(); 28 | return true; 29 | } 30 | } 31 | 32 | // ******************************************************* 33 | // ********************* ЧТЕНИЕ ************************** 34 | // ******************************************************* 35 | uint8_t GBUS_read_raw(uint8_t pin, uint8_t* buf, uint8_t size) { 36 | if (!digitalRead(pin)) { // проверяем старт бит (low) 37 | delayMicroseconds(GBUS_BIT_2); // ждём половину времени 38 | if (!digitalRead(pin)) { // если всё ещё старт бит (low) 39 | int8_t bitCount = 0; // счётчик битов 40 | uint8_t byteCount = 0; // счётчик байтов 41 | while (1) { 42 | delayMicroseconds(GBUS_BIT-GBUS_OFFSET_READ); // ждём бит 43 | uint8_t bit = digitalRead(pin); // читаем 44 | if (bitCount < 8) { // передача битов даты 45 | bitWrite(buf[byteCount], bitCount, bit); // пишем в буфер 46 | } else if (bitCount == 8) { // стоп бит (high) 47 | if (!bit) return 0; // ошибка стоп бита. Завершаем 48 | byteCount++; // счётчик собранных байтов 49 | } else if (bitCount == 9) { // старт бит (low) 50 | if (bit) return byteCount; // не дождались старт бита. Конец приёма, возврат количества 51 | if (byteCount >= size) return 0; // буфер переполнен. Завершаем 52 | bitCount = -1; // костыль 53 | } 54 | bitCount++; // следующий бит 55 | } 56 | } 57 | } 58 | return 0; 59 | } 60 | 61 | 62 | // ******************************************************* 63 | uint8_t GBUS_read(uint8_t pin, uint8_t addr, uint8_t* buf, uint8_t size) { 64 | uint8_t buf2[size + GBUS_OFFSET]; // буфер на приём 65 | uint8_t bytes = GBUS_read_raw(pin, buf2, (size + GBUS_OFFSET)); // принимаем, получаем количество байт посылки 66 | if (buf2[0] == bytes && (buf2[1] == addr || buf2[1] == 255)) { // если совпало количество байт и адрес 67 | #if (GBUS_CRC == 1) 68 | if (GBUS_crc_bytes(buf2, bytes) != 0) return 0; 69 | #endif 70 | for (uint8_t i = 0; i < bytes - GBUS_OFFSET; i++) buf[i] = buf2[i + 3]; // переписываем в буфер в скетче 71 | return buf2[2]; // возвращаем адрес 72 | } 73 | return 0; // иначе возвращаем ошибку 74 | } 75 | 76 | // ******************************************************* 77 | // структура буфера: [0, адрес получателя, адрес отправителя, CRC] 78 | uint8_t GBUS_read_request(uint8_t pin, uint8_t addr) { 79 | uint8_t buf[GBUS_OFFSET]; 80 | if (GBUS_read_raw(pin, buf, GBUS_OFFSET) == GBUS_OFFSET 81 | && (buf[1] == addr || buf[1] == 255) 82 | #if (GBUS_CRC == 1) 83 | && GBUS_crc_bytes(buf, GBUS_OFFSET) == 0 84 | #endif 85 | && buf[0] == 0) return buf[2]; 86 | else return 0; 87 | } 88 | 89 | // ******************************************************* 90 | // структура буфера: [1, адрес получателя, адрес отправителя, CRC] 91 | uint8_t GBUS_read_ack(uint8_t pin, uint8_t addr) { 92 | uint8_t buf[GBUS_OFFSET]; 93 | if (GBUS_read_raw(pin, buf, GBUS_OFFSET) == GBUS_OFFSET 94 | && (buf[1] == addr || buf[1] == 255) 95 | #if (GBUS_CRC == 1) 96 | && GBUS_crc_bytes(buf, GBUS_OFFSET) == 0 97 | #endif 98 | && buf[0] == 1) return buf[2]; 99 | else return 0; 100 | } 101 | 102 | 103 | // ******************************************************* 104 | // ******************** ОТПРАВКА ************************* 105 | // ******************************************************* 106 | void GBUS_send_raw(uint8_t pin, uint8_t* buf, uint8_t size) { 107 | for (uint8_t bytes = 0; bytes < size; bytes++) { 108 | for (int8_t bits = -1; bits < 9; bits++) { 109 | bool bit = 0; 110 | if (bits < 0) bit = 0; 111 | else if (bits < 8) bit = (buf[bytes] >> bits) & 1; 112 | else bit = 1; 113 | pinMode(pin, !bit); 114 | digitalWrite(pin, bit); 115 | delayMicroseconds(GBUS_BIT-GBUS_OFFSET_WRITE); 116 | } 117 | } 118 | } 119 | 120 | // ******************************************************* 121 | void GBUS_send(uint8_t pin, uint8_t to, uint8_t from, uint8_t* data, uint8_t size) { 122 | uint8_t buf[size + GBUS_OFFSET]; 123 | uint8_t crc = 0; 124 | buf[0] = size + GBUS_OFFSET; 125 | buf[1] = to; 126 | buf[2] = from; 127 | for (uint8_t i = 0; i < size; i++) buf[i + 3] = data[i]; 128 | #if (GBUS_CRC == 1) 129 | buf[size + 3] = GBUS_crc_bytes(buf, size + 3); 130 | #endif 131 | GBUS_send_raw(pin, buf, size+GBUS_OFFSET); 132 | } 133 | 134 | // ******************************************************* 135 | void GBUS_send_request(uint8_t pin, uint8_t to, uint8_t from) { 136 | uint8_t buf[GBUS_OFFSET] = {0, to, from}; 137 | #if (GBUS_CRC == 1) 138 | buf[3] = GBUS_crc_bytes(buf, 3); 139 | #endif 140 | GBUS_send_raw(pin, buf, GBUS_OFFSET); 141 | } 142 | 143 | // ******************************************************* 144 | void GBUS_send_ack(uint8_t pin, uint8_t to, uint8_t from) { 145 | uint8_t buf[GBUS_OFFSET] = {1, to, from}; 146 | #if (GBUS_CRC == 1) 147 | buf[3] = GBUS_crc_bytes(buf, 3); 148 | #endif 149 | GBUS_send_raw(pin, buf, GBUS_OFFSET); 150 | } -------------------------------------------------------------------------------- /src/GBUSmini.h: -------------------------------------------------------------------------------- 1 | #ifndef _GBUSmini_h 2 | #define _GBUSmini_h 3 | #include "GyverBus.h" 4 | 5 | // ==================== СТАНДАРТНЫЕ НАСТРОЙКИ ====================== 6 | // могут быть изменены здесь, либо прямо в скетче при помощи дефайна ПЕРЕД ПОДКЛЮЧЕНИЕМ БИБЛИОТЕКИ 7 | // дефайны в скетч соответственно GBUS_SPEED, GBUS_OFFSET_WRITE, GBUS_OFFSET_READ 8 | #define GBUS_DEFAULT_SPEED 400 // скорость (baud) 9 | #define GBUS_DEFAULT_WRITE 8 // коррекция задержки записи, мкс 10 | #define GBUS_DEFAULT_READ 5 // коррекция задержки чтения, мкс 11 | #define GBUSMINI_BUSY_TIMEOUT 50 // таймаут отправки после предыдущей активности на линии, мс 12 | 13 | // ========== ЛЁГКИЕ ФУНКЦИИ ОТПРАВКИ И ЧТЕНИЯ GBUS ========== 14 | // По одному проводу 15 | // Все функции (кроме GBUS_is_busy) блокируют выполнение кода на время приёма/отправки 16 | 17 | // Возвращает true, если линия занята. Таймаут GBUS_BUSY_TIMEOUT мс 18 | bool GBUS_is_busy(uint8_t pin); 19 | 20 | // Отправить сырые данные (пин, дата, размер) 21 | // Формат посылки GBUS [суммарное количество байт, адрес получателя, адрес отправителя, ...байты даты..., CRC] 22 | // Функция блокирующая на всё время отправки 23 | // 640 байт (Arduino Nano), 88 байт ATtiny13 (microCore) 24 | void GBUS_send_raw(uint8_t pin, uint8_t* data, uint8_t size); 25 | 26 | // Отправить данные с CRC (пин, адрес получателя, адрес отправителя, дата, размер) 27 | // Функция блокирующая на всё время отправки 28 | // 740 байт (Arduino Nano), 160 байт ATtiny13 (microCore) 29 | void GBUS_send(uint8_t pin, uint8_t to, uint8_t from, uint8_t* data, uint8_t size); 30 | 31 | // Прочитать сырые данные (пин, дата, размер) 32 | // Вызывать как можно чаще, чтобы не пропустить. Функция блокирующая на всё время приёма. 33 | // Возвращает количество принятых байт при завершении приёма 34 | // 520 байт (Arduino Nano), 220 байт ATtiny13 (microCore) 35 | uint8_t GBUS_read_raw(uint8_t pin, uint8_t* buf, uint8_t size); 36 | 37 | // Прочитать данные с CRC (пин, наш адрес, дата, размер) 38 | // Вызывать как можно чаще, чтобы не пропустить. Функция блокирующая на всё время приёма 39 | // Возвращает адрес отправителя при успешном завершении приёма. При ошибке возвращает 0 40 | // 650 байт (Arduino Nano), 330 байт ATtiny13 (microCore) 41 | uint8_t GBUS_read(uint8_t pin, uint8_t addr, uint8_t* buf, uint8_t size); 42 | 43 | // Отправить запрос (пин, адрес получателя, адрес отправителя) 44 | // Функция блокирующая на всё время отправки 45 | // 640 байт (Arduino Nano), 150 байт ATtiny13 (microCore) 46 | void GBUS_send_request(uint8_t pin, uint8_t to, uint8_t from); 47 | 48 | // Принять запрос (пин, наш адрес) 49 | // Вызывать как можно чаще, чтобы не пропустить. Функция блокирующая на всё время приёма 50 | // Возвращает адрес отправителя при успешном завершении приёма. При ошибке возвращает 0 51 | // 540 байт (Arduino Nano), 220 байт ATtiny13 (microCore) 52 | uint8_t GBUS_read_request(uint8_t pin, uint8_t addr); 53 | 54 | // Отправить подтверждение (пин, адрес получателя, адрес отправителя) 55 | // Функция блокирующая на всё время отправки 56 | void GBUS_send_ack(uint8_t pin, uint8_t to, uint8_t from); 57 | 58 | // Принять подтверждение (пин, наш адрес) 59 | // Вызывать как можно чаще, чтобы не пропустить. Функция блокирующая на всё время приёма 60 | // Возвращает адрес отправителя при успешном завершении приёма. При ошибке возвращает 0 61 | uint8_t GBUS_read_ack(uint8_t pin, uint8_t addr); 62 | 63 | // Отправить запрос и ждать подтверждения приёма, т.е. пытаться достучаться 64 | // (пин, адрес получателя, адрес отправителя, кол-во попыток, таймаут между попытками) 65 | // возвращает 0 при таймауте, 1 при успехе (получили ack) 66 | // см. примеры call response _ack 67 | uint8_t GBUS_send_request_ack(uint8_t pin, uint8_t to, uint8_t from, uint8_t tries, int timeout); 68 | 69 | 70 | // ******************************************************* 71 | // ********************** СЕРВИС ************************* 72 | // ******************************************************* 73 | 74 | #if !defined(GBUS_SPEED) 75 | #define GBUS_SPEED GBUS_DEFAULT_SPEED 76 | #endif 77 | #if !defined(GBUS_OFFSET_WRITE) 78 | #define GBUS_OFFSET_WRITE GBUS_DEFAULT_WRITE 79 | #endif 80 | #if !defined(GBUS_OFFSET_READ) 81 | #define GBUS_OFFSET_READ GBUS_DEFAULT_READ 82 | #endif 83 | 84 | #define GBUS_BIT (1000000UL / GBUS_SPEED) 85 | #define GBUS_BIT_2 (GBUS_BIT >> 1) 86 | 87 | #endif -------------------------------------------------------------------------------- /src/GyverBus.cpp: -------------------------------------------------------------------------------- 1 | #include "GyverBus.h" 2 | 3 | uint8_t packGBUScmd(uint8_t* buffer, uint8_t cmd, uint8_t to, uint8_t from) { 4 | buffer[0] = cmd; // команда 5 | buffer[1] = to; // адрес приёмника 6 | buffer[2] = from; // адрес передатчика 7 | if (GBUS_CRC) buffer[3] = GBUS_crc_bytes(buffer, 3); 8 | return GBUS_OFFSET; 9 | } 10 | 11 | GBUSstatus checkGBUS(uint8_t* buffer, uint8_t bufSize, uint8_t amount, uint8_t addr) { 12 | if (buffer[0] > bufSize) return RX_OVERFLOW; // буфер переполнен 13 | if (amount > GBUS_OFFSET && amount > buffer[0]) return RX_OVERFLOW; // пакет слишком большой 14 | if (buffer[1] != addr && buffer[1] != 255) return RX_ADDRESS_ERROR; // не наш адрес 15 | if (amount < GBUS_OFFSET || (amount > GBUS_OFFSET && amount < buffer[0])) return RX_ABORT; // передача прервана 16 | if (GBUS_CRC) if (GBUS_crc_bytes(buffer, amount) != 0) return RX_CRC_ERROR; // данные повреждены 17 | if (buffer[0] == 0) return RX_REQUEST; // реквест 18 | if (buffer[0] == 1) return RX_ACK; // подтверждение 19 | return RX_DATA; // данные приняты успешно 20 | } 21 | 22 | void GBUS_crc_update(uint8_t &crc, uint8_t data) { 23 | #if defined (__AVR__) 24 | // резкий алгоритм для AVR 25 | uint8_t counter; 26 | uint8_t buffer; 27 | asm volatile ( 28 | "EOR %[crc_out], %[data_in] \n\t" 29 | "LDI %[counter], 8 \n\t" 30 | "LDI %[buffer], 0x8C \n\t" 31 | "_loop_start_%=: \n\t" 32 | "LSR %[crc_out] \n\t" 33 | "BRCC _loop_end_%= \n\t" 34 | "EOR %[crc_out], %[buffer] \n\t" 35 | "_loop_end_%=: \n\t" 36 | "DEC %[counter] \n\t" 37 | "BRNE _loop_start_%=" 38 | : [crc_out]"=r" (crc), [counter]"=d" (counter), [buffer]"=d" (buffer) 39 | : [crc_in]"0" (crc), [data_in]"r" (data) 40 | ); 41 | #else 42 | // обычный для всех остальных 43 | uint8_t i = 8; 44 | while (i--) { 45 | crc = ((crc ^ data) & 1) ? (crc >> 1) ^ 0x8C : (crc >> 1); 46 | data >>= 1; 47 | } 48 | #endif 49 | } 50 | 51 | uint8_t GBUS_crc_bytes(uint8_t *buffer, uint8_t size) { 52 | uint8_t crc = 0; 53 | for (uint8_t i = 0; i < size; i++) GBUS_crc_update(crc, buffer[i]); 54 | return crc; 55 | } -------------------------------------------------------------------------------- /src/GyverBus.h: -------------------------------------------------------------------------------- 1 | /* 2 | GyverBus - библиотека для общения по протоколу GBUS 3 | Документация: https://alexgyver.ru/gyverbus/ 4 | - Очень простой, надёжный, устойчивый к помехам и задержкам, но медленный интерфейс связи на базе UART 5 | - Двухсторонняя связь по одному проводу 6 | - Асинхронная отправка и чтение (на базе millis()) 7 | - Двухсторонняя совместимость с аппаратным UART 8 | - Возможность принимать и отправлять данные внутри сети Ардуинок 9 | - Адресация до 254 устройств в сети (от 1 до 255) 10 | - Всеядная функция отправки и приёма (ест переменные, структуры, массивы) 11 | - Встроенная проверка CRC (контроль целостности) пакета данных 12 | - Возможность отправки и чтения короткого "запроса" 13 | - Поддерживаются все Arduino-совместимые платы 14 | - Сама библиотека предоставляет возможности по отладке (коды ошибок) 15 | - В примерах есть компактные варианты чтения и отправки данных, влезет даже в ATtiny 16 | 17 | AlexGyver, alex@alexgyver.ru 18 | https://alexgyver.ru/ 19 | MIT License 20 | 21 | Версии: 22 | v1.1: добавлена waitAck() и исправлена ошибочка 23 | v1.2: улучшена стабильность, функции оптимизированы, уменьшен вес 24 | v1.3: добавлен CRC в запрос и ответ 25 | v2.0: 26 | - Куча оптимизации 27 | - Логика работы переделана. Теперь GBUS работает для всех uart-библиотек 28 | - Однопроводной uart вынесен отдельным классом 29 | - Добавлена совместимость с esp8266 30 | - Переделана вся инициализация, смотри примеры! 31 | - Добавлены утилиты и примеры 32 | v2.1: вернул getStatus 33 | v2.2: небольшие багфиксы и оптимизация 34 | v2.3: добавлена возможность отправки широковещательного сообщения (всем), отправлять на адрес 255 35 | v2.4: исправлены ошибки, добавлена bool statusChanged() для GBUS 36 | v2.5: добавил пример с GyverTransfer, добавил смену адреса 37 | */ 38 | 39 | /* 40 | Что это и как работает? 41 | Библиотека GBUS.h позволяет общаться по протоколу GBUS через любой Stream-объект (Serial, SoftwareSerial, softUART и проч). Основное описание содержится в ней 42 | Библиотека GyverBus.h содержит базовые инструменты для упаковки и распаковки данных в байтовые пакеты с адресацией и CRC 43 | Библиотека softUART.h - это однопроводной UART, работающий на приём и отправку, причём не блокирующий выполнение кода 44 | Библиотека GBUSmini.h - это набор лёгких БЛОКИРУЮЩИХ функций для общения по одному проводу. Предусмотрено для мелких МК 45 | */ 46 | #ifndef _GyverBus_h 47 | #define _GyverBus_h 48 | #include 49 | 50 | // ============== НАСТРОЙКИ ============== 51 | #define GBUS_CRC 1 // 1 - вкл CRC, 0 - выкл (экономит память, но того не стоит) 52 | 53 | 54 | // СТАТУСЫ (НЕ ТРОГАТЬ) 55 | enum GBUSstatus { 56 | GBUS_IDLE, 57 | TRANSMITTING, 58 | TX_OVERFLOW, 59 | TX_COMPLETE, 60 | RECEIVING, 61 | RX_ERROR, 62 | RX_ABORT, 63 | RX_OVERFLOW, 64 | RX_ADDRESS_ERROR, 65 | RX_CRC_ERROR, 66 | RX_REQUEST, 67 | RX_DATA, 68 | RX_ACK, 69 | }; 70 | 71 | // ============================ ВСЯКИЕ УТИЛИТЫ ============================ 72 | 73 | // =========== GBUS =========== 74 | // проверить статус принятых данных (буфер, его размер, кол-во принятых байтов, наш адрес) 75 | // вернёт статус GBUSstatus 76 | GBUSstatus checkGBUS(uint8_t* buffer, uint8_t bufSize, uint8_t amount, uint8_t addr); 77 | 78 | 79 | // ====== УПАКОВЩИК GBUS ====== 80 | // запаковать данные для отправки (буфер, его размер, дата, адрес получателя, адрес отправителя) 81 | // вернёт количество упакованных байт 82 | // запакует согласно протоколу [суммарное количество байт, адрес получателя, адрес отправителя, ...байты даты..., CRC] 83 | template uint8_t packGBUSdata(uint8_t* buffer, uint8_t bufSize, T &data, uint8_t to, uint8_t from); 84 | 85 | // распаковать данные, минуя служебные байты (буфер, его размер, дата) 86 | // при успехе вернёт true. Вернёт false, если буфер слишком мал для даты 87 | template bool unpackGBUSdata(uint8_t* buffer, uint8_t bufSize, T &data); 88 | 89 | // запаковать команду в буфер (буфер, команда, кому, от кого) 90 | // команды: запрос (0), ответ (1) 91 | // запакует согласно протоколу [команда, адрес получателя, адрес отправителя, CRC] 92 | uint8_t packGBUScmd(uint8_t* buffer, uint8_t cmd, uint8_t to, uint8_t from); 93 | 94 | 95 | // ====== УПАКОВЩИК БАЙТОВ ====== 96 | // пакуем любой тип данных в байтовый буфер (буфер, дата) 97 | template void packDataBytes(uint8_t *buffer, T &data); 98 | 99 | // распаковываем из байтового буфера обратно (буфер, дата) 100 | template void unpackDataBytes(uint8_t *buffer, T &data); 101 | 102 | 103 | // ============= CRC ============= 104 | // обновить CRC байта (crc, байт) 105 | void GBUS_crc_update(uint8_t &crc, uint8_t data); 106 | 107 | // расчёт crc для буфера (буфер, количество байт для проверки) 108 | uint8_t GBUS_crc_bytes(uint8_t *data, uint8_t size); 109 | 110 | // ========================================= РЕАЛИЗАЦИЯ ========================================= 111 | // crc дефайн 112 | #if (GBUS_CRC == 1) 113 | #define GBUS_OFFSET 4 114 | #else 115 | #define GBUS_OFFSET 3 116 | #endif 117 | 118 | // константы 119 | #define ACK_IDLE 0 120 | #define ACK_WAIT 1 121 | #define ACK_ERROR 2 122 | #define ACK_ONLY 3 123 | #define ACK_DATA 4 124 | #define GBUS_BROADCAST 255 125 | 126 | template 127 | uint8_t packGBUSdata(uint8_t* buffer, uint8_t bufSize, T &data, uint8_t to, uint8_t from) { 128 | buffer[0] = sizeof(T) + GBUS_OFFSET; // размер пакета с учётом служебных 129 | if (buffer[0] > bufSize) return 0; // если переполним буфер 130 | buffer[1] = to; // адрес приёмника 131 | buffer[2] = from; // адрес передатчика 132 | const uint8_t *ptr = (const uint8_t*) &data; // указатель 133 | for (uint16_t i = 0; i < sizeof(T); i++) buffer[i + 3] = *ptr++; // пакуем дату 134 | if (GBUS_CRC) buffer[sizeof(T) + 3] = GBUS_crc_bytes(buffer, sizeof(T) + 3);// crc 135 | return buffer[0]; 136 | } 137 | 138 | template 139 | bool unpackGBUSdata(uint8_t* buffer, uint8_t bufSize, T &data) { 140 | if (sizeof(T) + GBUS_OFFSET > bufSize) return false; // если данные больше буфера (+ служебная инфа протокола) 141 | uint8_t *ptr = (uint8_t*) &data; 142 | for (uint16_t i = 0; i < sizeof(T); i++) *ptr++ = buffer[i + 3]; // пишем 143 | return true; 144 | } 145 | 146 | template 147 | void packDataBytes(uint8_t *buffer, T &data) { 148 | uint8_t *ptr = (uint8_t*) &data; 149 | for (uint16_t i = 0; i < sizeof(T); i++) { 150 | buffer[i] = *ptr++; 151 | } 152 | } 153 | 154 | template 155 | void unpackDataBytes(uint8_t *buffer, T &data) { 156 | uint8_t *ptr = (uint8_t*) &data; 157 | for (uint16_t i = 0; i < sizeof(T); i++) { 158 | *ptr++ = buffer[i]; 159 | } 160 | } 161 | 162 | #endif -------------------------------------------------------------------------------- /src/softUART.h: -------------------------------------------------------------------------------- 1 | #ifndef _softUART_h 2 | #define _softUART_h 3 | // Однопроводной UART с асинхронным чтением и отправкой (+ не блокирует прерывания) 4 | // БУФЕРА НА ПРИЁМ НЕТ!!! 5 | // Для отправки и приёма нужно почащё дёргать за available() или tick(), здесь это синонимы 6 | // Наследует класс Print, то есть можно отправлять всё что угодно, как через обычный Serial 7 | // Улучшенная производительность для AVR Arduino 8 | 9 | #define SOFTUART_TX_WAIT 50 // Таймаут ожидания наполнения буфера через write, мкс 10 | 11 | /* 12 | Интерфейс: UART. start бит 0, stop бит 1. Кодирование даты: HIGH - 0x1, LOW - 0x0 13 | 14 | 1 _______ ___ ___ ______ ___ .........._________ 15 | |___| |______| |___| |___| |___| конец передачи 16 | 0 start 0 1 2 3 4 5 6 7 stop start stop 17 | */ 18 | 19 | /* 20 | Инициализация: 21 | softUART<пин, тип> объект(скорость) 22 | - пин: номер пина 23 | - тип: GBUS_FULL - двухсторонняя связь (активен по умолчанию, можно не указывать) 24 | - тип: GBUS_TX - только отправка (экономит память) 25 | - тип: GBUS_RX - только приём (экономит память) 26 | - скорость: скорость в бодах 27 | */ 28 | // ============================================================================================= 29 | #define SOFTUART_BUF_SIZE 64 // Стандартный размер буфера на отправку, байт 30 | #include 31 | 32 | // КОНСТАНТЫ 33 | #define GBUS_RX 0 34 | #define GBUS_TX 1 35 | #define GBUS_FULL 2 36 | 37 | template 38 | class softUART : public Stream { 39 | public: 40 | using Print::write; 41 | 42 | softUART(long baud, byte bufSize = SOFTUART_BUF_SIZE) : _bufSize(bufSize) { 43 | #if defined(__AVR__) 44 | _port_reg = portOutputRegister(digitalPinToPort(_PIN)); 45 | _pin_reg = portInputRegister(digitalPinToPort(_PIN)); 46 | _ddr_reg = portModeRegister(digitalPinToPort(_PIN)); 47 | _bit_mask = digitalPinToBitMask(_PIN); 48 | *_ddr_reg &= ~_bit_mask; // INPUT 49 | *_port_reg |= _bit_mask; // HIGH 50 | #else 51 | pinMode(_PIN, INPUT_PULLUP); 52 | #endif 53 | _bitTime = 1000000UL / baud; 54 | _bitTime2 = (uint32_t)_bitTime >> 1; 55 | _timeout = _bitTime * 10 * 10; // таймаут как время передачи 10 байт 56 | if (_ROLE == GBUS_TX || _ROLE == GBUS_FULL) buffer = (byte *)malloc(_bufSize); 57 | } 58 | 59 | ~softUART() { 60 | if (_ROLE == GBUS_TX || _ROLE == GBUS_FULL) free(buffer); 61 | } 62 | 63 | enum BUS_stage { 64 | BUS_IDLE, 65 | BUS_START, 66 | BUS_SENDING, 67 | BUS_READING, 68 | }; 69 | 70 | bool isBusy() { 71 | return !(micros() - _tmr > _timeout); 72 | } 73 | 74 | int tick() {return available();} 75 | 76 | virtual int available() { 77 | if (_role == GBUS_RX) { // приёмник 78 | if (_ROLE == GBUS_RX || _ROLE == GBUS_FULL) { // компилятор вырежет при выбранной роли 79 | #if defined(__AVR__) 80 | byte bit = (*_pin_reg & _bit_mask); 81 | #else 82 | byte bit = digitalRead(_PIN); 83 | #endif 84 | switch(_busStage) { 85 | case BUS_IDLE: 86 | if (!bit) { // старт бит? 87 | _tmr = micros(); 88 | _busStage = BUS_START; 89 | } 90 | break; 91 | 92 | case BUS_START: 93 | if (micros() - _tmr >= _bitTime2) { 94 | if (!bit) { // да, старт бит 95 | _busStage = BUS_READING; // начинаем приём 96 | _bitCount = 0; 97 | _tmr += _bitTime2; // ждём пол-фрейма 98 | } else { // ошибка 99 | _busStage = BUS_IDLE; 100 | } 101 | } 102 | break; 103 | 104 | case BUS_READING: 105 | if (micros() - _tmr >= _bitTime) { // таймер 106 | _tmr += _bitTime; // следующий фрейм 107 | if (_bitCount < 8) { // чтение битов даты (0-7) 108 | bitWrite(_thisByte, _bitCount, bit); // пишем в буфер 109 | } else if (_bitCount == 8) { // проверяем стоп бит 110 | if (!bit) _busStage = BUS_IDLE; // не дождались стоп бита, конец приема 111 | else _readFlag = 1; // стоп бит. Байт принят 112 | } else if (_bitCount == 9) { // проверяем старт бит 113 | if (bit) _busStage = BUS_IDLE; // не дождались нового старт бита, конец приема 114 | _bitCount = -1; // костыль 115 | } 116 | _bitCount++; // следующий бит 117 | } 118 | break; 119 | } 120 | } 121 | return _readFlag; // вернули 1 если байт собран 122 | } else { // передатчик 123 | if (_ROLE == GBUS_TX || _ROLE == GBUS_FULL) { // компилятор вырежет при выбранной роли 124 | switch(_busStage) { 125 | case BUS_IDLE: 126 | if (_writeStart && micros() - _tmr > SOFTUART_TX_WAIT) { 127 | _writeStart = false; 128 | _busStage = BUS_START; 129 | } 130 | break; 131 | case BUS_START: 132 | if (!isBusy()) { // ждём окончания активности на линии 133 | _busStage = BUS_SENDING; 134 | _bitCount = -1; 135 | _byteCount = 0; 136 | _tmr = micros(); 137 | } 138 | break; 139 | 140 | case BUS_SENDING: 141 | if (micros() - _tmr >= _bitTime) { 142 | byte bit; 143 | if (_bitCount < 0) bit = 0; // старт бит 144 | else if (_bitCount < 8) { // передача даты 145 | bit = (buffer[_byteCount] >> _bitCount) & 1; // бит даты 146 | } else { 147 | bit = 1; // стоп бит 148 | _byteCount++; // след. байт 149 | _bitCount = -2; // костыль 150 | } 151 | // дрыг 152 | #if defined(__AVR__) 153 | if (bit) { 154 | *_ddr_reg &= ~_bit_mask; // INPUT 155 | *_port_reg |= _bit_mask; // HIGH 156 | } else { 157 | *_ddr_reg |= _bit_mask; // OUTPUT 158 | *_port_reg &= ~_bit_mask; // LOW 159 | } 160 | #else 161 | pinMode(_PIN, !bit); 162 | digitalWrite(_PIN, bit); 163 | #endif 164 | _bitCount++; 165 | _tmr += _bitTime; // таймер 166 | if (_byteCount == _txSize) { // передача окончена 167 | _busStage = BUS_IDLE; 168 | if (_ROLE == GBUS_FULL) _role = GBUS_RX;// переключение на приёмник 169 | _tmr = micros(); // сброс таймера 170 | } 171 | } 172 | break; 173 | } 174 | } 175 | return 0; // в режиме передатчика возвращаем 0 176 | } 177 | } 178 | 179 | virtual int read() { 180 | _readFlag = 0; 181 | return _thisByte; 182 | } 183 | 184 | virtual size_t write(uint8_t byte) { 185 | // КВМ (Костыль Вселенских Масштабов) 186 | // наполняем буфер по таймеру 187 | if (_ROLE == GBUS_TX || _ROLE == GBUS_FULL) { // компилер вырежет, если ты приёмный 188 | if (!_writeStart) { 189 | _writeStart = true; 190 | _txSize = 0; 191 | } 192 | if (_txSize < _bufSize) buffer[_txSize++] = byte; 193 | _tmr = micros(); 194 | _role = GBUS_TX; 195 | } 196 | } 197 | 198 | virtual void flush() {} 199 | int peek(){} 200 | 201 | private: 202 | bool _writeStart = false; 203 | const byte _bufSize = SOFTUART_BUF_SIZE; 204 | byte *buffer; //byte buffer[(_ROLE == GBUS_TX || _ROLE == GBUS_FULL) ? SOFTUART_BUF_SIZE : 1]; 205 | int8_t _bitCount = 0; 206 | byte _txSize = 0; 207 | byte _byteCount = 0; 208 | byte _thisByte; 209 | byte _readFlag = 0; 210 | uint32_t _tmr; 211 | byte _role = GBUS_RX; 212 | BUS_stage _busStage = BUS_IDLE; 213 | uint16_t _bitTime; 214 | uint16_t _bitTime2; 215 | long _timeout; 216 | 217 | #if defined(__AVR__) 218 | volatile uint8_t *_port_reg; 219 | volatile uint8_t *_pin_reg; 220 | volatile uint8_t *_ddr_reg; 221 | volatile uint8_t _bit_mask; 222 | #endif 223 | }; 224 | #endif --------------------------------------------------------------------------------