Init fork from Stuart Robinson's repo

This commit is contained in:
2024-10-03 14:30:13 +03:00
commit 9395706524
201 changed files with 45709 additions and 0 deletions

View File

@ -0,0 +1,314 @@
/*******************************************************************************************************
Programs for Arduino - Copyright of the author Stuart Robinson - 20/02/20
This program is supplied as is, it is up to the user of the program to decide if the program is
suitable for the intended purpose and free from errors.
*******************************************************************************************************/
/*******************************************************************************************************
Program Operation - The program transmits a LoRa packet without using a processor buffer, the LoRa
devices internal buffer is filled directly with variables. The program is for Atmel Arduinos.
The sensor used is a BME280. The pressure, humidity, and temperature are read and transmitted. There
is also a 16bit value of battery mV (simulated) and and a 8 bit status value at the packet end.
Although the LoRa packet transmitted and received has its own internal CRC error checking, you could
still receive packets of the same length from another source. If this valid packet were to be used
to recover the sensor values, you could be reading rubbish. To reduce the risk of this, when the packet
is transmitted the CRC value of the actual sensor data is calculated and sent out with the packet.
This CRC value is read by the receiver and used to check that the received CRC matches the supposed
sensor data in the packet. As an additional check there is some addressing information at the beginning
of the packet which is also checked for validity. Thus we can be relatively confident when reading the
received packet that its genuine and from this transmitter. The packet is built and sent in the
sendSensorPacket() function, there is a 'highlighted section' where the actual sensor data is added to
the packet.
Between readings the LoRa device, BME280 sensor, and Atmel microcontroller are put to sleep in units of
8 seconds using the Atmel processor internal watchdog.
The pin definitions, LoRa frequency and LoRa modem settings are in the Settings.h file.
There is also an option of using a logic pin to turn the resistor divider used to read battery voltage on
and off. This reduces current used in sleep mode. To use the feature set the define for pin BATVREADON
in 'Settings.h' to the pin used. If not using the feature set the pin number to -1.
The Atmel watchdog timer is a viable option for a very low current sensor node. A 'bare bones' ATmega328P
with regulator and LoRa device has a sleep current of 6.6uA, add the LoRa devices and BME280 sensor
module and the average sleep current only rises to 6.8uA.
One of these transmitter programs is running on a long term test with a 150mAh battery, to see how long
the battery actually lasts.
Serial monitor baud rate is set at 9600.
*******************************************************************************************************/
#include <SPI.h>
#include <SX128XLT.h>
#include "Settings.h"
#include <ProgramLT_Definitions.h>
#include <avr/wdt.h> //watchdog timer library for Atmel processors, integral to Arduino IDE
#include <LowPower.h> //get the library here; https://github.com/rocketscream/Low-Power
SX128XLT LT;
#include <Seeed_BME280.h> //get library here; https://github.com/Seeed-Studio/Grove_BME280
BME280 bme280; //create an instance of the BME280 senosor
#include <Wire.h>
uint32_t TXpacketCount;
uint8_t TXPacketL;
float temperature; //the BME280 temperature value
float pressure; //the BME280 pressure value
uint16_t humidity; //the BME280 humididty value
uint16_t voltage; //the battery voltage value
uint8_t statusbyte; //a status byte, not currently used
uint16_t CRCvalue; //the CRC value of the packet data up to this point
uint8_t packetlength; //the packet length that was sent, checked against length received
void loop()
{
TXpacketCount++;
Serial.print(TXpacketCount); //print the numbers of sends
Serial.print(F(" Sending > "));
readSensors(); //read the sensor values
printSensorValues(); //print the sensor values
if (sendSensorPacket())
{
Serial.println(F("SentOK"));
}
else
{
Serial.print(F("Send Error - IRQreg,"));
Serial.println(LT.readIrqStatus(), HEX);
}
Serial.print(F("Sleeping zzzz"));
Serial.flush(); //make sure all serial output has gone
//now put the sensor, LoRa device and processor to sleep
sleepBME280(); //sleep the BME280
LT.setSleep(CONFIGURATION_RETENTION); //sleep LoRa device, keeping register settings in sleep.
sleep8seconds(sleeps); //sleep Atmel processor in units of approx 8 seconds
//wait a bit ................
Serial.println(F(" - Awake !!")); //the processor has woken up
Serial.println();
LT.wake();
normalBME280(); //BME280 sensor to normal mode
}
uint8_t sendSensorPacket()
{
//The SX12XX buffer is filled with variables of a known type and in a known sequence. Make sure the
//receiver uses the same variable types and sequence to read variables out of the receive buffer.
uint8_t len;
LT.startWriteSXBuffer(0); //start the write packet to buffer process
LT.writeUint8(Sensor1); //this byte defines the packet type
LT.writeUint8('B'); //this byte identifies the destination node of the packet
LT.writeUint8(1); //this byte identifies the source node of the packet
/************************************************************************
Highlighted section - this is where the actual sensor data is added to the packet
************************************************************************/
LT.writeFloat(temperature); //add the BME280 temperature
LT.writeFloat(pressure); //add the BME280 pressure
LT.writeUint16(humidity); //add the BME280 humididty
LT.writeUint16(voltage); //add the battery voltage
LT.writeUint8(statusbyte); //add the status byte
/************************************************************************/
len = LT.endWriteSXBuffer(); //close the packet, get the length of data to be sent
addPacketErrorCheck(len); //add the additional CRC error checking to the packet end
//now transmit the packet, set a timeout of 5000mS, wait for it to complete sending
digitalWrite(LED1, HIGH); //turn on LED as an indicator
TXPacketL = LT.transmitSXBuffer(0, (len + 2), 5000, TXpower, WAIT_TX);
digitalWrite(LED1, LOW); //turn off indicator LED
return TXPacketL; //TXPacketL will be 0 if there was an error sending
}
void addPacketErrorCheck(uint8_t len)
{
//calculate the CRC of packet sensor data
CRCvalue = LT.CRCCCITTSX(3, (len - 1), 0xFFFF);
Serial.print(F("Calculated CRC value "));
Serial.println(CRCvalue, HEX);
LT.startWriteSXBuffer(len); //start the write packet again at location of CRC, past end of sensor data
LT.writeUint16(CRCvalue); //add the actual CRC value
LT.endWriteSXBuffer(); //close the packet
}
void readSensors()
{
//read the sensor values into the global variables
temperature = bme280.getTemperature();
pressure = bme280.getPressure();
humidity = bme280.getHumidity();
if (BATVREADON >= 0)
{
voltage = readBatteryVoltage(); //read resistor divider across battery
}
else
{
voltage = 9999; //set a default value
}
statusbyte = 0x55; //manually set this for now, its a test
}
void printSensorValues()
{
Serial.print(F("Temperature,"));
Serial.print(temperature, 1);
Serial.print(F("c,Pressure,"));
Serial.print(pressure, 0);
Serial.print(F("Pa,Humidity,"));
Serial.print(humidity);
Serial.print(F("%,Voltage,"));
Serial.print(voltage);
Serial.print(F("mV,Status,"));
Serial.print(statusbyte, HEX);
Serial.print(F(" "));
Serial.flush();
}
void sleep8seconds(uint32_t sleeps)
{
//uses the lowpower library
uint32_t index;
for (index = 1; index <= sleeps; index++)
{
//sleep 8 seconds
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
}
}
void sleepBME280()
{
//write this register value to BME280 to put it to sleep
writeBME280reg(BME280_REGISTER_CONTROL, B01111100);
}
void normalBME280()
{
//write this register value to BME280 to put it to read mode
writeBME280reg(BME280_REGISTER_CONTROL, B01111111);
}
void writeBME280reg(byte reg, byte regvalue)
{
//write a register value to the BME280
Wire.beginTransmission((uint8_t) BME280_ADDRESS);
Wire.write((uint8_t)reg);
Wire.write((uint8_t)regvalue);
Wire.endTransmission();
}
uint16_t readBatteryVoltage()
{
//relies on 1V1 internal reference and 91K & 11K resistor divider
//returns supply in mV @ 10mV per AD bit read
uint16_t temp;
uint16_t volts = 0;
byte index;
if (BATVREADON >= 0)
{
digitalWrite(BATVREADON, HIGH); //turn on MOSFET connecting resitor divider in circuit
}
analogReference(INTERNAL1V1);
temp = analogRead(BATTERYAD);
for (index = 0; index <= 4; index++) //sample AD 5 times
{
temp = analogRead(BATTERYAD);
volts = volts + temp;
}
volts = ((volts / 5) * ADMultiplier) + DIODEMV;
if (BATVREADON >= 0)
{
digitalWrite(BATVREADON, LOW); //turn off MOSFET connecting resitor divider in circuit
}
return volts;
}
void led_Flash(uint16_t flashes, uint16_t delaymS)
{
uint16_t index;
for (index = 1; index <= flashes; index++)
{
digitalWrite(LED1, HIGH);
delay(delaymS);
digitalWrite(LED1, LOW);
delay(delaymS);
}
}
void setup()
{
pinMode(LED1, OUTPUT);
led_Flash(2, 125);
if (BATVREADON >= 0)
{
pinMode(BATVREADON, OUTPUT);
}
Serial.begin(9600);
SPI.begin();
if (LT.begin(NSS, NRESET, RFBUSY, DIO1, LORA_DEVICE))
{
led_Flash(2, 125);
}
else
{
Serial.println(F("Device error"));
while (1)
{
led_Flash(50, 50); //long fast speed flash indicates LoRa device error
}
}
LT.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate);
if (!bme280.init())
{
Serial.println("BME280 Device error!");
led_Flash(100, 15); //long very fast speed flash indicates BME280 device error
}
Serial.println(F("Transmitter ready"));
Serial.println();
readSensors(); //do an initial sensor read
}

View File

@ -0,0 +1,38 @@
/*******************************************************************************************************
Programs for Arduino - Copyright of the author Stuart Robinson - 29/02/20
This program is supplied as is, it is up to the user of the program to decide if the program is
suitable for the intended purpose and free from errors.
*******************************************************************************************************/
//******* Setup hardware pin definitions here ! ***************
//These are the pin definitions for one of my own boards, the Easy Pro Mini,
//be sure to change the definitions to match your own setup.
#define NSS 10
#define RFBUSY 7
#define NRESET 9
#define LED1 8
#define DIO1 3
#define BATVREADON 8 //when high turns on the resistor divider to measure voltage, -1 if not used
#define BATTERYAD A7 //Resitor divider for battery connected here, -1 if not used
#define ADMultiplier 10.00 //adjustment to convert AD value read into mV of battery voltage
#define DIODEMV 98 //mV voltage drop accross diode @ low idle current
#define LORA_DEVICE DEVICE_SX1280 //we need to define the device we are using
//LoRa Modem Parameters
const uint32_t Frequency = 2445000000; //frequency of transmissions
const int32_t Offset = 0; //offset frequency for calibration purposes
const uint8_t Bandwidth = LORA_BW_0400; //LoRa bandwidth
const uint8_t SpreadingFactor = LORA_SF7; //LoRa spreading factor
const uint8_t CodeRate = LORA_CR_4_5; //LoRa coding rate
const int8_t TXpower = 10; //Power for transmissions in dBm
#define BME280_ADDRESS 0x76 //I2C bus address of BME280
#define BME280_REGISTER_CONTROL 0xF4 //BME280 register number for power control
const uint8_t sleeps = 2; //number of 8 second sleeps, gap between transmissions

View File

@ -0,0 +1,357 @@
/*******************************************************************************************************
Programs for Arduino - Copyright of the author Stuart Robinson - 29/02/20
This program is supplied as is, it is up to the user of the program to decide if the program is
suitable for the intended purpose and free from errors.
*******************************************************************************************************/
/*******************************************************************************************************
Program Operation - The program receives a LoRa packet without using a processor buffer, the LoRa devices
internal buffer is read direct for the received sensor data.
The sensor used in the matching '17_Sensor_Transmiter' program is a BME280 and the pressure, humidity,
and temperature are being and received. There is also a 16bit value of battery mV and and a 8 bit status
value at the end of the packet.
When the program starts, the LoRa device is setup to set the DIO1 pin high when a packet is received. When
a packet is received, its printed and assuming the packet is validated, the sensor results are printed to
the serial monitor and screen.
For the sensor data to be accepted as valid the folowing need to match;
The 16bit CRC on the received sensor data must match the CRC value transmitted with the packet.
The packet must start with a byte that matches the packet type sent, 'Sensor1'
The RXdestination byte in the packet must match this node ID of this receiver node, defined by 'This_Node'
In total thats 16 + 8 + 8 = 32bits of checking, so a 1:4294967296 chance (approx) that an invalid
packet is acted on and erroneous values displayed.
The pin definitions, LoRa frequency and LoRa modem settings are in the Settings.h file.
With a standard Arduino Pro Mini and SSD1306 display the current consumption was 20.25mA with the
display and 16.6mA without the display.
Serial monitor baud rate is set at 9600.
*******************************************************************************************************/
#include <SPI.h>
#include <SX128XLT.h>
#include "Settings.h"
#include <ProgramLT_Definitions.h>
SX128XLT LT;
#include <U8x8lib.h> //get library here > https://github.com/olikraus/u8g2
U8X8_SSD1306_128X64_NONAME_HW_I2C disp(U8X8_PIN_NONE); //use this line for standard 0.96" SSD1306
//U8X8_SH1106_128X64_NONAME_HW_I2C disp(U8X8_PIN_NONE); //use this line for 1.3" OLED often sold as 1.3" SSD1306
uint32_t RXpacketCount; //count of all packets received
uint32_t ValidPackets; //count of packets received with valid data
uint32_t RXpacketErrors; //count of all packets with errors received
bool packetisgood;
uint8_t RXPacketL; //length of received packet
int16_t PacketRSSI; //RSSI of received packet
int8_t PacketSNR; //signal to noise ratio of received packet
uint8_t RXPacketType;
uint8_t RXDestination;
uint8_t RXSource;
float temperature; //the BME280 temperature value
float pressure; //the BME280 pressure value
uint16_t humidity; //the BME280 humididty value
uint16_t voltage; //the battery voltage value
uint8_t statusbyte; //a status byte, not currently used
uint16_t TXCRCvalue; //the CRC value of the packet data as transmitted
void loop()
{
RXPacketL = LT.receiveSXBuffer(0, 0, WAIT_RX); //returns 0 if packet error of some sort, no timeout set
digitalWrite(LED1, HIGH); //something has happened
PacketRSSI = LT.readPacketRSSI();
PacketSNR = LT.readPacketSNR();
if (RXPacketL == 0)
{
packet_is_Error();
}
else
{
packet_Received_OK(); //its a valid packet LoRa wise, but it might not be a packet we want
}
digitalWrite(LED1, LOW);
Serial.println();
}
void packet_Received_OK()
{
//a LoRa packet has been received, which has passed the internal LoRa checks, including CRC, but it could be from
//an unknown source, so we need to check that its actually a sensor packet we are expecting, and has valid sensor data
uint8_t len;
uint8_t contenterrors; //keep a count of errors found in packet
RXpacketCount++;
Serial.print(RXpacketCount);
Serial.print(F(",PacketsReceived,"));
LT.startReadSXBuffer(0);
RXPacketType = LT.readUint8();
RXDestination = LT.readUint8();
RXSource = LT.readUint8();
/************************************************************************
Highlighted section - this is where the actual sensor data is read from
the packet
************************************************************************/
temperature = LT.readFloat(); //the BME280 temperature value
pressure = LT.readFloat(); //the BME280 pressure value
humidity = LT.readUint16(); //the BME280 humididty value
voltage = LT.readUint16(); //the battery voltage value
statusbyte = LT.readUint8(); //a status byte, not currently used
/************************************************************************/
len = LT.endReadSXBuffer();
printreceptionDetails(); //print details of reception, RSSI etc
Serial.println();
contenterrors = checkPacketValid(len); //pass length of packet to check routine
if (contenterrors == 0)
{
Serial.println(F(" Packet is good"));
ValidPackets++;
printSensorValues(); //print the sensor values
Serial.println();
printPacketCounts(); //print count of valid packets and errors
displayscreen1();
Serial.println();
}
else
{
Serial.println(F(" Packet is not valid"));
RXpacketErrors++;
disp.clearLine(7);
disp.setCursor(0, 7);
disp.print(F("Errors "));
disp.print(RXpacketErrors);
}
}
uint8_t checkPacketValid(uint8_t len)
{
//this function checks if the packet is valid and will be displayed
uint8_t errors = 0;
if (RXPacketType != Sensor1) //is it a Sensor1 type packet
{
errors++;
}
if (RXDestination != This_Node) //was the packet sent to this receiver node ?
{
errors++;
}
if (!checkCRCvalue(len)) //is the sent CRC value of sensor data valid ?
{
errors++;
}
Serial.println();
Serial.print(F("Error Check Count = "));
Serial.print(errors);
return errors;
}
bool checkCRCvalue(uint8_t len)
{
uint16_t CRCSensorData;
Serial.print(F("len = "));
Serial.println(len);
CRCSensorData = LT.CRCCCITTSX(3, (len - 1), 0xFFFF); //calculate the CRC of packet sensor data
Serial.print(F("(CRC of Received sensor data "));
Serial.print(CRCSensorData, HEX);
Serial.print(F(")" ));
TXCRCvalue = ((LT.getByteSXBuffer(len + 1) << 8) + (LT.getByteSXBuffer(len)));
Serial.print(F("(CRC transmitted "));
Serial.print(TXCRCvalue, HEX);
Serial.print(F(")" ));
if (TXCRCvalue != CRCSensorData)
{
Serial.print(F(" Sensor Data Not Valid"));
return false;
}
else
{
Serial.print(F(" Sensor Data is Valid"));
return true;
}
}
void printSensorValues()
{
Serial.print(F("Temp,"));
Serial.print(temperature, 1);
Serial.print(F("c,Press,"));
Serial.print(pressure, 0);
Serial.print(F("Pa,Humidity,"));
Serial.print(humidity);
Serial.print(F("%,Voltage,"));
Serial.print(voltage);
Serial.print(F("mV,Status,"));
Serial.print(statusbyte, HEX);
Serial.print(F(",CRC,"));
Serial.print(TXCRCvalue, HEX);
Serial.flush();
}
void printreceptionDetails()
{
Serial.print(F("RSSI,"));
Serial.print(PacketRSSI);
Serial.print(F("dBm,SNR,"));
Serial.print(PacketSNR);
Serial.print(F("dB,Length,"));
Serial.print(LT.readRXPacketL());
}
void printPacketCounts()
{
Serial.print(F("ValidPackets,"));
Serial.print(ValidPackets);
Serial.print(F(",Errors,"));
Serial.print(RXpacketErrors);
}
void packet_is_Error()
{
uint16_t IRQStatus;
RXpacketErrors++;
IRQStatus = LT.readIrqStatus();
if (IRQStatus & IRQ_RX_TIMEOUT)
{
Serial.print(F("RXTimeout "));
}
else
{
Serial.print(F("PacketError "));
printreceptionDetails();
Serial.print(F(",IRQreg,"));
Serial.print(IRQStatus, HEX);
LT.printIrqStatus();
Serial.println();
disp.clearLine(7);
disp.setCursor(0, 7);
disp.print(F("Errors "));
disp.print(RXpacketErrors);
}
}
void displayscreen1()
{
//show sensor data on display
disp.clearLine(0);
disp.setCursor(0, 0);
disp.print(F("Sensor "));
disp.print(RXSource);
disp.clearLine(1);
disp.setCursor(0, 1);
disp.print(temperature, 1);
disp.print(F("c"));
disp.clearLine(2);
disp.setCursor(0, 2);
disp.print(pressure, 0);
disp.print(F("Pa"));
disp.clearLine(3);
disp.setCursor(0, 3);
disp.print(humidity);
disp.print(F("%"));
disp.clearLine(4);
disp.setCursor(0, 4);
disp.print(voltage);
disp.print(F("mV"));
disp.clearLine(6);
disp.setCursor(0, 6);
disp.print(F("ValidPkts "));
disp.print(ValidPackets);
disp.setCursor(0, 7);
disp.print(F("Errors "));
disp.print(RXpacketErrors);
}
void led_Flash(uint16_t flashes, uint16_t delaymS)
{
uint16_t index;
for (index = 1; index <= flashes; index++)
{
digitalWrite(LED1, HIGH);
delay(delaymS);
digitalWrite(LED1, LOW);
delay(delaymS);
}
}
void setup()
{
pinMode(LED1, OUTPUT);
led_Flash(2, 125);
Serial.begin(9600);
disp.begin();
disp.setFont(u8x8_font_chroma48medium8_r);
disp.clear();
disp.setCursor(0, 0);
disp.print(F("Check LoRa"));
disp.setCursor(0, 1);
SPI.begin();
if (LT.begin(NSS, NRESET, RFBUSY, DIO1, LORA_DEVICE))
{
disp.print(F("LoRa OK"));
led_Flash(2, 125);
}
else
{
disp.print(F("Device error"));
Serial.println(F("Device error"));
while (1)
{
led_Flash(50, 50); //long fast speed flash indicates device error
}
}
LT.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate);
Serial.println(F("Receiver ready"));
Serial.println();
}

View File

@ -0,0 +1,38 @@
/*******************************************************************************************************
Programs for Arduino - Copyright of the author Stuart Robinson - 29/02/20
This program is supplied as is, it is up to the user of the program to decide if the program is
suitable for the intended purpose and free from errors.
*******************************************************************************************************/
//These are the pin definitions for one of my own boards, the Easy Pro Mini,
//be sure to change the definitions to match your own setup.
#define NSS 10
#define RFBUSY 7
#define NRESET 9
#define LED1 8
#define DIO1 3
#define BATVREADON 8 //when high turns on the resistor divider to measure voltage, -1 if not used
#define BATTERYAD A7 //Resistor divider for battery connected here, -1 if not used
#define ADMultiplier 10.00 //adjustment to convert AD value read into mV of battery voltage
#define DIODEMV 98 //mV voltage drop accross diode @ low idle current
#define LORA_DEVICE DEVICE_SX1280 //we need to define the device we are using
//*************** Setup LoRa Test Parameters Here ! ***************
//LoRa Modem Parameters
const uint32_t Frequency = 2445000000; //frequency of transmissions
const int32_t Offset = 0; //offset frequency for calibration purposes
const uint8_t Bandwidth = LORA_BW_0400; //LoRa bandwidth
const uint8_t SpreadingFactor = LORA_SF7; //LoRa spreading factor
const uint8_t CodeRate = LORA_CR_4_5; //LoRa coding rate
const int8_t TXpower = 10; //Power for transmissions in dBm
#define packet_delay 1000 //mS delay between packets
#define This_Node 'B' //this is the node that the remote sensors send data to