Show Posts
Pages: [1]
1  Using Arduino / Networking, Protocols, and Devices / Re: Vaisala WXT520 weather sensor on: October 24, 2012, 12:51:59 pm
Paul, I can't thank you enough!!!
While you were answering my questions, I tried some changes an I've solved LF issue smiley
I'm waiting for '\n' as EOD marker, and I've changed println(inData) with simple print(inData) and now I have only CR (no LF) at the end of each record but the data is imported properly even w/o LF. I understand now what is happening, but don't understand how the "stripping" is done, I need more time to figure this and get it into my head!
Next goal is to try and parse Vaisala response in a way that only integers and "," are written into inData char array. At the moment I don't have an idea where to go with this, but will try to look at existing examples. If anyone have some kind of advice I'll be grateful. Maybe it would be easier to do this kind of parsing at PC, but I'd like to try with Arduino smiley
Thanks for all the help so far !!!
2  Using Arduino / Networking, Protocols, and Devices / Re: Vaisala WXT520 weather sensor on: October 24, 2012, 12:00:21 pm
I've made some progress by decreasing baud rate to 9600 for "SoftwareSerial" interface (vaisala). I've been going through code and since I wasn't able to find what is wrong, I'v tried lower baud rate and it started to work, I can capture entire response from device and almost never have wrong data (sometimes I get "#" instead of something else, eg. it should be "D", but "#" is written into log file.
As Paul suggested, I've played with sprintf() and it is OK for constructing my SD file name. I've tried to use the same approach for constructing the "time stamp" and that isn't working 100%, the problem is that for example "15:09" is printed as "15:9", "15:00" is printed as "15:0", ...  smiley-confuse). I can't explain in a better way, sorry  smiley-red. I'm assuming that it has something to do with INTs to CHAR, but I can't figure out how to insert those "0". When I import my log file into "spreadsheet app" it automatically adds these missing "0", but I think it shouldn't be left like this.
Another issue I'm facing is that when I power up my logger, "time stamp" in front of Vaisala response is printed OK, and in the next pass through loop "time stamp" gets a LF at the end (I don't know why) as shown in following picture:



Why is it that the first line is OK, and after that, there's a LF?
Thanks in advance!!!

Code:
#include <SPI.h>
#include <Wire.h>
#include "RTClib.h"
#include <SD.h>
#include <LiquidCrystal.h>
#include <SoftwareSerial.h>

RTC_DS1307 RTC;
char filename[] = "00000000.TXT";
char date_time[] = "2000/12/31,12:00";
const int chipSelect = 4;      // CS for SD card
LiquidCrystal lcd(14,15,5,6,7,8); // RS,EN,D4,D5,D6,D7
SoftwareSerial vaisala(2, 3); // RX, TX

long previousMillis = 0; // to store when was the last time data request have been sent
long interval = 5000; // how often should data be requested
char *req_data = "0R0"; //string to request data from sensor
byte index=0;
char inData[200];

void setup (){
  pinMode(14, OUTPUT); // RS for LCD, Ethernet Shield present, there's not enough digital pins
  pinMode(15, OUTPUT); // EN for LCD, Ethernet Shield present, there's not enough digital pins
  lcd.begin(16,2);
  Wire.begin();
  Serial.begin(9600);
  vaisala.begin(9600);
  lcd.print(" Vaisala WXT520 ");
  lcd.setCursor(0,1);
  lcd.print(" data logger v1 ");
  delay(3000);
  if (! RTC.isrunning()) {
    lcd.clear();
    lcd.print("RTC not OK");
    Serial.println("RTC is NOT running!");
    while(1);
  }
  //RTC.adjust(DateTime(__DATE__, __TIME__)); // uncoment to set the date and time (only when uploading the sketch)
  delay(100);
 
  Serial.print("Initializing SD card...");
  lcd.clear();
  lcd.print("SD card init...");
  delay(1000); // to be able to see the message
 
  pinMode(10, OUTPUT); // default CS pin (Ethernet Shield)
 
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    lcd.clear();
    lcd.print("SD error !!!");
    Serial.println("Card failed, or not present");
    while(1);
  }
  Serial.println("card initialized.");
  lcd.clear();
  lcd.print("SD card OK!");
  delay(1000); // to be able to see the message
 
} // end of setup()

void loop (){
 
  long currentMillis = millis();
  if(currentMillis - previousMillis > interval)
  {
    vaisala.println(req_data); // request data from Vaisala     
    previousMillis = currentMillis;
  }
 
  if (vaisala.available()){
    while (vaisala.available()){
    char inByte = vaisala.read();
    if (inByte == '\r'){ // if EOD is detected
      getFilename(filename); // call method that constructs the file name
      File dataFile = SD.open(filename, FILE_WRITE);
      if (dataFile)
        {
          lcd.clear();
          lcd.print("Receiving data");
          delay(300); // to stop LCD flickering
        }
         // if the file isn't open, pop up an error:
        else
        {
          lcd.clear();
          lcd.print(" File error ! ");
          while(1);
        }
      timestamp(date_time); // call method for creating timestamp
      dataFile.print(date_time);
      dataFile.println(inData); // print data from char array
      dataFile.close(); // close file
      inData[index] = '\0'; // erase char array
      index=0; // reset array index
      break; // exit while loop
    }
    else{ //write bytes from buffer
      inData[index] = inByte; // update char array
      index++; // increase index counter
      inData[index] = '\0'; // finish array so it qualify as string
    }
  } // end of while loop
 } // end of if(vaisala.available)
} // end of loop()

// method for constructing file name
void getFilename(char *filename) {
  DateTime now = RTC.now();
  int year = now.year();
  int month = now.month();
  int day = now.day();
  sprintf(filename,"20%d%d%d%d%d%d.TXT",(year-2000)/10,year%10,month/10,month%10,day/10,day%10);
  return;
}

// method for creating timestamp string
void timestamp(char *date_time){
  DateTime now = RTC.now(); // collect date and time data
  int year = now.year();
  int month = now.month();
  int day = now.day();
  int hour = now.hour();
  int minute = now.minute();
  sprintf(date_time,"%d/%d/%d,%d:%d,",year,month,day,hour,minute);
  return;
}
3  Using Arduino / Networking, Protocols, and Devices / Re: Vaisala WXT520 weather sensor on: October 21, 2012, 02:02:56 pm
Here is another test sketch (I'm sending the command to Vaisala and the response is less than 63 bytes, all is working OK).
Whit this sketch I wanted to check if there is CR+LF at the end of response, and I'm 100% sure that it is there (CR+LF).
I'm using "Serial.print" command, and each response is printed on a new line, so CR+LF is there !
Code:
#include <SoftwareSerial.h>
SoftwareSerial vaisala(2, 3); // RX, TX
long previousMillis = 0; // to store when was the last time data request have been sent
long interval = 5000; // how often should data be requested
char *command = "0XU"; //string to request data from sensor
byte i=0;
char inData[200];
boolean ended = false;


void setup (){
  Serial.begin(19200);
  Serial.flush();
  vaisala.begin(19200);
  vaisala.flush();
}

void loop (){
 
  long currentMillis = millis();
  if(currentMillis - previousMillis > interval)
  {
    vaisala.println(command); // request data from Vaisala     
    previousMillis = currentMillis;
  }
  while (vaisala.available()>0){
    char inByte = vaisala.read();
    inData[i] = inByte;
    /* response is less than 63 bytes,
    CR+LF is at the end of each response,
    and in Serial monitor each new line is OK,
    so CR+LF is there 100%, if there was no CR+LF,
    each responce would be printed on same line*/
    Serial.print(inData[i]);
    i++;
  }
  i=0;
  inData[i] = '\0';
}

In the following image, I present the output from "Vaisala monitor" and "Serial monitor". If I could only rewrite the above code to work with more than 63 bytes... smiley-red

4  Using Arduino / Networking, Protocols, and Devices / Re: Vaisala WXT520 weather sensor on: October 21, 2012, 01:28:58 pm
1. My understanding is that I just need to set enough "places" in array so [200] is enough, I didn't know that it's wrong to actually have less than maximum in an array (if it is properly ended with a '\0'). Anyway, even if I match these two (array[xxx] and counter i<(xxx-1)), result is same.
2. I didn't bother to check why "blink / no delay" example is using "unsigned", I've just copied piece of code and this part is working like a charm, command is sent every X seconds.

Every piece of code I've found is working OK if Vaisala response is in the limits of 63 bytes!
I've tried a bunch of other approaches to capture 162 bytes as one record, but in all of them I can't detect EOD byte, to be exact, I never enter into "if (inChar == '\n') part of code. I'm starting to doubt the information in Vaisala documentation about CR/LF at the end of each response, but on the other hand, if I capture the data using some terminal application (Tera Term), and import that data into "Notepad++", CR+LF is clearly visible  smiley-roll
5  Using Arduino / Networking, Protocols, and Devices / Re: Vaisala WXT520 weather sensor on: October 20, 2012, 11:47:16 am
Here is a temporary test sketch (just to solve the Vaisala communication part) and if this part doesn't work properly there's no point to continue with rest of code features (RTC, SD Card, LCD). I've removed delay() and used millis() and that part is working OK (thanks PaulS!!).

Code:
#include <SoftwareSerial.h>

#define EOD '\n' // EOD - end of data marker

boolean ended = false;

long previousMillis = 0; // to store when was the last time data request have been sent
long interval = 5000; // how often should data be requested

char *command = "0R0"; //string to request data from sensor
char inData[200]; // char array for storing received bytes
byte i; // byte type is enough for storing received string
SoftwareSerial vaisala(2, 3); // RX, TX
 
void setup()
{
  Serial.begin(19200);
  vaisala.begin(19200);
}
 
void loop()
{
  unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval)
  {
    vaisala.println(command); // request data from Vaisala     
    previousMillis = currentMillis;
  }
 
  while(vaisala.available() > 0)
  {
    char inChar = vaisala.read();
    if(inChar == EOD)
    {
       ended = true;
       break;
    }
    else
    {
      if(i < 163)
      {
        inData[i] = inChar;
        i++;
        inData[i] = '\0';
      }
    }
  }
  if(ended)
  {
    Serial.println(inData);
    // Reset for the next packet
    ended = false;
    i = 0;
    inData[i] = '\0';
  }
}

This is what Vaisala have sent:
0R0,Dn=164D,Dm=192D,Dx=227D,Sn=0.0M,Sm=0.1M,Sx=0.2M,Ta=23.8C,Ua=49.6P,Pa=1010.0H,Rc=0.00M,Rd=0s,Ri=0.0M,Hc=0.0M,Hd=0s,Hi=0.0M,Th=23.8C,Vh=0.0N,Vs=14.4V,Vr=3.501V

And this is the only data visible in Serial monitor (only 3 lines of data, received over a period of couple of minutes, but Arduino have requested the data every 5 seconds, so it shoud be many more lines in Serial monitor. If I wait longer, Serial monitors shows new line with similar incorrect data):

0R0,Dn=162D,Dm=175D,Dx=188D,Sn=0.0M,Sm=0.1M,Sx=0.2M,Ta=23.8C,Ua=49.900=,,ih==r
0R0,Dn=190D,Dm=198D,Dx=212D,Sn=0.0M,Sm=0.1M,Sx=0.2M,Ta=23.8C,Ua=49.91=d0MHhhsVV0R0,Dn=150D,Dm=167D,Dx=190D,Sn=0.0M,Sm=0.1M,Sx=0.1M,Ta=23.8C,Ua=49.9..0HH==01=0R0,Dn
0R0,Dn=150D,Dm=174D,Dx=207D,Sn=0.0M,Sm=0.1M,Sx=0.2M,Ta=23.8C,Ua=50.11R,i.sMC,V00R0,Dn=153D,Dm=190D,Dx=212D,Sn=0.0M,Sm=0.1M,Sx=0.2M,Ta=23.8C,Ua=50.11==0MHThsr0R0,D


Just for reference, Vaisala is repeating a command in its response (in this case 0R0) and every line in Serial monitor is starting OK, but as you go further, errors are starting to happen. My conclusion is that the problem lies in EOD (CR+LF) detection. Other than that I'm in the dark, so please advise, thanks!
6  Using Arduino / Networking, Protocols, and Devices / Re: Vaisala WXT520 weather sensor on: October 20, 2012, 03:50:36 am
I think I've understood your point regarding delay(), and will try to switch to millis().
If serial buffer is based on FIFO, I don't see any problem about incoming data length, as long as there is incoming data my 'while available()>0' condition should be TRUE, and my 'inData char array' should be populated properly. However, the data is coming very fast and if I print the value of 'available()' in Serial monitor I can see that it is always begins with 63 and counts down to 0, so the buffer is read OK and sketch is working good if data is less than 63 bytes. If data is more than 63 bytes, I can't understand what is happening smiley-sad

Forgive my lack of knowledge, but I'm eager to get this into my head and try to learn what is going on  smiley-red
7  Using Arduino / Networking, Protocols, and Devices / Re: Vaisala WXT520 weather sensor on: October 19, 2012, 04:21:16 pm
I've managed to receive the data from sensor, but only by using 'for' loop. I did the same for reading and printing the buffer. This only works if length of data is smaller than 63 bytes, if length is larger (in my case, each received message is between 150 and 170 bytes long, depending on measured values), everything falls apart smiley-sad
I can customize the content of message in order to make it shorter, but it would be shame to lose all that info coming from device.
I've read of possibility to increase the buffer, but that is beyond my capabilities.
The biggest problem is how to detect 'end of message', I simply can't catch that info!
8  Using Arduino / Networking, Protocols, and Devices / Re: Vaisala WXT520 weather sensor on: October 19, 2012, 02:51:19 pm
1. Baud rate is "19200" and I know that END marker should be CR+LF. I've used '\n' but I don't think it's detected properly. My code is working when I'm using another PC, if I type a couple of characters and hit 'enter', Arduino receives it OK and all looks well (even if I comment '\0' line). So, I'm thinking that Vaisala device "can't hit 'enter' " or I don't know how to capture it, or how to mach the end of data.
When I did some testing using PC2 and opened a file from SD card (using Notepad++) I can see that every line that was received by Arduino is ended with CR+LF, so '\n' should be OK for 'end of data marker', but I can't figure out why it's not working when Vaisala is attached  smiley-sad

2. I need to send "0XR" command every time when I want new data from Vaisala. So, whenever I read one set of data, I need to send new request (pool the data) in order to receive new set of data. My idea is to set the delay at the end of loop(). If I want to query for data every 10 seconds, delay would be (10000). If there is some other solution I'll be glad to try it.
3. about sprintf() - will take a look and try to understand why it is better (this part in my code, and almost everything else, is copied from existing examples).
I'll do my best to make some progress, thanks a lot for all the comments and suggestions PaulS !!!
9  Using Arduino / Networking, Protocols, and Devices / Re: Vaisala WXT520 weather sensor on: October 19, 2012, 12:09:50 pm
Finally, I have my weather sensor operational. I can send and receive the data using terminal programs.
Unfortunately, my sketch is not working as I would like. I can send a "command" to Vaisala, but the response is not received properly.
I'm sure that Vaisala is sending the requested data because I have a separate "service connection" active and there is a "Vaisala monitor utility" where I can see all serial messages received and sent by Vaisala device.
I've tried to make some kind of debugging with LCD and Serial monitor, but got lost in the code, so I removed all these attempts.
Here is my sketch, so any suggestions are more than welcome:
Code:
#include <SPI.h>
#include <Wire.h>
#include "RTClib.h"
#include <SD.h>
#include <SoftwareSerial.h>
#include <LiquidCrystal.h>

/* vaisala stuff */
#define EOD '\n' // EOD - end of data marker
boolean ended = false; // using for condition
char *command = "0XU"; //string to request data from sensor
char inData[128]; // char array for storing received bytes
byte index; // byte type is enough for storing received string
SoftwareSerial vaisala(2, 3); // RX, TX
RTC_DS1307 RTC;
char filename[] = "00000000.TXT";
const int chipSelect = 4;      // CS for SD card
LiquidCrystal lcd(14,15,5,6,7,8); // RS,EN,D4,D5,D6,D7
 
void setup()
{
  pinMode(14, OUTPUT); // RS for LCD, Ethernet Shield present, there's not enough digital pins
  pinMode(15, OUTPUT); // EN for LCD, Ethernet Shield present, there's not enough digital pins
  lcd.begin(16,2);
  Serial.begin(19200);
  Wire.begin();
  vaisala.begin(19200);
  lcd.print(" Vaisala WXT520 ");
  lcd.setCursor(0,1);
  lcd.print(" data logger v1 ");
  delay(3000);
  if (! RTC.isrunning()) {
    lcd.clear();
    lcd.print("RTC not OK");
    Serial.println("RTC is NOT running!");
    //RTC.adjust(DateTime(__DATE__, __TIME__));
  }
  delay(100);
  Serial.print("Initializing SD card...");
  lcd.clear();
  lcd.print("SD card init...");
  delay(1000); // to be able to see the message
 
  pinMode(10, OUTPUT);
 
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    lcd.clear();
    lcd.print("SD error !!!");
    Serial.println("Card failed, or not present");
    return;
  }
  Serial.println("card initialized.");
  lcd.clear();
  lcd.print("SD card OK!");
  delay(1000); // to be able to see the message
  lcd.clear();
  lcd.print(" Receiving data ");
 
}
 
void loop()
{
  vaisala.println(command); //println because CR+LF must be sent
  // Read all serial data available, as fast as possible
   
  while(vaisala.available() > 0) // this should become FALSE when there is no more new bytes - it will be -1
  {
    delay(200); // let the buffer fill up
    char inChar = vaisala.read(); // every byte from buffer will be compared to EOD
    if(inChar == EOD) // if EOD is detected, set 'ended' to TRUE and get out of while loop (jump to packet processing section)
    {
       ended = true;
       break; // exit WHILE loop
    }
    else
    {
    if(index < 127) // EOD not detected so loop further through indexes
      {
        inData[index] = inChar;
        index++;
        // if following line is uncomented, I get one empty line after each line of data !!!
        //inData[index] = '\0'; // terminate with a NULL so that char array can qualify as string
      }
    }
  }
 
  if(ended) //EOD marker detected, process data
  {
      DateTime now = RTC.now();                              // get time from RTC 
      getFilename(filename); // call method that constructs the file name using "date" data
      File dataFile = SD.open(filename, FILE_WRITE);
 
        // if the file is available, write to it:
        if (dataFile)
        {
          // time stamp from RTC
          dataFile.print(now.day(), DEC);
          dataFile.print('/');
          dataFile.print(now.month(), DEC);
          dataFile.print('/');
          dataFile.print(now.year(), DEC);
          dataFile.print(" , ");
          dataFile.print(now.hour(), DEC);
          dataFile.print(':');
          dataFile.print(now.minute(), DEC);
          dataFile.print(" , ");
          dataFile.println(inData);
          dataFile.close();
          Serial.println(inData); // attach received data
        }
         // if the file isn't open, pop up an error:
        else
        {
          Serial.print("error opening ");
          Serial.println(filename);
        }
     // Reset for the next packet
    ended = false;
    index = 0;
    //inData[index] = '\0';
  }
     delay(5000); // how often to query for new data from serial device
}

// method for constructing the file name
void getFilename(char *filename) {
  DateTime now = RTC.now();
  int year = now.year();
  int month = now.month();
  int day = now.day();
  filename[0] = '2';
  filename[1] = '0';
  filename[2] = (year-2000)/10 + '0';
  filename[3] = year%10 + '0';
  filename[4] = month/10 + '0';
  filename[5] = month%10 + '0';
  filename[6] = day/10 + '0';
  filename[7] = day%10 + '0';
  filename[8] = '.';
  filename[9] = 'T';
  filename[10] = 'X';
  filename[11] = 'T';
  return;
}

Either I'm not detecting end of line marker (which is CR+LF), or there is some other error.
LCD is showing "Receiving data" message, but in Serial monitor I can't see received data, and SD card is empty (the file havent been created at all because no data is processed).

Thanks in advance!
10  Using Arduino / Networking, Protocols, and Devices / Re: Vaisala WXT520 weather sensor on: October 11, 2012, 01:41:36 pm
1,2 and 3 perfectly CLEAR, thanks Paul!
I'll try to create a test sketch to verify all you mentioned.
Since I can't try it on actual Vaisala sensor, I'll use a terminal on another PC and route typed text to Serial monitor.
If everything is OK with a sketch, I shouldn't see any data in serial monitor until I hit ENTER on PC2.

11  Using Arduino / Networking, Protocols, and Devices / Re: Vaisala WXT520 weather sensor on: October 11, 2012, 12:45:09 pm
PaulS, thank you for the example code!
I'm starting to get the logic for populating char array, but still can't resolve a couple of things.

1. I'm assuming that every response from device has CR+LF so I should use that information to finish reading the serial buffer, but I don't know the proper way to translate this into code.
In your example you're defining '>' for EOP. What should I use instead of > to detect CR?
a) '\0'
b) 13
c) something else

2. Why are you defining a BYTE for index?
I can understand the counter approach but I've always used an INT for this, so I'm confused.

3. Can you please explain the use of '\0'? I know that it is treated as byte an it is used for ending a string.

Thanks for your effort to help me!
12  Using Arduino / Networking, Protocols, and Devices / Re: Vaisala WXT520 weather sensor on: October 11, 2012, 08:51:05 am
Thanks for fast response!

1. I will take a look what is a difference using char and pointer (*), thanks for advice.
2. Yes, I need to send "request command" every time when I want to receive data, so I think it's OK to do it in a loop()

About my understanding of Serial: I was trying to explain that I know how to use Serial monitor and basic operations (read/write), I don't have a good knowledge regarding Serial class  smiley-red

I think that each response from device is finished with CR+LF (but I'll confirm this when my RS485 converter arrives), so I'll try to take that to stop reading the "vaisala" port. The biggest problem for me is to understand how to construct "char array" and check for "CR+LF". As I said, I've followed a couple of tutorials regarding this, but still can't get it into my head.

Thanks for all the help!
13  Using Arduino / Networking, Protocols, and Devices / Vaisala WXT520 weather sensor on: October 10, 2012, 03:36:50 pm
I'm new to Arduino, and eager to learn but there is too many information regarding same problems and I'm simply lost.
I would like to make a RS232 to SD data logger but I'm stuck when it comes to dealing with serial communication.
I'm aware that it has already been discussed and there are good tutorials (even already built loggers) but I would like to make it from scratch and get into this amazing Arduino world.
I understand "Serial" and Serial monitor, and I've been practicing with it, but can't figure out the best way to solve the following:
1. Send "0R0+CR+LF" via SoftwareSerial
2. Capture the response from device via SoftwareSerial and display it on Serial monitor (in the code comments, you'll see how the response looks like).
This is just a beginning, later I plan to write received string on SD card (just pass it as it is, without parsing it as it is already CSV).
I've built a RS232 shifter and it is working when I connect Arduino to another PC running terminal application (I can chat using Serial monitor and PC2).
 
Code:
/*Arduino Uno logger for Vaisala WXT520 weather sensor*/

#include <SoftwareSerial.h>

SoftwareSerial vaisala(2, 3); // RX, TX

String command = "0R0"; //request data from sensor, must be followed with CR+LF
String data = ""; // maybe change this approach and not use String

void setup()  
{
  vaisala.begin(19200); // default device settings are 19200,8,N,1
}

void loop()
{  
  vaisala.println(command); //println because CR+LF must be sent

//device will return the following string:
//  0R0,Dx=005D,Sx=2.8M,Ta=23.0C,Ua=30.0P,Pa=1028.2H,Rc=0.00M,Rd=10s,Th=23.6C<cr><lf>
/* capture whole received string and print it to Serial Monitor */
 if (vaisala.available()>0)
    data = vaisala.read();
  
  Serial.println(data);
  delay(2000); //
}

Unfortunately, I can't test this sketch because I can't properly communicate with the mentioned device but that is another issue I'll try to solve myself (I think built in RS232 port on device is broken, so I'll try to use RS485 but I'm waiting RS485/232 converter to arrive).
Regarding the device response given in the code comment, what is the best approach to deal with it?
Thanks in advance!!!
Pages: [1]