How do I properly draw a frame with an ILI9341? Arduino - arduino

I have a 2.8 inch TFT LCD from Adafruit driven by an ILI9341. To draw on the LCD, I use the commands 0x2A to set the width, 0x2B to set the height, and 0x2C to color each pixel (I2C). My problem is that I currently draw the background as a rectangle, and then each rectangle required. This creates a displeasing look since the colors start to mix and create disturbing, angled lines between the smaller rectangles. These are the functions I use to draw:
void drawRectangle(long sX, long sY, long eX, long eY, uint16_t clr) {
send32bitData(0x2A, (sX << 16) | eX);
send32bitData(0x2B, (sY << 16) | eY);
oneColor(clr, (eX - sX + 1) * (eY - sY + 1));
}
void oneColor(uint16_t clr, long area) {
uint8_t hi = clr >> 8;
uint8_t lo = clr;
uint8_t dHi = clr >> 6, bHi = clr >> 14, dLo = clr << 2, bLo = clr >> 6;
sendCommand(0x2C, true);
PORTC = 0x6;
for (long i = area; i--; i > 0) {
PORTC = 0x6;
PORTD = dHi;
PORTB = bHi;
PORTC = 0x2;
PORTC = 0x6;
PORTD = dLo;
PORTB = bLo;
PORTC = 0x2;
}
PORTC = 0x7;
}
Here's a video of that line. I'm assuming that I'm drawing wrong. I'd like to keep a huge array with colors for each pixel, but I have an Arduino Uno that 2048 bytes of variable space. If I had that array, then I would draw one rectangle for the whole screen and send each color to the memory. One thing that worked was drawing extremely slow. But, that's slow... I want to draw at ~70 fps while keeping each frame smooth.

Related

PLL Voltage scalling STM32

I am working with the STM32F767 Nucleo board and currently, I trying to set the PLL as the system clock. While I have been able, thanks to an example generated by the CubeMX, I really don't understand why it must be done so. The setup is:
HSI = 16MHz
PLLM = 8
VCO_Input_Frequency = 16/8 = 2MHz
PLLN = 144
Frequency = 144*2 = 288MHz
PLLP = 6
PLL_Output_Frequency = 288/6 = 48MHz
PPRE1 = 2
APB1_Frequency = 24MHz
APB1_Frequency_Timer = 2*24MHz = 48MHz
The following line of code is what is buging me:
//Sets the voltage scaling mode to 3, VOS = 0x1 = b1
PWR->CR1 |= PWR_CR1_VOS_0;
a = PWR->CR1; //Small delay
When this line is commented the period is 19.7ms and when is active the period is 20ms, as expected. It is very strange, this is how the generated code from CubeMX does. It makes the voltage scaling to 1 (low performance). I don't understand how seting the voltage scaling equals to 1 makes the PLL works correctly.
Down below is the code that configure the PLL:
void sys_clock_init(void){
int a;
//Sets the wait states to 1
FLASH->ACR |= 0x01;
a = FLASH->ACR; //Small delay
//Enables the power interface (for the power controller)
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
a = RCC->APB1ENR; //Small delay
//Clears the bits for the voltage scaling
PWR->CR1 &= ~(PWR_CR1_VOS);
//Sets the voltage scaling mode to 3, VOS = 0x1 = b1
PWR->CR1 |= PWR_CR1_VOS_0;
a = PWR->CR1; //Small delay
//Makes HSI the source of the PLL
RCC->PLLCFGR &= ~(0x400000);
//Clears the bits for the different factors
RCC->PLLCFGR &= ~(RCC_PLLCFGR_PLLM);
//Sets the PLLM = 0x08 = b100
RCC->PLLCFGR |= (RCC_PLLCFGR_PLLM_3);
//Clears the PLLN bits
RCC->PLLCFGR &= ~(RCC_PLLCFGR_PLLN);
//Sets PLLN = 0x90 = b10010000
RCC->PLLCFGR |=(RCC_PLLCFGR_PLLN_7 | RCC_PLLCFGR_PLLN_4);
//Clears the PLLP bits
RCC->PLLCFGR &= ~(RCC_PLLCFGR_PLLP);
//Sets the PLLP = 0x02 = b10
RCC->PLLCFGR |=(RCC_PLLCFGR_PLLP_1);.
//Clears the PPRE1 bits
RCC->CFGR &= ~(RCC_CFGR_PPRE1_2 | RCC_CFGR_PPRE1_1 | RCC_CFGR_PPRE1_0);
//Set bit PPRE1 = 0x02 = b100
RCC->CFGR |= (RCC_CFGR_PPRE1_2);// | RCC_CFGR_PPRE1_0);
//Turns the PLL ON
RCC->CR |= RCC_CR_PLLON;
//Waits for the PLL to be ready
while(!((RCC->CR & RCC_CR_PLLRDY) == RCC_CR_PLLRDY));
//Clears the switch bits
RCC->CFGR &= ~(RCC_CFGR_SW);
//Set the PLL as the System Clock
RCC->CFGR |= (RCC_CFGR_SW_1);}
I have also tested commenting the lines that sets VOS bits on the CubeMX code and the period is 19.75ms like mine.
This is my code to get that board to 16Mhz using the PLL and the external clock.
static int clock_init ( void )
{
unsigned int ra;
//switch to external clock.
ra=GET32(RCC_CR);
ra|=1<<16;
PUT32(RCC_CR,ra);
while(1) if(GET32(RCC_CR)&(1<<17)) break;
if(1)
{
ra=GET32(RCC_CFGR);
ra&=~3;
ra|=1;
PUT32(RCC_CFGR,ra);
while(1) if(((GET32(RCC_CFGR)>>2)&3)==1) break;
}
//HSE ready
//PLLM aim for 2mhz so 8/4=2
//PLLN input is 2, want >=100 and <=432 so between 50 and 216
//PLLP 16Mhz*8 = 128, 16MHz*6 = 96, not enough
//so PLLP is 8 VCO 128 so PLLN is 64
//don't really care about PLLQ but have to have something so 8
PUT32(RCC_PLLCFGR,0x20000000|(8<<24)|(1<<22)|(3<<16)|(64<<6)|(4<<0));
ra=GET32(RCC_CR);
ra|=1<<24;
PUT32(RCC_CR,ra);
while(1) if(GET32(RCC_CR)&(1<<25)) break;
ra=GET32(RCC_CFGR);
ra&=~3;
ra|=2;
PUT32(RCC_CFGR,ra);
while(1) if(((GET32(RCC_CFGR)>>2)&3)==2) break;
return(0);
}
PUT32/GET32 are abstraction functions to do str/ldr. I will try either 48 HSE or 48Mhz HSI, and post what I find.
static int clock_init ( void )
{
unsigned int ra;
//PLLM aim for 2mhx so 16/8 = 2;
//PLLN input is 2, want >=100 and <=432 so between 50 and 216
//PLLN = 144, VCO 288
//PLLP = 6, output 288/6 = 48MHz
//don't really care about PLLQ but have to have something so 6
PUT32(RCC_PLLCFGR,0x20000000|(6<<24)|(0<<22)|(2<<16)|(144<<6)|(8<<0));
ra=GET32(RCC_CR);
ra|=1<<24;
PUT32(RCC_CR,ra);
while(1) if(GET32(RCC_CR)&(1<<25)) break;
ra=GET32(RCC_CFGR);
ra&=~3;
ra|=2;
PUT32(RCC_CFGR,ra);
while(1) if(((GET32(RCC_CFGR)>>2)&3)==2) break;
return(0);
}
The uart works, but that is not saying much.
With the default of scale 1 I do see that a little fast. but if I use the 8MHz HSE then it looks better. I use systick to count 120 seconds. set systick to roll over every 1million counts then wait for 120 rollovers, compare to a stopwatch/timer.
Next using 16000000 in systick and counting 900 rollovers that should be 5 minutes and it is to within a second since comparing visually to a timer is only that accurate. Using HSE, scaling 1 (default)
Using HSI scaling 1 it is off by a few seconds to get 19.7ns though would be a lot of seconds and I don't see that many.
Now using HSI scaling 3:
static int clock_init ( void )
{
unsigned int ra;
ra=GET32(RCC_APB1ENR);
ra|=1<<28; //PWR enable
PUT32(RCC_APB1ENR,ra);
PUT32(FLASH_ACR,0x00000001);
PUT32(PWR_CR1,0x4000);
GET32(PWR_CR1);
//PLLM aim for 2mhx so 16/8 = 2;
//PLLN input is 2, want >=100 and <=432 so between 50 and 216
//PLLN = 144, VCO 288
//PLLP = 6, output 288/6 = 48MHz
//don't really care about PLLQ but have to have something so 6
PUT32(RCC_PLLCFGR,0x20000000|(6<<24)|(0<<22)|(2<<16)|(144<<6)|(8<<0));
ra=GET32(RCC_CR);
ra|=1<<24;
PUT32(RCC_CR,ra);
while(1) if(GET32(RCC_CR)&(1<<25)) break;
ra=GET32(RCC_CFGR);
ra&=~3;
ra|=2;
PUT32(RCC_CFGR,ra);
while(1) if(((GET32(RCC_CFGR)>>2)&3)==2) break;
return(0);
}
Does appear to be more accurate. 5 minutes measured as 5 minutes to the second. So it appears perhaps that the documentation isn't correct with respect to the accuracy of HSI (as there is this exception using default scaling).
48Mhz -> 20.83ns
20.62 - 21.04 with the documented error.
There is a reason for using external clocks. If you are interested in more accuracy since you have the NUCLEO board use the external clock HSE not the internal HSI.
Hmmm, actually 1% for the 16Mhz which is 3% when multiplied by 3 to get 48MHz. I think using the divisor in the PLL makes it worse, but I would have to ponder that some more.
20.21 to 21.46 is the range you should see at the calibration temperature, then vary from that based on die temp.

Arduino pulse train

I will give you a little introduction:
I am working on a water fuel cell of Stanley Meyer. For those who don't know the water fuel cell you can see it here.
For the water fuel cell one has to build a circuit. Here is the diagram:
Right now I am working on the pulse generator (variable) and the pulse gate (variable) to generate this waveform.
So, I want to do this with Arduino timers. I already can generate a "high frequency" pulse generator (1 kHz - 10 kHz, depending on the prescaling at the TCCR2B register) PWM at pin 3 with this code:
pinMode(3, OUTPUT);
pinMode(11, OUTPUT);
TCCR2A = _BV(COM2A0) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20);
TCCR2B = _BV(WGM22) | _BV(CS21) | _BV(CS20);
OCR2A = 180;
OCR2B = 50;
I can modify the frequency and pulse with:
sensorValue = analogRead(analogInPin);
sensorValue2 = analogRead(analogInPin2);
// Map it to the range of the analog out:
outputValue = map(sensorValue, 0, 1023, 30, 220);
outputValue2 = map(sensorValue2, 0, 1023, 10, 90);
OCR2A = outputValue;
This is working fine.
Now I want to modulate this pulse with another pulse train with "low frequency" (20 Hz to 100 Hz approximately) to act as a pulse gate. I was thinking to use Timer 0 to count and shutdown the signal when it counts some value and activate when arrives at the same value again, like this
TCCR0A = _BV(COM0A0) | _BV(COM0B0) | _BV(WGM01);
TCCR0B = _BV(CS02);
OCR0A = 90;
OCR0B = OCR0A * 0.8;
And compare with the counter
if (TCNT0 <= OCR0A)
TCCR2A ^= (1 << COM2A0);
But it does not work well. Any ideas for this?
These days I have tried to create a wave generator like the one that comes in your question. I can not eliminate the jitter or mismatch that appears, but I can create a wave like that. Try this example and modify it:
#include <TimerOne.h>
const byte CLOCKOUT = 11;
volatile byte counter=0;
void setup() {
Timer1.initialize(15); // Every 15 microseconds change the state
// of the pin in the wave function giving
// a period of 30 microseconds
Timer1.attachInterrupt(Onda);
pinMode(CLOCKOUT, OUTPUT);
digitalWrite(CLOCKOUT, HIGH);
}
void loop() {
if (counter>=29) { // With 29 changes I achieve the amount of pulses I need.
Timer1.stop(); // Here I create the dead time, which must be in HIGH.
PORTB = B00001000;
counter = 0;
delayMicroseconds(50);
Timer1.resume();
}
}
void Onda(){
PORTB ^= B00001000; // Change pin status
counter += 1;
}

Get 3 Values from processing to Arduino

I have a color tracking program in Processing, which works with a Kinect. When I click somewhere in the picture it saves this color and draws an ellipse around it. I just want to send 3 int values (one for red, green and blue) over myPort.write() to Arduino and save these 3 values in Arduino in 2 variables. My goal is to light a red LED if the red variable is the highest, and the green LED if green is the highest and so on.
I've tried several examples I found whiel googling, but nothing works. I don't know how Arduino should get the correct values in the variables!
EDIT: Here you have my Processing code. I glued it together from several other tutorials until I nearly cried..
import processing.serial.*;
Serial myPort;
import SimpleOpenNI.*;
SimpleOpenNI kinect;
// Frame
PImage currentFrame;
color trackColor;
int r1, g1, b1, r2, g2, b2;
void setup()
{
size(640, 480);
String portName = Serial.list()[0]; //change the 0 to a 1 or 2 etc. to match your port
myPort = new Serial(this, portName, 9600);
kinect = new SimpleOpenNI(this);
kinect.enableRGB();
trackColor = color (255, 0, 0);
smooth ();
currentFrame = createImage (640, 480, RGB);
}
void draw()
{
kinect.update();
currentFrame = kinect.rgbImage ();
image(currentFrame, 0, 0);
currentFrame.loadPixels();
// Before we begin searching, the "world record" for closest color is set to a high number that is easy for the first pixel to beat.
float worldRecord = 500;
// XY coordinate of closest color
int closestX = 0;
int closestY = 0;
// Begin loop to walk through every pixel
for (int x = 0; x < currentFrame.width; x ++ ) {
for (int y = 0; y < currentFrame.height; y ++ ) {
int loc = x + y*currentFrame.width;
// What is current color
color currentColor = currentFrame.pixels[loc];
r1 = (int)red(currentColor);
g1 = (int)green(currentColor);
b1 = (int)blue(currentColor);
r2 = (int)red(trackColor);
g2 = (int)green(trackColor);
b2 = (int)blue(trackColor);
// Using euclidean distance to compare colors
float d = dist(r1, g1, b1, r2, g2, b2); // We are using the dist( ) function to compare the current color with the color we are tracking.
// If current color is more similar to tracked color than
// closest color, save current location and current difference
if (d < worldRecord) {
worldRecord = d;
closestX = x;
closestY = y;
}
}
}
// We only consider the color found if its color distance is less than 10.
// This threshold of 10 is arbitrary and you can adjust this number depending on how accurate you require the tracking to be.
if (worldRecord < 10) {
// Draw a circle at the tracked pixel
fill(trackColor);
strokeWeight(4.0);
stroke(0);
ellipse(closestX, closestY, 30, 30);
}
if (mousePressed == true) {
color c = get(mouseX, mouseY);
//println("r: " + red(c) + " g: " + green(c) + " b: " + blue(c));
// Save color where the mouse is clicked in trackColor variable
int loc = mouseX + mouseY*(currentFrame.width);
trackColor = currentFrame.pixels[loc];
println("red " + r2);
println("green " + g2);
println("blue " + b2);
int colors[] = {r2, g2, b2};
for(int i=0; i < 3; i++) {
myPort.write(colors[i]);
}
}
println("ClosestX " + closestX);
myPort.write(closestX);
}
And my Arduino Code, where I don't know how to get several values.
int val;
int ledPin = 13;
int freq;
int piezoPin = 9;
int redLED = 3;
int greenLED = 5;
int blueLED = 7;
int red, green, blue;
void setup() {
pinMode(ledPin, OUTPUT); // Set pin as OUTPUT
Serial.begin(9600); // Start serial communication at 9600 bps
digitalWrite(ledPin, LOW);
}
void loop() {
if (Serial.available() > 0)
{ // If data is available to read,
val = Serial.read(); // read it and store it in val
}
if(red > green && red > blue) {
digitalWrite(redLED, HIGH); //light Red LED
}
if(green > red && green > blue) {
digitalWrite(greenLED, HIGH); //light Red LED
}
if(blue > red && blue > green) {
digitalWrite(blueLED, HIGH); //light Red LED
}
//Piezo buzzing higher when X-Position of tracked color is higher.
if (val < 100) {
freq = 50;
}
else if (val < 200) {
freq = 200;
}
else if (val < 300) {
freq = 400;
}
else if (val < 400) {
freq = 600;
}
else if (val < 500) {
freq = 800;
}
else (freq = 1000);
tone(piezoPin, freq);
}
EDIT2: Yes, additionally to lighing the LEDs I also want to have a sound from a piezo buzzer, but that works pretty well, so no questions on that... yet.
Help, please!!
Serial communication to your arduino works with a single byte at a time.
As luck would have it, the three components of a Processing Color are also three bytes.
One for red(0-255)
One for green(0-255)
One for blue(0-255)
Now all we need is a little more info so we can keep them separate.
Because a byte's minimum and maximum values are 0-255, there's no safe character we can use to keep track of the three different bytes, so we need a way to figure out where the info we send begins and ends.
An easy way to do this, is to set up a header and a footer for your messages ; something like :
<color>[byte (red)][byte (green)][byte (blue)]</color>
If we are going to read and decipher messages formatted like this, we are going to need a little buffer that will store the values we receive from Processing, so we can read them back and see if we can match the message format.
So, on the Arduino side, we need this :
String buffer = "";
String messageBegin = "<color>";
String messageEnd = "</color>";
//we read our serial data in the SerialEvent() function
//this is called *after* a loop(), and only if there is serial data in the buffer.
void serialEvent()
{
while(Serial.available())
{
buffer += (char)Serial.read();
}
}
void loop()
{
//now, inside loop, we no longer need to worry about gathering data from serial.
//we do still need to figure out if our message is complete, and then parse it.
//if our buffer contains both the beginning and the end of a message
//in the right order.
int beginIndex = buffer.lastIndexOf(messageBegin);
int endIndex = buffer.lastIndexOf(messageEnd);
if(beginIndex != -1 && endIndex != -1 && beginIndex < endIndex)
{
//we have a complete message!
//our red color starts 7 characters after where the message begins,
//because our "messageBegin" is 7 characters long
string lastMessage = buffer.substring(beginIndex+7);
//this is arguably not the prettiest way to get our byte values back.
//see if you can do better for bonus points!
byte messageAsBytes[80];
lastMessage.getBytes(messageAsBytes, messageAsBytes.length());
//we can now finally reconstruct the value we had from processing!
byte r = (byte)messageAsBytes[0];
byte g = (byte)messageAsBytes[1];
byte b = (byte)messageAsBytes[2];
//if we get a complete message, we can clear our buffer. (don't forget to do this!)
buffer = "";
}
}
On the processing side, all we need to do is make sure our messagebegin and messageend are sent along for the ride :
myPort.write("<color">);
for(int i=0; i < 3; i++) {
myPort.write(colors[i]);
}
myPort.write("</color">);

Strange magnetometer readout

I am attempting to readout the data from my MPU-9150 magnetometer and getting some odd numbers. I have accessed the magnetometer within the IMU and am getting data which changes with the orientation of the IMU but is not within the range specified by the product specification guide. I'm think its probably something to do with either the variable type i am using to store the data or the method i am using to manipulate the twos compliment data to make it readable, so here is the code anyway...
void MPU9150::getMag(double* mag_X, double* mag_Y, double* mag_Z){
uint8_t asax, asay, asaz;
I2Cdev::writeByte(MPU9150_ADDRESS, INT_PIN_CFG, 0x02);//Set i2c bypass enable pin to true to access magnetometer.
I2Cdev::writeByte(MPU9150_MAG_ADDRESS, MPU9150_MAG_CNTRL, 0x0f);//Fuse Rom access mode.
I2Cdev::readBytes(MPU9150_MAG_ADDRESS, MPU9150_MAG_ASAX, 3, buffer);//Get sensitivity adjustment values.
asax = buffer[0];
asay = buffer[1];
asaz = buffer[2];
// Serial.print("asax = "); Serial.print(asax); Serial.print("\n");
// Serial.print("asay = "); Serial.print(asay); Serial.print("\n");
// Serial.print("asaz = "); Serial.print(asaz); Serial.print("\n\n");
I2Cdev::writeByte(MPU9150_MAG_ADDRESS, MPU9150_MAG_CNTRL, 0X01);//Enable the magnetometer.
delay(10);
I2Cdev::readBytes(MPU9150_MAG_ADDRESS, MPU9150_MAG_XOUT_L, 6, buffer);//Read magnetometer readings.
mx = ((((int16_t)buffer[0]) << 8) | buffer[1]) * 0.3;
my = ((((int16_t)buffer[2]) << 8) | buffer[3]) * 0.3;
mz = ((((int16_t)buffer[4]) << 8) | buffer[5]) * 0.3;
*mag_X = mx * ((((asax - 128)*0.5)/(128)) + 1);//Adjust readings with sensitivity adjustment values.
*mag_Y = my * ((((asay - 128)*0.5)/(128)) + 1);
*mag_Z = mz * ((((asaz - 128)*0.5)/(128)) + 1);
}
The decimal range for each axis should be between 4096 and -4096, and there are 6 data registers each containing 8 bit high and low values for each axis. The data that i am getting seems to be in the range >10000 to <-10000 with the highest value i have seen at 9830. If anyone has any ideas they would be appreciated, thanks :)
EDIT: Buffer is a private integer array, used to hold the bytes from the axis registers.
private:
uint8_t buffer[14];
Also reversing the order of the bytes (as i have realised should be done as the first byte in each register is low and the second high) has resulted in the range of the output reduced to a range of about -170 to 170...
mx = (((int16_t)buffer[1]) << 8) | buffer[0];
my = (((int16_t)buffer[3]) << 8) | buffer[2];
mz = (((int16_t)buffer[5]) << 8) | buffer[4];

Why does XBee transmit fail sometimes?

I doing a project with Arduino Uno R3 and XBee S2 transmission. I use a couple of sensors like a wireless (RF) temperature sensor, two SHT75 sensors, a 3-axis accelerometer and an illumination sensor. And after collecting the data, we use XBee (S2, API mode) to send the data to the gateway. Every round is about one second.
The first problem is the data is about 16 bytes, but the packet does not send successful every round. Sometime it works, and sometimes it doesn't, but the payload of XBee can be 60 or 70 bytes in the datasheet... But if I put the payload as some simply an integer (like 1, 2, 3), not the data from sensor, and the transmission will be stable.
After meeting the problem above, I divided the data into two packets (each with an eight bytes payload), and the first packet is very stable, but the second is very unstable. As mentioned above, if I put some number into the second packets instead of the sensing data the second packet will become stable and send successfully every round.
So I think it's the code problem, but idk where is the problem. I try to change the baud rate or increasing the delay time between the two packets. Where is the problem? The following is my code:
#include <XBee.h>
#include <i2cmaster.h>
#include <string.h>
#include <ctype.h>
#include <Sensirion.h>
#include "Wire.h"
#include "MMA845XQ.h"
**///////////////////////////// XBee setup //////////////////////////////////**
XBee xbee = XBee();
XBeeAddress64 remoteAddress = XBeeAddress64(0x00000000, 0x00000000);
ZBRxResponse zbRx = ZBRxResponse();
ZBTxStatusResponse zbTxStus = ZBTxStatusResponse();
uint8_t payload[] = {0,0,0,0,0,0,0,0,0};
uint8_t payload1[] = {0,0,0,0,0,0,0,0,0};
**///////////////////////////// Accelerometer //////////////////////////////////**
MMA845XQ accel;
**////////////////////////// SHT1 serial data and clock ////////////////////**
const byte dataPin = 2;
const byte sclkPin = 3;
Sensirion sht = Sensirion(dataPin, sclkPin);
unsigned int rawData;
float temperature;
float humidity;
byte stat;
**////////////////////////// SHT2 serial data and clock ////////////////////**
const byte dataPin1 = 4;
const byte sclkPin1 = 5;
Sensirion sht1 = Sensirion(dataPin1, sclkPin1);
unsigned int rawData1;
float temperature1;
float humidity1;
byte stat1;
**//////////////////////////// Illumination sensor ////////////////////////**
int sensorPin = A0; // Select the input pin for the potentiometer
int sensorValue = 0; // Variable to store the value coming from the sensor
long int pardata, pardata_low, pardata_hi, real_pardata;
uint16_t illumindata = 0;
void setup () {
i2c_init(); //Initialise the I²C bus
PORTC = (1 << PORTC4) | (1 << PORTC5); //Enable pullups
Wire.begin();
accel.begin(false, 2);
Serial.begin(115200);
xbee.begin(Serial);
}
void loop () {
payload[0] = 10;
payload1[0] = 11;
**/////////////////////RF temperature sensor/////////////////////////////**
int dev = 0x5A<<1;
int data_low = 0;
int data_high = 0;
int pec = 0;
i2c_start_wait(dev + I2C_WRITE);
i2c_write(0x07);
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();
double tempFactor = 0.02; // 0.02 degrees per LSB (measurement resolution of the MLX90614)
double tempData = 0x0000; // Zero out the data
int frac; // Data past the decimal point
// This masks off the error bit of the high byte, then moves it left 8 bits and adds the low byte.
tempData = (double)(((data_high & 0x007F) << 8) + data_low);
tempData = (tempData * tempFactor)-0.01;
float celcius = tempData - 273.15;
float fahrenheit = (celcius*1.8) + 32;
celcius *= 100;
int a = int(celcius) + 1;
payload[1] = a >> 8 & 0xff;
payload[2] = a & 0xff;
**//////////////////////////// Illumination sensor ////////////////////////////////**
sensorValue = analogRead(sensorPin);
TSR(sensorValue);
payload[3] = pardata_low >> 8 & 0xff;
payload[4] = pardata_low & 0xff;
**//////////////////////////// 3-axis accelemeter sensor ////////////////////////////////**
accel.update();
payload[5] = accel.getX()*10;
payload[6] = accel.getY()*10;
payload[7] = accel.getZ()*10;
delay(100);
**////////////////////////////// XBee send first packet///////////////////////////////////////////////**
xbee = XBee();
xbee.begin(Serial);
ZBTxRequest zbTx = ZBTxRequest(remoteAddress, payload, sizeof(payload));
zbTx.setAddress16(0xfffe);
xbee.send(zbTx);
delay(500);
**//////////////// SHT 1x temperature and humidity sensor /////////////////////////**
sht.readSR(&stat); // Read sensor status register
sht.writeSR(LOW_RES); // Set sensor to low resolution
sht.readSR(&stat); // Read sensor status register again
sht.measTemp(&rawData); // sht.meas(TEMP, &rawData, BLOCK)
sht.meas(TEMP, &rawData, NONBLOCK);
temperature = sht.calcTemp(rawData);
sht.measHumi(&rawData); // sht.meas(HUMI, &rawData, BLOCK)
humidity = sht.calcHumi(rawData, temperature);
sht.meas(HUMI, &rawData, NONBLOCK);
humidity = sht.calcHumi(rawData, temperature);
temperature *= 100;
a = int(temperature) + 1;
payload1[1] = a >> 8 & 0xff;
payload1[2] = a & 0xff;
humidity *= 100;
a = int(humidity) + 1;
payload1[3] = a >> 8 & 0xff;
payload1[4] = a & 0xff;
delay(10);
sht1.readSR(&stat1);
sht1.writeSR(LOW_RES); // Set sensor to low resolution
sht1.readSR(&stat1);
sht1.measTemp(&rawData1); // sht.meas(TEMP, &rawData, BLOCK)
temperature1 = sht1.calcTemp(rawData1);
sht1.measHumi(&rawData1); // sht.meas(HUMI, &rawData, BLOCK)
humidity1 = sht1.calcHumi(rawData1, temperature1);
delay(10);
temperature1 *= 100;
a = int(temperature1) + 1;
payload1[5] = a >> 8 & 0xff;
payload1[6] = a & 0xff;
humidity1 *= 100;
a = int(humidity1) + 1;
payload1[7] = a >> 8 & 0xff;
payload1[8] = a & 0xff;
**////////////////////////////// XBee send second packet ///////////////////////////////////////////////**
xbee = XBee();
xbee.begin(Serial);
zbTx = ZBTxRequest(remoteAddress,payload1, sizeof(payload1));
zbTx.setAddress16(0xfffe);
xbee.send(zbTx);
delay(500);
}
void TSR(int sensorValue)
{
illumindata = (sensorValue * 4 * 5) / 1.5;
pardata = 6250/6144*illumindata*10;
if(pardata > 0)
{
if(pardata < 11500)
{
real_pardata = 0.0000000020561*pardata*pardata*pardata -
0.00002255*pardata*pardata +
0.25788*pardata -
6.481;
if (real_pardata < 0)
{
real_pardata = 0;
}
pardata_hi = real_pardata/65535;
pardata_low = real_pardata%65535;
}
else
{
real_pardata = 0.0000049204*pardata*pardata*pardata -
0.17114*pardata*pardata +
1978.7*pardata -
7596900;
if (real_pardata < 0)
{
real_pardata = 0;
}
pardata_hi = real_pardata/65535;
pardata_low = real_pardata%65535;
}
}
else
{
pardata_hi = 0;
pardata_low = 0;
}
}
as I am writing this I have solved the same problem you have, though with similar hardware setup. I have used bare avr atxmega128a3u (so no arduino board) and an Xbee S1 communicating on baud rate 115200. After a few days trying to figure this out I came to conclusion, that if your avr is not running at precise clock (external xtal) and you use slightly "faster" baud rate ( >= 115200 ) Xbee's serial hardware has probably trouble recovering clock signal resulting in errors in transmission. (Maybe Xbee has slow bit sampling rate).
Anyway, by ensuring your microprocessor is running at stable clock (you should be safe here 'cause arduino has an external xtal) and by using slower baud rate (try 57600, 19200 or 9600) should solve your problem. I hope so. :) ...And don't forget to reconfigure Xbee's baud rate in XCTU.
And also it might help if you initliaze xbee only once.Move these lines into setup() function:
setup(){
// This is changed
Serial.begin(9600);
// This is new
xbee = XBee();
xbee.begin(Serial);
// ...
}
EDIT: Also you might be interested in this website where you can see what is the % of error for given clock frequency and baud rate (as well as direct register values to set if you were using bare avr) http://www.wormfood.net/avrbaudcalc.php?postbitrate=9600&postclock=16&hidetables=1

Resources