Hi,
I finally managed to spend some time again on my little project but I am stuck now, after mane many hours.
The default sketch that came installed on my EmonTx v3 does send a temperature value if a sensor is connected to the terminal block. I tried to add another one and it worked fine, modified my sketch and payload and all is good, no problem(with that).
Now I have these two problems:
1) I am trying to read and print the sensor address. I have found a lot of examples but even though my sensors are connected and working, this sensors.getAddress(tempDeviceAddress, 0) always returns FALSE and then just prints that a Ghost device was found(taken from a common example). Although I probably don't really need the address I just want it to hardcode my sensors, given that they are deterministic it is probably not really required, but still, I want it. :)
2) Connecting a 1m wire to a bread board containing my test DS18B20 sensor works fine at startup. As soon as a just push in another much longer wire(60m) into the breadboard without or without a sensor on the other end(I tried both), then my original sensor seem to die and my temp reading goes to 0. I saw some schemetics that suggest a 4K7 resistor across Vdd and Data, but then I found on the OEM Wiki that a 4k7 is already on the board, pre-installed. I even tried a 100Ohm on the data pin before it goes to the wire same problem. My cable is not twister-pair or shielded.
Would really appreciate some expert help here, I am at my wits end with this, I know it is something basic, but I am just missing it.
I spent a lot of time on this example: http://openenergymonitor.org/emon/buildingblocks/DS18B20-temperature-sensing and that didn't help me either.....
Here is my very very very messy sketch:
***************************************************************************************
/*
emonTxV3 Discrete Sampling
If AC-AC adapter is detected assume emonTx is also powered from adapter (jumper shorted) and take Real Power Readings and disable sleep mode to keep load on power supply constant
If AC-AC addapter is not detected assume powering from battereis / USB 5V AC sample is not present so take Apparent Power Readings and enable sleep mode
Transmitt values via RFM12B radio
-----------------------------------------
Part of the openenergymonitor.org project
Authors: Glyn Hudson & Trystan Lea
Builds upon JCW JeeLabs RF12 library and Arduino
Licence: GNU GPL V3
*/
/*Recommended node ID allocation
------------------------------------------------------------------------------------------------------------
-ID- -Node Type-
0 - Special allocation in JeeLib RFM12 driver - reserved for OOK use
1-4 - Control nodes
5-10 - Energy monitoring nodes
11-14 --Un-assigned --
15-16 - Base Station & logging nodes
17-30 - Environmental sensing nodes (temperature humidity etc.)
31 - Special allocation in JeeLib RFM12 driver - Node31 can communicate with nodes on any network group
-------------------------------------------------------------------------------------------------------------
Change Log:
V1.3 - fix filter settle time to eliminate large inital reading
V1.2 - fix bug which caused Vrms to be returned as zero if CT1 was not connected
V1.1 - fix bug in startup Vrms calculation, startup Vrms startup calculation is now more accuratre
*/
#define emonTxV3 // Tell emonLib this is the emonTx V3 - don't read Vcc assume Vcc = 3.3V as is always the case on emonTx V3 eliminates bandgap error and need for calibration http://harizanov.com/2013/09/thoughts-on-avr-adc-accuracy/
#include <RFu_JeeLib.h> // Special modified version of the JeeJib library to work with the RFu328 https://github.com/openenergymonitor/RFu_jeelib
ISR(WDT_vect) { Sleepy::watchdogEvent(); } // Attached JeeLib sleep function to Atmega328 watchdog -enables MCU to be put into sleep mode inbetween readings to reduce power consumption
#include "EmonLib.h" // Include EmonLib energy monitoring library https://github.com/openenergymonitor/EmonLib
EnergyMonitor ct1, ct2, ct3, ct4;
#include <OneWire.h> //http://www.pjrc.com/teensy/td_libs_OneWire.html
#include <DallasTemperature.h> //http://download.milesburton.com/Arduino/MaximTemperature/DallasTemperature_LATEST.zip
//----------------------------emonTx V3 Settings---------------------------------------------------------------------------------------------------------------
const byte Vrms= 230; // Vrms for apparent power readings (when no AC-AC voltage sample is present)
const byte TIME_BETWEEN_READINGS= 10; //Time between readings
const float Ical1= 90.9; // (2000 turns / 22 Ohm burden) = 90.9
const float Ical2= 90.9; // (2000 turns / 22 Ohm burden) = 90.9
const float Ical3= 90.9; // (2000 turns / 22 Ohm burden) = 90.9
const float Ical4= 16.6; // (2000 turns / 120 Ohm burden) = 16.6
const float Vcal= 276.9; // (230V x 13) / (9V x 1.2) = 276.9
const float phase_shift= 1.7;
const int no_of_samples= 1480;
const int no_of_half_wavelengths= 20;
const int timeout= 2000; //emonLib timeout
const int ACAC_DETECTION_LEVEL= 3000;
const int TEMPERATURE_PRECISION= 11; //9 (93.8ms),10 (187.5ms) ,11 (375ms) or 12 (750ms) bits equal to resplution of 0.5C, 0.25C, 0.125C and 0.0625C
//#define FILTERSETTLETIME 25000 // Time (ms) to allow the filters to settle before sending data
#define ASYNC_DELAY 375 // DS18B20 conversion delay - 9bit requres 95ms, 10bit 187ms, 11bit 375ms and 12bit resolution takes 750ms
//-------------------------------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------------------------------
//----------------------------emonTx V3 hard-wired connections---------------------------------------------------------------------------------------------------------------
const byte LEDpin= 6; // emonTx V3 LED
const byte DS18B20_PWR= 19; // DS18B20 Power
#define ONE_WIRE_BUS 5 // DS18B20 Data
//-------------------------------------------------------------------------------------------------------------------------------------------
//Setup DS128B20
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
DeviceAddress tempDeviceAddress; // We'll use this variable to store a found device address
//-------------------------------------------------------------------------------------------------------------------------------------------
//-----------------------RFM12B SETTINGS----------------------------------------------------------------------------------------------------
#define RF_freq RF12_433MHZ // Frequency of RF12B module can be RF12_433MHZ, RF12_868MHZ or RF12_915MHZ. You should use the one matching the module you have.
const int nodeID = 10; // emonTx RFM12B node ID
const int networkGroup = 210;
typedef struct { int power1, power2, power3, power4, Vrms, temp0; } PayloadTX; // create structure - a neat way of packaging data for RF comms
PayloadTX emontx;
//-------------------------------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------------------------------
//Random Variables
//boolean settled = false;
boolean CT1, CT2, CT3, CT4, ACAC, debug, DS18B20_STATUS;
byte CT_count=0;
int numSensors;
//addresses of sensors, MAX 4!!
byte allAddress [4][8]; // 8 bytes per address
DeviceAddress deviceAddress;
void setup()
{
pinMode(LEDpin, OUTPUT);
pinMode(DS18B20_PWR, OUTPUT);
digitalWrite(LEDpin,HIGH);
Serial.begin(9600);
Serial.println("emonTx V3 Discrete Sampling V1.3");
Serial.println("OpenEnergyMonitor.org");
Serial.println("Performing power-on tests.....please wait 10s");
Serial.println("Werners custom SKETCH");
delay(10);
rf12_initialize(nodeID, RF_freq, networkGroup); // initialize RFM12B
for (int i=10; i>=0; i--) //Send RFM12B test sequence (for factory testing)
{
emontx.power1=i;
rf12_sendNow(0, &emontx, sizeof emontx);
delay(100);
}
rf12_sendWait(2);
emontx.power1=0;
rf12_sleep(RF12_SLEEP);
if (analogRead(1) > 0) {CT1 = 1; CT_count++;} else CT1=0; // check to see if CT is connected to CT1 input, if so enable that channel
if (analogRead(2) > 0) {CT2 = 1; CT_count++;} else CT2=0; // check to see if CT is connected to CT2 input, if so enable that channel
if (analogRead(3) > 0) {CT3 = 1; CT_count++;} else CT3=0; // check to see if CT is connected to CT3 input, if so enable that channel
if (analogRead(4) > 0) {CT4 = 1; CT_count++;} else CT4=0; // check to see if CT is connected to CT4 input, if so enable that channel
if ( CT_count == 0) CT1=1; // If no CT's are connect ed CT1-4 then by default read from CT1
// Quick check to see if there is a voltage waveform present on the ACAC Voltage input
// Check consists of calculating the RMS from 100 samples of the voltage input.
Sleepy::loseSomeTime(10000); //wait for settle
digitalWrite(LEDpin,LOW);
// Calculate if there is an ACAC adapter on analog input 0
//double vrms = calc_rms(0,1780) * (Vcal * (3.3/1024) );
double vrms = calc_rms(0,1780) * 0.87;
if (vrms>90) ACAC = 1; else ACAC=0;
if (ACAC)
{
for (int i=0; i<10; i++) // indicate AC has been detected by flashing LED 10 times
{
digitalWrite(LEDpin, HIGH); delay(200);
digitalWrite(LEDpin, LOW); delay(300);
}
}
else
{
delay(1000);
digitalWrite(LEDpin, HIGH); delay(2000); digitalWrite(LEDpin, LOW); // indicate DC power has been detected by turing LED on then off
}
//################################################################################################################################
//Setup and for presence of DS18B20
//################################################################################################################################
digitalWrite(DS18B20_PWR, HIGH); delay(50);
sensors.begin();
sensors.setWaitForConversion(false); //disable automatic temperature conversion to reduce time spent awake, conversion will be implemented manually in sleeping http://harizanov.com/2013/07/optimizing-ds18b20-code-for-low-power-appli...
numSensors=(sensors.getDeviceCount());
byte j=0; // search for one wire devices and
// copy to device address arrays.
while ((j < numSensors) && (oneWire.search(allAddress[j]))) j++;
digitalWrite(DS18B20_PWR, LOW);
if (numSensors==0) DS18B20_STATUS=0;
else DS18B20_STATUS=1;
Serial.print("DS18B20_STATUS ="); Serial.println(DS18B20_STATUS);
//################################################################################################################################
if (Serial) debug = 1; else debug=0; //if serial UART to USB is connected show debug O/P. If not then disable serial
if (debug==1)
{
Serial.print("CT 1 Calibration: "); Serial.println(Ical1);
Serial.print("CT 2 Calibration: "); Serial.println(Ical2);
Serial.print("CT 3 Calibration: "); Serial.println(Ical3);
Serial.print("CT 4 Calibration: "); Serial.println(Ical4);
delay(1000);
Serial.print("RMS Voltage on AC-AC Adapter input is: ~");
Serial.print(vrms,0); Serial.println("V");
if (ACAC)
{
Serial.println("AC-AC adapter detected - Real Power measurements enabled");
Serial.println("assuming powering from AC-AC adapter (jumper closed)");
Serial.print("Vcal: "); Serial.println(Vcal);
Serial.print("Phase Shift: "); Serial.println(phase_shift);
}
else
{
Serial.println("AC-AC adapter NOT detected - Apparent Power measurements enabled");
Serial.print("Assuming VRMS to be "); Serial.print(Vrms); Serial.println("V");
Serial.println("Assuming powering from batteries / 5V USB - power saving mode enabled");
}
if (CT_count==0) Serial.println("NO CT's detected, sampling from CT1 by default");
else
{
if (CT1) Serial.println("CT 1 detected");
if (CT2) Serial.println("CT 2 detected");
if (CT3) Serial.println("CT 3 detected");
if (CT4) Serial.println("CT 4 detected");
}
if (DS18B20_STATUS==1) {Serial.print("Detected "); Serial.print(numSensors); Serial.println(" DS18B20..using this for temperature reading");}
else Serial.println("Unable to detect DS18B20 temperature sensor");
// report parasite power requirements
Serial.print("Parasite power is: ");
if (sensors.isParasitePowerMode()) Serial.println("ON");
else Serial.println("OFF");
// Loop through each device, print out address
for(int i=0;i<numSensors; i++)
{
Serial.print("Searching for device # ="); Serial.println(i);
// Search the wire for address
if(sensors.getAddress(tempDeviceAddress, i))
{
Serial.print("Found device ");
Serial.print(i, DEC);
Serial.print(" with address: ");
for (uint8_t i = 0; i < 8; i++)
{
if (deviceAddress[i] < 16) Serial.print("0");
Serial.print(deviceAddress[i], HEX);
}
// printAddress(tempDeviceAddress);
Serial.println();
Serial.print("Setting resolution to ");
Serial.println(TEMPERATURE_PRECISION,DEC);
delay(100);
// set the resolution to 9 bit (Each Dallas/Maxim device is capable of several different resolutions)
sensors.setResolution(tempDeviceAddress, TEMPERATURE_PRECISION);
Serial.print("Resolution actually set to: ");
Serial.print(sensors.getResolution(tempDeviceAddress), DEC);
Serial.println();
}else{
Serial.print("Found ghost device at ");
Serial.print(i, DEC);
Serial.println(" but could not detect address. Check power and cabling");
}
}
Serial.println("RFM12B Initiated: ");
Serial.print("Node: "); Serial.print(nodeID);
Serial.print(" Freq: ");
if (RF_freq == RF12_433MHZ) Serial.print("433Mhz");
if (RF_freq == RF12_868MHZ) Serial.print("868Mhz");
if (RF_freq == RF12_915MHZ) Serial.print("915Mhz");
Serial.print(" Network: "); Serial.println(networkGroup);
delay(500);
}
else
Serial.end();
if (CT1) ct1.current(1, Ical1); // CT ADC channel 1, calibration. calibration (2000 turns / 22 Ohm burden resistor = 90.909)
if (CT2) ct2.current(2, Ical2); // CT ADC channel 2, calibration.
if (CT3) ct3.current(3, Ical3); // CT ADC channel 3, calibration.
//CT 3 is high accuracy @ low power - 4.5kW Max @ 240V
if (CT4) ct4.current(4, Ical4); // CT channel ADC 4, calibration. calibration (2000 turns / 120 Ohm burden resistor = 16.66)
if (ACAC)
{
if (CT1) ct1.voltage(0, Vcal, phase_shift); // ADC pin, Calibration, phase_shift
if (CT2) ct2.voltage(0, Vcal, phase_shift); // ADC pin, Calibration, phase_shift
if (CT3) ct3.voltage(0, Vcal, phase_shift); // ADC pin, Calibration, phase_shift
if (CT4) ct4.voltage(0, Vcal, phase_shift); // ADC pin, Calibration, phase_shift
}
// Do some measurements to allow the software filter to settle - don't use the result
if (ACAC)
{
if (CT1) for (int j=0; j<5; j++) ct1.calcVI(no_of_half_wavelengths,timeout);
if (CT2) for (int j=0; j<5; j++) ct2.calcVI(no_of_half_wavelengths,timeout);
if (CT3) for (int j=0; j<5; j++) ct3.calcVI(no_of_half_wavelengths,timeout);
if (CT4) for (int j=0; j<5; j++) ct4.calcVI(no_of_half_wavelengths,timeout);
}
else
{
if (CT1) for (int j=0; j<5; j++) ct1.calcIrms(no_of_samples);
if (CT2) for (int j=0; j<5; j++) ct2.calcIrms(no_of_samples);
if (CT3) for (int j=0; j<5; j++) ct3.calcIrms(no_of_samples);
if (CT4) for (int j=0; j<5; j++) ct4.calcIrms(no_of_samples);
}
}
void loop()
{
if (ACAC) {
delay(200); //if powering from AC-AC allow time for power supply to settle
emontx.Vrms=0; //Set Vrms to zero, this will be overwirtten by wither CT 1-4
}
if (CT1)
{
if (ACAC)
{
ct1.calcVI(no_of_half_wavelengths,timeout); emontx.power1=ct1.realPower;
emontx.Vrms=ct1.Vrms*100;
}
else
emontx.power1 = ct1.calcIrms(no_of_samples)*Vrms; // Calculate Apparent Power 1 1480 is number of samples
if (debug==1) {Serial.print(emontx.power1); Serial.print(" ");}
}
if (CT2)
{
if (ACAC)
{
ct2.calcVI(no_of_half_wavelengths,timeout); emontx.power2=ct2.realPower;
emontx.Vrms=ct2.Vrms*100;
}
else
emontx.power2 = ct2.calcIrms(no_of_samples)*Vrms; // Calculate Apparent Power 1 1480 is number of samples
if (debug==1) {Serial.print(emontx.power2); Serial.print(" ");}
}
if (CT3)
{
if (ACAC)
{
ct3.calcVI(no_of_half_wavelengths,timeout); emontx.power3=ct3.realPower;
emontx.Vrms=ct3.Vrms*100;
}
else
emontx.power3 = ct3.calcIrms(no_of_samples)*Vrms; // Calculate Apparent Power 1 1480 is number of samples
if (debug==1) {Serial.print(emontx.power3); Serial.print(" ");}
}
if (CT4)
{
if (ACAC)
{
ct4.calcVI(no_of_half_wavelengths,timeout); emontx.power4=ct4.realPower;
emontx.Vrms=ct4.Vrms*100;
}
else
emontx.power4 = ct4.calcIrms(no_of_samples)*Vrms; // Calculate Apparent Power 1 1480 is number of samples
if (debug==1) {Serial.print(emontx.power4); Serial.print(" ");}
}
if (ACAC)
{
if ((debug==1) && (!CT_count==0)) Serial.print(emontx.Vrms);
}
if ((debug==1) && (!CT_count==0)) {Serial.println(); delay(20);}
// because millis() returns to zero after 50 days !
//if (!settled && millis() > FILTERSETTLETIME) settled = true; - replaced by filter settle routine at end of setup
if (DS18B20_STATUS==1)
{
digitalWrite(DS18B20_PWR, HIGH); Sleepy::loseSomeTime(50);
for(int j=0;j<numSensors;j++) sensors.setResolution(allAddress[j], TEMPERATURE_PRECISION); // and set the a to d conversion resolution of each.
sensors.requestTemperatures(); // Send the command to get temperatures
Sleepy::loseSomeTime(ASYNC_DELAY); //Must wait for conversion, since we use ASYNC mode
float temp0=(sensors.getTempC(allAddress[0]));
//float temp1=(sensors.getTempC(allAddress[1]));
digitalWrite(DS18B20_PWR, LOW);
if ((temp0<125.0) && (temp0>-40.0)) emontx.temp0=(temp0*10); //if reading is within range for the sensor convert float to int ready to send via RF
// if ((temp1<125.0) && (temp1>-40.0)) emontx.temp1=(temp1*10);
if (debug==1) {Serial.print("temperature0: "); Serial.println(emontx.temp0*0.1); delay(20);}
// if (debug==1) {Serial.print("temperature1: "); Serial.println(emontx.temp1*0.1); delay(20);}
if (debug==1) {Serial.println("DONE with this pass"); delay(20);}
}
// if (settled) // send data only after filters have settled
//{
send_rf_data(); // *SEND RF DATA* - see emontx_lib
if (ACAC)
{
delay(TIME_BETWEEN_READINGS*1000);
digitalWrite(LEDpin, HIGH); delay(200); digitalWrite(LEDpin, LOW); // flash LED - turn off to save power
}
else
emontx_sleep(TIME_BETWEEN_READINGS); // sleep or delay in seconds
// }
}
void send_rf_data()
{
rf12_sleep(RF12_WAKEUP);
rf12_sendNow(0, &emontx, sizeof emontx); //send temperature data via RFM12B using new rf12_sendNow wrapper
rf12_sendWait(2);
rf12_sleep(RF12_SLEEP);
}
void emontx_sleep(int seconds) {
Sleepy::loseSomeTime(seconds*1000);
}
double calc_rms(int pin, int samples)
{
unsigned long sum = 0;
for (int i=0; i<samples; i++) // 178 samples takes about 20ms
{
int raw = (analogRead(0)-512);
sum += (unsigned long)raw * raw;
}
double rms = sqrt((double)sum / samples);
return rms;
}
// function to print a device address
//void printAddress(DeviceAddress deviceAddress)
//{
// for (uint8_t i = 0; i < 8; i++)
// {
// if (deviceAddress[i] < 16) Serial.print("0");
// Serial.print(deviceAddress[i], HEX);
// }
//}
***************************************************************************************
Re: Unable to detect DS18B20 sensor addresses and long one-wire radius problem
I don't think we know very much that is not in the Building Blocks page "DS18B20 temperature sensing". You'll find a link to a sketch to get the addresses of the sensors, but remember, all that was written for the emonTx V2, so you will need to make some small changes to suit the V3. Have you checked out the driver IC for long cable runs? - the problem there is you are most probably getting reflections because the cable is acting as a transmission line that does not have the proper terminating impedances, so the data is going backwards and forwards and interfering with itself. The idea of the resistor is to try to alleviate that problem, the driver IC should do a better job. Maxim's "Guidelines" app. note seems to infer 150 m should be possible.
As far as I know, nobody has tried to use the DS18B20 over a distance of 60 m, but we have had success reported at 30 m. If you still have no success, you might like to consider using a separate emonTH instead of the cable.
Re: Unable to detect DS18B20 sensor addresses and long one-wire radius problem
Thanks for your Reply Robert.
I managed to solve problem 1 by doing the following:
There are still some options to make it neater, but for now this works fine. Anycase, this will only be required initially when you add new sensors.
ito Problem 2: I also thought the problem is related to reflections and spent a lot of time on researching resistor options to see if it will solve it, but to no avail. A lot of the Arduino pages suggest that long cable runs/one-wire radius are possible. I'll try twisted CAT5 cable to see how that goes. If I go a 2nd EmonTH I will have different transmission issues as my hot water tanks are solar powered and on my roof. I was hoping to run a single cable and plug in a number or TempSensors for various measurements. What do you mean when you say
Are you referring to the DS18B20?
Thanks
Re: Unable to detect DS18B20 sensor addresses and long one-wire radius problem
Quote from the page you said you had studied for a long time:
"Notes and further reading
For large numbers of sensors and long cable runs use the DS2480B 1-wire driver chip. More info here."
On Maxim's website, you will find some Application Notes that might help you.
Re: Unable to detect DS18B20 sensor addresses and long one-wire radius problem
Hi, so after 6 weeks I managed to get some more time to play with this prolem of mine(I blame wife, work and kids)
I am still not able to use the built in 1-wire connections on the Tx3 to get a single ds18b20 temp sensor to work over a 60m cable(tried a few cables incl cat5e).
After reading up a bit more on the option as documented on the Wiki and pointed out by Robert Wall I came to the conclusion that the DS2480 driver chip will require it's own serial connections on whatever board you use it(TX3 or R-Pi or Arduino etc). Currently in my setup the Tx3 is transmitting wirelessly to my R-Pi which has the RFM12pi shield plugged in. So using my R-Pi's serial connection is not an option.
QUESTION: Would you suggest that my best course of action is to use the Tx3's but then will have to unplug and reconnect various connections during development phase while I upload sketches with the programmer etc.?
I could always just have a 2nd R-Pi that drive just my 1-wire network?
Re: Unable to detect DS18B20 sensor addresses and long one-wire radius problem
What does your temperature sensor network look like? From what you wrote earlier, you have many sensors close to each other, but then a long cable run to your RPi. If I'm correct, then either a second RPi (presumably you'd use Ethernet and the Cat5e that you tested with to get the data back) or a second emonTx, without the driver IC, might be the easier option.
I can well understand that development of the software for the DS 2480 would be hard without a second serial port, and that's the main reason for suggesting the RPi / second emonTx solution.
Re: Unable to detect DS18B20 sensor addresses and long one-wire radius problem
Thanks Robert. Correct, all my sensors are between 40 and 60m from my "server room", so a 2nd Pi with a cat5 cable might be the only option. I'll have to run a 2nd cable for power though, unless I manage to keep my 2nd Pi in my "server room" and just hook the sensors on the cable at the far end. Assuming I have no long cable run issues on the Pi and DS2480 driver.
Will post back here when I eventually manage to solve it.
Thanks for your quick replies.