From 2320f5c05ae9b60045c88897c38875eaa6181746 Mon Sep 17 00:00:00 2001 From: Pat Thoyts Date: Wed, 21 Oct 2015 15:32:39 +0100 Subject: [PATCH 1/1] IoT hub nRF24 receiver with a temperature sensor --- Radio_Clock_Receiver.ino | 372 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 372 insertions(+) create mode 100644 Radio_Clock_Receiver.ino diff --git a/Radio_Clock_Receiver.ino b/Radio_Clock_Receiver.ino new file mode 100644 index 0000000..47356e4 --- /dev/null +++ b/Radio_Clock_Receiver.ino @@ -0,0 +1,372 @@ +// Radio Transmitting Clock +// +// Circuit consists of an Arduino Nano with a DS13xx, NRF24L01+ board +// and I2C for connecting the LED display device. +// We have the I2C interface connected to a pair of mosfets to +// brodge to 3V3 signalling and a 78L33 device is putting 3V3 on the breadboard +// main power bus. The NRF24 board is 3V3 only. +// Added an LED with 330R to pin 6 for heartbeat. +#define F_CPU 20000000UL +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void I2C_Init(); +static void LCD_Init(); +static void RTC_Init(); +static void Radio_Init(); +static void DS18B20_Init(); +static void LedDisplay_Init(); +static void printAddress(DeviceAddress address); + +#define RADIO_CE_PIN 8 +#define RADIO_CHANNEL 85 +const uint8_t SENSOR_HUB_ADDRESS = 1; + +#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); + +OneWire W1Bus(4); // OneWire bus connected to pin 4. +DallasTemperature w1sensors(&W1Bus); +DeviceAddress w1address; +RH_NRF24 nrf24; +RHDatagram Radio(nrf24, SENSOR_HUB_ADDRESS); +DisplayI2C LedDisplay(0x22, 1); +RTC_DS1307 RTC; +MilliTimer HeartbeatTimer, DS18B20Timer, OutputTimer, TimingTimer; +LEDPulse Heartbeat(6); +DateTime CurrentTime; +float CurrentTemperature = 0.0f; +float SlaveTemperature = 0.0f; +uint8_t SlaveAddress = 0; +bool UseRadio = false; +bool UseDS18B20 = false; +bool UseRTC = false; +bool UseLCDDisplay = false; +bool UseLedDisplay = false; +bool LedDisplayUpdate = false; + +enum OutputState_t {Output_None, Output_A, Output_B, Output_C, + Output_D, Output_E, Output_F, Output_G, + Output_H, Output_I, Output_Temperature, + Output_RequestNext, Output_LCD}; +OutputState_t OutputState = Output_None; + +void setup() +{ + Wire.begin(); + Serial.begin(57600); + delay(400); + Serial.println(F("# NRF24 Clock Receiver")); + I2C_Init(); + LCD_Init(); + RTC_Init(); + Radio_Init(); + DS18B20_Init(); + LedDisplay_Init(); + pinMode(7, OUTPUT); digitalWrite(7, LOW); +} + +void loop() +{ + bool new_date = false; + if (LedDisplayUpdate) + { + LedDisplay.Update(); + LedDisplayUpdate = false; + } + if (HeartbeatTimer.poll(10)) + { + Heartbeat.Next(); + } + if (TimingTimer.poll(10)) + { + PORTD ^= _BV(7); + } + if (OutputState != Output_None) + { + Output(); + } + if (UseDS18B20 && DS18B20Timer.poll(1500)) + { + // read the temperature result from our chosen sensor. + CurrentTemperature = w1sensors.getTempC(w1address); + // trigger another conversion. + //w1sensors.requestTemperatures(); + } + if (UseRadio && Radio.available()) + { + uint8_t buffer[RH_NRF24_MAX_MESSAGE_LEN]; + uint8_t len = sizeof(buffer), client_addr, target_addr, id = 0, flags = 0; + if (Radio.recvfrom(buffer, &len, &client_addr, &target_addr, &id, &flags)) + { + SlaveAddress = client_addr; + SlaveTemperature = *(float *)buffer; + } + } + if (OutputTimer.poll(1000)) + { + OutputState = Output_A; + } +} + +static void Output() +{ + switch (OutputState) + { + case Output_A: + { + if (UseLedDisplay) + { + if (UseDS18B20) + { + LedDisplay.SetValue(CurrentTemperature * 100); + } + } + OutputState = Output_B; + break; + } + case Output_B: + { + if (CurrentTime.unixtime() == 0) + { + Serial.print(millis()/1000, DEC); + OutputState = Output_Temperature; + } + else + OutputState = Output_C; + break; + } + case Output_C: + { + Serial.print(CurrentTime.unixtime(), DEC); + Serial.print(' '); + OutputState = Output_D; + break; + } + case Output_D: + { + Serial.print(CurrentTime.day(), DEC); + Serial.print('/'); + OutputState = Output_E; + break; + } + case Output_E: + { + Serial.print(CurrentTime.month(), DEC); + Serial.print('/'); + OutputState = Output_F; + break; + } + case Output_F: + { + Serial.print(CurrentTime.year(), DEC); + Serial.print(' '); + OutputState = Output_G; + break; + } + case Output_G: + { + if (CurrentTime.hour() < 10) Serial.print('0'); + Serial.print(CurrentTime.hour(), DEC); + Serial.print(':'); + OutputState = Output_H; + break; + } + case Output_H: + { + if (CurrentTime.minute() < 10) Serial.print('0'); + Serial.print(CurrentTime.minute(), DEC); + Serial.print(':'); + OutputState = Output_I; + break; + } + case Output_I: + { + if (CurrentTime.second() < 10) Serial.print('0'); + Serial.print(CurrentTime.second(), DEC); + OutputState = Output_Temperature; + break; + } + case Output_Temperature: + { + Serial.print(' '); + Serial.print(CurrentTemperature); + if (SlaveTemperature != 0.0f) + { + Serial.print(F(" [")); + Serial.print(SlaveAddress, HEX); + Serial.print(' '); + Serial.print(SlaveTemperature); + Serial.print(']'); + } + Serial.println(); + OutputState = Output_RequestNext; + break; + } + case Output_RequestNext: + { + // trigger another conversion. + w1sensors.requestTemperatures(); + OutputState = Output_LCD; + break; + } + case Output_LCD: + { + if (UseLCDDisplay) + { + LCD.clear(); + LCD.print(CurrentTemperature); + if (UseRTC) + { + LCD.setCursor(0, 1); + DateTime now = RTC.now(); + PrintTimeOnStream(&LCD, now); + } + } + OutputState = Output_None; + break; + } + } +} + +static void Radio_Init() +{ + // defaults to channel 2, 2Mbps and 0dBm + if (Radio.init()) + { + nrf24.setChannel(RADIO_CHANNEL); + Radio.setThisAddress(SENSOR_HUB_ADDRESS); + UseRadio = true; + Serial.println(F("Radio initialized")); + } + else + { + Serial.println(F("Radio initialization failed")); + } +} + +static void DS18B20_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(w1address, n)) + { + Serial.print(n); + Serial.print(F(": ")); + printAddress(&Serial, w1address); + Serial.println(); + UseDS18B20 = 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); + } +} + +// print the time (HH:MM:SS) on a stream. +static void PrintTimeOnStream(Print *stream, DateTime now) +{ + if(now.hour() < 10) stream->print('0'); + stream->print(now.hour()); + stream->print(':'); + if(now.minute() < 10) stream->print('0'); + stream->print(now.minute()); + stream->print(':'); + if(now.second() < 10) stream->print('0'); + stream->print(now.second()); +} + +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("Radio Clock Recvr")); + LCD.setCursor(0,1); + LCD.print(F("v1.0")); + } +} + +static void RTC_Init() +{ + if (UseRTC) + { + RTC.begin(); + //RTC.adjust(DateTime(__DATE__, __TIME__)); + if (!RTC.isrunning()) + { + Serial.println(F("WARNING: RTC uninitialized")); + } + } +} + +static void LedDisplay_Init() +{ + if (UseLedDisplay) + { + DisplayI2C::SetupTimer2(); + LedDisplay.Setup(); + } +} + +ISR(TIMER2_OVF_vect) +{ + TCNT2 = DisplayI2C::TimerInterval; // reset the timer + LedDisplayUpdate = true; // set flag for loop function +} -- 2.23.0