V_88:
Hi Sembazuru,Thanks for taking the trouble of actually testing it and all. I really appreciate it.
So of all the codes we have tried, which one is it? Is it the one with the case statements? Could you post it? I want to burn it and test it for myself.
Thanks a lot. I will follow the other thread also.
Ok, here is what I came up with combining what was found in that other thread. I ran a test with these two sketches that has an intentional noise component added. I send analogRead()s from the transmitter to the receiver from floating analog pins. While running I threw in a lot of noise by touching the analog pins and randomly shorting pairs to each other. I actually did see my random noise fool the the data structure once, but it recovered very quickly. (See around line 1814 of the attached file for the the instance that I found.)
I commented pretty heavily in both sketches to try to explain what is going on. If you don't understand why or how something is working, please ask and I will attempt to explain.
Oh, watch out. I changed the baud rate for the hardware serial port (Serial.begin();). This is the baud rate that you need to set your serial monitor to. Either change your serial monitor to 115200, or change the code back to 9600.
Transmitter
#include <SoftwareSerial.h>
//#include <i2cmaster.h> // commented out temporarily because I don't have the sensor
SoftwareSerial XBeeTX(2, 3); // RX, TX
const byte dev = 0x5A<<1; // This is a constant, so use the const keyword to allow the compiler to decide how best to optimize
const char data_start = '*'; // This is a constant, so use the const keyword to allow the compiler to decide how best to optimize
const char data_format[] = "%c%02X%02X"; // %c is a single character, %02X is a 2 character ASCII encoded hex number representing 1 byte
char dataStream[6]; // data_format will result in 5 characters plus 1 NULL character automatically applied by the sprintf() function so we need a 6 element array as a buffer
byte data_low;
byte data_high;
byte pec;
void setup()
{
Serial.begin(115200);
XBeeTX.begin(9600);
// i2c_init(); //Initialise the i2c bus
// PORTC = (1 << PORTC4) | (1 << PORTC5);//enable pullups
}
void loop()
{
// i2c_start_wait(dev+I2C_WRITE);
// i2c_write(0x07);
// read
// i2c_rep_start(dev+I2C_READ);
// data_low = i2c_readAck(); //Read 1 byte and then send ack
// data_high = i2c_readAck(); //Read 1 byte and then send ack
// pec = i2c_readNak();
// i2c_stop();
// sprintf() method of output
sprintf(dataStream, data_format, data_start, data_high, data_low); // 1(data_start) + 2(data_high) + 2(data_low) + 1(NULL) = 6 bytes
XBeeTX.print(dataStream);
Serial.print(dataStream); // for diagnostics
Serial.println(F(" Sent over XBee.")); // also for diagnostics, using the F() macro to avoid wasting SRAM with diagnostic messages
delay(1000); // adjust to what ever delay you want.
// remove the following lines when I2C is re-enabled
data_high++; // I don't have an I2C temp sensor, so this is just dummy data
data_low++; // incrementing both each iteration of loop() to check all possible values of each
XBeeTX.write(analogRead(A0)); // Add some noise
XBeeTX.write(analogRead(A1)); // Add some noise
XBeeTX.write(analogRead(A2)); // Add some noise
XBeeTX.write(analogRead(A3)); // Add some noise
}
Receiver
#include <SoftwareSerial.h>
//#include <ctype.h> // compiles w/o this include in ERW 1.0.5 What version of the IDE are you using? Do you need to uncomment this line to get it to compile in your IDE?
SoftwareSerial XBeeRX(2, 3); // RX, TX
const char data_start = '*'; // This is a constant, so use the const keyword to allow the compiler to decide how best to optimize
const char data_format[] = "%c%02X%02X"; // for sprintf() %c is a single character and %02X is a 2 character ASCII encoded hex number representing 1 byte
char dataStream[6]; // data_format will result in 5 characters plus 1 NULL character automatically applied by the sprintf() function so we need a 6 element array as a buffer
boolean newReading = false; // Because we use this before explicitly setting it, just to make sure the default is false we set it here.
byte readPosition;
byte data_low;
byte data_high;
char data_in;
void setup()
{
Serial.begin(115200);
XBeeRX.begin(9600);
}
void loop()
{
if (XBeeRX.available())
{
data_in = XBeeRX.read();
Serial.println(data_in, HEX); // Show the recieved HEX value immediately as recieved for diagnostics.
switch(readPosition)
{
case 0: // Waiting for the start of data token to be received. Ignore any serial data until data_start is received.
{
if (data_in == data_start)
readPosition++;
break;
}
case 1: // data_start processed. Current character should be ASCII representation of the high nybble of data_high.
{
data_high = HexCharToValue(data_in)<<4;
readPosition++;
break;
}
case 2: // high nybble of data_high processed. Current character should be ASCII representation of the low nybble of data_high.
{
data_high = HexCharToValue(data_in)+data_high;
readPosition++;
break;
}
case 3: // low nybble of data_high processed. Current character should be ASCII representation of the high nybble of data_low.
{
data_low = HexCharToValue(data_in)<<4;
readPosition++;
break;
}
case 4: // high nybble of data_low processed. Current character should be ASCII representation of the low nybble of data_low.
{
data_low = HexCharToValue(data_in)+data_low;
readPosition = 0; // Finished receiving expected data structure. Return readPosition to zero to wait for the next data_start token
newReading = true;
}
}
}
if (newReading == true) // newReading is a boolean type, so this is the same as "if (newReading)" which while saving keystrokes might not be as obvious an intent
{
sprintf(dataStream, data_format, data_start, data_high, data_low); // reconvert converted serial input to verify the deconversion process worked
Serial.print(dataStream); // Diagnostics to verify reconversion matches expected input
// This whole section of declarations should properly be at the top of either loop() as local variables, or at the top of the sketch as globals. If globals, tempFactor should be a constant
double tempFactor = 0.02; // double and float are the same datatype. Only use one of the two to avoid confusion unless there is a really good reason not to.
unsigned int tempData; // floating point math is executionally expensive on AVR processors. All we really need here is a 16-bit holding bin, polarity is not important.
float kelvin; // after applying the tempFactor, this is what one really has, so why not indicate it with a descriptive variable name?
float celsius; // corrected the spelling of celsius...
int frac; // what is this variable used for? Future use? Or can it be removed?
tempData = ((data_high & 0x007F) << 8) + data_low; // come to think of it, the name data_word might be better for self-documenting code instead of tempData
kelvin = (tempData * tempFactor)-0.01; // what is the -0.01 for? I don't remember seeing anything about this in the temperature sensor datasheet. But I may have missed it.
celsius = kelvin - 273.15; // Wow... In how many text and reference books have I seen this formula? ;-)
Serial.print(F(" Celsius: ")); // Save SRAM by using F() macro for constant text messages
Serial.println(celsius);
newReading = false;
}
}
byte HexCharToValue (char x)
{
byte value;
int upper; // Why int? Should match x, so make this a char. (will save 1 byte of stack space in the process).
byte first_result;
if (isxdigit(x))
{
upper = toupper(x);
first_result = upper - 0x30;
if (first_result < 0x0A)
{
value = first_result;
}
else
{ // This can be shortened to value = first_result - 7; because -0x10 + 9 = -7 but the following two lines documents the intent better.
value = first_result - 0x10;
value = value + 9; // My error. 'A' is 0x41. Subtracting 0x30 and then 0x10 will leave 0x01. To get that to be decimal 10, add decimal 9. (Head-palm at myself)
}
}
else
{
value = 0;
}
return value;
}
Once it works as is, revert the transmitter code to actually reading your temperature sensor.
Also, please respond to the questions and alternate options that I pose in the comments.
V_88.txt (19.6 KB)