#include <SPI.h>
// Pin definitions (adjust to your schematic)
#define SS 5 // Chip select for SX1278
#define RST 14 // Reset pin for SX1278
#define DIO0 26 // DIO0 pin (used for IRQ flags)
#define MOTION_SENSOR 4 // PIR sensor pin
// Set this to 'true' for transmitter mode, 'false' for receiver mode.
bool isTransmitter = true;
// Write a value to an SX1278 register via SPI
void writeRegister(byte addr, byte value) {
digitalWrite(SS, LOW);
SPI.transfer(addr | 0x80); // MSB=1 for write
SPI.transfer(value);
digitalWrite(SS, HIGH);
}
// Read a value from an SX1278 register via SPI
byte readRegister(byte addr) {
digitalWrite(SS, LOW);
SPI.transfer(addr & 0x7F); // MSB=0 for read
byte value = SPI.transfer(0x00);
digitalWrite(SS, HIGH);
return value;
}
// Reset the SX1278 using the RST pin
void resetSX1278() {
digitalWrite(RST, LOW);
delay(100);
digitalWrite(RST, HIGH);
delay(100);
}
// Initialize the SX1278 in LoRa mode and set frequency to ~433 MHz
void initSX1278() {
// Put the SX1278 in sleep mode with LoRa enabled (RegOpMode = 0x80)
writeRegister(0x01, 0x80);
delay(10);
// Set frequency registers for ~433 MHz.
// Calculation: FRF = Frequency / FSTEP, where FSTEP ≈ 61.035 Hz.
// For 433 MHz, FRF ≈ 433e6 / 61.035 ≈ 7090667 (0x6C, 0x80, 0x00)
writeRegister(0x06, 0x6C);
writeRegister(0x07, 0x80);
writeRegister(0x08, 0x00);
// Put the SX1278 in standby mode (RegOpMode = 0x81)
writeRegister(0x01, 0x81);
delay(10);
// If receiver, switch to continuous RX mode (RegOpMode = 0x85)
if (!isTransmitter) {
writeRegister(0x01, 0x85);
}
Serial.println("SX1278 configured in LoRa mode.");
}
void setup() {
Serial.begin(115200);
pinMode(MOTION_SENSOR, INPUT_PULLUP);
pinMode(SS, OUTPUT);
pinMode(RST, OUTPUT);
pinMode(DIO0, INPUT);
SPI.begin(); // Uses default SPI pins (SCK=18, MISO=19, MOSI=23 on ESP32)
resetSX1278();
initSX1278();
if (isTransmitter) {
Serial.println("Device set as TRANSMITTER");
} else {
Serial.println("Device set as RECEIVER");
}
}
void loop() {
if (isTransmitter) {
sendLoRaMessage();
delay(2000); // Wait 2 seconds between transmissions
} else {
receiveLoRaMessage();
delay(100); // Small delay for polling in RX mode
}
}
// Function to send a LoRa message based on the PIR sensor state
void sendLoRaMessage() {
int motionState = digitalRead(MOTION_SENSOR);
char payload = (motionState == HIGH) ? 'M' : 'N';
Serial.println("Transmitting...");
if (motionState == HIGH) {
Serial.println("Motion detected! Sending LoRa message...");
} else {
Serial.println("No motion detected. Sending LoRa message...");
}
// Set FIFO pointer to 0 (RegFifoAddrPtr at 0x0D)
writeRegister(0x0D, 0x00);
// Write the payload to FIFO (RegFifo at 0x00)
writeRegister(0x00, payload);
// Set payload length to 1 byte (RegPayloadLength at 0x22)
writeRegister(0x22, 0x01);
// Set SX1278 to TX mode (RegOpMode = 0x83)
writeRegister(0x01, 0x83);
// Wait for TxDone flag (bit 3 in RegIrqFlags at 0x12, mask 0x08)
while (!(readRegister(0x12) & 0x08)) {
// Wait until transmission is complete
}
// Clear TxDone flag by writing 0x08 to RegIrqFlags
writeRegister(0x12, 0x08);
// Return to standby mode (RegOpMode = 0x81)
writeRegister(0x01, 0x81);
}
// Function to receive a LoRa message and display it
void receiveLoRaMessage() {
// Check the RxDone flag (bit 6 in RegIrqFlags at 0x12, mask 0x40)
if (readRegister(0x12) & 0x40) {
// Clear RxDone flag
writeRegister(0x12, 0x40);
// Read current FIFO address from RegFifoRxCurrentAddr (0x10)
byte currentAddr = readRegister(0x10);
// Set FIFO pointer to current address (RegFifoAddrPtr at 0x0D)
writeRegister(0x0D, currentAddr);
// Get number of received bytes from RegRxNbBytes (0x13)
byte nbBytes = readRegister(0x13);
String msg = "";
for (byte i = 0; i < nbBytes; i++) {
msg += (char)readRegister(0x00);
}
Serial.print("Received: ");
Serial.println(msg);
} else {
Serial.println("No LoRa packet received.");
}
}