LoRa на Arduino: урок с нуля до передатчика
LoRa это технология радиосвязи для IoT-устройств: она передаёт данные на километры при очень малом потреблении. В основе лежит чип SX1276 от Semtech, а на рынке модули продаются как RA-02, Heltec WiFi LoRa и RFM95. Урок проведёт от распиновки до рабочего передатчика.
Главное отличие LoRa от WiFi в том, что дальность достигается ценой скорости: вместо мегабит в секунду вы получаете от сотен бит до нескольких килобит, но зато уверенно пробиваете стены и за десятки километров.
Это урок по железу, но каркас кода проверяется в симуляторе LoRa: в браузере работает эхо-демо, где переданный пакет возвращается приёмнику в том же скетче.
Распиновка SX1276 (SPI)
LoRa-модули подключаются по SPI: MOSI на D11, MISO на D12, SCK на D13. Эти три линии общие с любым другим SPI-устройством, например с картой SD. Остальные выводы у модуля свои: NSS или CS отвечает за выбор микросхемы, RST за сброс, а DIO0 нужен для прерываний, в простейшем скетче его можно не подключать. В коде библиотеки они задаются в конструкторе или отдельными вызовами setChipSelect и setReset.
Питание: SX1276 рассчитан строго на 3.3 В, и подача 5 В на голый чип сожжёт его. На платах с адаптером стоит стабилизатор AMS1117-3.3, и тогда питать можно от 5 В, но на дешёвых клонах стабилизатор иногда экономят. На модуле RA-02 с настоящим чипом питание 3.3 В обязательно, и на выводе 5 V подавать нельзя.
Антенна нужна всегда, даже если вы просто проверяете скетч. Без нагрузки на выходе передатчика чип перегревается и может сгореть, а реальная дальность вместо километров превращается в десятки метров. Для 868 МГц подойдёт проволочная антенна длиной около 8.6 см, это четверть длины волны, или готовая SMA-антенна на нужную частоту. Для 433 МГц длина проволоки вдвое больше, около 17.3 см.
Библиотека LoRa.h и код передатчика
#include <LoRa.h>LoRa lora;int counter = 0;void setup() { Serial.begin(9600); while (!Serial); Serial.println("LoRa передатчик"); lora.begin(868E6); // 868 МГц для Европы/России lora.setSpreadingFactor(7); // SF7 = быстро lora.setTxPower(17); // 17 dBm (макс) Serial.println("Готов к передаче");}void loop() { Serial.print("Отправка пакета #"); Serial.println(counter); lora.beginPacket(); lora.print("ping #"); lora.print(counter); lora.endPacket(); counter++; delay(2000);}Вызов begin с числом 868E6 задаёт частоту 868 МГц. Частота передаётся в герцах, поэтому 433E6 это 433 МГц, а 915E6 это 915 МГц. Для России и Европы берите 868 МГц, для Азии 433 МГц, для США 915 МГц. Перед покупкой проверьте правила вашей страны: в диапазоне 868 МГц в России можно работать без лицензии при мощности до 25 мВт ERP, а в Европе действует ограничение на долю времени работы в эфире.
setSpreadingFactor выбирает значение от 7 до 12. Чем оно выше, тем длиннее время передачи одного символа, тем ниже скорость, но тем лучше приёмник вытаскивает слабый сигнал из шума. При полосе 125 кГц и кодировании 4/5 скорость составляет примерно 5468 бит/с на SF7 и около 293 бит/с на SF12. setTxPower задаёт мощность: библиотека принимает значения до 20, и всё, что выше 14, включает усилитель через отдельный вывод PA_BOOST. У SX1276 предел 17 dBm.
Работа с пакетом устроена так: beginPacket открывает новый пакет, print или print добавляют в него данные, а endPacket отправляет его в эфир и ждёт окончания передачи. Важно, что endPacket блокирующий: всё это время скетч не делает ничего другого, и на слабом сигнале ожидание может занять заметное время.
Код приёмника
#include <LoRa.h>LoRa lora;void setup() { Serial.begin(9600); Serial.println("LoRa приёмник"); lora.begin(868E6);}void loop() { int packetSize = lora.parsePacket(); if (packetSize) { Serial.print("Получено: "); while (lora.available()) { Serial.write((char)lora.read()); } Serial.print(" RSSI: "); Serial.println(lora.packetRssi()); }}parsePacket проверяет входящий буфер: если пакета нет, он возвращает 0, если есть, то длину в байтах. Дальше содержимое читается побайтно, read отдаёт один символ, а available сообщает, сколько ещё осталось. Вызывать parsePacket нужно постоянно, потому что пока вы его не вызвали, модуль не разберёт входящий пакет и не заполнит буфер. Именно на этом чаще всего спотыкаются: приёмник молчит, пока в цикле нет вызова.
packetRssi отдаёт уровень сигнала в dBm. В документации библиотеки LoRa.h значение около -50 dBm считается отличным сигналом, а -100 dBm и ниже означают, что приём на грани. packetSnr показывает отношение сигнал к шуму, и положительное значение означает, что пакет декодирован уверенно. Оба параметра стоит выводить при отладке: вместе они сразу показывают, проблема в антенне, в питании или в частоте.
В симуляторе работает эхо-демо: endPacket кладёт пакет в буфер, parsePacket читает его в том же скетче. Для настоящей связи нужны два модуля SX1276. Подробнее про LoRa-связь — в лендинге. nRF24L01 — альтернатива для 2.4 ГГц.
| Параметр | Значение | Заметка |
|---|---|---|
| Частота | 433/868/915 МГц | 868 для РФ/Европы |
| Spreading Factor | SF7..SF12 | SF12 = максимум дальности |
| Bandwidth | 125/250/500 кГц | 125 стандарт |
| TxPower | 5..17 dBm | 17 = макс для SX1276 |
| Дальность | до 15 км (открыто) | Зависит от SF и антенны |
| Ток TX | 20-120 мА | Больше мощность = больше ток |
Что сначала не получилось
Первая сборка выглядела так: я подключил модуль к breadboard, запитал его от 5 V и стал ждать пакетов. Ничего не пришло, а потом модуль перестал отвечать совсем. Причина была в питании: на моём клоне стабилизатора не было, и 5 В убили чип. После замены на модуль с AMS1117-3.3 и подключения антенны связь появилась сразу.
Второй затык был с приёмником. Я перенёс код передатчика, заменил endPacket на parsePacket и забыл, что приёмник должен постоянно опрашивать буфер. Передатчик при этом работал, и я потратил время на проверку антенны и расстояния, вместо того чтобы просто добавить вызов parsePacket в цикл.
Личный опыт: связь между двумя точками
Рабочий стенд у меня получился из двух Uno, двух модулей SX1276 с адаптерами и двух проволочных антенн по 8.6 см. Передатчик слал строку с номером пакета раз в две секунды, приёмник печатал её и RSSI. На расстоянии около 30 метров на улице, в прямой видимости, пакеты приходили все, а RSSI держался в зоне отличного сигнала.
Затем я вынес приёмник в другой конец квартиры, за две бетонные стены, и там связь стала рваной. Помогло два изменения: spreading factor поднял с SF7 до SF10, а скорость уменьшил с одной отправки в секунду до одной в пять секунд. Пакеты пошли стабильно, потому что при большем SF каждый символ передаётся дольше и приёмник успевает накопить энергию слабого сигнала. Это и есть главный компромисс LoRa: дальность покупается скоростью.
Авторская позиция: что взять новичку
Берите готовый модуль с адаптером, а не голый чип: так у вас сразу будет стабилизатор и разъём под антенну. Для первой пары устройств возьмите одинаковые модули, разные частоты работать не будут. И сразу определитесь с задачей: если вам нужна скорость, а не дальность, берите SF7 и полосу 125 кГц, а если наоборот, SF10-12. И не забывайте про антенну: это единственная деталь, которая реально определяет дальность, и она не стоит ничего.