From 5098a49f2ab9ccfcfc37eeaa1879db284af281d6 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Wed, 21 Oct 2015 12:32:15 +0100 Subject: [PATCH] Added support for EEPROM stored configuration values. The radio addresses and channel can be placed in EEPROM now. --- nRF24_BLE_Temperature.ino | 406 ++++++++++++++++++++------------------ 1 file changed, 218 insertions(+), 188 deletions(-) diff --git a/nRF24_BLE_Temperature.ino b/nRF24_BLE_Temperature.ino index 88e6b8b..57e6ce3 100644 --- a/nRF24_BLE_Temperature.ino +++ b/nRF24_BLE_Temperature.ino @@ -1,214 +1,243 @@ #include #include #include +#include #include #include -#include -#include -#include -#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 PrintAddress(Print *stream, DeviceAddress address); - -#define RADIO_CE_PIN 8 -#define RADIO_CHANNEL 85 +#include +#include +#include +#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 - -#define SENSOR_HUB_ADDRESS 1 -#define DEVICE_ADDRESS 2 - -#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, + +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); -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() -{ - if (Radio.init()) - { - Radio.setThisAddress(DEVICE_ADDRESS); - if (nrf24.setChannel(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, SENSOR_HUB_ADDRESS)) - { - Serial.println(F("Radio: failed to send")); - } - //if (!nrf24.sleep()) - // Serial.println(F("Radio: failed to enter sleep mode")); - } -} - -// 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")); - } -} - -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 */ +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); } - -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); -} static void UpdateDisplay() { lcd.home(); - lcd.print(currentTemperature); - lcd.print((char)0xdf); + lcd.print(currentTemperature); + lcd.print((char)0xdf); lcd.print("C "); lcd.print(static_cast(GetHumidity())/1000.0f); lcd.print(" RH"); - lcd.setCursor(0, 1); - lcd.print("BTLE Beacon: "); + 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]; + 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) - { - BTLE.announce(channel_index, btle_packet, btle_packet_len); - } - btle_time = millis() - start; + 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) { -- 2.23.0