Go Down

Topic: Vaisala WXT520 weather sensor (Read 3533 times) previous topic - next topic

fermevc

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: [Select]

#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!

PaulS

Code: [Select]
char inData[200]; // char array for storing received bytes

      if(i < 163)
      {
        inData[i] = inChar;
        i++;
        inData[i] = '\0';
      }

You have a 200 element array that you are leaving the last 36 elements unused. Why is that?

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

  unsigned long currentMillis = millis();

  if(currentMillis - previousMillis > interval)
  {

Why are you mixing signed and unsigned?

fermevc

#17
Oct 21, 2012, 08:28 pm Last Edit: Oct 21, 2012, 09:06 pm by fermevc Reason: 1
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:

fermevc

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: [Select]

#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:


fermevc

#19
Oct 24, 2012, 07:00 pm Last Edit: Oct 24, 2012, 07:04 pm by fermevc Reason: 1
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", ...  :~). 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: [Select]

#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;
}

PaulS

Quote
I can't explain in a better way, sorry

You need to put a 0 in front of the width, to pad with 0s.

%2d will format an integer to take no more than 2 characters. %02d will format an integer to take exactly 2 characters, with leading 0's if the value is less than 10.

Quote
Why is it that the first line is OK, and after that, there's a LF?

Because the string is terminated with a CR and an LF and you are only stripping out the CR.

fermevc

Paul, I can't thank you enough!!!
While you were answering my questions, I tried some changes an I've solved LF issue :)
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 :)
Thanks for all the help so far !!!

PaulS

Quote
Maybe it would be easier to do this kind of parsing at PC, but I'd like to try with Arduino

A hint, then. It's done exactly the same way - strtok() and atoi().

To properly solve the CR/LF issue:
Code: [Select]
    if (inByte == '\r' || inByte == '\n') // If character is LF or CR
{
   if(strlen(inData) > 0) // Make sure there is some data
   {
      // Write to the file and do other stuff

Go Up