Serial print refresh time

Hi guys,

Had an Arduino (Uno) for a while now, but never used these forums. I've got a simple sketch reading the output of an LM35 temp sensor to define the PWM duty cycle of an output to control a fan. I'm also outputting the temperature via serial to the serial monitor. I've got a delay(200) at the end of the loop so that the temp is only sent once every 1/4s, however - I've just noticed, this is holding up the entire loop for that time too.

Now - I'm well aware temp sensors take a while to respond, and so waiting such a time isn't actually a problem here at all, the system responds perfectly well... but, for future reference - how do I send the temp via serial at set intervals, yet not hold up the rest of the loop from, well - looping again!

Furthermore, as you can see in the code - I've got the temp, and "deg C" on two different prints, followed by a blank println - how can I get these two little snippets to appear on the same line in the serial monitor, with one line of code. I thought maybe Serial.println(temp, "deg C"); may work, but not so.

Many thanks in advance!

int tempPin = 1; // defines the LM35 input into analogue pin 1
int valFan = 0; // creates an integer used for temperature mapping, this being mapped fan speed - default to 0
int fanPin = 9; // defines the fan output connected to digital pin 5
int onboardLED = 13;

void setup()
{
  analogReference(INTERNAL); // sets ADC ref voltage to internal 1.1v to increase resolution
  pinMode(fanPin, OUTPUT); // defines fanPin as an output
  pinMode(onboardLED, OUTPUT); // defines onboardLED as an output
  digitalWrite(onboardLED, LOW); // turns off onboard pin 13 LED
  Serial.begin(9600); // initialises serial comms at 9600 baud rate
  digitalWrite(fanPin, HIGH); // pulses fan output to max
  delay(250); // waits 250ms
  digitalWrite(fanPin, LOW); // then switches output to fan off before commencing loop, helps to kickstart sticky fans into motion at low PWM duty cycles
}

void loop()
{
  valFan = map(analogRead(tempPin), 0, 500, 0, 255); // used to map valFan between 0 and 255 for PWM, between 2 and 55 degrees C (LM35 output = 0v @ 2deg C, + 10mV/degC)
  valFan = constrain(valFan, 0, 255); // sets limits of valFan
  analogWrite(fanPin, valFan); // write PWM to fanPin
  int temp = (1.1 * analogRead(tempPin) * 100 / 1024); // converts analog reading into degrees C
  Serial.print(temp); // prints to serial monitor
  Serial.print(" deg C");
  Serial.println("");
    delay(200); // updates serial monitor every 200ms (+ miniscule execution time of the rest of the loop)
}

Check the blink without delay example to see how to perform an action at every given interval without using delay().

jtw11:
Furthermore, as you can see in the code - I've got the temp, and "deg C" on two different prints, followed by a blank println - how can I get these two little snippets to appear on the same line in the serial monitor, with one line of code. I thought maybe Serial.println(temp, "deg C"); may work, but not so.

Serial.print("This "); 
Serial.print("prints on "); 
Serial.println("the same line!");

Arrch:

Serial.print("This "); 

Serial.print("prints on ");
Serial.println("the same line!");

Sorry, the question was worded a little strange - what I meant is, using the code the way I've written it does print "32 deg C" for example on a fresh serial monitor line each time, I meant is there a command so that I can code it in one line, in the program, itself.

jtw11:
Sorry, the question was worded a little strange - what I meant is, using the code the way I've written it does print "32 deg C" for example on a fresh serial monitor line each time, I meant is there a command so that I can code it in one line, in the program, itself.

sprintf() function will allow you to format a null terminated char array (string) with variables.

Brilliant, just tested the new code without a delay (set serial output to 20 seconds for test) - and it everything else responds instantly. Thanks very much! Here's the code if you're interested. Will look into cleaning up the serial commands themselves though.

int tempPin = 1; // defines the LM35 input into analogue pin 1
int valFan = 0; // creates an integer used for temperature mapping, this being mapped fan speed - default to 0
int fanPin = 9; // defines the fan output connected to digital pin 5
int onboardLED = 13;
long previousMillis = 0;
long interval = 20000;

void setup()
{
  analogReference(INTERNAL); // sets ADC ref voltage to internal 1.1v to increase resolution
  pinMode(fanPin, OUTPUT); // defines fanPin as an output
  pinMode(onboardLED, OUTPUT); // defines onboardLED as an output
  digitalWrite(onboardLED, LOW); // turns off onboard pin 13 LED
  Serial.begin(9600); // initialises serial comms at 9600 baud rate
  digitalWrite(fanPin, HIGH); // pulses fan output to max
  delay(250); // waits 250ms
  digitalWrite(fanPin, LOW); // then switches output to fan off before commencing loop, helps to kickstart sticky fans into motion at low PWM duty cycles
}

void loop()
{
  valFan = map(analogRead(tempPin), 0, 500, 0, 255); // used to map valFan between 0 and 255 for PWM, between 2 and 55 degrees C (LM35 output = 0v @ 2deg C, + 10mV/degC)
  valFan = constrain(valFan, 0, 255); // sets limits of valFan
  analogWrite(fanPin, valFan); // write PWM to fanPin
  unsigned long currentMillis = millis();
  if(currentMillis - previousMillis > interval)
  {
    previousMillis = currentMillis;
    int temp = (1.1 * analogRead(tempPin) * 100 / 1024); // converts analog reading into degrees C
    Serial.print(temp); // prints to serial monitor
    Serial.print(" deg C");
    Serial.println("");
  }
}
1 Like

Looks good.

As good practice, I would also make the pins and interval constants.

Arrch:
Looks good.

As good practice, I would also make the pins and interval constants.

Sorry - not quite with you. Are you referring to the 'long interval = 20000"? ...and as for the pins?

jtw11:
Sorry - not quite with you. Are you referring to the 'long interval = 20000"? ...and as for the pins?

Yes. It's not going to make a difference with your current code, but it's good practice to define them as constants if there is no plan to change them within the code.

Hmm - nope, still not got it! :smiley:

Do you mean, as opposed to 'long interval', write 'long const interval'? 'const interval' throws an error at me.

As for pins, what isn't quite best practice?

You'll have to excuse me - before Arduino, I had no experience whatsoever with any C variant.

jtw11:
Do you mean, as opposed to 'long interval', write 'long const interval'? 'const interval' throws an error at me.

const unsigned long interval =

As for pins, what isn't quite best practice?

Not sure what you mean by that.

Something like:

const int tempPin = 5;

would be best practice. You could also change it to a short, but I don't know which way the compiler handles constant declaration, so I'm not sure if that's necessary.

Ah okay, I see where you're coming from.

const int tempPin = 1; // defines the LM35 input into analogue pin 1
int valFan = 0; // creates an integer used for temperature mapping, this being mapped fan speed - default to 0
const int fanPin = 9; // defines the fan output connected to digital pin 5
const int onboardLED = 13;
long previousMillis = 0;
const unsigned long interval = 500;

What exactly is the benefit to defining pins and intervals in this way?

If there are lots of references to them, there's only one place to change them if you decide to move a pin, or need a little longer to do something.

AWOL:
If there are lots of references to them, there's only one place to change them if you decide to move a pin, or need a little longer to do something.

I see what you're trying to say, but using 'int tempPin = 1;' for example, I simply reference tempPin in the program, and if I want to change the pin, I just change the 1 for something else.

So why, 'const int tempPin = 1;' instead of the old 'int tempPin = 1;'?

So why, 'const int tempPin = 1;' instead of the old 'int tempPin = 1;'?

The "const" tells the compiler the value will never change. Therefore, instead of allocating a variable and taking up valuable RAM space, and slowing the system down reading and writing from RAM, it just uses the number "1".

It's functionally the same as

#define tempPin 1

but has the advantage that it is typecast to an int.

jtw11:

AWOL:
If there are lots of references to them, there's only one place to change them if you decide to move a pin, or need a little longer to do something.

I see what you're trying to say, but using 'int tempPin = 1;' for example, I simply reference tempPin in the program, and if I want to change the pin, I just change the 1 for something else.

So why, 'const int tempPin = 1;' instead of the old 'int tempPin = 1;'?

If you mess up and change that value somewhere in your code, your code will still compile fine, but you're likely to see logic errors. By defining it as a constant, you're compiler will throw an error if you mess up and try and change the value in the code and it's A LOT easier to debug compiler errors than it is logic errors.

Also, in reply to how to join your strings together into one print - you can use sprintf to build up a string before printing to serial:

char buffer[80];

// ...

sprintf(buffer,"The temperature is %f degrees C", temperature);

Serial.println(buffer);

where %f is a placeholder for a "float" or "double" variable - there are others for other variable types - plenty of references online.

majenko:

So why, 'const int tempPin = 1;' instead of the old 'int tempPin = 1;'?

The "const" tells the compiler the value will never change. Therefore, instead of allocating a variable and taking up valuable RAM space, and slowing the system down reading and writing from RAM, it just uses the number "1".

It's functionally the same as

#define tempPin 1

but has the advantage that it is typecast to an int.

Aha, that's the explanation I was looking for! (thanks to everybody else too!) On that subject, are there any other ways to reduce the program size, as this sketch actually forms part of a complete automated engine dyno control program.

are there any other ways to reduce the program size

Yes. Write it in assembly instead of C++.

But seriously, some tips:

  1. Avoid float / double - the floating point library adds loads of bulk.
  2. Don't use variables bigger than you need. The processor is 8-bit. Anything bigger than a BYTE or CHAR uses extra instructions to emulate a larger value.
  3. Think about the flow of your program. Write it tight, and the resultant program will be tight.

Having taken snippets and applied them for use in my code from the 'blink without delay' example, could somebody please explain to me the use of 'unsigned long' in place of 'int'? It seems 'int' takes up just a few bytes more, but I'm not sure what 'unsigned long' really is, or indeed why the example uses it. English please? :smiley:

const int tempPin = 1; // defines the LM35 input into analogue pin 1
int valFan = 0; // creates an integer used for temperature mapping, this being mapped fan speed - default to 0
const int fanPin = 9; // defines the fan output connected to digital pin 5
const int onboardLED = 13;
long previousMillis = 0;
const unsigned long interval = 500;

The "const unsigned long" is just seen as (and takes up the room of) 500.

However, when it's being used in comparisons, it's being combined with / compared against other values that are unsigned long. This just helps the compiler to know what it's doing so it doesn't get confused between different length variables.

For example, if you subtract an int from a long, should the result be an int or a long? If you're putting it in a variable, then it's whatever the destination variable is cast as. If you're just using it as a comparison, what then? By telling the compiler it's an unsigned long, it's telling it that the value is of the same type as that returned by the millis() function.

Unsigned long is twice as big (RAM wise) as an int. As it's a "const" though, it doesn't use RAM.

Byte, char - 8 bits.
Int, short - 16 bits.
Long - 32 bits.
Long long - 64 bits.

(the "unsigned" doesn't affect the size, just the range of the content)

Oh, and

long previousMillis = 0;

should really be

unsigned long previousMillis = 0;

to keep the signs the same.