Pages: [1]   Go Down
Author Topic: Writing from Serial to Char array and then Serial.print(array) not working  (Read 887 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Sr. Member
****
Karma: 4
Posts: 289
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I have written a routine that is executed when serial data is available.  First it waits to make sure all bytes have been received and then it writes those bytes to a character array.  For debugging I wanted to then serially print that data back to the serial monitor to make sure that the data was coming in correctly.  When I execute the code I just get junk back on the Serial monitor.  I hope someone can tell me what I might be doing wrong.  My code is below:

Code:
void receive_serial()
{
  int i = Serial.available();
  delay(10);
 
  //wait to make sure that all bytes have been received
  while(i != Serial.available())
  {
    i = Serial.available();
    delay(10);
  }
 
  char myString[Serial.available()];
 
 
  while(Serial.available())
  {
    int j = 0;
    myString[j] = Serial.read();
    ++j;
     
  }
 
  Serial.print(myString);
}
Logged

Arduino Uno;
Mega328

Offline Offline
Edison Member
*
Karma: 19
Posts: 1041
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

That doesn't compile and not just because of the lack of setup() and loop() (the compiler can't find the length of myString)

Anyway, your problem is that you're Serial.print()ing the pointer to the start of the array without saying how long it is. The second argument to print when you're trying to do that is the number of characters to print.
Logged

0
Offline Offline
Sr. Member
****
Karma: 4
Posts: 289
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Sorry....this is all of the code:

Code:
/*
 * BBQControl.c
 *
 * Created: 8/7/2011 12:34:32 PM
 *  Author: Saleem and Leslie
 */

 

#define LCD_Command_A 0x7C
#define LCD_Command_B 0xFE
#define LCD_Clear_Screen 0x01
#define LCD_Cursor_Position(a) {Serial.print(LCD_Command_B,BYTE); Serial.print(a+128,BYTE);}
#define chipSelect 10

#include <math.h>
#include <stdint.h>
#include <PID_v1.h>
#include <stdio.h>

//PID Variables
double Input = 0;  //Our Current Temperature
double Output = 0;  //Our Control Variable
double Setpoint = 0;  //Our Setpoint
double Kp = 10;      //Proportional
double Ki = .1;      //Integral
double Kd = 50;      //Derivative

PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
 
void setup()
{
pinMode(A0,INPUT);
Serial.begin(9600);
        myPID.SetMode(AUTOMATIC);
}       

uint32_t count;


void loop()
{
    uint16_t ADCVal;
    uint16_t temperature;
    //String dataString = "";
   
    ADCVal = analogRead(A0);
   
    temperature = (get_temperature(ADCVal));
   
    for(int i = 0;i<98;i++)
    {
      ADCVal = analogRead(A0);
      temperature += (get_temperature(ADCVal));
    }
   
    temperature = temperature/100;
    Serial.println(temperature);
    Input = (double)temperature;
    myPID.Compute();
    Serial.println(Input);
    Serial.println(Output);
   
   if(Serial.available())
    {
      receive_serial();
    }
   
   
     
    delay(1000);
}

void receive_serial()
{
  int i = Serial.available();
  delay(10);
 
  //wait to make sure that all bytes have been received
  while(i != Serial.available())
  {
    i = Serial.available();
    delay(10);
  }
 
  char myString[Serial.available()];
 
 
  while(Serial.available())
  {
    int j = 0;
    myString[j] = Serial.read();
    ++j;
     
  }
 
  Serial.print(myString);
}

void get_parameters(uint16_t ADCvalue, uint16_t *beta, float *r_infinity)
{

if      (ADCvalue < 15)   {*beta = 5191; *r_infinity=0.07028;}
else if (ADCvalue <= 39)  {*beta = 5085; *r_infinity=0.08597;}
else if (ADCvalue <= 158) {*beta = 4942; *r_infinity=0.11637;}
else if (ADCvalue <= 530) {*beta = 4767; *r_infinity=0.17766;}
else if (ADCvalue <= 577) {*beta = 4671; *r_infinity=0.23249;}
else if (ADCvalue <= 670) {*beta = 4641; *r_infinity=0.25289;}
else if (ADCvalue <= 757) {*beta = 4604; *r_infinity=0.28168;}
else if (ADCvalue <= 832) {*beta = 4566; *r_infinity=0.31618;}
else if (ADCvalue <= 892) {*beta = 4526; *r_infinity=0.35779;}
else if (ADCvalue <= 938) {*beta = 4485; *r_infinity=0.40755;}
else if (ADCvalue <= 1023){*beta = 4453; *r_infinity=0.45243;}
return;
}


//*************Hardware SetUp***************
//
//     ADC Input
//        |
//        Rpad    |  Rtherm
// Vcc--------/\/\/\------/\/\/\------ground
//
//******************************************


float get_temperature(uint16_t ADCVal){
//temperature in kelvin = beta/ln(R/Rinfinity)
uint16_t beta = 0;
        uint8_t servo_command;
float Ri = 0;
float Rpad = 100000;
float Rtherm = Rpad/(1-((float)ADCVal/1024.0)) - 100000;
float Temperature;
float t;

get_parameters(ADCVal, &beta, &Ri);

t=beta/log(Rtherm/Ri);
t = ((9.0/5.0)*(t-273))+32;
Temperature = t;


//Out to LCD
//LCD_Cursor_Position(72);
//Serial.print(ADCVal);
        //Serial.print("    ");
//LCD_Cursor_Position(28);
        //Serial.print(beta);
        //Serial.print("    ");
//LCD_Cursor_Position(8);
return Temperature;

}
Logged

Arduino Uno;
Mega328

0
Offline Offline
Sr. Member
****
Karma: 4
Posts: 289
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

That makes sense that the compiler needs to know how much memory to allocate to myString but is there any way to do it on the fly?  I won't know before hand how many bytes are going to be sent.  It will be comma delimited data that I will need to break up into separate variables to update my Setpoint, Kp, Ki, and Kd variables.
Logged

Arduino Uno;
Mega328

Offline Offline
Edison Member
*
Karma: 19
Posts: 1041
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

That makes sense that the compiler needs to know how much memory to allocate to myString but is there any way to do it on the fly?  I won't know before hand how many bytes are going to be sent.  It will be comma delimited data that I will need to break up into separate variables to update my Setpoint, Kp, Ki, and Kd variables.

Ok, I guess that does compile, but I have no idea why. The general way to do it is to make the char array as big as the biggest set of data you'll need and then go from there. The String class does dynamically allocate memory, but that can lead to fragmentation and bad stuff.
Logged

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

The functions that operate on strings (lower case s) expect strings, not arrays of chars. The difference is that a string is an array of chars that is NULL terminated. Your array of chars is NOT a string, so you should not be passing the array to a function that expects a string, like Serial.print().

NULL terminate your array. Of course, that means that you need to make the array big enough to hold the NULL.
Logged

0
Offline Offline
Sr. Member
****
Karma: 4
Posts: 289
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The functions that operate on strings (lower case s) expect strings, not arrays of chars. The difference is that a string is an array of chars that is NULL terminated. Your array of chars is NOT a string, so you should not be passing the array to a function that expects a string, like Serial.print().

NULL terminate your array. Of course, that means that you need to make the array big enough to hold the NULL.

PaulS - Adding the NULL termination fixed it and it is echoing back the data perfectly!  Thank you for that fix.  To add the NULL I just added it manually via:

Code:
int j = 0;
  while(Serial.available())
  {
    
    myString[j] = Serial.read();
    ++j;
    
    
  }
  myString[j] = '\0';
  
  Serial.println(myString);

Is that the typical way to do it or did I characteristically do it the ugliest possible way?  Also WizenedEE brought up a good point that the compiler doesn't know how much space to allocate to myString at compile time so does the fact that it compiled and ran correctly mean that I am just getting lucky that I am not overwriting important stuff during the execution?  My code is still using this:

Code:
char myString[Serial.available()];
« Last Edit: January 01, 2012, 08:58:06 am by jerseyguy1996 » Logged

Arduino Uno;
Mega328

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

Quote
Is that the typical way to do it or did I characteristically do it the ugliest possible way?
I prefer to ensure that the string is always NULL terminated:
Code:
while(Serial.available())
  {
    myString[j] = Serial.read();
    ++j;
   myString[j] = '\0'; 
  }

Your way will work since you are using a while loop and terminating the array at the end of the while loop. My way, though, means that I don't have to remember to terminate it at the end of the loop.

Also, if you do any error checking, to be sure that there is room in the array for the new character, you also need to ensure that there is room for the NULL. With my way, you'd check that there is room for the character and NULL, once, and add them both.
Logged

0
Offline Offline
Sr. Member
****
Karma: 4
Posts: 289
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

All of these recommendations worked great!  Thank you PaulS and WizenedEE!
Logged

Arduino Uno;
Mega328

Pages: [1]   Go Up
Jump to: