Pages: [1]   Go Down
Author Topic: Serial Read Issue (again)  (Read 953 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 43
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi, I thought I had my project all working but for some reason it is still not 100%.

Basically I have an AppleScript that is sending serial data to the Arduino Uno and the Uno is displaying it on an LCD.

It works great except for the fact that it only works when the Arduino serial monitor is open. At first it was the common problem of the board resetting with each serial read. I fixed this issue by cutting the trace on my Uno.

Currently, if I have my Uno running and the AppleScript sending data every 10 seconds, I will eventually get some corrupt data on my LCD.

As soon as I open the serial monitor and send data from my AppleScript, it works perfectly.

It's driving me nuts.

Any ideas?

Thanks.

Phil
Code:

#define SOP '<'
#define EOP '>'

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display


bool started = false;
bool ended = false;
int countStrt = 0;

char inData[80];
byte index;
int timeout=0;
int timeoutFlag=0;
long previousCount = 0 ;

void setup()
{
  Serial.begin(57600);
  lcd.init();
  lcd.backlight();
  lcd.clear();


}

void loop()
{




  if (timeout == 0 || timeout > 15) {    // test to see if the Arduino is still waiting

    previousCount = 0 ; // reset count
    if (timeoutFlag==0) { // to avoid LCD refresh
      lcd.clear();
      lcd.print("Waiting for App....");
      timeoutFlag =1;
    }


  }
  timeout++;


  while(Serial.available() > 0)
  {


    char inChar = Serial.read();
    if(inChar == SOP) //wait for start packet
    {

      timeoutFlag=0; // reset timeout flag
      timeout = 1; // got some data
      index = 0;
      inData[index] = '\0';
      started = true;
      ended = false;
    }
    else if(inChar == EOP)
    {
      ended = true;
      break;
    }
    else
    {
      if(index < 20)
      {

        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
    // Serial.println(inData);

    char* viewCount = inData; // convert inData to a string

    long newCount = atol(viewCount);


    // Serial.println(newCount);
    if (newCount != previousCount ){
      lcd.clear();
      lcd.print("YouTube Views");

      if (previousCount > 0){

        for (long z=previousCount; z < newCount; z++){ //count up the counter

            String newViewCount = String(z);
          lcd.setCursor(0, 1);
          lcd.print(newViewCount); // display viewCount
          // Serial.println(newViewCount); // display viewCount
          delay (10);
        }
      } // end count up loop

      String newViewCount = String(newCount);

      lcd.setCursor(0, 1);
      lcd.print(viewCount); // display viewCount
      // Serial.println(newViewCount); // display viewCount


        // Reset for the next packet

        previousCount = newCount;
      started = false;
      ended = false;
      index = 0;
      inData[index] = '\0';

    }
  }

  delay (1000);
}




Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 43
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Replying to my own thread here...

It seems to be an issue with incorrect NULL termination of my string.

I'm still trying to fix my code and am not sure what needs to be done exactly but I feel like I'm getting closer.

Again, any tips would be greatly received.

Phil


Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 614
Posts: 49365
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
    char* viewCount = inData; // convert inData to a string
Why? inData is perfectly acceptable as input to atol(), as long as it contains only numeric data (which making a pointer to point does nothing to ensure).

Code:
    long newCount = atol(viewCount);
Pretty optimistic, aren't you?

Code:
            String newViewCount = String(z);
          lcd.setCursor(0, 1);
          lcd.print(newViewCount); // display viewCount
You know that the print() method has an overload that takes a long, right? There is no need to waste resources converting the long to a String, and then copying that string to another string. (You know that you are invoking 3 constructors with that first statement, right? Two to create the String objects and one to copy the data from one to the other. Waste, waste, waste.)

Code:
      String newViewCount = String(newCount);
Three more constructors calls to get the long back to a character representation (that is already in inData). On top of this waste, you never use newViewCount.

None of this has anything to do with your problem, though they should be fixed.

Quote
Currently, if I have my Uno running and the AppleScript sending data every 10 seconds, I will eventually get some corrupt data on my LCD.

As soon as I open the serial monitor and send data from my AppleScript, it works perfectly.
This tells me that AppleScript is not configuring the serial port correctly.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 43
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Wow, thanks again for your input (you must be able to tell I'm a novice).

I'll reply to thew best of my knowledge....
Quote
Why? inData is perfectly acceptable as input to atol(), as long as it contains only numeric data (which making a pointer to point does nothing to ensure).
For some reason, I couldn't get atol() to work with my inData variable.

Quote
Pretty optimistic, aren't you?
My video is close to reaching 1000,000 views on YouTube, this counter is part of the celebration although it's looking like this serial problem might mean the project doesn't get done in time.

Quote
This tells me that AppleScript is not configuring the serial port correctly.

The big issue is the serial monitor problem. I am using a command line tool to send that data to the serial port, the tool is specifically written for Arduino. Information on that tool is here.

http://todbot.com/blog/2006/12/06/arduino-serial-c-code-to-talk-to-arduino/

I have hacked my script apart to just the basics as that might help discover the issue.

Basically all it does is:

Wait for something from the serial port.
If it is "<" then collect all of the following characters.
Once it get ">" stop reading the data.
Print data to the LCD.

Again this script only functions correctly if the serial monitor is open.

One more behavior is that if I open the serial monitor then close it, it often still works. Could it be that the serial monitor is doing some kind of initialization of the serial port?.

Anyway, here is my simplified code.

Code:
#define SOP '<'
#define EOP '>'

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display


bool started = false;
bool ended = false;
int countStrt = 0;

char inData[80];
byte index;
int timeout=0;
int timeoutFlag=0;
long previousCount = 0 ;

void setup()
{
   Serial.begin(57600);
   lcd.init();
   lcd.backlight();
   lcd.clear();


}

void loop()
{
 
 
     
  while(Serial.available() > 0)
  {   
     char inChar = Serial.read();
   
    if(inChar == SOP) //start packet
    {
   

      index = 0;
      inData[index] = '\0';
      started = true;
      ended = false;
    }
    else if(inChar == EOP)
    {
      ended = true;
      break;
    }
    else
    {
      if(index < 20)
      {

        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
    // Serial.println(inData);

     lcd.clear();

    lcd.print(inData);

       started = false;
      ended = false;
      index = 0;
      inData[index] = '\0';

   
}}

I would LOVE to figure this out before my video reaches 1000,000 views !!!

Thanks again.

Phil





Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 614
Posts: 49365
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Could it be that the serial monitor is doing some kind of initialization of the serial port?.
That is exactly what happens when you open the serial monitor.

Quote
For some reason, I couldn't get atol() to work with my inData variable.
Without more details, we can't help you. But, as you've seen, converting the text to a number, and converting the number back to text is unnecessary.

Quote
My video is close to reaching 1000,000 views on YouTube
Well, congrats. I didn't think you would be dealing with numbers that high.

Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 43
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks Paul, I am not too worried about my bad coding and inefficient use of variables (I will go back and fix all those in time).

What I really need help with is the serial read issue that only works effectively when serial monitor is open.

I am wondering what a next logical step would be in debugging my issue.

If we think it could be the arduino-serial app that I'm using to send the data, are there other tools I could use to test my setup?

I usually use OSX but have access to Windows Vista too.

Any idea of other tools that could send a string to a serial port?

Or, any other advice on this issue?

Thanks.

Phil

Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 43
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

wooop wooop.

I think I have figured it out.

I tried using "serialport x" to send the text to my arduino and it seems to be working perfectly !!!!

Thanks for all your help so far.

Phil
Logged

Pages: [1]   Go Up
Jump to: