├── .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 | [](https://github.com/GyverLibs/GyverBus/releases/latest/download/GyverBus.zip)
2 | [](https://registry.platformio.org/libraries/gyverlibs/GyverBus)
3 | [](https://alexgyver.ru/)
4 | [](https://alexgyver.ru/support_alex/)
5 | [](https://github-com.translate.goog/GyverLibs/GyverBus?_x_tr_sl=ru&_x_tr_tl=en)
6 |
7 | [](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
--------------------------------------------------------------------------------