7 Commits

Author SHA1 Message Date
Alex 48e1fa1e98 v1.2 2021-06-17 12:49:46 +03:00
Alex bd9e4b19ae Update README.md 2021-06-14 21:55:30 +03:00
Alex ecfcdf1bf9 v1.1 2021-06-14 21:53:39 +03:00
Alex 1e37f86364 Update README.md 2021-06-14 18:38:06 +03:00
Alex cb09165d3e v1.1 2021-06-14 18:36:58 +03:00
Alex ef9eca0f9f Update Gyver433.h 2021-05-26 01:09:20 +03:00
Alex a06be3a93e Update README.md 2021-05-25 00:05:07 +03:00
15 changed files with 574 additions and 258 deletions
+80 -36
View File
@@ -1,10 +1,13 @@
![License: MIT](https://img.shields.io/badge/License-MIT-green.svg) ![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)
![author](https://img.shields.io/badge/author-AlexGyver-informational.svg) ![author](https://img.shields.io/badge/author-AlexGyver-informational.svg)
# Gyver433_TX # Gyver433
Библиотека для радиомодулей 433 МГц и Arduino Библиотека для радиомодулей 433 МГц и Arduino
- Не использует прерывания и таймеры (кроме нулевого, читает micros()) - Супер лёгкая либа, заведётся даже на тини13 (отправка)
- Встроенный CRC контроль целостности - Поддержка кривых китайских модулей
- Интерфейс Manchester или Pulselength
- Встроенный CRC контроль целостности (CRC8 или XOR)
- Ускоренный алгоритм IO для AVR Arduino - Ускоренный алгоритм IO для AVR Arduino
- Опционально работа в прерывании (приём данных)
### Совместимость ### Совместимость
Совместима со всеми Arduino платформами (используются Arduino-функции) Совместима со всеми Arduino платформами (используются Arduino-функции)
@@ -19,11 +22,11 @@
<a id="install"></a> <a id="install"></a>
## Установка ## Установка
- Библиотеку можно найти по названию **Gyver433_TX** и установить через менеджер библиотек в: - Библиотеку можно найти по названию **Gyver433** и установить через менеджер библиотек в:
- Arduino IDE - Arduino IDE
- Arduino IDE v2 - Arduino IDE v2
- PlatformIO - PlatformIO
- [Скачать библиотеку](https://github.com/GyverLibs/Gyver433_TX/archive/refs/heads/main.zip) .zip архивом для ручной установки: - [Скачать библиотеку](https://github.com/GyverLibs/Gyver433/archive/refs/heads/main.zip) .zip архивом для ручной установки:
- Распаковать и положить в *C:\Program Files (x86)\Arduino\libraries* (Windows x64) - Распаковать и положить в *C:\Program Files (x86)\Arduino\libraries* (Windows x64)
- Распаковать и положить в *C:\Program Files\Arduino\libraries* (Windows x32) - Распаковать и положить в *C:\Program Files\Arduino\libraries* (Windows x32)
- Распаковать и положить в *Документы/Arduino/libraries/* - Распаковать и положить в *Документы/Arduino/libraries/*
@@ -33,80 +36,121 @@
<a id="init"></a> <a id="init"></a>
## Инициализация ## Инициализация
```cpp ```cpp
// указать пин // === КЛАССЫ ===
Gyver433_RX rx(2); // Gyver433_RX - приёмник
Gyver433_TX tx(2); // Gyver433_TX - передатчик
// === ИНИЦИАЛИЗАЦИЯ ===
Gyver433_xx<пин> xx;
Gyver433_xx<пин, буфер> xx;
Gyver433_xx<пин, буфер, CRC> xx;
// пин: цифровой пин
// буфер: размер буфера в байтах. На "ручную" отправку буфер не нужен. По умолч. 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 бит/с
``` ```
<a id="usage"></a> <a id="usage"></a>
## Использование ## Использование
```cpp ```cpp
// ========= Gyver433_TX ========= // ========= Gyver433_TX =========
void sendData(T &data); // отправить данные любого типа void sendData(T &data); // отправить данные любого типа (CRC добавляется автоматически)
void write(uint8_t* buf, uint8_t size); // отправить массив байт указанного размера (CRC не добавляется)
uint8_t buffer[]; // доступ к буферу для отладки
// ========= Gyver433_RX ========= // ========= Gyver433_RX =========
uint8_t tick(); // неблокирующий приём, вернёт кол-во успешно принятых байт uint16_t tick(); // неблокирующий приём, вернёт кол-во успешно принятых байт
uint8_t tickWait(); // блокирующий приём, вернёт кол-во успешно принятых байт uint16_t tickWait(); // блокирующий приём (более надёжный), вернёт кол-во успешно принятых байт
uint16_t tickISR(); // тикер для прерывания по CHANGE (см. пример isr_rx)
bool readData(T &data); // прочитает буфер в любой тип данных (в указанную переменную) bool readData(T &data); // прочитает буфер в любой тип данных (в указанную переменную)
int getSize(); // получить размер принятых данных uint16_t getSize(); // получить размер принятых данных
uint16_t gotData(); // вернёт количество успешно принятых в tickISR() байт (см. пример isr_rx)
uint8_t buffer[]; // доступ к буферу для отладки
// ============= 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
``` ```
<a id="example"></a> <a id="example"></a>
## Пример ## Примеры
Остальные примеры смотри в **examples**! Остальные примеры смотри в **examples**!
![Logo](/doc/scheme.jpg)
### Отправка ### Отправка
```cpp ```cpp
// мелкий передатчик 3.6V SYN115
#define G433_BUFSIZE 50 // размер буфера
#define G433_SPEED 2000 // скорость бит/сек (минимальная)
#include <Gyver433.h> #include <Gyver433.h>
Gyver433_TX tx(2); // указали пин Gyver433_TX<2, 20> tx; // указали пин и размер буфера
void setup() { void setup() {
} }
char data[] = "Hello from #xx"; char data[] = "Hello from #xx"; // строка для отправки
byte count = 0; byte count = 0; // счётчик для отправки
void loop() { void loop() {
// добавляем счётчик в строку
data[12] = (count / 10) + '0'; data[12] = (count / 10) + '0';
data[13] = (count % 10) + '0'; data[13] = (count % 10) + '0';
if (++count >= 100) count = 0; if (++count >= 100) count = 0;
tx.sendData(data); tx.sendData(data);
delay(100); delay(100);
} }
``` ```
### Приём ### Приём
```cpp ```cpp
// крупный приёмник 5.0 SYN480R
#define G433_BUFSIZE 50 // размер буфера
#define G433_SPEED 2000 // скорость бит/сек (минимальная)
#include <Gyver433.h> #include <Gyver433.h>
Gyver433_RX rx(2); Gyver433_RX<2, 20> rx; // указали пин и размер буфера
void setup() { void setup() {
Serial.begin(9600); Serial.begin(9600);
} }
void loop() {
if (rx.tickWait()) { // если успешно принято больше 0
Serial.write(rx.buffer, rx.size); // выводим
Serial.println();
}
}
```
### Приём в прерывании
```cpp
#include <Gyver433.h>
Gyver433_RX<2, 20> rx; // указали пин и размер буфера
void setup() {
Serial.begin(9600);
attachInterrupt(0, isr, CHANGE); // прерывание пина радио по CHANGE
}
void isr() {
rx.tickISR(); // спец. тикер вызывается в прерывании
}
void loop() { void loop() {
// tick принимает асинхронно, но может ловить ошибки при загруженном коде if (rx.gotData()) { // если успешно принято больше 0
// tickWait блокирует выполнение, но принимает данные чётко Serial.write(rx.buffer, rx.size); // выводим
if (rx.tickWait()) { Serial.println();
byte buf[64]; }
rx.readData(buf); delay(200); // имитация загруженного кода
for (byte i = 0; i < rx.size; i++) Serial.write(buf[i]);
}
} }
``` ```
<a id="versions"></a> <a id="versions"></a>
## Версии ## Версии
- v1.0 - v1.0
- v1.1 - оптимизация, новый интерфейс, поддержка дешёвых синих модулей, работа в прерывании
- v1.2 - улучшение качества связи, оптимизация работы в прерывании
<a id="feedback"></a> <a id="feedback"></a>
## Баги и обратная связь ## Баги и обратная связь
+36
View File
@@ -0,0 +1,36 @@
// демо-пример: инициализация и настройки
// крупный приёмник SYN480R [VCC: 3.3-5.5V, logic: VCC]
// или MX-RM-5V (RF-5V) [VCC: 5V, logic: 5V]
// дефайны перед подключением библиотеки
//#define G433_MANCHESTER // интерфейс Manchester Coding для экспериментов =)
//#define G433_SPEED 1000 // скорость 100-8000 бит/с, по умолч. 2000 бит/с
#include <Gyver433.h>
//Gyver433_RX<пин> rx;
//Gyver433_RX<пин, буфер> rx;
//Gyver433_RX<пин, буфер, CRC> rx;
// пин: цифровой пин
// буфер: размер буфера в байтах. По умолч. 64
// CRC: проверка целостности данных: G433_CRC8 (надёжный), G433_XOR (лёгкий), G433_NOCRC (отключено). По умолч. G433_CRC8
Gyver433_RX<2, 20> rx;
void setup() {
Serial.begin(9600);
}
void loop() {
// "тик" опрашивает радио и вернёт количество успешно принятых байт
// tick принимает асинхронно, но может ловить ошибки при загруженном коде
// tickWait блокирует выполнение, но принимает данные чётко
//if (rx.tick()) {
if (rx.tickWait()) {
// принятые данные доступны в .buffer
// и имеют размер .size
Serial.write(rx.buffer, rx.size);
Serial.println();
}
}
+40
View File
@@ -0,0 +1,40 @@
// демо-пример: инициализация и настройки
// мелкий передатчик SYN115 [VCC: 1.8-3.6V, logic: VCC]
// или FS1000A [VCC: 3-12V, logic: 5V]
// дефайны перед подключением библиотеки
//#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 бит/с
#include <Gyver433.h>
//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;
void setup() {
}
char data[] = "Hello from #xx"; // строка для отправки
byte count = 0; // счётчик для отправки
void loop() {
// добавляем счётчик в строку
data[12] = (count / 10) + '0';
data[13] = (count % 10) + '0';
if (++count >= 100) count = 0;
// отправка данных любого типа. Блокирующая на период отправки
tx.sendData(data);
// отправка 10 раз в сек
delay(100);
}
+26
View File
@@ -0,0 +1,26 @@
// приём в прерывании. Отправляет пример demo_tx
//#define G433_SPEED 1000 // скорость 100-8000 бит/с, по умолч. 2000 бит/с
#include <Gyver433.h>
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);
}
+16
View File
@@ -0,0 +1,16 @@
// обмен сырыми данными без CRC и буфера на отправку
// отправляет пример raw_tx
#include <Gyver433.h>
Gyver433_RX<2, 20, G433_NOCRC> rx; // буфер на приём нужен!
void setup() {
Serial.begin(9600);
}
void loop() {
if (rx.tickWait()) {
Serial.write(rx.buffer, rx.size);
Serial.println();
}
}
+26
View File
@@ -0,0 +1,26 @@
// обмен сырыми данными без CRC и буфера на отправку
// принимает пример raw_rx
//#define G433_SPEED 1000 // скорость 100-8000 бит/с, по умолч. 2000 бит/с
#include <Gyver433.h>
Gyver433_TX<2, 0, G433_NOCRC> tx; // буфер на отправку 0! Экономим
void setup() {
}
char data[] = "Hello from #xx"; // строка для отправки
byte count = 0; // счётчик для отправки
void loop() {
// добавляем счётчик в строку
data[12] = (count / 10) + '0';
data[13] = (count % 10) + '0';
if (++count >= 100) count = 0;
// отправка данных типа byte*
tx.write(data, sizeof(data));
// отправка 10 раз в сек
delay(100);
}
-22
View File
@@ -1,22 +0,0 @@
// крупный приёмник 5.0 SYN480R
#define G433_BUFSIZE 50 // размер буфера
#define G433_SPEED 2000 // скорость бит/сек (минимальная)
#include <Gyver433.h>
Gyver433_RX rx(2);
void setup() {
Serial.begin(9600);
}
void loop() {
// tick принимает асинхронно, но может ловить ошибки при загруженном коде
// tickWait блокирует выполнение, но принимает данные чётко
if (rx.tickWait()) {
byte buf[64];
rx.readData(buf);
for (byte i = 0; i < rx.size; i++) Serial.write(buf[i]);
}
}
+5 -12
View File
@@ -1,28 +1,21 @@
// крупный приёмник 5.0V SYN480R // выводим данные на дисплей. Отправляет пример demo_tx
#define G433_BUFSIZE 50 // размер буфера //#define G433_SPEED 1000 // скорость 100-8000 бит/с, по умолч. 2000 бит/с
#define G433_SPEED 2000 // скорость бит/сек (минимальная)
#include <Gyver433.h> #include <Gyver433.h>
Gyver433_RX rx(2); // указали пин Gyver433_RX<2> rx; // указали пин
#include <Wire.h>
#include <LiquidCrystal_I2C.h> #include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3f, 16, 2); // или 0x27 LiquidCrystal_I2C lcd(0x3f, 16, 2); // или 0x27
void setup() { void setup() {
Serial.begin(9600);
lcd.init(); lcd.init();
lcd.backlight(); lcd.backlight();
} }
void loop() { void loop() {
// tick принимает асинхронно, но может ловить ошибки при загруженном коде
// tickWait блокирует выполнение, но принимает данные чётко
if (rx.tick()) { if (rx.tick()) {
byte buf[64];
rx.readData(buf); // прочитать в buf
lcd.clear(); lcd.clear();
lcd.home(); lcd.home();
for (byte i = 0; i < rx.size; i++) lcd.write(buf[i]); for (byte i = 0; i < rx.size; i++) lcd.write(rx.buffer[i]);
} }
} }
+6 -9
View File
@@ -1,10 +1,9 @@
// передача структуры данных // приём структуры данных
// крупный приёмник 5.0V SYN480R
#define G433_BUFSIZE 50 // размер буфера //#define G433_SPEED 1000 // скорость 100-8000 бит/с, по умолч. 2000 бит/с
#define G433_SPEED 2000 // скорость бит/сек (минимальная)
#include <Gyver433.h> #include <Gyver433.h>
Gyver433_RX rx(2); // указали пин Gyver433_RX<2, 10> rx; // указали пин и размер буфера
// формат пакета для приёма (такой же как отправляется) // формат пакета для приёма (такой же как отправляется)
struct dataPack { struct dataPack {
@@ -19,11 +18,9 @@ void setup() {
} }
void loop() { void loop() {
// tick принимает асинхронно, но может ловить ошибки при загруженном коде
// tickWait блокирует выполнение, но принимает данные чётко
if (rx.tick()) { if (rx.tick()) {
dataPack data; dataPack data; // "буферная" структура
rx.readData(data); // прочитать в buf rx.readData(data); // переписываем данные в неё
Serial.println("Received:"); Serial.println("Received:");
Serial.println(data.counter); Serial.println(data.counter);
-18
View File
@@ -1,18 +0,0 @@
// мелкий передатчик 3.6V SYN115
#define G433_BUFSIZE 50 // размер буфера
#define G433_SPEED 2000 // скорость бит/сек (минимальная)
#include <Gyver433.h>
Gyver433_TX tx(2); // указали пин
void setup() {
}
char data[] = "Hello from #xx";
byte count = 0;
void loop() {
data[12] = (count / 10) + '0';
data[13] = (count % 10) + '0';
if (++count >= 100) count = 0;
tx.sendData(data);
delay(100);
}
+7 -6
View File
@@ -1,10 +1,10 @@
// передача структуры данных // передача структуры данных
// мелкий передатчик 3.6V SYN115
#define G433_BUFSIZE 50 // размер буфера //#define G433_SPEED 1000 // скорость 100-8000 бит/с, по умолч. 2000 бит/с
#define G433_SPEED 2000 // скорость бит/сек (минимальная) #define G433_SLOW // отправляю раз в секунду на SYN480R
#include <Gyver433.h> #include <Gyver433.h>
Gyver433_TX tx(2); // указали пин Gyver433_TX<2, 10> tx; // указали пин и размер буфера
// формат пакета для отправки // формат пакета для отправки
struct dataPack { struct dataPack {
@@ -25,13 +25,14 @@ void loop() {
data.analog = analogRead(0); // тут ацп data.analog = analogRead(0); // тут ацп
data.time = millis(); // тут миллис data.time = millis(); // тут миллис
Serial.println("Transmit:"); tx.sendData(data);
Serial.println("Transmitted:");
Serial.println(data.counter); Serial.println(data.counter);
Serial.println(data.randomNum); Serial.println(data.randomNum);
Serial.println(data.analog); Serial.println(data.analog);
Serial.println(data.time); Serial.println(data.time);
Serial.println(); Serial.println();
tx.sendData(data);
delay(1000); delay(1000);
} }
+15 -1
View File
@@ -13,14 +13,28 @@ Gyver433_RX KEYWORD1
# Methods and Functions (KEYWORD2) # Methods and Functions (KEYWORD2)
####################################### #######################################
sendData KEYWORD2 sendData KEYWORD2
sendDataSlow KEYWORD2
write KEYWORD2
writeSlow KEYWORD2
tick KEYWORD2 tick KEYWORD2
tickISR KEYWORD2
tickWait KEYWORD2 tickWait KEYWORD2
readData KEYWORD2 readData KEYWORD2
size KEYWORD2 size KEYWORD2
buffer KEYWORD2
getSize KEYWORD2 getSize KEYWORD2
gotData KEYWORD2
G433_crc8 KEYWORD2
G433_crc_xor KEYWORD2
####################################### #######################################
# Constants (LITERAL1) # Constants (LITERAL1)
####################################### #######################################
G433_CRC8 LITERAL1
G433_XOR LITERAL1
G433_NOCRC LITERAL1
G433_FAST LITERAL1
G433_MEDIUM LITERAL1
G433_SLOW LITERAL1
G433_SPEED LITERAL1 G433_SPEED LITERAL1
G433_BUFSIZE LITERAL1 G433_MANCHESTER LITERAL1
+1 -1
View File
@@ -1,5 +1,5 @@
name=Gyver433 name=Gyver433
version=1.0 version=1.2
author=AlexGyver <alex@alexgyver.ru> author=AlexGyver <alex@alexgyver.ru>
maintainer=AlexGyver <alex@alexgyver.ru> maintainer=AlexGyver <alex@alexgyver.ru>
sentence=Simple library for 433 MHz radio sentence=Simple library for 433 MHz radio
+109
View File
@@ -0,0 +1,109 @@
// Быстрый IO для AVR (для остальных будет digitalxxxxx)
// v1.0
#ifndef FastIO_h
#define FastIO_h
#include <Arduino.h>
bool fastRead(const uint8_t pin); // быстрое чтение пина
void fastWrite(const uint8_t pin, bool val); // быстрая запись
uint8_t fastShiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder); // быстрый shiftIn
void fastShiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t data); // быстрый shiftOut
// ================================================================
bool fastRead(const uint8_t pin) {
#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__)
return bitRead(PINB, pin);
#elif defined(AVR)
uint8_t *_pin_reg = portInputRegister(digitalPinToPort(pin));
uint8_t _bit_mask = digitalPinToBitMask(pin);
return bool(*_pin_reg & _bit_mask);
#else
return digitalRead(pin);
#endif
return 0;
}
void fastWrite(const uint8_t pin, bool val) {
#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__)
bitWrite(PORTB, pin, val);
#elif defined(AVR)
uint8_t *_port_reg = portInputRegister(digitalPinToPort(pin));
uint8_t _bit_mask = digitalPinToBitMask(pin);
_port_reg = portOutputRegister(digitalPinToPort(pin));
_bit_mask = digitalPinToBitMask(pin);
if (val) *_port_reg |= _bit_mask; // HIGH
else *_port_reg &= ~_bit_mask; // LOW
#else
digitalWrite(pin, val);
#endif
}
uint8_t fastShiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder) {
#if defined(AVR)
volatile uint8_t *_clk_port = portOutputRegister(digitalPinToPort(clockPin));
volatile uint8_t *_dat_port = portInputRegister(digitalPinToPort(dataPin));
uint8_t _clk_mask = digitalPinToBitMask(clockPin);
uint8_t _dat_mask = digitalPinToBitMask(dataPin);
uint8_t data = 0;
for (uint8_t i = 0; i < 8; i++) {
*_clk_port |= _clk_mask;
if (bitOrder == MSBFIRST) {
data <<= 1;
if (bool(*_dat_port & _dat_mask)) data |= 1;
} else {
data >>= 1;
if (bool(*_dat_port & _dat_mask)) data |= 1 << 7;
}
*_clk_port &= ~_clk_mask;
}
return data;
#else
return shiftIn(dataPin, clockPin, bitOrder);
#endif
}
void fastShiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t data) {
#if defined(AVR)
volatile uint8_t *_clk_port = portOutputRegister(digitalPinToPort(clockPin));
volatile uint8_t *_dat_port = portOutputRegister(digitalPinToPort(dataPin));
uint8_t _clk_mask = digitalPinToBitMask(clockPin);
uint8_t _dat_mask = digitalPinToBitMask(dataPin);
for (uint8_t i = 0; i < 8; i++) {
if (bitOrder == MSBFIRST) {
if (data & (1 << 7)) *_dat_port |= _dat_mask;
else *_dat_port &= ~_dat_mask;
data <<= 1;
} else {
if (data & 1) *_dat_port |= _dat_mask;
else *_dat_port &= ~_dat_mask;
data >>= 1;
}
*_clk_port |= _clk_mask;
*_clk_port &= ~_clk_mask;
}
#else
shiftOut(dataPin, clockPin, bitOrder, data);
#endif
}
#endif
+207 -153
View File
@@ -3,9 +3,12 @@
Документация: Документация:
GitHub: https://github.com/GyverLibs/Gyver433 GitHub: https://github.com/GyverLibs/Gyver433
Возможности: Возможности:
- Не использует прерывания и таймеры (кроме нулевого, читает micros()) - Супер лёгкая либа, заведётся даже на тини13 (отправка)
- Встроенный CRC контроль целостности - Поддержка кривых китайских модулей
- Интерфейс Manchester или Pulselength
- Встроенный CRC контроль целостности (CRC8 или XOR)
- Ускоренный алгоритм IO для AVR Arduino - Ускоренный алгоритм IO для AVR Arduino
- Опционально работа в прерывании (приём данных)
AlexGyver, alex@alexgyver.ru AlexGyver, alex@alexgyver.ru
https://alexgyver.ru/ https://alexgyver.ru/
@@ -13,57 +16,69 @@
Версии: Версии:
v1.0 - релиз v1.0 - релиз
v1.1 - оптимизация, новый интерфейс, поддержка дешёвых синих модулей, работа в прерывании
v1.2 - улучшение качества связи, оптимизация работы в прерывании
*/ */
#ifndef Gyver433_h #ifndef Gyver433_h
#define Gyver433_h #define Gyver433_h
#include <Arduino.h> #include <Arduino.h>
#include "FastIO.h"
/* uint8_t G433_crc8(uint8_t *buffer, uint8_t size); // ручной CRC8
Передатчик: uint8_t G433_crc_xor(uint8_t *buffer, uint8_t size); // ручной CRC XOR
Gyver433_TX tx(пин) - создать объект #define TRAINING_TIME_SLOW (500000ul) // время синхронизации для SLOW_MODE
sendData(data) - отправить, любой тип данных
Приёмник:
Gyver433_RX rx(пин) - создать объект
tick() - вызывать постоянно для чтения. Асинхронный. Вернёт количество принятых байт
tickWait() - тож самое, но блокирует выполнение, принимает более четко
readData(data) - прочитать, любой тип данных
size - количество принятых байтов
*/
// =========================================================================
#ifndef G433_SPEED #ifndef G433_SPEED
#define G433_SPEED 2000 // скорость бит/сек (минимальная) #define G433_SPEED 2000
#endif
#ifndef G433_BUFSIZE
#define G433_BUFSIZE 64 // размер буфера приёма и отправки
#endif #endif
// тайминги интерфейса (компилятор посчитает) // тайминги интерфейса
#define HIGH_PULSE (1000000ul/G433_SPEED) #define FRAME_TIME (1000000ul / G433_SPEED) // время фрейма (либо HIGH)
#define LOW_PULSE (HIGH_PULSE/2) #define HALF_FRAME (FRAME_TIME / 2) // полфрейма (либо LOW)
#define START_PULSE (HIGH_PULSE*2) #define START_PULSE (FRAME_TIME * 2) // стартовый импульс
#define PULSE_HYST (LOW_PULSE/2)
#define START_MIN (START_PULSE-PULSE_HYST)
#define START_MAX (START_PULSE+PULSE_HYST)
#define LOW_MIN (LOW_PULSE-PULSE_HYST)
#define LOW_MAX (LOW_PULSE+PULSE_HYST)
#define HIGH_MIN (HIGH_PULSE-PULSE_HYST)
#define HIGH_MAX (HIGH_PULSE+PULSE_HYST)
// crc // окно времени для обработки импульса
uint8_t G433_crc(uint8_t *buffer, uint8_t size); #define START_MIN (START_PULSE * 3 / 4)
void G433_crc_byte(uint8_t &crc, uint8_t data); #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)
// жоский delay для avr
#ifdef AVR
#define G433_DELAY _delay_us
#else
#define G433_DELAY delayMicroseconds
#endif
// режимы CRC
#define G433_CRC8 0
#define G433_XOR 1
#define G433_NOCRC 2
// количество синхроимпульсов
#if defined(G433_FAST)
#define TRAINING_PULSES 10
#elif defined(G433_MEDIUM)
#define TRAINING_PULSES 50
#elif defined(G433_SLOW)
#define TRAINING_PULSES (TRAINING_TIME_SLOW / FRAME_TIME / 2)
#else
#define TRAINING_PULSES 50
#endif
// crc8 один байт
void G433_crc8_byte(uint8_t &crc, uint8_t data);
// ============ ПЕРЕДАТЧИК ============ // ============ ПЕРЕДАТЧИК ============
template <uint8_t TX_PIN, uint16_t TX_BUF = 64, uint8_t CRC_MODE = G433_CRC8>
class Gyver433_TX { class Gyver433_TX {
public: public:
Gyver433_TX(uint8_t pin) : _pin(pin) { Gyver433_TX() {
#if defined(__AVR__) pinMode(TX_PIN, OUTPUT);
_port_reg = portOutputRegister(digitalPinToPort(pin));
_bit_mask = digitalPinToBitMask(pin);
#endif
pinMode(pin, OUTPUT);
} }
// отправка, блокирующая. Кушает любой тип данных // отправка, блокирующая. Кушает любой тип данных
@@ -71,158 +86,192 @@ public:
void sendData(T &data) { void sendData(T &data) {
const uint8_t *ptr = (const uint8_t*) &data; const uint8_t *ptr = (const uint8_t*) &data;
for (uint16_t i = 0; i < sizeof(T); i++) buffer[i] = *ptr++; for (uint16_t i = 0; i < sizeof(T); i++) buffer[i] = *ptr++;
buffer[sizeof(T)] = G433_crc(buffer, sizeof(T)); // CRC последним байтом if (CRC_MODE == G433_CRC8) {
bool flag = 0; // флаг дрыга buffer[sizeof(T)] = G433_crc8(buffer, sizeof(T));
for (uint8_t i = 0; i < 30; i++) { // 30 импульсов для синхронизации write(buffer, sizeof(T) + 1);
flag = !flag; } else if (CRC_MODE == G433_XOR) {
fastDW(flag); buffer[sizeof(T)] = G433_crc_xor(buffer, sizeof(T));
delayMicroseconds(HIGH_PULSE); write(buffer, sizeof(T) + 1);
} else {
write(buffer, sizeof(T));
} }
fastDW(1); // старт бит }
delayMicroseconds(START_PULSE); // старт бит
for (int n = 0; n < sizeof(T) + 1; n++) { // буфер + CRC // отправка сырого набора байтов
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); // старт бит
#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++) { for (uint8_t b = 0; b < 8; b++) {
fastDW(flag); fastWrite(TX_PIN, !(data & 1));
flag = !flag; G433_DELAY(HALF_FRAME);
if (bitRead(buffer[n], b)) delayMicroseconds(HIGH_PULSE); fastWrite(TX_PIN, (data & 1));
else delayMicroseconds(LOW_PULSE); G433_DELAY(HALF_FRAME);
data >>= 1;
} }
} }
fastDW(0); // передача окончена fastWrite(TX_PIN, 0); // конец передачи
} #else
bool flag = 0;
private: for (uint16_t n = 0; n < size; n++) {
void fastDW(bool state) { uint8_t data = buf[n];
#if defined(__AVR__) for (uint8_t b = 0; b < 8; b++) {
if (state) *_port_reg |= _bit_mask; // HIGH if (data & 1) G433_DELAY(FRAME_TIME);
else *_port_reg &= ~_bit_mask; // LOW else G433_DELAY(HALF_FRAME);
#else fastWrite(TX_PIN, flag = !flag);
digitalWrite(_pin, state); data >>= 1;
#endif }
}
#endif
} }
uint8_t buffer[G433_BUFSIZE];
const uint8_t _pin; // доступ к буферу
#if defined(__AVR__) uint8_t buffer[TX_BUF];
volatile uint8_t *_port_reg;
volatile uint8_t _bit_mask; private:
#endif
}; };
// ============ ПРИЁМНИК ============ // ============ ПРИЁМНИК ============
template <uint8_t RX_PIN, uint16_t RX_BUF = 64, uint8_t CRC_MODE = G433_CRC8>
class Gyver433_RX { class Gyver433_RX {
public: public:
Gyver433_RX(uint8_t pin){ Gyver433_RX() {
#if defined(__AVR__) pinMode(RX_PIN, INPUT);
_pin_reg = portInputRegister(digitalPinToPort(pin));
_bit_mask = digitalPinToBitMask(pin);
#endif
} }
// неблокирующий приём, вернёт кол-во успешно принятых байт // неблокирующий приём, вернёт кол-во успешно принятых байт
uint8_t tick() { uint16_t tick() {
bool newState = fastDR(); // читаем пин if (pinChanged()) checkState();
if (newState != prevState) { // ловим изменение сигнала return gotData();
uint32_t thisUs = micros(); }
uint32_t thisPulse = thisUs - tmr;
if (parse == 1) { // в прошлый раз поймали фронт // tick для вызова в прерывании по CHANGE
if (thisPulse > START_MIN && thisPulse < START_MAX) { // старт бит? void tickISR() {
parse = 2; // ключ на старт #ifdef G433_MANCHESTER
tmr = thisUs; if (pinChanged()) checkState();
byteCount = 0; #else
bitCount = 0; checkState();
size = 0; #endif
for (uint8_t i = 0; i < G433_BUFSIZE; i++) buffer[i] = 0;
} else { // не старт бит
parse = 0;
}
} else if (parse == 2) { // идёт парсинг
if (thisPulse > LOW_MIN && thisPulse < LOW_MAX) { // low бит
// просто пропускаем (в буфере уже нули)
tmr = thisUs;
bitCount++;
if (bitCount == 8) {
bitCount = 0;
byteCount++;
if (byteCount > G433_BUFSIZE) parse = 0; // оверфлоу
}
} else if (thisPulse > HIGH_MIN && thisPulse < HIGH_MAX) { // high бит
bitSet(buffer[byteCount], bitCount); // ставим бит единичку
tmr = thisUs;
bitCount++;
if (bitCount == 8) {
bitCount = 0;
byteCount++;
if (byteCount > G433_BUFSIZE) parse = 0; // оверфлоу
}
} else { // ошибка или конец передачи
tmr = thisUs;
parse = 0;
// проверяем, есть ли данные и целые ли они
if (byteCount > 0 && G433_crc(buffer, byteCount) == 0) {
size = byteCount - 2; // длина даты (минус crc)
return size;
}
else return 0;
}
}
if (newState && !prevState && parse == 0) { // ловим фронт
parse = 1; // в следующий раз ждём флаг
tmr = thisUs;
}
prevState = newState;
}
return 0;
} }
// блокирующий приём, вернёт кол-во успешно принятых байт // блокирующий приём, вернёт кол-во успешно принятых байт
uint8_t tickWait() { uint16_t tickWait() {
do { do {
tick(); if (tick()) return size;
} while (parse == 2); } while (parse == 2);
if (byteCount > 0) { return 0;
byteCount = 0;
return size;
} else return 0;
} }
// прочитает буфер в любой тип данных // прочитает буфер в любой тип данных
template <typename T> template <typename T>
bool readData(T &data) { bool readData(T &data) {
if (sizeof(T) > G433_BUFSIZE) return false; if (sizeof(T) > RX_BUF) return false;
uint8_t *ptr = (uint8_t*) &data; uint8_t *ptr = (uint8_t*) &data;
for (uint16_t i = 0; i < sizeof(T); i++) *ptr++ = buffer[i]; for (uint16_t i = 0; i < sizeof(T); i++) *ptr++ = buffer[i];
return true; return true;
} }
// вернёт true при получении корректных данных
uint16_t gotData() {
if (parse == 2 && millis() - tmr2 >= 10) { // фрейм не закрыт
parse = size = 0; // приём окончен
if (byteCount > 1) { // если что то приняли
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
}
return size;
}
return 0;
}
// получить размер принятых данных // получить размер принятых данных
int getSize() { uint16_t getSize() {
return size; return size;
} }
int size = 0; // размер принятых данных
uint16_t size = 0;
// доступ к буферу
uint8_t buffer[RX_BUF];
private: private:
bool fastDR() { bool pinChanged() {
#if defined(__AVR__) bit = fastRead(RX_PIN);
return bool(*_pin_reg & _bit_mask); if (bit != prevBit) {
#else prevBit = bit;
return digitalRead(_pin); return 1;
#endif } return 0;
} }
uint8_t buffer[G433_BUFSIZE];
bool prevState; 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; uint8_t parse = 0;
uint32_t tmr = 0; uint32_t tmr = 0, tmr2 = 0;
uint8_t bitCount = 0, byteCount = 0; uint8_t bitCount = 0, byteCount = 0;
#if defined(__AVR__)
volatile uint8_t *_pin_reg;
volatile uint8_t _bit_mask;
#endif
}; };
void G433_crc_byte(uint8_t &crc, uint8_t data) { // ===== CRC =====
void G433_crc8_byte(uint8_t &crc, uint8_t data) {
#if defined (__AVR__) #if defined (__AVR__)
// резкий алгоритм для AVR // резкий алгоритм для AVR
uint8_t counter; uint8_t counter;
@@ -251,9 +300,14 @@ void G433_crc_byte(uint8_t &crc, uint8_t data) {
#endif #endif
} }
uint8_t G433_crc(uint8_t *buffer, uint8_t size) { uint8_t G433_crc8(uint8_t *buffer, uint8_t size) {
uint8_t crc = 0; uint8_t crc = 0;
for (uint8_t i = 0; i < size; i++) G433_crc_byte(crc, buffer[i]); for (uint8_t i = 0; i < size; i++) G433_crc8_byte(crc, buffer[i]);
return crc;
}
uint8_t G433_crc_xor(uint8_t *buffer, uint8_t size) {
uint8_t crc = 0;
for (uint8_t i = 0; i < size; i++) crc ^= buffer[i];
return crc; return crc;
} }
#endif #endif