-
Notifications
You must be signed in to change notification settings - Fork 204
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
400 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,234 @@ | ||
#pragma once | ||
/* | ||
Суперлёгкая библиотека для радиомодулей 433 МГц | ||
- Не использует прерывания и таймеры (кроме нулевого, читает micros()) | ||
- Встроенный CRC контроль целостности | ||
- Ускоренный алгоритм IO для AVR Arduino | ||
Передатчик: | ||
Gyver433_TX tx(пин) - создать объект | ||
sendData(data) - отправить, любой тип данных | ||
Приёмник: | ||
Gyver433_RX tx(пин) - создать объект | ||
tick() - вызывать постоянно для чтения. Асинхронный. Вернёт количество принятых байт | ||
tickWait() - тож самое, но блокирует выполнение, принимает более четко | ||
readData(data) - прочитать, любой тип данных | ||
size - количество принятых байтов | ||
*/ | ||
|
||
#define G433_SPEED 2000 // скорость бит/сек (минимальная) | ||
#define G433_BUFSIZE 64 // размер буфера приёма и отправки | ||
|
||
// тайминги интерфейса (компилятор посчитает) | ||
#define HIGH_PULSE (1000000ul/G433_SPEED) | ||
#define LOW_PULSE (HIGH_PULSE/2) | ||
#define START_PULSE (HIGH_PULSE*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 | ||
byte G433_crc(byte *buffer, byte size); | ||
void G433_crc_byte(uint8_t &crc, uint8_t data); | ||
|
||
// ============ ПЕРЕДАТЧИК ============ | ||
class Gyver433_TX { | ||
public: | ||
Gyver433_TX(byte pin) : _pin(pin) { | ||
#if defined(__AVR__) | ||
_port_reg = portOutputRegister(digitalPinToPort(pin)); | ||
_bit_mask = digitalPinToBitMask(pin); | ||
#endif | ||
pinMode(pin, OUTPUT); | ||
} | ||
|
||
// отправка, блокирующая. Кушает любой тип данных | ||
template <typename T> | ||
void sendData(T &data) { | ||
const uint8_t *ptr = (const uint8_t*) &data; | ||
for (uint16_t i = 0; i < sizeof(T); i++) buffer[i] = *ptr++; | ||
buffer[sizeof(T)] = G433_crc(buffer, sizeof(T)); // CRC последним байтом | ||
bool flag = 0; // флаг дрыга | ||
for (byte i = 0; i < 30; i++) { // 30 импульсов для синхронизации | ||
flag = !flag; | ||
fastDW(flag); | ||
delayMicroseconds(HIGH_PULSE); | ||
} | ||
fastDW(1); // старт бит | ||
delayMicroseconds(START_PULSE); // старт бит | ||
for (int n = 0; n < sizeof(T) + 1; n++) { // буфер + CRC | ||
for (byte 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) { | ||
#if defined(__AVR__) | ||
if (state) *_port_reg |= _bit_mask; // HIGH | ||
else *_port_reg &= ~_bit_mask; // LOW | ||
#else | ||
digitalWrite(_pin, state); | ||
#endif | ||
} | ||
byte buffer[G433_BUFSIZE]; | ||
const byte _pin; | ||
#if defined(__AVR__) | ||
volatile uint8_t *_port_reg; | ||
volatile uint8_t _bit_mask; | ||
#endif | ||
}; | ||
|
||
|
||
// ============ ПРИЁМНИК ============ | ||
class Gyver433_RX { | ||
public: | ||
Gyver433_RX(byte pin){ | ||
#if defined(__AVR__) | ||
_pin_reg = portInputRegister(digitalPinToPort(pin)); | ||
_bit_mask = digitalPinToBitMask(pin); | ||
#endif | ||
} | ||
|
||
// неблокирующий приём, вернёт кол-во успешно принятых байт | ||
byte tick() { | ||
bool newState = fastDR(); // читаем пин | ||
if (newState != prevState) { // ловим изменение сигнала | ||
uint32_t thisUs = micros(); | ||
uint32_t thisPulse = thisUs - tmr; | ||
if (parse == 1) { // в прошлый раз поймали фронт | ||
if (thisPulse > START_MIN && thisPulse < START_MAX) { // старт бит? | ||
parse = 2; // ключ на старт | ||
tmr = thisUs; | ||
byteCount = 0; | ||
bitCount = 0; | ||
size = 0; | ||
for (byte 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; | ||
} | ||
|
||
// блокирующий приём, вернёт кол-во успешно принятых байт | ||
byte tickWait() { | ||
do { | ||
tick(); | ||
} while (parse == 2); | ||
if (byteCount > 0) { | ||
byteCount = 0; | ||
return size; | ||
} else return 0; | ||
} | ||
|
||
// прочитает буфер в любой тип данных | ||
template <typename T> | ||
bool readData(T &data) { | ||
if (sizeof(T) > G433_BUFSIZE) return false; | ||
uint8_t *ptr = (uint8_t*) &data; | ||
for (uint16_t i = 0; i < sizeof(T); i++) *ptr++ = buffer[i]; | ||
return true; | ||
} | ||
|
||
int size = 0; | ||
|
||
private: | ||
bool fastDR() { | ||
#if defined(__AVR__) | ||
return bool(*_pin_reg & _bit_mask); | ||
#else | ||
return digitalRead(_pin); | ||
#endif | ||
} | ||
byte buffer[G433_BUFSIZE]; | ||
bool prevState; | ||
byte parse = 0; | ||
uint32_t tmr = 0; | ||
byte 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) { | ||
#if defined (__AVR__) | ||
// резкий алгоритм для AVR | ||
uint8_t counter; | ||
uint8_t buffer; | ||
asm volatile ( | ||
"EOR %[crc_out], %[data_in] \n\t" | ||
"LDI %[counter], 8 \n\t" | ||
"LDI %[buffer], 0x8C \n\t" | ||
"_loop_start_%=: \n\t" | ||
"LSR %[crc_out] \n\t" | ||
"BRCC _loop_end_%= \n\t" | ||
"EOR %[crc_out], %[buffer] \n\t" | ||
"_loop_end_%=: \n\t" | ||
"DEC %[counter] \n\t" | ||
"BRNE _loop_start_%=" | ||
: [crc_out]"=r" (crc), [counter]"=d" (counter), [buffer]"=d" (buffer) | ||
: [crc_in]"0" (crc), [data_in]"r" (data) | ||
); | ||
#else | ||
// обычный для всех остальных | ||
uint8_t i = 8; | ||
while (i--) { | ||
crc = ((crc ^ data) & 1) ? (crc >> 1) ^ 0x8C : (crc >> 1); | ||
data >>= 1; | ||
} | ||
#endif | ||
} | ||
|
||
byte G433_crc(byte *buffer, byte size) { | ||
byte crc = 0; | ||
for (byte i = 0; i < size; i++) G433_crc_byte(crc, buffer[i]); | ||
return crc; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// крупный приёмник 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]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// крупный приёмник 5.0V SYN480R | ||
#define G433_BUFSIZE 50 // размер буфера | ||
#define G433_SPEED 2000 // скорость бит/сек (минимальная) | ||
|
||
#include <Gyver433.h> | ||
Gyver433_RX rx(2); // указали пин | ||
|
||
#include <Wire.h> | ||
#include <LiquidCrystal_I2C.h> | ||
LiquidCrystal_I2C lcd(0x3f, 16, 2); // или 0x27 | ||
|
||
void setup() { | ||
Serial.begin(9600); | ||
lcd.init(); | ||
lcd.backlight(); | ||
} | ||
|
||
void loop() { | ||
// tick принимает асинхронно, но может ловить ошибки при загруженном коде | ||
// tickWait блокирует выполнение, но принимает данные чётко | ||
if (rx.tick()) { | ||
byte buf[64]; | ||
rx.readData(buf); // прочитать в buf | ||
lcd.clear(); | ||
lcd.home(); | ||
for (byte i = 0; i < rx.size; i++) lcd.write(buf[i]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
// передача структуры данных | ||
// крупный приёмник 5.0V SYN480R | ||
#define G433_BUFSIZE 50 // размер буфера | ||
#define G433_SPEED 2000 // скорость бит/сек (минимальная) | ||
|
||
#include <Gyver433.h> | ||
Gyver433_RX rx(2); // указали пин | ||
|
||
// формат пакета для приёма (такой же как отправляется) | ||
struct dataPack { | ||
byte counter; | ||
byte randomNum; | ||
int analog; | ||
uint32_t time; | ||
}; | ||
|
||
void setup() { | ||
Serial.begin(9600); | ||
} | ||
|
||
void loop() { | ||
// tick принимает асинхронно, но может ловить ошибки при загруженном коде | ||
// tickWait блокирует выполнение, но принимает данные чётко | ||
if (rx.tick()) { | ||
dataPack data; | ||
rx.readData(data); // прочитать в buf | ||
|
||
Serial.println("Received:"); | ||
Serial.println(data.counter); | ||
Serial.println(data.randomNum); | ||
Serial.println(data.analog); | ||
Serial.println(data.time); | ||
Serial.println(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// мелкий передатчик 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); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// передача структуры данных | ||
// мелкий передатчик 3.6V SYN115 | ||
|
||
#define G433_BUFSIZE 50 // размер буфера | ||
#define G433_SPEED 2000 // скорость бит/сек (минимальная) | ||
#include <Gyver433.h> | ||
Gyver433_TX tx(2); // указали пин | ||
|
||
// формат пакета для отправки | ||
struct dataPack { | ||
byte counter; | ||
byte randomNum; | ||
int analog; | ||
uint32_t time; | ||
}; | ||
dataPack data; | ||
|
||
void setup() { | ||
Serial.begin(9600); | ||
} | ||
|
||
void loop() { | ||
data.counter++; // тут счётчик | ||
data.randomNum = random(256); // случайное число | ||
data.analog = analogRead(0); // тут ацп | ||
data.time = millis(); // тут миллис | ||
|
||
Serial.println("Transmit:"); | ||
Serial.println(data.counter); | ||
Serial.println(data.randomNum); | ||
Serial.println(data.analog); | ||
Serial.println(data.time); | ||
Serial.println(); | ||
|
||
tx.sendData(data); | ||
delay(1000); | ||
} |
Oops, something went wrong.