7 Commits

Author SHA1 Message Date
Alex 48c3ee21a4 upd 2021-09-09 17:57:11 +03:00
Alex e6f45643b9 upd 2021-09-09 17:54:30 +03:00
Alex 96520e1b3b upd 2021-08-24 01:30:02 +03:00
Alex 8196c8e583 v1.4 2021-07-17 23:04:48 +03:00
Alex f4c573bf88 Update Gyver433.h 2021-06-20 22:01:08 +03:00
Alex 060fcbb9ce v1.3 2021-06-20 12:05:51 +03:00
Alex d10b64cbe6 upd 2021-06-17 17:24:48 +03:00
15 changed files with 381 additions and 457 deletions
+52 -47
View File
@@ -2,15 +2,15 @@
![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
- Супер лёгкая либа, заведётся даже на тини13 (отправка)
- Поддержка кривых китайских модулей - Поддержка кривых китайских модулей
- Интерфейс Manchester или Pulselength - Встроенный CRC контроль целостности
- Встроенный CRC контроль целостности (CRC8 или XOR)
- Ускоренный алгоритм IO для AVR Arduino - Ускоренный алгоритм IO для AVR Arduino
- Опционально работа в прерывании (приём данных) - Асинхронный приём в прерывании
- Супер лёгкая либа, заведётся даже на тини13
### Совместимость ### Совместимость
Совместима со всеми Arduino платформами (используются Arduino-функции) Совместима со всеми Arduino платформами (используются Arduino-функции)
- При подключении прерывания на esp8266 не забудь аттрибут `IRAM_ATTR`
## Содержание ## Содержание
- [Установка](#install) - [Установка](#install)
@@ -36,26 +36,18 @@
<a id="init"></a> <a id="init"></a>
## Инициализация ## Инициализация
```cpp ```cpp
// === КЛАССЫ === // === ПЕРЕДАТЧИК ===
// Gyver433_RX - приёмник Gyver433_TX<пин> tx;
// Gyver433_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 // 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>
@@ -64,31 +56,45 @@ Gyver433_xx<пин, буфер, CRC> xx;
// ========= Gyver433_TX ========= // ========= Gyver433_TX =========
void sendData(T &data); // отправить данные любого типа (CRC добавляется автоматически) void sendData(T &data); // отправить данные любого типа (CRC добавляется автоматически)
void write(uint8_t* buf, uint8_t size); // отправить массив байт указанного размера (CRC не добавляется) void write(uint8_t* buf, uint8_t size); // отправить массив байт указанного размера (CRC не добавляется)
uint8_t buffer[]; // доступ к буферу для отладки uint8_t buffer[]; // доступ к буферу приёма
uint8_t byteBuf; // доступ к буферу принятого байта
// ========= Gyver433_RX ========= // ========= Gyver433_RX =========
uint16_t tick(); // неблокирующий приём, вернёт кол-во успешно принятых байт void tickISR(); // тикер приёма для вызова в прерывании по CHANGE
uint16_t tickWait(); // блокирующий приём (более надёжный), вернёт кол-во успешно принятых байт uint8_t tickISRraw(); // ручной приём в прерывании по CHANGE. Вернёт 1 (начало приёма), 2 (принят байт), 3 (конец пакета)
uint16_t tickISR(); // тикер для прерывания по CHANGE (см. пример isr_rx) uint16_t tick(); // неблокирующий приём. Вернёт количество успешно принятых байт
uint16_t tickWait(); // блокирующий приём. Вернёт количество успешно принятых байт
bool readData(T &data); // прочитает буфер в любой тип данных (в указанную переменную) bool readData(T &data); // прочитает буфер в любой тип данных (в указанную переменную)
uint16_t getSize(); // получить размер принятых данных uint16_t getSize(); // получить размер принятых данных
uint16_t gotData(); // вернёт количество успешно принятых в tickISR() байт (см. пример isr_rx) uint16_t gotData(); // вернёт количество успешно принятых в tickISR() байт (см. пример isr_rx)
uint8_t buffer[]; // доступ к буферу для отладки uint8_t getRSSI(); // получить качество приёма (процент успешных передач 0.. 100)
uint8_t buffer[]; // доступ к буферу приёма
uint8_t byteBuf; // доступ к буферу принятого байта
// ============= CRC ============= // ============= CRC =============
// можно использовать встроенные функции для генерации байта CRC для ручной упаковки пакетов // можно использовать встроенные функции для генерации байта CRC для ручной упаковки пакетов
uint8_t G433_crc8(uint8_t *buffer, uint8_t size); // ручной CRC8 uint8_t G433_crc8(uint8_t *buffer, uint8_t size); // ручной CRC8
uint8_t G433_crc_xor(uint8_t *buffer, uint8_t size); // ручной CRC XOR 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] скорость, должна быть одинакова на RX и TX, 100-10000 бит/с, по умолч. 2000 бит/с
#define G433_RSSI_COUNT 8 // [RX] количество успешно принятых пакетов для расчёта RSSI (по умолч. 8)
#define G433_CUT_RSSI // [RX] убрать расчёт RSSI из кода (сэкономит чуть памяти)
``` ```
<a id="example"></a> <a id="example"></a>
## Примеры ## Примеры
Остальные примеры смотри в **examples**! Остальные примеры смотри в **examples**!
![Logo](/doc/scheme.jpg) ![scheme](/doc/scheme.jpg)
### Отправка ### Отправка
```cpp ```cpp
#include <Gyver433.h> #include <Gyver433.h>
Gyver433_TX<2, 20> tx; // указали пин и размер буфера Gyver433_TX<2> tx; // указали пин
void setup() { void setup() {
} }
@@ -106,23 +112,6 @@ void loop() {
} }
``` ```
### Приём
```cpp
#include <Gyver433.h>
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 ```cpp
#include <Gyver433.h> #include <Gyver433.h>
@@ -133,8 +122,9 @@ void setup() {
attachInterrupt(0, isr, CHANGE); // прерывание пина радио по CHANGE attachInterrupt(0, isr, CHANGE); // прерывание пина радио по CHANGE
} }
// спец. тикер вызывается в прерывании
void isr() { void isr() {
rx.tickISR(); // спец. тикер вызывается в прерывании rx.tickISR();
} }
void loop() { void loop() {
@@ -142,15 +132,30 @@ void loop() {
Serial.write(rx.buffer, rx.size); // выводим Serial.write(rx.buffer, rx.size); // выводим
Serial.println(); 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
<a id="versions"></a> <a id="versions"></a>
## Версии ## Версии
- v1.0 - v1.0
- v1.1 - оптимизация, новый интерфейс, поддержка дешёвых синих модулей, работа в прерывании - v1.1 - оптимизация, новый интерфейс, поддержка дешёвых синих модулей, работа в прерывании
- v1.2 - улучшение качества связи, оптимизация работы в прерывании - v1.2 - улучшение качества связи, оптимизация работы в прерывании
- v1.3 - добавлен вывод RSSI
- v1.4 - переделан FastIO
- v1.4.1 - убран FastIO, CRC вынесен отдельно
- v2.0 - убран буфер на отправку, убран манчестер, полностью переделан и оптимизирован интерфейс связи
<a id="feedback"></a> <a id="feedback"></a>
## Баги и обратная связь ## Баги и обратная связь
+34 -17
View File
@@ -1,36 +1,53 @@
// демо-пример: инициализация и настройки // демо-пример приёма в прерывании
// крупный приёмник SYN480R [VCC: 3.3-5.5V, logic: VCC] // SYN480R, крупный чип: 3.3-5.5V
// или MX-RM-5V (RF-5V) [VCC: 5V, logic: 5V] // MX-RM-5V (RF-5V): 5V
// RX470 (WL101-341): 3-5V
// дефайны перед подключением библиотеки // дефайны перед подключением библиотеки
//#define G433_MANCHESTER // интерфейс Manchester Coding для экспериментов =) //#define G433_SPEED 2000 // скорость 100-10000 бит/с, по умолч. 2000 бит/с
//#define G433_SPEED 1000 // скорость 100-8000 бит/с, по умолч. 2000 бит/с
#include <Gyver433.h> #include <Gyver433.h>
//Gyver433_RX<пин> rx; //Gyver433_RX<пин> rx;
//Gyver433_RX<пин, буфер> rx; //Gyver433_RX<пин, буфер> rx;
//Gyver433_RX<пин, буфер, CRC> rx;
// пин: цифровой пин // пин: цифровой пин
// буфер: размер буфера в байтах. По умолч. 64 // буфер: размер приёмного буфера в байтах. По умолч. 64
// CRC: проверка целостности данных: G433_CRC8 (надёжный), G433_XOR (лёгкий), G433_NOCRC (отключено). По умолч. G433_CRC8
#include <Gyver433.h>
Gyver433_RX<2, 20> rx; Gyver433_RX<2, 20> rx;
void setup() { void setup() {
Serial.begin(9600); Serial.begin(9600);
// взводим прерывания по CHANGE
attachInterrupt(0, isr, CHANGE);
}
// тикер вызывается в прерывании
void isr() {
rx.tickISR();
} }
void loop() { void loop() {
// "тик" опрашивает радио и вернёт количество успешно принятых байт // gotData() вернёт количество удачно принятых байт
// tick принимает асинхронно, но может ловить ошибки при загруженном коде if (rx.gotData()) { // если больше 0
// tickWait блокирует выполнение, но принимает данные чётко // ЧИТАЕМ. СПОСОБ 1
// я знаю, что передатчик отправляет char[15]
char data[15];
//if (rx.tick()) { // читаем принятые данные в data
if (rx.tickWait()) { // если данные совпадают по размеру - ок
// принятые данные доступны в .buffer if (rx.readData(data)) Serial.print(data);
// и имеют размер .size else Serial.print("Data error");
Serial.write(rx.buffer, rx.size);
Serial.println(); // ЧИТАЕМ. СПОСОБ 2
// вывести сырые данные из буфера в порт
//Serial.write(rx.buffer, rx.size);
// выведем также качество соединения
Serial.print(", RSSI: ");
Serial.println(rx.getRSSI());
} }
// имитация загруженного кода. Не влияет на приём
delay(50);
} }
+8 -15
View File
@@ -1,24 +1,17 @@
// демо-пример: инициализация и настройки // демо-пример отправки
// мелкий передатчик SYN115 [VCC: 1.8-3.6V, logic: VCC] // SYN115, маленький чип: 1.8-3.6V
// или FS1000A [VCC: 3-12V, logic: 5V] // FS1000A: 3-12V
// WL102-341: 2.0-3.6V
// дефайны перед подключением библиотеки // дефайны перед подключением библиотеки
//#define G433_FAST // короткая синхронизация для зелёных модулей //#define G433_FAST // короткая синхронизация для зелёных модулей
//#define G433_MEDIUM // средняя синхронизация для SYN480R при отправке ЧАЩЕ 400мс (активно по умолчанию) //#define G433_MEDIUM // средняя синхронизация для SYN480R при отправке ЧАЩЕ 400мс (активно по умолчанию)
//#define G433_SLOW // длинная синхронизация для SYN480R при отправке РЕЖЕ 400мс //#define G433_SLOW // длинная синхронизация для SYN480R при отправке РЕЖЕ 400мс
//#define G433_MANCHESTER // интерфейс Manchester Coding для экспериментов =) //#define G433_SPEED 2000 // скорость 100-10000 бит/с, по умолч. 2000 бит/с
//#define G433_SPEED 1000 // скорость 100-8000 бит/с, по умолч. 2000 бит/с
#include <Gyver433.h> #include <Gyver433.h>
//Gyver433_TX<пин> tx; //Gyver433_RX<пин> tx;
//Gyver433_TX<пин, буфер> tx; Gyver433_TX<2> tx;
//Gyver433_TX<пин, буфер, CRC> tx;
// пин: цифровой пин
// буфер: размер буфера в байтах. На "ручную" отправку буфер не нужен. По умолч. 64
// CRC: проверка целостности данных: G433_CRC8 (надёжный), G433_XOR (лёгкий), G433_NOCRC (отключено). По умолч. G433_CRC8
Gyver433_TX<2, 20> tx;
void setup() { void setup() {
} }
@@ -32,7 +25,7 @@ void loop() {
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);
// отправка 10 раз в сек // отправка 10 раз в сек
-26
View File
@@ -1,26 +0,0 @@
// приём в прерывании. Отправляет пример 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);
}
+9 -3
View File
@@ -1,15 +1,21 @@
// обмен сырыми данными без CRC и буфера на отправку // обмен сырыми данными без CRC
// отправляет пример raw_tx // отправляет пример raw_tx
// принимаем без прерывания! для примера
//#define G433_SPEED 1000 // скорость 100-10000 бит/с, по умолч. 2000 бит/с
#include <Gyver433.h> #include <Gyver433.h>
Gyver433_RX<2, 20, G433_NOCRC> rx; // буфер на приём нужен! Gyver433_RX<2, 20, G433_NOCRC> rx; // буфер 20 байт
void setup() { void setup() {
Serial.begin(9600); Serial.begin(9600);
} }
void loop() { void loop() {
if (rx.tickWait()) { // этот тикер нужно вызывать как можно чаще
// лучше принимать в прерывании, см. пример demo
if (rx.tick()) {
// выводим сырые байты в порт
Serial.write(rx.buffer, rx.size); Serial.write(rx.buffer, rx.size);
Serial.println(); Serial.println();
} }
+4 -4
View File
@@ -1,10 +1,10 @@
// обмен сырыми данными без CRC и буфера на отправку // обмен сырыми данными без CRC
// принимает пример raw_rx // принимает пример raw_rx
//#define G433_SPEED 1000 // скорость 100-8000 бит/с, по умолч. 2000 бит/с //#define G433_SPEED 1000 // скорость 100-10000 бит/с, по умолч. 2000 бит/с
#include <Gyver433.h> #include <Gyver433.h>
Gyver433_TX<2, 0, G433_NOCRC> tx; // буфер на отправку 0! Экономим Gyver433_TX<2, G433_NOCRC> tx;
void setup() { void setup() {
} }
@@ -19,7 +19,7 @@ void loop() {
if (++count >= 100) count = 0; if (++count >= 100) count = 0;
// отправка данных типа byte* // отправка данных типа byte*
tx.write(data, sizeof(data)); tx.write((byte*)data, sizeof(data));
// отправка 10 раз в сек // отправка 10 раз в сек
delay(100); delay(100);
+1 -1
View File
@@ -1,5 +1,5 @@
// выводим данные на дисплей. Отправляет пример demo_tx // выводим данные на дисплей. Отправляет пример demo_tx
//#define G433_SPEED 1000 // скорость 100-8000 бит/с, по умолч. 2000 бит/с //#define G433_SPEED 1000 // скорость 100-10000 бит/с, по умолч. 1500 бит/с
#include <Gyver433.h> #include <Gyver433.h>
Gyver433_RX<2> rx; // указали пин Gyver433_RX<2> rx; // указали пин
+9 -7
View File
@@ -1,12 +1,12 @@
// приём структуры данных // приём структуры данных
//#define G433_SPEED 1000 // скорость 100-8000 бит/с, по умолч. 2000 бит/с //#define G433_SPEED 1000 // скорость 100-10000 бит/с, по умолч. 2000 бит/с
#include <Gyver433.h> #include <Gyver433.h>
Gyver433_RX<2, 10> rx; // указали пин и размер буфера Gyver433_RX<2, 12> rx; // указали пин и размер буфера
// формат пакета для приёма (такой же как отправляется) // формат пакета для приёма (такой же как отправляется)
struct dataPack { struct DataPack {
byte counter; byte counter;
byte randomNum; byte randomNum;
int analog; int analog;
@@ -19,14 +19,16 @@ void setup() {
void loop() { void loop() {
if (rx.tick()) { if (rx.tick()) {
dataPack data; // "буферная" структура DataPack data; // "буферная" структура
rx.readData(data); // переписываем данные в неё if (rx.readData(data)) { // переписываем данные в неё
// если данные подходят - выводим
Serial.println("Received:");
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();
} else {
Serial.println("Wrong data");
}
} }
} }
+5 -6
View File
@@ -1,19 +1,19 @@
// передача структуры данных // передача структуры данных
//#define G433_SPEED 1000 // скорость 100-8000 бит/с, по умолч. 2000 бит/с //#define G433_SPEED 1000 // скорость 100-10000 бит/с, по умолч. 2000 бит/с
#define G433_SLOW // отправляю раз в секунду на SYN480R #define G433_SLOW // отправляю раз в секунду на SYN480R
#include <Gyver433.h> #include <Gyver433.h>
Gyver433_TX<2, 10> tx; // указали пин и размер буфера Gyver433_TX<2> tx; // указали пин
// формат пакета для отправки // формат пакета для отправки
struct dataPack { struct DataPack {
byte counter; byte counter = 0;
byte randomNum; byte randomNum;
int analog; int analog;
uint32_t time; uint32_t time;
}; };
dataPack data; DataPack data;
void setup() { void setup() {
Serial.begin(9600); Serial.begin(9600);
@@ -24,7 +24,6 @@ void loop() {
data.randomNum = random(256); // случайное число data.randomNum = random(256); // случайное число
data.analog = analogRead(0); // тут ацп data.analog = analogRead(0); // тут ацп
data.time = millis(); // тут миллис data.time = millis(); // тут миллис
tx.sendData(data); tx.sendData(data);
Serial.println("Transmitted:"); Serial.println("Transmitted:");
+5 -4
View File
@@ -13,12 +13,11 @@ Gyver433_RX KEYWORD1
# Methods and Functions (KEYWORD2) # Methods and Functions (KEYWORD2)
####################################### #######################################
sendData KEYWORD2 sendData KEYWORD2
sendDataSlow KEYWORD2
write KEYWORD2 write KEYWORD2
writeSlow KEYWORD2
tick KEYWORD2 tick KEYWORD2
tickISR KEYWORD2
tickWait KEYWORD2 tickWait KEYWORD2
tickISR KEYWORD2
tickISRraw KEYWORD2
readData KEYWORD2 readData KEYWORD2
size KEYWORD2 size KEYWORD2
buffer KEYWORD2 buffer KEYWORD2
@@ -26,10 +25,12 @@ getSize KEYWORD2
gotData KEYWORD2 gotData KEYWORD2
G433_crc8 KEYWORD2 G433_crc8 KEYWORD2
G433_crc_xor KEYWORD2 G433_crc_xor KEYWORD2
getRSSI KEYWORD2
####################################### #######################################
# Constants (LITERAL1) # Constants (LITERAL1)
####################################### #######################################
G433_CLI LITERAL1
G433_CRC8 LITERAL1 G433_CRC8 LITERAL1
G433_XOR LITERAL1 G433_XOR LITERAL1
G433_NOCRC LITERAL1 G433_NOCRC LITERAL1
@@ -37,4 +38,4 @@ G433_FAST LITERAL1
G433_MEDIUM LITERAL1 G433_MEDIUM LITERAL1
G433_SLOW LITERAL1 G433_SLOW LITERAL1
G433_SPEED LITERAL1 G433_SPEED LITERAL1
G433_MANCHESTER LITERAL1 G433_CUT_RSSI LITERAL1
+1 -1
View File
@@ -1,5 +1,5 @@
name=Gyver433 name=Gyver433
version=1.2 version=2.0
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
@@ -1,109 +0,0 @@
// Быстрый 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
+41
View File
@@ -0,0 +1,41 @@
#include "G433_crc.h"
void G433_crc8_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
}
uint8_t G433_crc8(uint8_t *buffer, uint8_t size) {
uint8_t crc = 0;
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;
}
+7
View File
@@ -0,0 +1,7 @@
#ifndef G433_crc_h
#define G433_crc_h
#include <Arduino.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
void G433_crc8_byte(uint8_t &crc, uint8_t data); // crc8 один байт
#endif
+188 -200
View File
@@ -3,12 +3,11 @@
Документация: Документация:
GitHub: https://github.com/GyverLibs/Gyver433 GitHub: https://github.com/GyverLibs/Gyver433
Возможности: Возможности:
- Супер лёгкая либа, заведётся даже на тини13 (отправка)
- Поддержка кривых китайских модулей - Поддержка кривых китайских модулей
- Интерфейс Manchester или Pulselength - Встроенный CRC контроль целостности
- Встроенный CRC контроль целостности (CRC8 или XOR)
- Ускоренный алгоритм IO для AVR Arduino - Ускоренный алгоритм IO для AVR Arduino
- Опционально работа в прерывании (приём данных) - Асинхронный приём в прерывании
- Супер лёгкая либа, заведётся даже на тини13
AlexGyver, alex@alexgyver.ru AlexGyver, alex@alexgyver.ru
https://alexgyver.ru/ https://alexgyver.ru/
@@ -18,63 +17,66 @@
v1.0 - релиз v1.0 - релиз
v1.1 - оптимизация, новый интерфейс, поддержка дешёвых синих модулей, работа в прерывании v1.1 - оптимизация, новый интерфейс, поддержка дешёвых синих модулей, работа в прерывании
v1.2 - улучшение качества связи, оптимизация работы в прерывании v1.2 - улучшение качества связи, оптимизация работы в прерывании
v1.3 - добавлен вывод RSSI
v1.4 - переделан FastIO
v1.4.1 - убран FastIO, CRC вынесен отдельно
v2.0 - убран буфер на отправку, убран манчестер, полностью переделан и оптимизирован интерфейс связи
*/ */
#ifndef Gyver433_h #ifndef _Gyver433_h
#define Gyver433_h #define _Gyver433_h
#include <Arduino.h> #include <Arduino.h>
#include "FastIO.h" #include "G433_crc.h"
uint8_t G433_crc8(uint8_t *buffer, uint8_t size); // ручной CRC8 #define TRAINING_TIME_SLOW (500000) // время синхронизации для SLOW_MODE
uint8_t G433_crc_xor(uint8_t *buffer, uint8_t size); // ручной CRC XOR
#define TRAINING_TIME_SLOW (500000ul) // время синхронизации для SLOW_MODE
// ========================================================================= // =========================================================================
#ifndef G433_SPEED #ifndef G433_SPEED
#define G433_SPEED 2000 #define G433_SPEED 2000
#endif #endif
// тайминги интерфейса #ifndef G433_RSSI_COUNT
#define FRAME_TIME (1000000ul / G433_SPEED) // время фрейма (либо HIGH) #define G433_RSSI_COUNT 8
#define HALF_FRAME (FRAME_TIME / 2) // полфрейма (либо LOW) #endif
#define START_PULSE (FRAME_TIME * 2) // стартовый импульс
// окно времени для обработки импульса // тайминги интерфейса
#define START_MIN (START_PULSE * 3 / 4) #define G433_HIGH (1000000ul / G433_SPEED) // время HIGH
#define START_MAX (START_PULSE * 5 / 4) #define G433_LOW (G433_HIGH / 2) // время LOW
#define FRAME_MIN (FRAME_TIME * 3 / 4) #define G433_START (G433_HIGH * 2) // стартовый импульс
#define FRAME_MAX (FRAME_TIME * 5 / 4) #define G433_TRAIN (G433_HIGH * 3 / 2) // синхроимпульс
#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 // жоский delay для avr
#ifdef AVR #ifdef AVR
#define G433_DELAY _delay_us #define G433_DELAY(x) _delay_us(x)
#else #else
#define G433_DELAY delayMicroseconds #define G433_DELAY(x) delayMicroseconds(x)
#endif #endif
// режимы CRC // режимы CRC
#define G433_CRC8 0 #define G433_NOCRC 0
#define G433_XOR 1 #define G433_CRC8 1
#define G433_NOCRC 2 #define G433_XOR 2
// количество синхроимпульсов // количество синхроимпульсов
#if defined(G433_FAST) #if defined(G433_FAST)
#define TRAINING_PULSES 10 #define TRAINING_TIME 10000
#elif defined(G433_MEDIUM) #elif defined(G433_MEDIUM)
#define TRAINING_PULSES 50 #define TRAINING_TIME 100000
#elif defined(G433_SLOW) #elif defined(G433_SLOW)
#define TRAINING_PULSES (TRAINING_TIME_SLOW / FRAME_TIME / 2) #define TRAINING_TIME (TRAINING_TIME_SLOW)
#else #else
#define TRAINING_PULSES 50 #define TRAINING_TIME 100000
#endif #endif
// crc8 один байт // =================================== ПЕРЕДАТЧИК ===================================
void G433_crc8_byte(uint8_t &crc, uint8_t data); template <uint8_t TX_PIN, uint8_t CRC_MODE = G433_CRC8>
// ============ ПЕРЕДАТЧИК ============
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() { Gyver433_TX() {
@@ -83,66 +85,63 @@ public:
// отправка, блокирующая. Кушает любой тип данных // отправка, блокирующая. Кушает любой тип данных
template <typename T> template <typename T>
void sendData(T &data) { bool sendData(T &data) {
const uint8_t *ptr = (const uint8_t*) &data; uint8_t *ptr = (uint8_t*) &data;
for (uint16_t i = 0; i < sizeof(T); i++) buffer[i] = *ptr++; write(ptr, sizeof(T));
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));
}
} }
// отправка сырого набора байтов // отправка сырого набора байтов
void write(uint8_t* buf, uint16_t size) { void write(uint8_t* buf, uint16_t size) {
for (uint16_t i = 0; i < TRAINING_PULSES; i++) { uint8_t crc;
fastWrite(TX_PIN, 1); if (CRC_MODE == G433_CRC8) crc = G433_crc8(buf, size);
G433_DELAY(FRAME_TIME); else if (CRC_MODE == G433_XOR) crc = G433_crc_xor(buf, size);
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); // ждём flag = 0;
for (uint16_t n = 0; n < size; n++) { for (uint16_t i = 0; i < (TRAINING_TIME / G433_TRAIN / 2) * 2 + 1; i++) {
uint8_t data = buf[n]; fastWrite(TX_PIN, flag = !flag);
for (uint8_t b = 0; b < 8; b++) { G433_DELAY(G433_TRAIN);
fastWrite(TX_PIN, !(data & 1));
G433_DELAY(HALF_FRAME);
fastWrite(TX_PIN, (data & 1));
G433_DELAY(HALF_FRAME);
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); // стоп
} }
fastWrite(TX_PIN, 0); // конец передачи
#else // отправить байт (без старт бита!)
bool flag = 0; void write(uint8_t data) {
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++) {
if (data & 1) G433_DELAY(FRAME_TIME); if (data & 1) G433_DELAY(G433_HIGH);
else G433_DELAY(HALF_FRAME); else G433_DELAY(G433_LOW);
fastWrite(TX_PIN, flag = !flag); fastWrite(TX_PIN, flag = !flag);
data >>= 1; data >>= 1;
} }
} }
private:
// быстрый IO
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);
#else
digitalWrite(pin, val);
#endif #endif
} }
// доступ к буферу bool flag = 0;
uint8_t buffer[TX_BUF];
private:
}; };
// ============ ПРИЁМНИК ============ // =================================== ПРИЁМНИК ===================================
template <uint8_t RX_PIN, uint16_t RX_BUF = 64, uint8_t CRC_MODE = G433_CRC8> template <uint8_t RX_PIN, uint16_t RX_BUF = 64, uint8_t CRC_MODE = G433_CRC8>
class Gyver433_RX { class Gyver433_RX {
public: public:
@@ -150,52 +149,110 @@ public:
pinMode(RX_PIN, INPUT); pinMode(RX_PIN, INPUT);
} }
// неблокирующий приём, вернёт кол-во успешно принятых байт // неблокирующий приём. Вернёт количество успешно принятых байт
uint16_t tick() { uint16_t tick() {
if (pinChanged()) checkState(); if (pinChanged()) tickISR();
return gotData(); return gotData();
} }
// tick для вызова в прерывании по CHANGE // блокирующий приём. Вернёт количество успешно принятых байт
void tickISR() {
#ifdef G433_MANCHESTER
if (pinChanged()) checkState();
#else
checkState();
#endif
}
// блокирующий приём, вернёт кол-во успешно принятых байт
uint16_t tickWait() { uint16_t tickWait() {
do { do {
if (tick()) return size; if (pinChanged()) tickISR();
} while (parse == 2); } 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; return 0;
} }
// прочитает буфер в любой тип данных // прочитает буфер в любой тип данных
template <typename T> template <typename T>
bool readData(T &data) { bool readData(T &data) {
if (sizeof(T) > RX_BUF) return false; if (sizeof(T) > RX_BUF) return false; // великовато для буфера
if (sizeof(T) != size) 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() { uint8_t getRSSI() {
if (parse == 2 && millis() - tmr2 >= 10) { // фрейм не закрыт #ifndef G433_CUT_RSSI
parse = size = 0; // приём окончен return RSSI;
if (byteCount > 1) { // если что то приняли #endif
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;
} }
// получить размер принятых данных // получить размер принятых данных
@@ -207,107 +264,38 @@ public:
uint16_t size = 0; uint16_t size = 0;
// доступ к буферу // доступ к буферу
uint8_t buffer[RX_BUF]; uint8_t buffer[RX_BUF + !!CRC_MODE];
uint8_t byteBuf;
private: private:
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);
#else
return digitalRead(pin);
#endif
return 0;
}
bool pinChanged() { bool pinChanged() {
bit = fastRead(RX_PIN); if (prevBit != fastRead(RX_PIN)) {
if (bit != prevBit) { prevBit = !prevBit;
prevBit = bit;
return 1; return 1;
} return 0; } return 0;
} }
void checkState() { bool prevBit;
uint32_t thisPulse = micros() - tmr; // время импульса volatile uint8_t state = 0;
if (parse == 1) { // в прошлый раз поймали фронт volatile uint8_t parse = 0, trains = 0;
#ifdef G433_MANCHESTER volatile uint32_t tmr = 0;
tmr += thisPulse; // сброс таймера приёма uint8_t bits = 0, bytes = 0;
#ifndef G433_CUT_RSSI
uint8_t errCount = 0, rcCount = 0, RSSI = 100;
#endif #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;
}; };
// ===== CRC =====
void G433_crc8_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
}
uint8_t G433_crc8(uint8_t *buffer, uint8_t size) {
uint8_t crc = 0;
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;
}
#endif #endif