Added support for EEPROM stored configuration values.
authorPat Thoyts <patthoyts@users.sourceforge.net>
Wed, 21 Oct 2015 11:32:15 +0000 (12:32 +0100)
committerPat Thoyts <patthoyts@users.sourceforge.net>
Wed, 21 Oct 2015 11:32:15 +0000 (12:32 +0100)
The radio addresses and channel can be placed in EEPROM now.

nRF24_BLE_Temperature.ino

index 88e6b8bc62ee0c919b63a5ffc8091b83447d47b5..57e6ce30310d103b848c391a5b1890d2a4a1f99a 100644 (file)
 #include <Arduino.h>
 #include <Wire.h>
 #include <SPI.h>
+#include <EEPROM.h>
 #include <OneWire.h>
 #include <DallasTemperature.h>
-#include <LiquidCrystal_I2C.h>\r
-#include <RHDatagram.h>\r
-#include <RH_NRF24.h>\r
-#include "BLE24.h"\r
-\r
-static void I2C_Init();\r
-static void LCD_Init();\r
-static void RTC_Init();\r
-static void Radio_Init();\r
-static void DS18B20_Init();\r
-static void PrintAddress(Print *stream, DeviceAddress address);\r
-\r
-#define RADIO_CE_PIN  8\r
-#define RADIO_CHANNEL 85\r
+#include <LiquidCrystal_I2C.h>
+#include <RHDatagram.h>
+#include <RH_NRF24.h>
+#include "BLE24.h"
+
+static void I2C_Init();
+static void LCD_Init();
+static void RTC_Init();
+static void Radio_Init();
+static void DS18B20_Init();
+static void EEPROM_Init();
+static void PrintAddress(Print *stream, DeviceAddress address);
+
+#define RADIO_CE_PIN  8
 #define PIN_LED 6
 #define PIN_ONEWIRE 4
-\r
-#define SENSOR_HUB_ADDRESS 1\r
-#define DEVICE_ADDRESS 2\r
-\r
-#define LCD_ADDR 0x20\r
-#define LCD_EN_BIT 4\r
-#define LCD_RW_BIT 5\r
-#define LCD_RS_BIT 6\r
-#define LCD_D4_BIT 0\r
-#define LCD_BL_BIT 7\r
-\r
-LiquidCrystal_I2C lcd(LCD_ADDR, LCD_EN_BIT, LCD_RW_BIT, LCD_RS_BIT,\r
+
+const int DEFAULT_RADIO_CHANNEL = 85;
+const int DEFAULT_RADIO_DEV_ADDRESS = 3;
+const int DEFAULT_RADIO_HUB_ADDRESS = 1;
+const uint8_t EEPROM_INITIALIZED_MAGIC = 0xA5;
+
+EEMEM uint8_t ee_initialized = EEPROM_INITIALIZED_MAGIC;
+EEMEM int ee_nrf_channel = DEFAULT_RADIO_CHANNEL;
+EEMEM int ee_nrf_dev_address = DEFAULT_RADIO_DEV_ADDRESS;
+EEMEM int ee_nrf_hub_address = DEFAULT_RADIO_HUB_ADDRESS;
+EEMEM char ee_serial[4] = {0xde, 0xad, 0xbe, 0xef};
+
+#define LCD_ADDR 0x20
+#define LCD_EN_BIT 4
+#define LCD_RW_BIT 5
+#define LCD_RS_BIT 6
+#define LCD_D4_BIT 0
+#define LCD_BL_BIT 7
+
+LiquidCrystal_I2C lcd(LCD_ADDR, LCD_EN_BIT, LCD_RW_BIT, LCD_RS_BIT,
 LCD_D4_BIT, LCD_D4_BIT+1, LCD_D4_BIT+2, LCD_D4_BIT+3);
 
 #define SENSOR_RESOLUTION 12
 OneWire w1bus(PIN_ONEWIRE);
 DallasTemperature w1sensors(&w1bus);
 DeviceAddress w1sensorAddress;
-RH_NRF24 nrf24(PIN_CSN, PIN_CE);\r
-RHDatagram Radio(nrf24, SENSOR_HUB_ADDRESS);
+RH_NRF24 nrf24(PIN_CSN, PIN_CE);
+RHDatagram Radio(nrf24);
 CBTLE BTLE;
 bool UseLCDDisplay = false;
 bool UseOneWire = false;
 bool UseRadio = false;
 float currentTemperature = 20.0f;
 uint8_t state = 0;
+int nrf24_radio_channel, nrf24_radio_dev_address, nrf24_radio_hub_address;
 unsigned long btle_time = 0;
 
-static void Radio_Init()\r
-{\r
-    if (Radio.init())\r
-    {\r
-        Radio.setThisAddress(DEVICE_ADDRESS);\r
-        if (nrf24.setChannel(RADIO_CHANNEL))\r
-        {\r
-            UseRadio = true;\r
-            Serial.println(F("Radio initialized"));\r
-        }\r
-        else\r
-        {\r
-            Serial.println(F("Radio: failed to select channel"));\r
-        }\r
-    }\r
-    else\r
-    {\r
-        Serial.println(F("Radio initialization failed"));\r
-    }\r
-}\r
-\r
-static void Radio_End()\r
-{\r
-    \r
-}\r
-\r
-static void Radio_Send(uint8_t *data, uint8_t len)\r
-{\r
-    if (UseRadio)\r
-    {\r
-        nrf24.setModeTx();\r
-        if (!Radio.sendto(data, len, SENSOR_HUB_ADDRESS))\r
-        {\r
-            Serial.println(F("Radio: failed to send"));\r
-        }\r
-        //if (!nrf24.sleep())\r
-        //    Serial.println(F("Radio: failed to enter sleep mode"));\r
-    }\r
-}\r
-\r
-// Find any 1-wire sensors and use the first one. Trigger an async conversion.\r
-static void OneWire_Init()\r
-{\r
-    Serial.println(F("Initializing OneWire bus..."));\r
-    w1sensors.begin();\r
-    w1sensors.setResolution(12);\r
-    w1sensors.setWaitForConversion(false);\r
-    int count = w1sensors.getDeviceCount();\r
-    for (int n = 0; n < count; ++n)\r
-    {\r
-        if (w1sensors.getAddress(w1sensorAddress, n))\r
-        {\r
-            Serial.print(n);\r
-            Serial.print(F(": "));\r
-            PrintAddress(&Serial, w1sensorAddress);\r
-            Serial.println();\r
-            UseOneWire = true;\r
-            w1sensors.requestTemperatures();\r
-        }\r
-    }\r
-}\r
-\r
-static void PrintAddress(Print *stream, DeviceAddress address)\r
-{\r
-    for (int n = 0; n < 8; ++n)\r
-    {\r
-        if (address[n] < 16)\r
-        stream->print('0');\r
-        stream->print(address[n], HEX);\r
-    }\r
-}\r
-\r
-static void I2C_Init()\r
-{\r
-    for (uint8_t addr = 0; addr < 127; ++addr)\r
-    {\r
-        Wire.beginTransmission(addr);\r
-        uint8_t err = Wire.endTransmission();\r
-        if (err == 0)\r
-        {\r
-            Serial.print(F("# Found I2C device at 0x"));\r
-            if (addr < 16) Serial.print('0');\r
-            Serial.print(addr, HEX);\r
-            if (addr == 0x20) { Serial.print(F(" (LCD)")); UseLCDDisplay = true; }\r
-            if (addr == 0x22) { Serial.print(F(" (LED)")); /*UseLedDisplay = true;*/ }\r
-            if (addr == 0x57) { Serial.print(F(" (EEPROM)")); }\r
-            if (addr == 0x68) { Serial.print(F(" (RTC)")); /* UseRTC = true; */}\r
-            Serial.println();\r
-        }\r
-        else if (err == 4)\r
-        {\r
-            Serial.print(F("# Unknown error at address 0x"));\r
-            if (addr < 16) Serial.print('0');\r
-            Serial.print(addr, HEX);\r
-        }\r
-    }\r
-}\r
-\r
-static void LCD_Init()\r
-{\r
-    if (UseLCDDisplay)\r
-    {\r
-        lcd.begin(16, 2);\r
-        lcd.clear();\r
-        lcd.print(F("BTLE Beacon"));\r
-    }\r
-}\r
-\r
-volatile int analogValue;\r
-static void Analog_Init()\r
-{\r
-    analogValue = 0;\r
-    // REFS[1:0]: 0b00: AREF; 0b01: AVCC; 0b11: internal 1V1\r
-    // ADLAR = 0: do not enable left adjust\r
-    // MUX[3:0]: using pin A1 (0b0001)\r
-    ADMUX = _BV(MUX0) | _BV(REFS0);// Internal 5V\r
-    // ADEN: enable the ADC\r
-    // ADATE: enable auto trigger\r
-    // ADIE: adc interrupt enabled\r
-    // ADPS[2:0]: adc clock prescale 16MHz/128 so 125kHz\r
-    ADCSRA = _BV(ADEN) | _BV(ADATE) | _BV(ADIE)\r
-    | _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0);\r
-    // ADTS[2:0]: AutoTrigger Source: use free running mode\r
-    ADCSRB = 0;\r
-    // Disable the digital functions for pin A2\r
-    DIDR0 |= _BV(ADC2D);\r
-    // ADSC: start the freerunning conversion\r
-    //    if not freerunning we could alternate between a set of sources\r
-    //     like AD8 which is the internal temperature.\r
-    ADCSRA |= _BV(ADSC);\r
-}\r
-\r
-static int GetAnalogValue() { return analogValue; }\r
-static int GetAnalogMillivolts() { return (analogValue * 5120) / 1024; }\r
-\r
-static long GetHumidity()\r
-{\r
-    // Vref is externally provided and set to 5ishV.\r
-    long millivolts = (analogValue * 5120) / 1024;\r
-    // HU10 range is 1V == 0% to 3V == 100%.\r
-    long rh = ((millivolts - 1000) * 100000) / 2000;\r
-    return rh; /* value is percentage * 1000 */\r
+static void EEPROM_Init()
+{
+    uint8_t initialized = eeprom_read_byte(&ee_initialized);
+    if (initialized)
+    {
+        EEPROM.get((intptr_t)&ee_nrf_channel, nrf24_radio_channel);
+        EEPROM.get((intptr_t)&ee_nrf_dev_address, nrf24_radio_dev_address);
+        EEPROM.get((intptr_t)&ee_nrf_hub_address, nrf24_radio_hub_address);
+    }
+    else
+    {
+        nrf24_radio_channel = DEFAULT_RADIO_CHANNEL;
+        nrf24_radio_dev_address = DEFAULT_RADIO_DEV_ADDRESS;
+        nrf24_radio_hub_address = DEFAULT_RADIO_HUB_ADDRESS;
+    }
+}
+
+static void Radio_Init()
+{
+    if (Radio.init())
+    {
+        Radio.setThisAddress(nrf24_radio_dev_address);
+        if (nrf24.setChannel(nrf24_radio_channel))
+        {
+            UseRadio = true;
+            Serial.println(F("Radio initialized"));
+        }
+        else
+        {
+            Serial.println(F("Radio: failed to select channel"));
+        }
+    }
+    else
+    {
+        Serial.println(F("Radio initialization failed"));
+    }
+}
+
+static void Radio_End()
+{
+}
+
+static void Radio_Send(uint8_t *data, uint8_t len)
+{
+    if (UseRadio)
+    {
+        nrf24.setModeTx();
+        if (!Radio.sendto(data, len, nrf24_radio_hub_address))
+        {
+            Serial.println(F("Radio: failed to send"));
+        }
+    }
+}
+
+// Find any 1-wire sensors and use the first one. Trigger an async conversion.
+static void OneWire_Init()
+{
+    Serial.println(F("Initializing OneWire bus..."));
+    w1sensors.begin();
+    w1sensors.setResolution(12);
+    w1sensors.setWaitForConversion(false);
+    int count = w1sensors.getDeviceCount();
+    for (int n = 0; n < count; ++n)
+    {
+        if (w1sensors.getAddress(w1sensorAddress, n))
+        {
+            Serial.print(n);
+            Serial.print(F(": "));
+            PrintAddress(&Serial, w1sensorAddress);
+            Serial.println();
+            UseOneWire = true;
+            w1sensors.requestTemperatures();
+        }
+    }
+}
+
+static void PrintAddress(Print *stream, DeviceAddress address)
+{
+    for (int n = 0; n < 8; ++n)
+    {
+        if (address[n] < 16)
+        stream->print('0');
+        stream->print(address[n], HEX);
+    }
+}
+
+static void I2C_Init()
+{
+    for (uint8_t addr = 0; addr < 127; ++addr)
+    {
+        Wire.beginTransmission(addr);
+        uint8_t err = Wire.endTransmission();
+        if (err == 0)
+        {
+            Serial.print(F("# Found I2C device at 0x"));
+            if (addr < 16) Serial.print('0');
+            Serial.print(addr, HEX);
+            if (addr == 0x20) { Serial.print(F(" (LCD)")); UseLCDDisplay = true; }
+            if (addr == 0x22) { Serial.print(F(" (LED)")); /*UseLedDisplay = true;*/ }
+            if (addr == 0x57) { Serial.print(F(" (EEPROM)")); }
+            if (addr == 0x68) { Serial.print(F(" (RTC)")); /* UseRTC = true; */}
+            Serial.println();
+        }
+        else if (err == 4)
+        {
+            Serial.print(F("# Unknown error at address 0x"));
+            if (addr < 16) Serial.print('0');
+            Serial.print(addr, HEX);
+        }
+    }
+}
+
+static void LCD_Init()
+{
+    if (UseLCDDisplay)
+    {
+        lcd.begin(16, 2);
+        lcd.clear();
+        lcd.print(F("BTLE Beacon"));
+        lcd.setCursor(0, 1);
+        lcd.print(F("chan:"));
+        lcd.print(nrf24_radio_channel);
+        lcd.print(F(" id:"));
+        lcd.print(nrf24_radio_dev_address);
+    }
+}
+
+volatile int analogValue;
+static void Analog_Init()
+{
+    analogValue = 0;
+    // REFS[1:0]: 0b00: AREF; 0b01: AVCC; 0b11: internal 1V1
+    // ADLAR = 0: do not enable left adjust
+    // MUX[3:0]: using pin A1 (0b0001)
+    ADMUX = _BV(MUX0) | _BV(REFS0);// Internal 5V
+    // ADEN: enable the ADC
+    // ADATE: enable auto trigger
+    // ADIE: adc interrupt enabled
+    // ADPS[2:0]: adc clock prescale 16MHz/128 so 125kHz
+    ADCSRA = _BV(ADEN) | _BV(ADATE) | _BV(ADIE)
+    | _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0);
+    // ADTS[2:0]: AutoTrigger Source: use free running mode
+    ADCSRB = 0;
+    // Disable the digital functions for pin A2
+    DIDR0 |= _BV(ADC2D);
+    // ADSC: start the freerunning conversion
+    //    if not freerunning we could alternate between a set of sources
+    //     like AD8 which is the internal temperature.
+    ADCSRA |= _BV(ADSC);
+}
+
+static int GetAnalogValue() { return analogValue; }
+static int GetAnalogMillivolts() { return (analogValue * 5120) / 1024; }
+
+static long GetHumidity()
+{
+    // Vref is externally provided and set to 5ishV.
+    long millivolts = (analogValue * 5120) / 1024;
+    // HU10 range is 1V == 0% to 3V == 100%.
+    long rh = ((millivolts - 1000) * 100000) / 2000;
+    return rh; /* value is percentage * 1000 */
+}
+
+ISR(ADC_vect)
+{
+    // NOTE: MUST read the low byte first, reading ADCH resets.
+    analogValue = ADCL | (ADCH << 8);
+    // If not in free-running mode then start another conversion
+    // ADCSRA |= _BV(ADSC);
 }
-\r
-ISR(ADC_vect)\r
-{\r
-    // NOTE: MUST read the low byte first, reading ADCH resets.\r
-    analogValue = ADCL | (ADCH << 8);\r
-    // If not in free-running mode then start another conversion\r
-    // ADCSRA |= _BV(ADSC);\r
-}\r
 
 static void UpdateDisplay()
 {
     lcd.home();
-    lcd.print(currentTemperature);\r
-    lcd.print((char)0xdf);\r
+    lcd.print(currentTemperature);
+    lcd.print((char)0xdf);
     lcd.print("C ");
     lcd.print(static_cast<float>(GetHumidity())/1000.0f);
     lcd.print(" RH");
-    lcd.setCursor(0, 1);\r
-    lcd.print("BTLE Beacon: ");\r
+    lcd.setCursor(0, 1);
+    lcd.print("BTLE Beacon: ");
     lcd.print(btle_time);
     lcd.print("ms");
 }
@@ -225,6 +254,7 @@ static void Send_IoT()
 
 void setup()
 {
+    EEPROM_Init();
     Analog_Init();
     Wire.begin();
     SPI.begin();
@@ -256,16 +286,16 @@ void setup()
 void loop()
 {
     unsigned int channel_index;
-    uint8_t btle_packet[BTLE_BUFFER_SIZE];\r
+    uint8_t btle_packet[BTLE_BUFFER_SIZE];
     unsigned int btle_packet_len;
 
     unsigned long start = millis();
     btle_packet_len = BTLE.mkpacket(btle_packet, sizeof(btle_packet), currentTemperature);
-    for (unsigned int channel_index = 0; channel_index < BTLE_NUM_CHANNELS; ++channel_index)\r
-    {\r
-        BTLE.announce(channel_index, btle_packet, btle_packet_len);\r
-    }\r
-    btle_time = millis() - start;\r
+    for (unsigned int channel_index = 0; channel_index < BTLE_NUM_CHANNELS; ++channel_index)
+    {
+        BTLE.announce(channel_index, btle_packet, btle_packet_len);
+    }
+    btle_time = millis() - start;
 
     if (UseOneWire)
     {