Init fork from Stuart Robinson's repo
This commit is contained in:
@ -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
|
||||
}
|
||||
@ -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
|
||||
Reference in New Issue
Block a user