Hello, Masters! I was wondering if you could help me out on my new project
I want to display the rms current sent by another controller wirelessly.
Here's the parts I'm using:
2 - Arduino UNO
2 - Xbee Shield
2 - XBee S2B ZigBee PRO 10mW Wire antenna
I configured the first arduino to be the Zigbee Coordinator API and the other the Zigbee Router AT using XCTU New Gen Software. I also enabled the Router's Channel Verification.
I used dragonrobo7's code [I found [here](Monitoring AC Current with Arduino and ACS712 - Sensors - Arduino Forum)] for the 5A-ACS712 current sensor. It works perfectly, but when I tried separating the calculation(Router Xbee) and the display(Coordinator Xbee) it becomes unstable. It even gives zero values which doesn't happen when I use a single controller.
float val = Serial.println(readCurrent(currentPin), 3);
Serial.println() returns the number of characters written to the serial port. Do you really expect that the function wrote 3.14159 characters to the serial port? Is there a snowball's chance in hell that the number is other than an integer value?
Which XBee shields are you using? Getting the XBee off the hardware serial port would be #1 priority, so I could see what the problem was. Is the problem with reading the sensor? Is it with the calculations? Is it with the transmission?
How far apart are the XBees?
float current = Serial.read();
Serial.println(current);
You sent the data as a string. How can you expect to read the whole value by reading one character? Have you bothered to look at what Serial.read() returns? It is NOT a float!
Why are you NOT reading the data the way it was sent?
Edit You can't just write a float to serial and then read the float out in the receiver The Serial.read will just be reading 1 character from the serial port, regardless of whether there is any incomming data or not.
Sorry, I don't really know what I'm doing.
I watched 'Xbee Basics' tutorial lesson 1-4 by tunnelsup. I used the code from lesson 4: Reading analog data from remote xbee. Everything seems to be working properly but then I remembered I need to read the sensor value from an xbee with a micro controller. I think I panicked realizing my mistake and thinking about the rms current so I watched another video that uses 2 arduino and 2 xbee and I ended up doing 'that' code.
I just need to know the sender and receiver code if I'll be using 2 arduino's with xbee.
If you could help me, I would be so happy.
Maybe like this?
Sender:
int sensorPin = 14;
float val;
void setup(){
Serial.begin(9600);
}
void loop(){
val = analogRead(sensorPin);
Serial.print(val); //How to send this as byte?
}
Receiver:
float val;
void setup(){
Serial.begin(9600);
}
void loop(){
if(Serial.available() >= 21){
if(Serial.read() == 0x7E){
for(int i = 1; i < 19; i++){
byte discardByte = Serial.read();
}
int analogMSB = Serial.read();
int analogLSB = Serial.read();
int analogReading = analogLSB + (analogMSB * 256);
//Is val the value read by the sensor or do I need to divide it by 1023 like the original code?
val = analogReading;
Serial.print(val);
}
}
}
I found a code for tranmitter/receiver arduino-xbee here --> Redirecting... but it send an integer instead of float. Could you help me convert it and shorten the code?
I used this for the
Transmitter:
/*
Adapted from the "XBee Analog Duplex Transmission" example in "Making
Things Talk", O'Reilly, First Edition, Sep-2007. See pages 193-206.
This sketch configures an XBee radio via the serial port,
reads the voltage value on analog pin 0 (PC0) and transmits
an ASCII string corresponding to the measured voltage.
(* jcl *)
*/
#define SENSOR_PIN 0 // input sensor
#define THRESHOLD 1 // how much change you need to see on
// the sensor before sending
int lastSensorReading = 0; // previous state of the switch
void setup() {
Serial.begin(9600);
set_xbee_destination_address();
}
void set_xbee_destination_address() {
long count = 0;
// put the radio in command mode:
Serial.print("+++");
// wait for the radio to respond with "OK\r"
char thisByte = 0;
while (thisByte != '\r') {
if (Serial.available() > 0) {
thisByte = Serial.read();
}
if (count++ > 100000) break;
}
if (count <= 100000) {
// set the destination address, using 16-bit addressing.
// if you're using two radios, one radio's destination
// should be the other radio's MY address, and vice versa:
Serial.print("ATDH0, DL5678\r");
// set my address using 16-bit addressing:
Serial.print("ATMY1234\r");
// set the PAN ID. If you're working in a place where many people
// are using XBees, you should set your own PAN ID distinct
// from other projects.
Serial.print("ATID1111\r");
// put the radio in data mode:
Serial.print("ATCN\r");
}
}
void loop() {
// listen for incoming serial data:
// listen to the potentiometer:
char sensorValue = readSensor();
// if there's something to send, send it:
if (sensorValue > 0) {
Serial.print(sensorValue, DEC );
Serial.print("\r");
}
}
char readSensor() {
char message = 0;
// read the sensor:
float sensorReading = analogRead(SENSOR_PIN);
// look for a change from the last reading
// that's greater than the threshold:
if (abs(sensorReading - lastSensorReading) > THRESHOLD) {
message = sensorReading/4;
lastSensorReading = sensorReading;
}
return message;
}
Receiver:
/*
Adapted from the "XBee Analog Duplex Sender" program in "Making
Things Talk", O'Reilly, First Edition, Sep-2007. See pages 193-206.
This sketch configures an XBee radio via the serial port,
reads serial data from XBee and outputs the received
strings to an ZB1-LCD2 LCD screen.
(* jcl *)
*/
#include <avr/interrupt.h>
#include <avr/io.h>
int inByte= -1; // incoming byte from serial RX
char inString[6]; // string for incoming serial data
int stringPos = 0; // string index counter
void setup() {
char *msg = "wiblock MTT XB DEMO";
Serial.begin(9600);
Serial.println(msg);
// set XBee's destination address:
setDestination();
}
void setDestination() {
long count = 0;
// put the radio in command mode:
Serial.print("+++");
// wait for the radio to respond with "OK\r"
char thisByte = 0;
while (thisByte != '\r') {
if (Serial.available() > 0) {
thisByte = Serial.read();
}
if (count++ > 100000) break;
}
if (count <= 100000) {
// set the destination address, using 16-bit addressing.
// if you're using two radios, one radio's destination
// should be the other radio's MY address, and vice versa:
Serial.print("ATDH0, DL1234\r");
// set my address using 16-bit addressing:
Serial.print("ATMY5678\r");
// set the PAN ID. If you're working in a place where many people
// are using XBees, you should set your own PAN ID distinct
// from other projects.
Serial.print("ATID1111\r");
// put the radio in data mode:
Serial.print("ATCN\r");
}
}
void loop() {
// listen for incoming serial data:
if (Serial.available() > 0) handleSerial();
}
void handleSerial() {
inByte = Serial.read();
// save only ASCII numeric characters (ASCII 0 - 9):
if ((inByte >= '0') && (inByte <= '9')){
inString[stringPos] = inByte;
stringPos++;
}
// if you get an ASCII carriage return:
if (inByte == '\r') {
inString[5] = 0;
// output string to LCD
//lcd.cursorTo(2, 0); //line=2, x=0.
Serial.println(inString);
// clear the string with spaces
for (int c = 0; c < 6; c++) {
inString[c] = ' ';
}
// reset the string pointer:
stringPos = 0;
}
}
If the XBee is not reading digital or analog sensors connected to any of it's pins, and there are only two XBees, keep it simple and do not use API mode.
The sender should use:
float pi = 3.14159;
Serial.print("<");
Serial.print(pi);
Serial.print(">");
The receiver code would look like this:
#define SOP '<'
#define EOP '>'
bool started = false;
bool ended = false;
char inData[80];
byte index;
void setup()
{
Serial.begin(57600);
// Other stuff...
}
void loop()
{
// Read all serial data available, as fast as possible
while(Serial.available() > 0)
{
char inChar = Serial.read();
if(inChar == SOP)
{
index = 0;
inData[index] = '\0';
started = true;
ended = false;
}
else if(inChar == EOP)
{
ended = true;
break;
}
else
{
if(index < 79)
{
inData[index] = inChar;
index++;
inData[index] = '\0';
}
}
}
// We are here either because all pending serial
// data has been read OR because an end of
// packet marker arrived. Which is it?
if(started && ended)
{
// The end of packet marker arrived. Process the packet
// Reset for the next packet
started = false;
ended = false;
index = 0;
inData[index] = '\0';
}
}
Where is says "Process the packet", inData would contain "3.14159" and would be properly NULL terminated, so you could add:
float cake = atof(inData);
and cake would equal pi (to a few decimal places).
PaulS:
If the XBee is not reading digital or analog sensors connected to any of it's pins, and there are only two XBees, keep it simple and do not use API mode.
If I were to use 2 or more sender xbees, what should I add to the code? Also, what should I do if the receiver can only listen to one device at a time? Should I set the sender xbees different delay for each?
Then, on the receiver, you'd use strtok() to get the ID token, atoi() to convert it to a number, and use strtok() again (with NULL as the 1st argument) to get the value token, and atof() to convert it to a value. The ID might tell you where to store the value. Or not.
Sir PaulS, I placed your code inside dragonrobo7's code
Router:
const int currentPin = 14;
const unsigned long sampleTime = 100000UL; // sample over 100ms, it is an exact number of cycles for both 50Hz and 60Hz mains
const unsigned long numSamples = 250UL; // choose the number of samples to divide sampleTime exactly, but low enough for the ADC to keep up
const unsigned long sampleInterval = sampleTime/numSamples; // the sampling interval, must be longer than then ADC conversion time
int adc_zero; //auto adjusted relative digital zero
void setup(){
Serial.begin(9600);
adc_zero = determineVQ(currentPin); //Quiescent output voltage - the average voltage ACS712 shows with no load (0 A)
delay(1000);
}
void loop(){
float current = (readCurrent(currentPin), 3);
Serial.print("<");
Serial.print(current);
Serial.print(">");
}
int determineVQ(int PIN) {
long VQ = 0; //ave VQ
//read 1000 samples to stabilize value
for (int i = 0; i < 1000; i++) {
VQ += analogRead(PIN);
delay(1); //depends on sampling (on filter capacitor), can be 1/80000 (80kHz) max.
}
VQ /= 1000;
return int(VQ);
}
float readCurrent(int PIN)
{
unsigned long currentAcc = 0;
unsigned int count = 0;
unsigned long prevMicros = micros() - sampleInterval ;
while (count < numSamples)
{
if (micros() - prevMicros >= sampleInterval)
{
long adc_raw = analogRead(currentPin) - adc_zero;
currentAcc += (unsigned long)(adc_raw * adc_raw);
++count;
prevMicros += sampleInterval;
}
}
float rms = sqrt((float)currentAcc/(float)numSamples) * (50 / 1024.0);
return rms;
}
and all I'm getting is 3.00 so I tested just your code like this
Router:
int sensorPin = 14;
float val;
void setup(){
Serial.begin(9600);
}
void loop(){
val = analogRead(sensorPin);
Serial.print("<");
Serial.print(val);
Serial.print(">");
}
Coordinator:
#define SOP '<'
#define EOP '>'
bool started = false;
bool ended = false;
char inData[80];
byte index;
void setup()
{
Serial.begin(9600);
// Other stuff...
}
void loop()
{
// Read all serial data available, as fast as possible
while(Serial.available() > 0)
{
char inChar = Serial.read();
if(inChar == SOP)
{
index = 0;
inData[index] = '\0';
started = true;
ended = false;
}
else if(inChar == EOP)
{
ended = true;
break;
}
else
{
if(index < 79)
{
inData[index] = inChar;
index++;
inData[index] = '\0';
}
}
}
// We are here either because all pending serial
// data has been read OR because an end of
// packet marker arrived. Which is it?
if(started && ended)
{
// The end of packet marker arrived. Process the packet
float cake = atof(inData);
Serial.println(cake);
delay(150);
// Reset for the next packet
started = false;
ended = false;
index = 0;
inData[index] = '\0';
}
}
here, I'm getting values ranging from 300-400 then 0 then 1000 then back to 300-400. Did I do something wrong?
What do you think that this statement is doing? It isn't, but how to fix this mess depends on what you think it is supposed to be doing.
What it looks like is that you took this statement:
Serial.print(readCurrent(currentPin), 3);
and simply replaced "Serial.print" with "float current = ".
I tried running your original code on the router side
float pi = 3.14159;
Serial.print("<");
Serial.print(pi);
Serial.print(">");
I sometimes receive 142.00, 3.00 and 0.00 instead of 3.14 all the way. Is this caused by jumbled bytes?
What do you think that this statement is doing? It isn't, but how to fix this mess depends on what you think it is supposed to be doing.
When I used "float current = (readCurrent(currentPin), 3);" I stored the returned rms value of the readCurrent() to 'current'? Why is it not the same as "float pi = 3.14"? I don't get it
Sir PaulS, is the answer converting float to string? like using dtostrf()? because you used atof() in the receiver Xbee
Or could someone please post a link for 2 arduinos with xbee transferring analog data? I think that's my problem, the articles or posts I've read either uses 1 remote xbee and an arduino with xbee to transfer analog data or 2 arduino with xbee controlling potentiometer or LED.
When I used "float current = (readCurrent(currentPin), 3);" I stored the returned rms value of the readCurrent() to 'current'? Why is it not the same as "float pi = 3.14"? I don't get it
No, you don't. You get a value, using readCurrent(). Then, you apply the comma operator to that value and 3. The comma operator is not doing what you think it is. So, quit doing that shit.