This commit is contained in:
Alex
2021-06-14 18:36:58 +03:00
parent ef9eca0f9f
commit cb09165d3e
15 changed files with 560 additions and 301 deletions
+51 -14
View File
@@ -2,9 +2,12 @@
![author](https://img.shields.io/badge/author-AlexGyver-informational.svg) ![author](https://img.shields.io/badge/author-AlexGyver-informational.svg)
# Gyver433 # Gyver433
Библиотека для радиомодулей 433 МГц и Arduino Библиотека для радиомодулей 433 МГц и Arduino
- Не использует прерывания и таймеры (кроме нулевого, читает micros()) - Супер лёгкая либа, заведётся даже на тини13 (отправка)
- Встроенный CRC контроль целостности - Поддержка кривых китайских модулей
- Интерфейс Manchester Coding (v1.1)
- Встроенный CRC контроль целостности (CRC8 или XOR)
- Ускоренный алгоритм IO для AVR Arduino - Ускоренный алгоритм IO для AVR Arduino
- Опционально работа в прерывании (приём данных)
### Совместимость ### Совместимость
Совместима со всеми Arduino платформами (используются Arduino-функции) Совместима со всеми Arduino платформами (используются Arduino-функции)
@@ -33,22 +36,40 @@
<a id="init"></a> <a id="init"></a>
## Инициализация ## Инициализация
```cpp ```cpp
// указать пин //Классы:
Gyver433_RX rx(2); Gyver433_RX // приёмник
Gyver433_TX tx(2); Gyver433_TX // передатчик
Gyver433_xx<пин, буфер, CRC> xx;
// пин: цифровой пин
// буфер: размер буфера в байтах. На "ручную" отправку буфер не нужен (пример raw_tx). По умолч. 64 байта
// CRC: проверка целостности данных: G433_CRC8 (надёжный), G433_XOR (лёгкий), G433_NOCRC (отключено). По умолч. G433_CRC8
// Дефайны-настройки перед подключением библиотеки
#define G433_SLOW_MODE // "медленный режим" для синих модулей SYN480R
#define G433_SPEED 1000 // скорость 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(); // неблокирующий приём, вернёт кол-во успешно принятых байт uint8_t tick(); // неблокирующий приём, вернёт кол-во успешно принятых байт
uint8_t tickWait(); // блокирующий приём, вернёт кол-во успешно принятых байт uint8_t tickWait(); // блокирующий приём, вернёт кол-во успешно принятых байт
bool readData(T &data); // прочитает буфер в любой тип данных (в указанную переменную) bool readData(T &data); // прочитает буфер в любой тип данных (в указанную переменную)
int getSize(); // получить размер принятых данных int getSize(); // получить размер принятых данных
bool gotData(); // вернёт true при получении корректных данных (если tick опрашивается в другом месте)
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>
@@ -56,26 +77,41 @@ int getSize(); // получить размер принятых д
Остальные примеры смотри в **examples**! Остальные примеры смотри в **examples**!
### Отправка ### Отправка
```cpp ```cpp
// мелкий передатчик 3.6V SYN115 // ======== ПЕРЕДАТЧИК =========
#define G433_SLOW_MODE
#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);
} }
// ======== ПРИЁМНИК =========
#define G433_SLOW_MODE
#include <Gyver433.h>
Gyver433_RX<2, 20> rx; // указали пин и размер буфера
void setup() {
Serial.begin(9600);
}
void loop() {
if (rx.tickWait()) {
Serial.write(rx.buffer, rx.size);
Serial.println();
}
}
``` ```
### Приём ### Приём
@@ -107,6 +143,7 @@ void loop() {
<a id="versions"></a> <a id="versions"></a>
## Версии ## Версии
- v1.0 - v1.0
- v1.1 - оптимизация, новый интерфейс, поддержка дешёвых синих модулей, работа в прерывании
<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]
// "медленный режим" для синих модулей SYN480R
// Объявляется перед подключением библиотеки
// Зелёным модулям не нужен!
#define G433_SLOW_MODE
// можно указать скорость, по умолч. стоит 2000 бит/с
// рабочий диапазон: 100-8000 бит/с
//#define G433_SPEED 1000
#include <Gyver433.h>
// Gyver433_TX<пин, буфер, CRC>
// пин: цифровой пин
// буфер: размер приёмного буфера в байтах
// 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();
}
}
+37
View File
@@ -0,0 +1,37 @@
// мелкий передатчик SYN115 [VCC: 1.8-3.6V, logic: VCC]
// или FS1000A [VCC: 3-12V, logic: 5V]
// "медленный режим" для синих модулей SYN115
// Объявляется перед подключением библиотеки
// зелёным модулям не нужен!
#define G433_SLOW_MODE
// можно указать скорость, по умолч. стоит 2000 бит/с
// рабочий диапазон: 100-8000 бит/с
//#define G433_SPEED 1000
#include <Gyver433.h>
// Gyver433_TX<пин, буфер, CRC>
// пин: цифровой пин
// буфер: размер буфера в байтах. На "ручную" отправку буфер не нужен. По умолч. 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);
}
+28
View File
@@ -0,0 +1,28 @@
// приём в прерывании. Отправляет пример demo_tx
#define G433_SLOW_MODE
#include <Gyver433.h>
Gyver433_RX<2, 20> rx; // указали пин и размер буфера
void setup() {
Serial.begin(9600);
// взводим прерывания по CHANGE
attachInterrupt(0, isr, CHANGE);
}
void isr() {
rx.tick(); // тикер вызывается в прерывании
}
void loop() {
// .gotData() вернёт true при получении корректных данных
// и сам сбросится до следующего приёма
// внутри gotData() встроен тик!
if (rx.gotData()) {
Serial.write(rx.buffer, rx.size);
Serial.println();
}
// имитация загруженного кода
delay(200);
}
+16
View File
@@ -0,0 +1,16 @@
// обмен сырыми данными без CRC и буфера на отправку
#define G433_SLOW_MODE
#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();
}
}
+24
View File
@@ -0,0 +1,24 @@
// обмен сырыми данными без CRC и буфера на отправку
#define G433_SLOW_MODE
#include <Gyver433.h>
Gyver433_TX<2, 0, G433_NOCRC> 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;
// отправка данных типа 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]);
}
}
+3 -11
View File
@@ -1,28 +1,20 @@
// крупный приёмник 5.0V SYN480R // выводим данные на дисплей. Отправляет пример demo_tx
#define G433_BUFSIZE 50 // размер буфера
#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]);
} }
} }
+5 -9
View File
@@ -1,10 +1,8 @@
// передача структуры данных // приём структуры данных
// крупный приёмник 5.0V SYN480R
#define G433_BUFSIZE 50 // размер буфера
#define G433_SPEED 2000 // скорость бит/сек (минимальная)
#define G433_SLOW_MODE
#include <Gyver433.h> #include <Gyver433.h>
Gyver433_RX rx(2); // указали пин Gyver433_RX<2, 10> rx; // указали пин и размер буфера
// формат пакета для приёма (такой же как отправляется) // формат пакета для приёма (такой же как отправляется)
struct dataPack { struct dataPack {
@@ -19,11 +17,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);
}
+4 -5
View File
@@ -1,10 +1,8 @@
// передача структуры данных // передача структуры данных
// мелкий передатчик 3.6V SYN115
#define G433_BUFSIZE 50 // размер буфера #define G433_SLOW_MODE
#define G433_SPEED 2000 // скорость бит/сек (минимальная)
#include <Gyver433.h> #include <Gyver433.h>
Gyver433_TX tx(2); // указали пин Gyver433_TX<2, 10> tx; // указали пин и размер буфера
// формат пакета для отправки // формат пакета для отправки
struct dataPack { struct dataPack {
@@ -25,6 +23,8 @@ void loop() {
data.analog = analogRead(0); // тут ацп data.analog = analogRead(0); // тут ацп
data.time = millis(); // тут миллис data.time = millis(); // тут миллис
tx.sendData(data);
Serial.println("Transmit:"); Serial.println("Transmit:");
Serial.println(data.counter); Serial.println(data.counter);
Serial.println(data.randomNum); Serial.println(data.randomNum);
@@ -32,6 +32,5 @@ void loop() {
Serial.println(data.time); Serial.println(data.time);
Serial.println(); Serial.println();
tx.sendData(data);
delay(1000); delay(1000);
} }
+9 -1
View File
@@ -13,14 +13,22 @@ Gyver433_RX KEYWORD1
# Methods and Functions (KEYWORD2) # Methods and Functions (KEYWORD2)
####################################### #######################################
sendData KEYWORD2 sendData KEYWORD2
write KEYWORD2
tick KEYWORD2 tick 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_SPEED LITERAL1 G433_SPEED LITERAL1
G433_BUFSIZE LITERAL1 G433_SLOW_MODE LITERAL1
+1 -1
View File
@@ -1,5 +1,5 @@
name=Gyver433 name=Gyver433
version=1.0 version=1.1
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
+157 -140
View File
@@ -6,6 +6,7 @@
- Не использует прерывания и таймеры (кроме нулевого, читает micros()) - Не использует прерывания и таймеры (кроме нулевого, читает micros())
- Встроенный CRC контроль целостности - Встроенный CRC контроль целостности
- Ускоренный алгоритм IO для AVR Arduino - Ускоренный алгоритм IO для AVR Arduino
- Работает с хорошими и плохими 433 МГц модулями
AlexGyver, alex@alexgyver.ru AlexGyver, alex@alexgyver.ru
https://alexgyver.ru/ https://alexgyver.ru/
@@ -13,59 +14,67 @@
Версии: Версии:
v1.0 - релиз v1.0 - релиз
v1.1 - оптимизация, новый интерфейс, поддержка дешёвых синих модулей, работа в прерывании
*/ */
#ifndef Gyver433_h #ifndef Gyver433_h
#define Gyver433_h #define Gyver433_h
#include <Arduino.h> #include <Arduino.h>
#include "FastIO.h"
/* // настройки из скетча:
Передатчик: // #define G433_SLOW_MODE - включить "медленный режим" для плохих модулей
Gyver433_TX tx(пин) - создать объект // #define G433_SPEED n - скорость, бит/сек. Рекомендуется 2000. Работает вплоть до 6000
sendData(data) - отправить, любой тип данных
Приёмник: uint8_t G433_crc8(uint8_t *buffer, uint8_t size); // ручной CRC8
Gyver433_RX rx(пин) - создать объект uint8_t G433_crc_xor(uint8_t *buffer, uint8_t size); // ручной CRC XOR
tick() - вызывать постоянно для чтения. Асинхронный. Вернёт количество принятых байт #define TRAINING_TIME_SLOW (500000ul) // время синхронизации для SLOW_MODE
tickWait() - тож самое, но блокирует выполнение, принимает более четко
readData(data) - прочитать, любой тип данных
size - количество принятых байтов
*/
// =========================================================================
#ifndef G433_SPEED #ifndef G433_SPEED
#define G433_SPEED 2000 // скорость бит/сек (минимальная) #define G433_SPEED 3000 // скорость по умолчанию
#endif
#ifndef G433_BUFSIZE
#define G433_BUFSIZE 64 // размер буфера приёма и отправки
#endif #endif
// тайминги интерфейса (компилятор посчитает) // тайминги интерфейса
#define HIGH_PULSE (1000000ul/G433_SPEED) #define FRAME_TIME (1000000ul / G433_SPEED) // время фрейма
#define LOW_PULSE (HIGH_PULSE/2) #define HALF_FRAME (FRAME_TIME / 2) // полфрейма
#define START_PULSE (HIGH_PULSE*2) #define START_PULSE (FRAME_TIME * 2) // стартовый импульс
#define PULSE_HYST (LOW_PULSE/2) #define TRAINING_AMOUNT_SLOW (TRAINING_TIME_SLOW / FRAME_TIME / 2) // количество импульсов для SLOW_MODE
#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 // количество импульсов в зависимости от SLOW_MODE
uint8_t G433_crc(uint8_t *buffer, uint8_t size); #ifdef G433_SLOW_MODE
void G433_crc_byte(uint8_t &crc, uint8_t data); #define TRAINING_AMOUNT 40
#else
#define TRAINING_AMOUNT 10
#endif
// окно времени для обработки старта и фрейма
#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)
// жоский delay для avr
#ifdef AVR
#define G433_DELAY(x) _delay_us(x)
#else
#define G433_DELAY(x) delayMicroseconds(x)
#endif
// режимы CRC
#define G433_CRC8 0
#define G433_XOR 1
#define G433_NOCRC 2
// 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) { Gyver433_TX() {
#if defined(__AVR__) pinMode(TX_PIN, OUTPUT);
_port_reg = portOutputRegister(digitalPinToPort(pin));
_bit_mask = digitalPinToBitMask(pin);
#else
_pin = pin;
#endif
pinMode(pin, OUTPUT);
} }
// отправка, блокирующая. Кушает любой тип данных // отправка, блокирующая. Кушает любой тип данных
@@ -73,111 +82,117 @@ 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
for (uint8_t b = 0; b < 8; b++) {
fastDW(flag);
flag = !flag;
if (bitRead(buffer[n], b)) delayMicroseconds(HIGH_PULSE);
else delayMicroseconds(LOW_PULSE);
}
}
fastDW(0); // передача окончена
} }
private: // отправка сырого набора байтов
void fastDW(bool state) { void write(uint8_t* buf, uint16_t size) {
#if defined(__AVR__) #ifdef G433_SLOW_MODE
if (state) *_port_reg |= _bit_mask; // HIGH for (uint16_t i = 0; i < ((millis() - tmr > 400) ? TRAINING_AMOUNT_SLOW : TRAINING_AMOUNT); i++) {
else *_port_reg &= ~_bit_mask; // LOW
#else #else
digitalWrite(_pin, state); for (uint16_t i = 0; i < TRAINING_AMOUNT; i++) {
#endif
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); // старт бит
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;
}
}
fastWrite(TX_PIN, 0); // конец передачи
#ifdef G433_SLOW_MODE
tmr = millis();
#endif #endif
} }
uint8_t buffer[G433_BUFSIZE];
#if defined(__AVR__) // доступ к буферу
volatile uint8_t *_port_reg; uint8_t buffer[TX_BUF];
volatile uint8_t _bit_mask;
#else private:
uint8_t _pin; #ifdef G433_SLOW_MODE
uint32_t tmr = 0;
#endif #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);
#else
_pin = pin;
#endif
} }
// неблокирующий приём, вернёт кол-во успешно принятых байт // неблокирующий приём, вернёт кол-во успешно принятых байт
uint8_t tick() { uint8_t tick() {
bool newState = fastDR(); // читаем пин uint32_t thisPulse = micros() - tmr; // время импульса
if (newState != prevState) { // ловим изменение сигнала if (parse == 2 && thisPulse >= FRAME_TIME * 2) { // фрейм не закрыт
uint32_t thisUs = micros(); parse = size = 0; // приём окончен
uint32_t thisPulse = thisUs - tmr; if (byteCount > 1) { // если что то приняли
if (parse == 1) { // в прошлый раз поймали фронт if (CRC_MODE == G433_CRC8) { // CRC8
if (thisPulse > START_MIN && thisPulse < START_MAX) { // старт бит? if (!G433_crc8(buffer, byteCount)) {
parse = 2; // ключ на старт size = byteCount - 2;
tmr = thisUs; dataReady = 1;
byteCount = 0;
bitCount = 0;
size = 0;
for (uint8_t i = 0; i < G433_BUFSIZE; i++) buffer[i] = 0;
} else { // не старт бит
parse = 0;
} }
} else if (parse == 2) { // идёт парсинг } else if (CRC_MODE == G433_XOR) { // CRC XOR
if (thisPulse > LOW_MIN && thisPulse < LOW_MAX) { // low бит if (!G433_crc_xor(buffer, byteCount)) {
// просто пропускаем (в буфере уже нули) size = byteCount - 2;
tmr = thisUs; dataReady = 1;
bitCount++; }
if (bitCount == 8) { } else { // без CRC
bitCount = 0; size = byteCount - 1;
byteCount++; dataReady = 1;
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; return size;
} }
else return 0; bool bit = fastRead(RX_PIN); // читаем пин
if (bit != prevBit) { // ловим изменение сигнала
if (parse == 1) { // в прошлый раз поймали фронт
tmr += thisPulse; // сброс таймера
if (thisPulse > START_MIN && thisPulse < START_MAX) { // старт бит?
parse = 2; // ключ на старт
byteCount = bitCount = size = 0; // сброс
dataReady = 0;
for (uint8_t i = 0; i < RX_BUF; i++) buffer[i] = 0; // чистим буфер
} else parse = 0; // не старт бит
} else if (parse == 2) { // идёт парсинг
if (thisPulse > FRAME_MIN && thisPulse < FRAME_MAX) { // фронт внутри таймфрейма
tmr += thisPulse; // синхронизируем тайминги
buffer[byteCount] >>= 1; // двигаем байт
if (bit && !prevBit) buffer[byteCount] |= _BV(7); // пишем единичку
bitCount++; // счётчик битов
}
if (bitCount == 8) { // собрали байт
bitCount = 0; // сброс
if (++byteCount >= RX_BUF) parse = 0; // буфер переполнен
} }
} }
if (newState && !prevState && parse == 0) { // ловим фронт if (bit && !prevBit && parse == 0) { // ловим фронт
parse = 1; // в следующий раз ждём флаг parse = 1; // флаг на старт
tmr = thisUs; tmr += thisPulse; // сброс таймера
} }
prevState = newState; prevBit = bit;
} }
return 0; return 0;
} }
@@ -185,52 +200,49 @@ public:
// блокирующий приём, вернёт кол-во успешно принятых байт // блокирующий приём, вернёт кол-во успешно принятых байт
uint8_t tickWait() { uint8_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 при получении корректных данных
bool gotData() {
tick();
if (dataReady) {
dataReady = 0;
return 1;
} return 0;
}
// получить размер принятых данных // получить размер принятых данных
int getSize() { int getSize() {
return size; return size;
} }
// размер принятых данных
int size = 0; int size = 0;
// доступ к буферу
uint8_t buffer[RX_BUF];
private: private:
bool fastDR() { bool prevBit, dataReady = 0;
#if defined(__AVR__)
return bool(*_pin_reg & _bit_mask);
#else
return digitalRead(_pin);
#endif
}
uint8_t buffer[G433_BUFSIZE];
bool prevState;
uint8_t parse = 0; uint8_t parse = 0;
uint32_t tmr = 0; uint32_t tmr = 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;
#else
uint8_t _pin;
#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;
@@ -259,9 +271,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