It's working and allows me to send data via the rf24+ network he programmed (big thanks!). Most of the nodes run on battery (3V coin cell) so I need a way to monitor the battery. He suggest a voltage divider with 1M ohm and 470k Ohm + a capacitor, which I build into my pcb. Now I am trying to get correct voltage reading from the nodes, but all I get is fast changing numbers which cant be true. Only possible error I found is that I am using a digital pin as an input. I used a wire to an analog pin too though, and it did not seem to help. Is it possible to use the digital pin or do I have to change that?
Here ist my software (based on his examples):
/*
Copyright (C) 2012 James Coliz, Jr. <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
Update 2014 - TMRh20
*/
/**
* Simplest possible example of using RF24Network
*
* TRANSMITTER NODE
* Every 2 seconds, send a payload to the receiver node.
*/
#include <RF24Network.h>
#include <RF24.h>
#include <SPI.h>
RF24 radio(10,9); // nRF24L01(+) radio attached using Getting Started board
RF24Network network(radio); // Network uses that radio
const uint16_t this_node = 1; // Address of our node
const uint16_t other_node = 0; // Address of the other node
const unsigned long interval = 2000; //ms // How often to send 'hello world to the other unit
unsigned long last_sent; // When did we last send?
unsigned long packets_sent; // How many have we sent already
const unsigned voltage_reference = 3.3 * 256; // 3.3V
const int voltage_pin = 5;
struct payload_t { // Structure of our payload
unsigned long ms;
unsigned long voltage;
};
void setup(void)
{
Serial.begin(57600);
Serial.println("RF24Network/examples/helloworld_tx/");
// Sensors use the stable internal 1.1V voltage
#ifdef INTERNAL1V1
analogReference(INTERNAL1V1);
#else
analogReference(INTERNAL);
#endif
pinMode(voltage_pin, INPUT);
SPI.begin();
radio.begin();
network.begin(/*channel*/ 90, /*node address*/ this_node);
}
uint32_t measure_voltage()
{
// Take the voltage reading
// Convert the voltage reading to volts*256
return ( analogRead(voltage_pin) * voltage_reference );
}
void loop() {
network.update(); // Check the network regularly
unsigned long now = millis(); // If it's time to send a message, send it!
if ( now - last_sent >= interval )
{
last_sent = now;
Serial.print("Sending...");
payload_t payload = { millis(), measure_voltage() };
RF24NetworkHeader header(/*to node*/ other_node);
bool ok = network.write(header,&payload,sizeof(payload));
if (ok)
Serial.println("ok.");
else
Serial.println("failed.");
}
}
I played around with the voltage_reference part and changed it from 5v to 3.3 V (that what the coin cell gives me). I also added the analogReference(INTERNAL); part which I found online. I am somehow lost here because I dont even know if the error is software, hardware or me
Thanks alot, I knew I overlooked something. I just connected an analog pin and the old pin with a cable and I still get strange reading from the analog pin. Somewhat about 10000. What excactly has to be done with the values? Do you need the analogRead(voltage_pin) * voltage_reference part really? And what should this voltage_reference be? 5V? 3.3V?
Some help here would be awesome. And/or perhaps a good source where I find stuff like this.
I can calculate the dividing factor for my voltage divider but what value do I use here instead of the 5V? The 3.3 from the coin cell? Or still 5V because thats what the arduino is able to use?
I read through this and I feel like I understand it now. Still my programm isn't working. I only get 0.0 and 1.1 as an answer. Where's the error?
Sender (shortened)
...
const unsigned long interval = 1000;
unsigned long last_sent; // When did we last send?
unsigned long packets_sent; // How many have we sent already
const int voltage_pin = A0;
// number of analog samples to take per reading
#define NUM_SAMPLES 10
void setup(void)
{
Serial.begin(57600);
// Sensors use the stable internal 1.1V voltage
#ifdef INTERNAL1V1
analogReference(INTERNAL1V1);
#else
analogReference(INTERNAL);
#endif
SPI.begin();
radio.begin();
network.begin(/*channel*/ 90, /*node address*/ this_node);
}
float measure_voltage()
{
int sum = 0; // sum of samples taken
unsigned char sample_count = 0; // current sample number
float voltage = 0.0; // calculated voltage
while (sample_count < NUM_SAMPLES) {
sum += analogRead(voltage_pin);
sample_count++;
delay(10);
}
// calculate the voltage
voltage = ((float)sum / (float)NUM_SAMPLES * 1.1) / 1024.0;
// 1.1 volt is the internal reference
// the first part gets the average reading and 1024 is the possible resolution
//1.47 is the voltage divider factor (1M and 470k)
Serial.print(voltage * 1.47);
return voltage * 1.47;
Serial.println (" V");
}
void loop() {
network.update(); // Check the network regularly
unsigned long now = millis(); // If it's time to send a message, send it!
if ( now - last_sent >= interval )
{
last_sent = now;
Serial.print("Sending...");
unsigned long payload = measure_voltage();
RF24NetworkHeader header(/*to node*/ other_node);
bool ok = network.write(header,&payload,sizeof(payload));
if (ok)
Serial.println("ok.");
else
Serial.println("failed.");
}
}
The formular should be right as far as I can tell...
receiver:
...
void setup(void)
{
Serial.begin(57600);
SPI.begin();
radio.begin();
network.begin(/*channel*/ 90, /*node address*/ this_node);
}
void loop(void){
network.update(); // Check the network regularly
while ( network.available() ) { // Is there anything ready for us?
RF24NetworkHeader header; // If so, grab it and print it out
float payload;
network.read(header,&payload,sizeof(payload));
Serial.print("Received Voltage #");
Serial.println(payload);
}
}
The problem seems to be with the voltage reading. However, your program has a lot of extraneous junk that confuses you and me and everyone else. Start with the very simple Arduino IDE example program ReadAnalogVoltage and get that working to your satisfaction before you move on.
void setup() {
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
}
void loop() {
// read the input on analog pin 0:
int sensorValue = analogRead(A0);
// Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
float voltage = sensorValue * (5.0 / 1023.0);
// print out the value you read:
Serial.println(voltage);
}
Well it's only the communication stuff. But sure I'll try out an easier method. Thing is I have to add the "analogReference(INTERNAL);" part and use 1.1 instead of 5?! Or do I miss something here? Because this "arduino" is running on ~3V not on the normal 5.
Btw what's the best way for a serial connection to my test pcb? I could connect an arduino (rx & tx) but does that not change the outcome (cause of the 5V?)?
At this point you can remove everything and just use the analogread code posted above. Using the 1v1 internal voltage may give you better precision eventually but first get it running with just analogread. If your VCC isn't 5v then you need to switch the 5.0 in
float voltage = sensorValue * (5.0 / 1023.0);
to whatever your VCC is.
Are you sure your circuit is laid out as listed in that article? Is your voltage divider actually dividing? Confirmation with a multimeter would be useful
So, if you need more accurate measurements, you can :
More simple :
Set the reference to internal
With a voltmeter measure the voltage at the pin Aref : it is exactly the same that Vref
See datasheet, for Atmege 328P page 244 (last version Atmel-8271H-AVR 08 2014)
24.5.2 ADC Voltage Reference
The reference voltage for the ADC (VREF) indicates the conversion range for the ADC. Single ended channels that exceed VREF will result in codes close to 0x3FF. VREF can be selected as either AVCC, internal 1.1V reference, or external AREF pin. AVCC is connected to the ADC through a passive switch. The internal 1.1V reference is generated from the internal bandgap reference (VBG) through an internal amplifier. In either case, the external AREF pin is directly connected to the ADC, and the reference voltage can be made more immune to noise by connecting a capacitor between the AREF pin and ground. VREF can also be measured at the AREF pin with a high impedance voltmeter. Note that VREF is a high impedance source, and only a capacitive load should be connected in a system. If the user has a fixed voltage source connected to the AREF pin, the user may not use the other reference voltage options in the application, as they will be shorted to the external voltage. If no external voltage is applied to the AREF pin, the user may switch between AVCC and 1.1V as reference selection. The first ADC conversion
result after switching reference voltage source may be inaccurate, and the user is advised to discard this result.
???????
You don't need a serial monitor nor other things
When your ADC reference is set to INTERNAL, just measure the voltage between GND and Aref, it's all.
A voltage reference is sure the best but you have to wire extra components : voltage reference with decoupling capacitor and often a resistor. You can improve drasticaly your measurement by using my method without any extra component.
You just have a multimeter but this unit is mandatory with our activity and a model which coast less than 10$ is sufficient .
Thanks again guys! With your help I got it to work and already build in the energy saving features I needed. Now I have a wierd (hopefully) last problem. Everything works fine while I send messages from node 1 to node 0. Now I wanted to start sending from 11 to 1 to 0 and I can't get this to work. I know these adresses are octal but afaik 0 - 01 - 011 - ... should be the right values?!
Or am I wrong here? Is there another setting you need?
(still using maniacbugs RF24Network) here is my sender code. I am only changing const uint16_t this_node = 01; // Address of our node to 011 on the second platform.
/*
Copyright (C) 2012 James Coliz, Jr. <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
Update 2014 - TMRh20
*/
/**
* Simplest possible example of using RF24Network
*
* TRANSMITTER NODE
* Every 2 seconds, send a payload to the receiver node.
*/
#include <RF24Network.h>
#include <RF24.h>
#include <SPI.h>
#include <LowPower.h>
RF24 radio(10,9); // nRF24L01(+) radio attached using Getting Started board
RF24Network network(radio); // Network uses that radio
const uint16_t channel = 90; // Channel we use
const uint16_t this_node = 01; // Address of our node
const uint16_t other_node = 0; // Address of the other node
const unsigned long interval = 1000; //ms // How often to send 'hello world to the other unit
unsigned long last_sent; // When did we last send?
unsigned long packets_sent; // How many have we sent already
const int voltage_pin = A0;
const float voltage_reference = 1.1;
const float voltage_divider_factor = 3.13;
// number of analog samples to take per reading
#define NUM_SAMPLES 10
void setup(void)
{
// Sensors use the stable internal 1.1V voltage
#ifdef INTERNAL1V1
analogReference(INTERNAL1V1);
#else
analogReference(INTERNAL);
#endif
SPI.begin();
radio.begin();
network.begin(/*channel*/ channel, /*node address*/ this_node);
radio.setDataRate(RF24_250KBPS);
}
float measure_voltage()
{
int sum = 0; // sum of samples taken
unsigned char sample_count = 0; // current sample number
while (sample_count < NUM_SAMPLES) {
sum += analogRead(voltage_pin);
sample_count++;
delay(10);
}
// average value
int raw = sum / NUM_SAMPLES;
// value at pin (1024 = possible resolution of the atmega328P
float voltage_at_pin = (voltage_reference / 1024) * raw;
float real_voltage = voltage_at_pin * voltage_divider_factor;
return real_voltage;
}
void loop() {
network.update(); // Check the network regularly
if (millis() - last_sent > interval) {
last_sent = millis();
float voltage = measure_voltage();
radio.powerUp();
RF24NetworkHeader header(/*to node*/ other_node);
bool ok = network.write(header,&voltage,sizeof(voltage));
radio.powerDown();
}
//LowPower.powerDown(SLEEP_1S, ADC_OFF, BOD_OFF);
}