From e6f45643b90efa224077e9b6514bd2ac4a9ee841 Mon Sep 17 00:00:00 2001 From: Alex <84599917+GyverLibs@users.noreply.github.com> Date: Thu, 9 Sep 2021 17:54:30 +0300 Subject: [PATCH] upd --- README.md | 96 +++---- examples/demo_rx/demo_rx.ino | 50 ++-- examples/demo_tx/demo_tx.ino | 23 +- examples/isr_rx/isr_rx.ino | 26 -- examples/raw_rx/raw_rx.ino | 12 +- examples/raw_tx/raw_tx.ino | 6 +- examples/rx433_lcd/rx433_lcd.ino | 4 +- examples/rx433_struct/rx433_struct.ino | 26 +- examples/tx433_struct/tx433_struct.ino | 13 +- keywords.txt | 8 +- library.properties | 2 +- src/Gyver433.h | 344 ++++++++++++------------- 12 files changed, 292 insertions(+), 318 deletions(-) delete mode 100644 examples/isr_rx/isr_rx.ino diff --git a/README.md b/README.md index e2576d8..835a1bc 100644 --- a/README.md +++ b/README.md @@ -2,15 +2,15 @@ ![author](https://img.shields.io/badge/author-AlexGyver-informational.svg) # Gyver433 Библиотека для радиомодулей 433 МГц и Arduino -- Супер лёгкая либа, заведётся даже на тини13 (отправка) - Поддержка кривых китайских модулей -- Интерфейс Manchester или Pulselength -- Встроенный CRC контроль целостности (CRC8 или XOR) +- Встроенный CRC контроль целостности - Ускоренный алгоритм IO для AVR Arduino -- Опционально работа в прерывании (приём данных) +- Асинхронный приём в прерывании +- Супер лёгкая либа, заведётся даже на тини13 ### Совместимость Совместима со всеми Arduino платформами (используются Arduino-функции) +- При подключении прерывания на esp8266 не забудь аттрибут `IRAM_ATTR` ## Содержание - [Установка](#install) @@ -36,27 +36,18 @@ ## Инициализация ```cpp -// === КЛАССЫ === -// Gyver433_RX - приёмник -// Gyver433_TX - передатчик +// === ПЕРЕДАТЧИК === +Gyver433_TX<пин> tx; +Gyver433_TX<пин, CRC> tx; + +// === ПРИЁМНИК === +Gyver433_RX<пин> rx; +Gyver433_RX<пин, буфер> rx; +Gyver433_RX<пин, буфер, CRC> rx; -// === ИНИЦИАЛИЗАЦИЯ === -Gyver433_xx<пин> xx; -Gyver433_xx<пин, буфер> xx; -Gyver433_xx<пин, буфер, CRC> xx; // пин: цифровой пин -// буфер: размер буфера в байтах. На "ручную" отправку буфер не нужен. По умолч. 64 +// буфер: размер буфера в байтах, по умолч. 64 // CRC: проверка целостности данных: G433_CRC8 (надёжный), G433_XOR (лёгкий), G433_NOCRC (отключено). По умолч. G433_CRC8 - - -// === ДЕФАЙНЫ-НАСТРОЙКИ === -// вызывать перед подключением библиотеки -#define G433_FAST // [TX] короткая синхронизация для зелёных модулей -#define G433_MEDIUM // [TX] средняя синхронизация при отправке на SYN480R ЧАЩЕ 400мс (активно по умолчанию) -#define G433_SLOW // [TX] длинная синхронизация при отправке на SYN480R РЕЖЕ 400мс -#define G433_MANCHESTER // [должно быть одинаково на RX и TX] интерфейс Manchester Coding для экспериментов =) -#define G433_SPEED 1000 // [должно быть одинаково на RX и TX] скорость 100-8000 бит/с, по умолч. 2000 бит/с -#define G433_RSSI_COUNT 10 // [RX] количество успешно принятых пакетов для расчёта RSSI (по умолч. 10) ``` @@ -65,22 +56,35 @@ Gyver433_xx<пин, буфер, CRC> xx; // ========= Gyver433_TX ========= void sendData(T &data); // отправить данные любого типа (CRC добавляется автоматически) void write(uint8_t* buf, uint8_t size); // отправить массив байт указанного размера (CRC не добавляется) -uint8_t buffer[]; // доступ к буферу для отладки +uint8_t buffer[]; // доступ к буферу приёма +uint8_t byteBuf; // доступ к буферу принятого байта // ========= Gyver433_RX ========= -uint16_t tick(); // неблокирующий приём, вернёт кол-во успешно принятых байт -uint16_t tickWait(); // блокирующий приём (более надёжный), вернёт кол-во успешно принятых байт -uint16_t tickISR(); // тикер для прерывания по CHANGE (см. пример isr_rx) +void tickISR(); // тикер приёма для вызова в прерывании по CHANGE +uint8_t tickISRraw(); // ручной приём в прерывании по CHANGE. Вернёт 1 (начало приёма), 2 (принят байт), 3 (конец пакета) +uint16_t tick(); // неблокирующий приём. Вернёт количество успешно принятых байт +uint16_t tickWait(); // блокирующий приём. Вернёт количество успешно принятых байт bool readData(T &data); // прочитает буфер в любой тип данных (в указанную переменную) uint16_t getSize(); // получить размер принятых данных uint16_t gotData(); // вернёт количество успешно принятых в tickISR() байт (см. пример isr_rx) -uint8_t buffer[]; // доступ к буферу для отладки -uint8_t getRSSI(); // получить качество приёма (процент успешных передач) +uint8_t getRSSI(); // получить качество приёма (процент успешных передач 0.. 100) + +uint8_t buffer[]; // доступ к буферу приёма +uint8_t byteBuf; // доступ к буферу принятого байта // ============= CRC ============= // можно использовать встроенные функции для генерации байта CRC для ручной упаковки пакетов uint8_t G433_crc8(uint8_t *buffer, uint8_t size); // ручной CRC8 uint8_t G433_crc_xor(uint8_t *buffer, uint8_t size); // ручной CRC XOR + +// ====== ДЕФАЙНЫ-НАСТРОЙКИ ====== +// вызывать перед подключением библиотеки +#define G433_FAST // [TX] короткая синхронизация для зелёных модулей +#define G433_MEDIUM // [TX] средняя синхронизация при отправке на SYN480R ЧАЩЕ 400мс (активно по умолчанию) +#define G433_SLOW // [TX] длинная синхронизация при отправке на SYN480R РЕЖЕ 400мс +#define G433_SPEED 1000 // [одинаково на RX и TX] скорость 100-10000 бит/с, по умолч. 2000 бит/с +#define G433_RSSI_COUNT 10 // [RX] количество успешно принятых пакетов для расчёта RSSI (по умолч. 10) +#define G433_CUT_RSSI // [RX] убрать расчёт RSSI из кода (сэкономить места) ``` @@ -90,7 +94,7 @@ uint8_t G433_crc_xor(uint8_t *buffer, uint8_t size); // ручной CRC XOR ### Отправка ```cpp #include -Gyver433_TX<2, 20> tx; // указали пин и размер буфера +Gyver433_TX<2> tx; // указали пин void setup() { } @@ -108,23 +112,6 @@ void loop() { } ``` -### Приём -```cpp -#include -Gyver433_RX<2, 20> rx; // указали пин и размер буфера - -void setup() { - Serial.begin(9600); -} - -void loop() { - if (rx.tickWait()) { // если успешно принято больше 0 - Serial.write(rx.buffer, rx.size); // выводим - Serial.println(); - } -} -``` - ### Приём в прерывании ```cpp #include @@ -135,8 +122,9 @@ void setup() { attachInterrupt(0, isr, CHANGE); // прерывание пина радио по CHANGE } +// спец. тикер вызывается в прерывании void isr() { - rx.tickISR(); // спец. тикер вызывается в прерывании + rx.tickISR(); } void loop() { @@ -144,10 +132,21 @@ void loop() { Serial.write(rx.buffer, rx.size); // выводим Serial.println(); } - delay(200); // имитация загруженного кода + delay(50); // имитация загруженного кода } ``` +## Заметка по модулям: +Передатчики: +- SYN115, маленький чип: 1.8-3.6V, макс. скорость 8000 +- FS1000A: 3-12V, макс. скорость 10000 +- WL102-341: 2.0-3.6V, макс. скорость 6000 + +Приёмники: +- SYN480R, крупный чип: 3.3-5.5V +- MX-RM-5V (RF-5V): 5V +- RX470 (WL101-341): 3-5V + ## Версии - v1.0 @@ -156,6 +155,7 @@ void loop() { - v1.3 - добавлен вывод RSSI - v1.4 - переделан FastIO - v1.4.1 - убран FastIO, CRC вынесен отдельно +- v2.0 - убран буфер на отправку, убран манчестер, полностью переделан и оптимизирован интерфейс связи ## Баги и обратная связь diff --git a/examples/demo_rx/demo_rx.ino b/examples/demo_rx/demo_rx.ino index 8bb2e78..61ae7a3 100644 --- a/examples/demo_rx/demo_rx.ino +++ b/examples/demo_rx/demo_rx.ino @@ -1,39 +1,53 @@ -// демо-пример: инициализация и настройки -// крупный приёмник SYN480R [VCC: 3.3-5.5V, logic: VCC] -// или MX-RM-5V (RF-5V) [VCC: 5V, logic: 5V] +// демо-пример приёма в прерывании +// SYN480R, крупный чип: 3.3-5.5V +// MX-RM-5V (RF-5V): 5V +// RX470 (WL101-341): 3-5V // дефайны перед подключением библиотеки -//#define G433_MANCHESTER // интерфейс Manchester Coding для экспериментов =) -//#define G433_SPEED 1000 // скорость 100-8000 бит/с, по умолч. 2000 бит/с +//#define G433_SPEED 2000 // скорость 100-10000 бит/с, по умолч. 2000 бит/с #include //Gyver433_RX<пин> rx; //Gyver433_RX<пин, буфер> rx; -//Gyver433_RX<пин, буфер, CRC> rx; // пин: цифровой пин -// буфер: размер буфера в байтах. По умолч. 64 -// CRC: проверка целостности данных: G433_CRC8 (надёжный), G433_XOR (лёгкий), G433_NOCRC (отключено). По умолч. G433_CRC8 +// буфер: размер приёмного буфера в байтах. По умолч. 64 +#include Gyver433_RX<2, 20> rx; void setup() { Serial.begin(9600); + // взводим прерывания по CHANGE + attachInterrupt(0, isr, CHANGE); } -void loop() { - // "тик" опрашивает радио и вернёт количество успешно принятых байт - // tick принимает асинхронно, но может ловить ошибки при загруженном коде - // tickWait блокирует выполнение, но принимает данные чётко +// тикер вызывается в прерывании +void isr() { + rx.tickISR(); +} - //if (rx.tick()) { - if (rx.tickWait()) { - // принятые данные доступны в .buffer - // и имеют размер .size - Serial.write(rx.buffer, rx.size); +void loop() { + // gotData() вернёт количество удачно принятых байт + if (rx.gotData()) { // если больше 0 + // ЧИТАЕМ. СПОСОБ 1 + // я знаю, что передатчик отправляет char[15] + char data[15]; + + // читаем принятые данные в data + // если данные совпадают по размеру - ок + if (rx.readData(data)) Serial.print(data); + else Serial.print("Data error"); - // выведем также качество связи + // ЧИТАЕМ. СПОСОБ 2 + // вывести сырые данные из буфера в порт + //Serial.write(rx.buffer, rx.size); + + // выведем также качество соединения Serial.print(", RSSI: "); Serial.println(rx.getRSSI()); } + + // имитация загруженного кода. Не влияет на приём + delay(50); } diff --git a/examples/demo_tx/demo_tx.ino b/examples/demo_tx/demo_tx.ino index 03dba9c..5dd9efe 100644 --- a/examples/demo_tx/demo_tx.ino +++ b/examples/demo_tx/demo_tx.ino @@ -1,24 +1,17 @@ -// демо-пример: инициализация и настройки -// мелкий передатчик SYN115 [VCC: 1.8-3.6V, logic: VCC] -// или FS1000A [VCC: 3-12V, logic: 5V] +// демо-пример отправки +// SYN115, маленький чип: 1.8-3.6V +// FS1000A: 3-12V +// WL102-341: 2.0-3.6V // дефайны перед подключением библиотеки //#define G433_FAST // короткая синхронизация для зелёных модулей //#define G433_MEDIUM // средняя синхронизация для SYN480R при отправке ЧАЩЕ 400мс (активно по умолчанию) //#define G433_SLOW // длинная синхронизация для SYN480R при отправке РЕЖЕ 400мс -//#define G433_MANCHESTER // интерфейс Manchester Coding для экспериментов =) -//#define G433_SPEED 1000 // скорость 100-8000 бит/с, по умолч. 2000 бит/с +//#define G433_SPEED 2000 // скорость 100-10000 бит/с, по умолч. 2000 бит/с #include -//Gyver433_TX<пин> tx; -//Gyver433_TX<пин, буфер> tx; -//Gyver433_TX<пин, буфер, CRC> tx; - -// пин: цифровой пин -// буфер: размер буфера в байтах. На "ручную" отправку буфер не нужен. По умолч. 64 -// CRC: проверка целостности данных: G433_CRC8 (надёжный), G433_XOR (лёгкий), G433_NOCRC (отключено). По умолч. G433_CRC8 - -Gyver433_TX<2, 20> tx; +//Gyver433_RX<пин> tx; +Gyver433_TX<2> tx; void setup() { } @@ -32,7 +25,7 @@ void loop() { data[13] = (count % 10) + '0'; if (++count >= 100) count = 0; - // отправка данных любого типа. Блокирующая на период отправки + // отправка данных любого типа tx.sendData(data); // отправка 10 раз в сек diff --git a/examples/isr_rx/isr_rx.ino b/examples/isr_rx/isr_rx.ino deleted file mode 100644 index 9b1b7da..0000000 --- a/examples/isr_rx/isr_rx.ino +++ /dev/null @@ -1,26 +0,0 @@ -// приём в прерывании. Отправляет пример demo_tx -//#define G433_SPEED 1000 // скорость 100-8000 бит/с, по умолч. 2000 бит/с - -#include -Gyver433_RX<2, 20> rx; // указали пин и размер буфера - -void setup() { - Serial.begin(9600); - // взводим прерывания по CHANGE - attachInterrupt(0, isr, CHANGE); -} - -void isr() { - rx.tickISR(); // спец. тикер вызывается в прерывании по CHANGE -} - -void loop() { - // .gotData() вернёт количество удачно принятых в прерывании байт - if (rx.gotData()) { // если больше 0 - Serial.write(rx.buffer, rx.size); - Serial.println(); - } - - // имитация загруженного кода - delay(100); -} diff --git a/examples/raw_rx/raw_rx.ino b/examples/raw_rx/raw_rx.ino index ac76d05..2e6a4f4 100644 --- a/examples/raw_rx/raw_rx.ino +++ b/examples/raw_rx/raw_rx.ino @@ -1,15 +1,21 @@ -// обмен сырыми данными без CRC и буфера на отправку +// обмен сырыми данными без CRC // отправляет пример raw_tx +// принимаем без прерывания! для примера + +//#define G433_SPEED 1000 // скорость 100-10000 бит/с, по умолч. 2000 бит/с #include -Gyver433_RX<2, 20, G433_NOCRC> rx; // буфер на приём нужен! +Gyver433_RX<2, 20, G433_NOCRC> rx; // буфер 20 байт void setup() { Serial.begin(9600); } void loop() { - if (rx.tickWait()) { + // этот тикер нужно вызывать как можно чаще + // лучше принимать в прерывании, см. пример demo + if (rx.tick()) { + // выводим сырые байты в порт Serial.write(rx.buffer, rx.size); Serial.println(); } diff --git a/examples/raw_tx/raw_tx.ino b/examples/raw_tx/raw_tx.ino index 850e367..ec8eb75 100644 --- a/examples/raw_tx/raw_tx.ino +++ b/examples/raw_tx/raw_tx.ino @@ -1,10 +1,10 @@ -// обмен сырыми данными без CRC и буфера на отправку +// обмен сырыми данными без CRC // принимает пример raw_rx -//#define G433_SPEED 1000 // скорость 100-8000 бит/с, по умолч. 2000 бит/с +//#define G433_SPEED 1000 // скорость 100-10000 бит/с, по умолч. 2000 бит/с #include -Gyver433_TX<2, 0, G433_NOCRC> tx; // буфер на отправку 0! Экономим +Gyver433_TX<2, G433_NOCRC> tx; void setup() { } diff --git a/examples/rx433_lcd/rx433_lcd.ino b/examples/rx433_lcd/rx433_lcd.ino index bd14071..a93ed67 100644 --- a/examples/rx433_lcd/rx433_lcd.ino +++ b/examples/rx433_lcd/rx433_lcd.ino @@ -1,5 +1,5 @@ // выводим данные на дисплей. Отправляет пример demo_tx -//#define G433_SPEED 1000 // скорость 100-8000 бит/с, по умолч. 2000 бит/с +//#define G433_SPEED 1000 // скорость 100-10000 бит/с, по умолч. 1500 бит/с #include Gyver433_RX<2> rx; // указали пин @@ -18,4 +18,4 @@ void loop() { lcd.home(); for (byte i = 0; i < rx.size; i++) lcd.write(rx.buffer[i]); } -} +} \ No newline at end of file diff --git a/examples/rx433_struct/rx433_struct.ino b/examples/rx433_struct/rx433_struct.ino index c67da59..d5f1d7a 100644 --- a/examples/rx433_struct/rx433_struct.ino +++ b/examples/rx433_struct/rx433_struct.ino @@ -1,12 +1,12 @@ // приём структуры данных -//#define G433_SPEED 1000 // скорость 100-8000 бит/с, по умолч. 2000 бит/с +//#define G433_SPEED 1000 // скорость 100-10000 бит/с, по умолч. 2000 бит/с #include -Gyver433_RX<2, 10> rx; // указали пин и размер буфера +Gyver433_RX<2, 12> rx; // указали пин и размер буфера // формат пакета для приёма (такой же как отправляется) -struct dataPack { +struct DataPack { byte counter; byte randomNum; int analog; @@ -19,14 +19,16 @@ void setup() { void loop() { if (rx.tick()) { - dataPack data; // "буферная" структура - rx.readData(data); // переписываем данные в неё - - Serial.println("Received:"); - Serial.println(data.counter); - Serial.println(data.randomNum); - Serial.println(data.analog); - Serial.println(data.time); - Serial.println(); + DataPack data; // "буферная" структура + if (rx.readData(data)) { // переписываем данные в неё + // если данные подходят - выводим + Serial.println(data.counter); + Serial.println(data.randomNum); + Serial.println(data.analog); + Serial.println(data.time); + Serial.println(); + } else { + Serial.println("Wrong data"); + } } } diff --git a/examples/tx433_struct/tx433_struct.ino b/examples/tx433_struct/tx433_struct.ino index 1bec95a..9a55578 100644 --- a/examples/tx433_struct/tx433_struct.ino +++ b/examples/tx433_struct/tx433_struct.ino @@ -1,19 +1,19 @@ // передача структуры данных -//#define G433_SPEED 1000 // скорость 100-8000 бит/с, по умолч. 2000 бит/с +//#define G433_SPEED 1000 // скорость 100-10000 бит/с, по умолч. 2000 бит/с #define G433_SLOW // отправляю раз в секунду на SYN480R #include -Gyver433_TX<2, 10> tx; // указали пин и размер буфера +Gyver433_TX<2> tx; // указали пин // формат пакета для отправки -struct dataPack { - byte counter; +struct DataPack { + byte counter = 0; byte randomNum; int analog; uint32_t time; }; -dataPack data; +DataPack data; void setup() { Serial.begin(9600); @@ -24,9 +24,8 @@ void loop() { data.randomNum = random(256); // случайное число data.analog = analogRead(0); // тут ацп data.time = millis(); // тут миллис - tx.sendData(data); - + Serial.println("Transmitted:"); Serial.println(data.counter); Serial.println(data.randomNum); diff --git a/keywords.txt b/keywords.txt index 9ea093a..bf4a4bb 100644 --- a/keywords.txt +++ b/keywords.txt @@ -13,12 +13,11 @@ Gyver433_RX KEYWORD1 # Methods and Functions (KEYWORD2) ####################################### sendData KEYWORD2 -sendDataSlow KEYWORD2 write KEYWORD2 -writeSlow KEYWORD2 tick KEYWORD2 -tickISR KEYWORD2 tickWait KEYWORD2 +tickISR KEYWORD2 +tickISRraw KEYWORD2 readData KEYWORD2 size KEYWORD2 buffer KEYWORD2 @@ -31,6 +30,7 @@ getRSSI KEYWORD2 ####################################### # Constants (LITERAL1) ####################################### +G433_CLI LITERAL1 G433_CRC8 LITERAL1 G433_XOR LITERAL1 G433_NOCRC LITERAL1 @@ -38,4 +38,4 @@ G433_FAST LITERAL1 G433_MEDIUM LITERAL1 G433_SLOW LITERAL1 G433_SPEED LITERAL1 -G433_MANCHESTER LITERAL1 \ No newline at end of file +G433_CUT_RSSI LITERAL1 \ No newline at end of file diff --git a/library.properties b/library.properties index 797b725..dd76b2e 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Gyver433 -version=1.4.1 +version=2.0 author=AlexGyver maintainer=AlexGyver sentence=Simple library for 433 MHz radio diff --git a/src/Gyver433.h b/src/Gyver433.h index 8e9454c..09a5ac2 100644 --- a/src/Gyver433.h +++ b/src/Gyver433.h @@ -3,12 +3,11 @@ Документация: GitHub: https://github.com/GyverLibs/Gyver433 Возможности: - - Супер лёгкая либа, заведётся даже на тини13 (отправка) - Поддержка кривых китайских модулей - - Интерфейс Manchester или Pulselength - - Встроенный CRC контроль целостности (CRC8 или XOR) + - Встроенный CRC контроль целостности - Ускоренный алгоритм IO для AVR Arduino - - Опционально работа в прерывании (приём данных) + - Асинхронный приём в прерывании + - Супер лёгкая либа, заведётся даже на тини13 AlexGyver, alex@alexgyver.ru https://alexgyver.ru/ @@ -21,14 +20,15 @@ v1.3 - добавлен вывод RSSI v1.4 - переделан FastIO v1.4.1 - убран FastIO, CRC вынесен отдельно + v2.0 - убран буфер на отправку, убран манчестер, полностью переделан и оптимизирован интерфейс связи */ -#ifndef Gyver433_h -#define Gyver433_h +#ifndef _Gyver433_h +#define _Gyver433_h #include #include "G433_crc.h" -#define TRAINING_TIME_SLOW (500000ul) // время синхронизации для SLOW_MODE +#define TRAINING_TIME_SLOW (500000) // время синхронизации для SLOW_MODE // ========================================================================= #ifndef G433_SPEED @@ -36,27 +36,27 @@ #endif #ifndef G433_RSSI_COUNT -#define G433_RSSI_COUNT 10 +#define G433_RSSI_COUNT 16 #endif // тайминги интерфейса -#define FRAME_TIME (1000000ul / G433_SPEED) // время фрейма (либо HIGH) -#define HALF_FRAME (FRAME_TIME / 2) // полфрейма (либо LOW) -#define START_PULSE (FRAME_TIME * 2) // стартовый импульс +#define G433_HIGH (1000000ul / G433_SPEED) // время HIGH +#define G433_LOW (G433_HIGH / 2) // время LOW +#define G433_START (G433_HIGH * 2) // стартовый импульс +#define G433_TRAIN (G433_HIGH * 3 / 2) // синхроимпульс -// окно времени для обработки импульса -#define START_MIN (START_PULSE * 3 / 4) -#define START_MAX (START_PULSE * 5 / 4) -#define FRAME_MIN (FRAME_TIME * 3 / 4) -#define FRAME_MAX (FRAME_TIME * 5 / 4) -#define HALF_FRAME_MIN (HALF_FRAME * 3 / 4) -#define HALF_FRAME_MAX (HALF_FRAME * 5 / 4) +#define G433_WINDOW (G433_HIGH / 4) +#define G433_EDGE_L (G433_LOW - G433_WINDOW) +#define G433_EDGE_LH (G433_HIGH - G433_WINDOW) +#define G433_EDGE_HT (G433_HIGH + G433_WINDOW) +#define G433_EDGE_TS (G433_TRAIN + G433_WINDOW) +#define G433_EDGE_S (G433_START + G433_WINDOW) // жоский delay для avr #ifdef AVR -#define G433_DELAY _delay_us +#define G433_DELAY(x) _delay_us(x) #else -#define G433_DELAY delayMicroseconds +#define G433_DELAY(x) delayMicroseconds(x) #endif // режимы CRC @@ -66,17 +66,17 @@ // количество синхроимпульсов #if defined(G433_FAST) -#define TRAINING_PULSES 10 +#define TRAINING_TIME 10000 #elif defined(G433_MEDIUM) -#define TRAINING_PULSES 50 +#define TRAINING_TIME 100000 #elif defined(G433_SLOW) -#define TRAINING_PULSES (TRAINING_TIME_SLOW / FRAME_TIME / 2) +#define TRAINING_TIME (TRAINING_TIME_SLOW) #else -#define TRAINING_PULSES 50 +#define TRAINING_TIME 100000 #endif -// ============ ПЕРЕДАТЧИК ============ -template +// =================================== ПЕРЕДАТЧИК =================================== +template class Gyver433_TX { public: Gyver433_TX() { @@ -86,144 +86,173 @@ public: // отправка, блокирующая. Кушает любой тип данных template bool sendData(T &data) { - if (sizeof(T) > TX_BUF) return 0; - const uint8_t *ptr = (const uint8_t*) &data; - for (uint16_t i = 0; i < sizeof(T); i++) buffer[i] = *ptr++; - if (CRC_MODE == G433_CRC8) { - buffer[sizeof(T)] = G433_crc8(buffer, sizeof(T)); - write(buffer, sizeof(T) + 1); - } else if (CRC_MODE == G433_XOR) { - buffer[sizeof(T)] = G433_crc_xor(buffer, sizeof(T)); - write(buffer, sizeof(T) + 1); - } else { - write(buffer, sizeof(T)); - } - return 1; + uint8_t *ptr = (uint8_t*) &data; + write(ptr, sizeof(T)); } // отправка сырого набора байтов void write(uint8_t* buf, uint16_t size) { - for (uint16_t i = 0; i < TRAINING_PULSES; i++) { - fastWrite(TX_PIN, 1); - G433_DELAY(FRAME_TIME); - fastWrite(TX_PIN, 0); - G433_DELAY(FRAME_TIME); - } - fastWrite(TX_PIN, 1); // старт - G433_DELAY(START_PULSE); // ждём - fastWrite(TX_PIN, 0); // старт бит + uint8_t crc; + if (CRC_MODE == G433_CRC8) crc = G433_crc8(buf, size); + else if (CRC_MODE == G433_XOR) crc = G433_crc_xor(buf, size); - #ifdef G433_MANCHESTER - G433_DELAY(HALF_FRAME); // ждём - for (uint16_t n = 0; n < size; n++) { - uint8_t data = buf[n]; - for (uint8_t b = 0; b < 8; b++) { - fastWrite(TX_PIN, !(data & 1)); - G433_DELAY(HALF_FRAME); - fastWrite(TX_PIN, (data & 1)); - G433_DELAY(HALF_FRAME); - data >>= 1; - } + // раскачка радио + flag = 0; + for (uint16_t i = 0; i < (TRAINING_TIME / G433_TRAIN / 2) * 2 + 1; i++) { + fastWrite(TX_PIN, flag = !flag); + G433_DELAY(G433_TRAIN); } - fastWrite(TX_PIN, 0); // конец передачи - #else - bool flag = 0; - for (uint16_t n = 0; n < size; n++) { - uint8_t data = buf[n]; - for (uint8_t b = 0; b < 8; b++) { - if (data & 1) G433_DELAY(FRAME_TIME); - else G433_DELAY(HALF_FRAME); - fastWrite(TX_PIN, flag = !flag); - data >>= 1; - } + + // старт бит + fastWrite(TX_PIN, 0); // старт + G433_DELAY(G433_START); // ждём + fastWrite(TX_PIN, 1); // старт бит + + for (uint16_t i = 0; i < size; i++) write(buf[i]); // дата + if (CRC_MODE) write(crc); // CRC + G433_DELAY(G433_TRAIN); + fastWrite(TX_PIN, flag = !flag); // стоп + } + + // отправить байт (без старт бита!) + void write(uint8_t data) { + for (uint8_t b = 0; b < 8; b++) { + if (data & 1) G433_DELAY(G433_HIGH); + else G433_DELAY(G433_LOW); + fastWrite(TX_PIN, flag = !flag); + data >>= 1; } - #endif } - // доступ к буферу - uint8_t buffer[TX_BUF + !!CRC_MODE]; - private: + // быстрый IO void fastWrite(const uint8_t pin, bool val) { -#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) + #if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) if (pin < 8) bitWrite(PORTD, pin, val); else if (pin < 14) bitWrite(PORTB, (pin - 8), val); else if (pin < 20) bitWrite(PORTC, (pin - 14), val); -#elif defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny13__) + #elif defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny13__) bitWrite(PORTB, pin, val); -#else + #else digitalWrite(pin, val); -#endif + #endif } + + bool flag = 0; }; -// ============ ПРИЁМНИК ============ +// =================================== ПРИЁМНИК =================================== template class Gyver433_RX { -public: +public: Gyver433_RX() { pinMode(RX_PIN, INPUT); } - // неблокирующий приём, вернёт кол-во успешно принятых байт - uint16_t tick() { - if (pinChanged()) checkState(); + // неблокирующий приём. Вернёт количество успешно принятых байт + uint16_t tick() { + if (pinChanged()) tickISR(); return gotData(); } - // tick для вызова в прерывании по CHANGE - void tickISR() { - #ifdef G433_MANCHESTER - if (pinChanged()) checkState(); - #else - checkState(); - #endif - } - - // блокирующий приём, вернёт кол-во успешно принятых байт + // блокирующий приём. Вернёт количество успешно принятых байт uint16_t tickWait() { do { - if (tick()) return size; - } while (parse == 2); + if (pinChanged()) tickISR(); + } while (state == 1); + return gotData(); + } + + // ручной приём в прерывании по CHANGE. Вернёт 1 (начало приёма), 2 (принят байт), 3 (конец пакета) + // принятый байт можно прочитать в byteBuf + uint8_t tickISRraw() { + uint32_t pulse = micros() - tmr; // время импульса + tmr += pulse; // сброс таймера. Равносильно tmr = micros() + if (pulse <= G433_EDGE_L) return parse = 0; // импульс слишком короткий + trains <<= 1; // счётчик train импульсов (0b11111111 << 1) + if (pulse <= G433_EDGE_HT && parse) { // окно LOW/HIGH и идёт парсинг + byteBuf >>= 1; // двигаем байт-буфер + if (pulse > G433_EDGE_LH) byteBuf |= (1 << 7); // пишем бит, если это HIGH + if (!(++bits & 0x7)) return 2; // 2: ПРИНЯТ БАЙТ: собрали байт (каждые 8 бит, 0x7 == 0b111) + } else if (pulse <= G433_EDGE_TS) { // окно START + trains |= 1; // добавляем 1 справа к trains + if (parse) { // был парсинг, а это стоп бит + parse = 0; // стоп машина + return 3; // 3: ПРИНЯТ ПАКЕТ: принят стоп-бит + } + } else if (pulse <= G433_EDGE_S) { // окно STOP/TRAINING + if (trains == 0xFE) { // было 7 train импульсов (0xFE == 0b11111110) + bits = 0; // прерываем парсинг, если он был + parse = 1; // старт бит, начинаем парсинг + return 1; // 1: СТАРТ ПРИЁМА + } + } else return parse = 0; // слишком длинный импульс, выходим return 0; } + // тикер приёма для вызова в прерывании по CHANGE + void tickISR() { + switch (tickISRraw()) { + case 1: // СТАРТ БИТ + if (!state) { // старта не было + state = 1; // старт + bytes = 0; // сброс + } // старт был - ошибка приёма + break; + case 2: // ПРИНЯТ БАЙТ + if (state == 1) { // парсинг идёт + buffer[bytes] = byteBuf; // пишем в буфер + bytes++; // счётчик принятых + if (bytes > sizeof(buffer)) { // буфер переполнен + state = 3; // флаг на чтение + } + } + break; + case 3: // КОНЕЦ ПАКЕТА + if (state == 1) state = 2; // флаг на чтение + break; + } + } + + // если пакет прочитан успешно - вернёт количество байт в нём + uint16_t gotData() { + if (state >= 2) { // флаг на чтение + size = 0; // обнуляем размер + if (state != 3 && bytes != 0) { // если буфер не переполнен, проверяем CRC + if (CRC_MODE == G433_CRC8) { // CRC8 + if (!G433_crc8(buffer, bytes)) size = bytes - 1; + } else if (CRC_MODE == G433_XOR) { // CRC XOR + if (!G433_crc_xor(buffer, bytes)) size = bytes - 1; + } else size = bytes; // без CRC + } + #ifndef G433_CUT_RSSI + if (!size) errCount++; // принято 0 байт - ошибка + if (++rcCount >= G433_RSSI_COUNT) { + RSSI = 100 - errCount * 100 / G433_RSSI_COUNT; + errCount = rcCount = 0; + } + #endif + state = 0; + return size; + } + return 0; + } + // прочитает буфер в любой тип данных template bool readData(T &data) { - if (sizeof(T) > RX_BUF) return false; - uint8_t *ptr = (uint8_t*) &data; + if (sizeof(T) > RX_BUF) return false; // великовато для буфера + if (sizeof(T) != size) return false; // данные не соответствуют + uint8_t *ptr = (uint8_t*) &data; for (uint16_t i = 0; i < sizeof(T); i++) *ptr++ = buffer[i]; return true; } - // вернёт true при получении корректных данных - uint16_t gotData() { - if (parse == 2 && millis() - tmr2 >= 10) { // фрейм не закрыт - parse = size = 0; // приём окончен - if (byteCount > (1 + !!CRC_MODE)) { // если что то приняли - if (!bitCount) { // байт закрыт - if (CRC_MODE == G433_CRC8) { // CRC8 - if (!G433_crc8(buffer, byteCount)) size = byteCount - 2; - } else if (CRC_MODE == G433_XOR) { // CRC XOR - if (!G433_crc_xor(buffer, byteCount)) size = byteCount - 2; - } else size = byteCount - 1; // без CRC - } - // расчёт RSSI - if (!size) errCount++; - if (++rcCount >= G433_RSSI_COUNT) { - RSSI = 100 - errCount * 100 / G433_RSSI_COUNT; - errCount = rcCount = 0; - } - } - return size; - } - return 0; - } - // получить качество приёма (процент успешных передач) uint8_t getRSSI() { + #ifndef G433_CUT_RSSI return RSSI; + #endif } // получить размер принятых данных @@ -236,80 +265,37 @@ public: // доступ к буферу uint8_t buffer[RX_BUF + !!CRC_MODE]; + uint8_t byteBuf; private: bool fastRead(const uint8_t pin) { -#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) + #if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) if (pin < 8) return bitRead(PIND, pin); else if (pin < 14) return bitRead(PINB, pin - 8); else if (pin < 20) return bitRead(PINC, pin - 14); -#elif defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny13__) + #elif defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny13__) return bitRead(PINB, pin); -#else + #else return digitalRead(pin); -#endif + #endif return 0; } bool pinChanged() { - bit = fastRead(RX_PIN); - if (bit != prevBit) { - prevBit = bit; + if (prevBit != fastRead(RX_PIN)) { + prevBit = !prevBit; return 1; } return 0; } - void checkState() { - uint32_t thisPulse = micros() - tmr; // время импульса - if (parse == 1) { // в прошлый раз поймали фронт - #ifdef G433_MANCHESTER - tmr += thisPulse; // сброс таймера приёма - #endif - if (thisPulse > START_MIN && thisPulse < START_MAX) { // старт бит? - tmr2 = millis(); // сброс таймера активности - parse = 2; // ключ на старт - byteCount = bitCount = size = 0; // сброс - } else parse = 0; // не старт бит - } else if (parse == 2) { // идёт парсинг - #ifdef G433_MANCHESTER - if (thisPulse > FRAME_MIN && thisPulse < FRAME_MAX) { // фронт внутри таймфрейма - tmr += thisPulse; // синхронизируем тайминги - tmr2 = millis(); // сброс таймера активности - buffer[byteCount] >>= 1; // двигаем байт - buffer[byteCount] |= (bit << 7); // пишем данные - bitCount++; // счётчик битов - } - #else - uint8_t state = 2; - if (thisPulse > HALF_FRAME_MIN && thisPulse < HALF_FRAME_MAX) state = 0; // low бит - else if (thisPulse > FRAME_MIN && thisPulse < FRAME_MAX) state = 1; // high бит - if (state != 2) { - buffer[byteCount] >>= 1; // двигаем байт - buffer[byteCount] |= (state << 7); // пишем данные - bitCount++; // счётчик битов - tmr2 = millis(); // сброс таймера активности - } - #endif - if (bitCount == 8) { // собрали байт - bitCount = 0; // сброс - if (++byteCount >= RX_BUF) parse = 0; // буфер переполнен - } - } - #ifdef G433_MANCHESTER - if (bit && parse == 0) { // ловим фронт - parse = 1; // флаг на старт - tmr += thisPulse; // сброс таймера - } - #else - if (parse == 0) parse = 1; // принудительно стартуем - tmr += thisPulse; // сброс таймера приёма - #endif - } - bool bit, prevBit; - uint8_t parse = 0; - uint32_t tmr = 0, tmr2 = 0; - uint8_t bitCount = 0, byteCount = 0; - uint8_t errCount = 0, rcCount = 0, RSSI = 0; + bool prevBit; + volatile uint8_t state = 0; + volatile uint8_t parse = 0, trains = 0; + volatile uint32_t tmr = 0; + uint8_t bits = 0, bytes = 0; +#ifndef G433_CUT_RSSI + uint8_t errCount = 0, rcCount = 0, RSSI = 100; +#endif }; #endif \ No newline at end of file