0
Offline
Full Member
Karma: 2
Posts: 237
Arduino rocks
|
 |
« on: September 01, 2011, 05:15:48 pm » |
I am logging temperature data on an SD Card. I want to have the arduino write the temperature plus a number that represent the iteration number of the loop so: 0,74 1,74 2,74 3,74 4,74 5,74 6,74 7,74 8,74 9,74 10,74 11,74 0,74 1,74 2,74 3,74 4,74 5,74 6,74 7,74 8,74 9,74 10,74 11,74 You can see though that it iterates through the loop 12 times and then resets and starts over. It will do this indefinately. I thought perhaps I was exceeding RAM so I commented out a few serial.print lines but it still does it. If I remove the count variable and just write the temperature to the SD card it doesn't reset, or if I just run it without an SD Card it doesn't reset so it is definately something to do with count variable. Any ideas? Here is the total 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 <SD.h>
boolean _sd_available = false; void setup() { pinMode(A0,INPUT); Serial.begin(9600); initLCD(); //check for brownout if(MCUSR & (1<<BORF)) { LCD_Cursor_Position(84); Serial.print("Brownout Reset "); delay(2000); } //initialize SD card LCD_Cursor_Position(84); Serial.print("Initializing SD"); // make sure that the default chip select pin is set to // output, even if you don't use it: pinMode(10, OUTPUT); // see if the card is present and can be initialized: if (!SD.begin(chipSelect)) { LCD_Cursor_Position(84); Serial.println("SD Failed "); _sd_available = false; } else { LCD_Cursor_Position(84); Serial.println("SD Active "); _sd_available = true; } }
uint32_t count; void loop() { uint16_t ADCVal; uint16_t temperature; String dataString = ""; ADCVal = analogRead(A0); temperature = (get_temperature(ADCVal)); LCD_Cursor_Position(8); Serial.print(temperature); Serial.print(" "); if (_sd_available) { dataString += String(count++); dataString += ","; dataString += String(temperature); // open the file. note that only one file can be open at a time, // so you have to close this one before opening another. File dataFile = SD.open("logger.txt", FILE_WRITE); // if the file is available, write to it: if (dataFile) { dataFile.println(dataString); dataFile.close(); // print to the serial port too: //Serial.println(dataString); } // if the file isn't open, pop up an error: else { LCD_Cursor_Position(84); Serial.println("error opening "); } } delay(500); }
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 // //******************************************
uint16_t get_temperature(uint16_t ADCVal){ //temperature in kelvin = beta/ln(R/Rinfinity) uint16_t beta = 0; 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; }
void initLCD(){ delay(1000); //wait for LCD to wake up Serial.print(LCD_Command_B,BYTE); Serial.print(LCD_Clear_Screen,BYTE); //clear screen delay(20); LCD_Cursor_Position(0); Serial.print("Temp = "); //LCD_Cursor_Position(64); //cursor move to second line //Serial.print("ADC = "); //LCD_Cursor_Position(20); //cursor move to third line //Serial.print("Beta = ");
}
|
|
|
|
|
Logged
|
Arduino Uno; Mega328
|
|
|
|
Global Moderator
Melbourne, Australia
Offline
Shannon Member
Karma: 218
Posts: 13896
Lua rocks!
|
 |
« Reply #1 on: September 01, 2011, 08:22:35 pm » |
String dataString = ""; ...
dataString += String(count++); dataString += ","; dataString += String(temperature); That is going to gobble up RAM - concatenating strings.
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Sr. Member
Karma: 1
Posts: 360
I'm 15. I like making things. I like breaking things better.
|
 |
« Reply #2 on: September 01, 2011, 08:24:39 pm » |
The string concatenation seems like it may be the issue. You just keep adding to the same string. Why not append it to the file and then clear the string?
|
|
|
|
|
Logged
|
Alice asked the Chesire Cat, who was sitting in a tree, "What road do I take?" The cat asked, "Where do you want to go?" "I don't know," Alice answered. "Then," said the cat," it really doesn't matter, does it?"
-Lewis Carrol
|
|
|
|
0
Offline
Full Member
Karma: 2
Posts: 237
Arduino rocks
|
 |
« Reply #3 on: September 01, 2011, 08:37:12 pm » |
Doesn't: String dataString = ""; release the memory at the beginning of each loop? It doesn't seem to be creating a longer and longer string each time through the loop because what is being written to the SD card seems to be correct. If it was appending more and more values to the string it seems like the .txt file would look like this: 0,74 0,741,74 0,741,742,74 etc. How do I insure that the memory taken up by my string is released at the end of each iteration through loop?
|
|
|
|
|
Logged
|
Arduino Uno; Mega328
|
|
|
|
0
Offline
Sr. Member
Karma: 1
Posts: 360
I'm 15. I like making things. I like breaking things better.
|
 |
« Reply #4 on: September 01, 2011, 08:40:37 pm » |
Sorry-missed that. Thought you were constantly appending to the string, and re-writing the file each time.
Anyway, it is bad practice to rely on default values (your count variable is never defined) but this shouldnt be your issue. So you said if you replace the SD card writes with Serial prints, it doesnt happen? When you say reset, does the whole arduino actually reset, or just the count variable?
|
|
|
|
|
Logged
|
Alice asked the Chesire Cat, who was sitting in a tree, "What road do I take?" The cat asked, "Where do you want to go?" "I don't know," Alice answered. "Then," said the cat," it really doesn't matter, does it?"
-Lewis Carrol
|
|
|
|
Global Moderator
Melbourne, Australia
Offline
Shannon Member
Karma: 218
Posts: 13896
Lua rocks!
|
 |
« Reply #5 on: September 01, 2011, 08:41:29 pm » |
Doesn't: String dataString = ""; release the memory at the beginning of each loop? Yes it does, but the String class uses dynamic memory allocation. This is prone to fragmentation. Especially if you are making counters and things which get larger, it is going to be allocating different sized pieces of memory. Without checking your code in detail, you are probably better off using a static buffer, eg. char buf [20]; // or whatever size you think you need
sprintf (buf, "%i,%i", a, b); // print two numbers to buf
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Full Member
Karma: 2
Posts: 237
Arduino rocks
|
 |
« Reply #6 on: September 02, 2011, 08:23:59 am » |
So you said if you replace the SD card writes with Serial prints, it doesnt happen? When you say reset, does the whole arduino actually reset, or just the count variable? No, I commented out a few serial prints in order to use less RAM thinking that may be the problem. If I comment out all references to a "count" variable and just write the temperature to the SD card without a count I don't have the problem. Likewise if I don't have the SD card inserted at all (the program skips the code segment dealing with writing to the SD Card) I don't have the problem. The whole arduino resets. I thought maybe the writes to the SD card were pulling too much current so I put a check at the beginning of the program to see if the brownout flag was set but that doesn't seem to be the problem.
|
|
|
|
|
Logged
|
Arduino Uno; Mega328
|
|
|
|
0
Offline
Full Member
Karma: 2
Posts: 237
Arduino rocks
|
 |
« Reply #7 on: September 02, 2011, 08:35:09 am » |
Yes it does, but the String class uses dynamic memory allocation. This is prone to fragmentation. Especially if you are making counters and things which get larger, it is going to be allocating different sized pieces of memory. Without checking your code in detail, you are probably better off using a static buffer, eg. char buf [20]; // or whatever size you think you need
sprintf (buf, "%i,%i", a, b); // print two numbers to buf
So would I just do it with: sprintf(buf, "%i,%i", count++, temperature); dataFile.println(buf); //out to sd card
|
|
|
|
|
Logged
|
Arduino Uno; Mega328
|
|
|
|
New Jersey
Offline
Edison Member
Karma: 24
Posts: 2351
|
 |
« Reply #8 on: September 02, 2011, 08:57:43 am » |
That'll do it. Consider using snprintf instead though - defends against buffer overflow.
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Full Member
Karma: 2
Posts: 237
Arduino rocks
|
 |
« Reply #9 on: September 03, 2011, 05:42:22 pm » |
First off, Nick and Wildbill, your suggestions worked great. However, I ran into another problem. Is there any difference between: sprintf (buff, "%u,%u", count++, temperature); and sprintf (buff, "%u,%u", temperature, count++); The reason I ask is that the first method doesn't work. It adds count++ to the buffer but temperature always gets written to buff as zero such as: 0,0 1,0 2,0 3,0 The second method works great printing: 74,0 74,1 74,2 74,3
Here is the whole code segment: uint32_t count; void loop() { uint16_t ADCVal; uint16_t temperature; //String dataString = ""; char buff[15]; ADCVal = analogRead(A0); temperature = (get_temperature(ADCVal)); sprintf (buff, "%u,%u", temperature, count++); It wouldn't be the end of the world to have: temperature, count printed to the SD card but it bugs me as to why one way works and the other doesn't.
|
|
|
|
|
Logged
|
Arduino Uno; Mega328
|
|
|
|
Global Moderator
Melbourne, Australia
Offline
Shannon Member
Karma: 218
Posts: 13896
Lua rocks!
|
 |
« Reply #10 on: September 03, 2011, 06:01:33 pm » |
Your variable count is a 32-bit integer, whereas %u expects 16 bits. So it advances its internal point ahead 16 bits and prints 0 as the second value (being the other 16 bits of count). Either make count 16 bits, or make it %lu. This works: void setup () { char buff[15]; uint16_t temperature = 42; uint32_t count = 123; Serial.begin (115200); Serial.println ();
sprintf (buff, "Test: %lu, %u", count, temperature);
Serial.println (buff); }
void loop () { }
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Full Member
Karma: 2
Posts: 237
Arduino rocks
|
 |
« Reply #11 on: September 03, 2011, 06:25:28 pm » |
Once again that worked like a charm! I really appreciate your help!
|
|
|
|
|
Logged
|
Arduino Uno; Mega328
|
|
|
|
|