Serial print refresh time

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.

Ah, I was just about to ask that question - one signed, one unsigned. So, I've changed them to both signed - but embarrassingly, I still don't understand the different between signed and unsigned, i'm aware one can contain neg values whilst the other can't. I can't sit here with a command in my code that I don't really know why it's there, even if it works.

I completely understand why I've made some of 'const', so as to prevent the controller putting things in and out of RAM unnecessarily.

I think maybe i'm confused between bytes, ints & longs. Which do I actually need to use here for the millis and intervals. I can't see why I need to sign, or unsign either.

EDIT: Aha, the table on this page seems to explain it! http://www.cplusplus.com/doc/tutorial/variables/

Well no, not really actually - because surely I can just use a 'short' instead, as the value is between 0 and 65535. Then signed or unsigned is simply a sign convention thing. Correct?

All help up until now greatly appreciated!

Given two values

unsigned short a = 0xD5;
signed short b = 0xD5;

a is interpreted as 213
b is interpreted as -43

This is important in comparison, multiplication, division operations as well as conversions for stuff like Serial prints because how it's interpreted would affect the result.

Addition, subtraction and bitwise operations don't care as the result (in binary) is the same no matter how it's interpreted.

Arrch:
Given two values

unsigned short a = 0xD5;

signed short b = 0xD5;




a is interpreted as 211
b is interpreted as -43

Am I missing something here, where have the Ds come from?

jtw11:
Am I missing something here, where have the Ds come from?

0xD5 is the hex representation of 213 and -43.

Edit: D5 is 213, not 211.

The whole example is nonsense.

jtw11:
Ah, I was just about to ask that question - one signed, one unsigned. So, I've changed them to both signed - but embarrassingly, I still don't understand the different between signed and unsigned, i'm aware one can contain neg values whilst the other can't. I can't sit here with a command in my code that I don't really know why it's there, even if it works.

You should make them unsigned, not signed. millis() and micros() will never return a negative value. Look at the reference of a function to see it's return type. 9 times out of 10, that's the data type you want to store the value into.

millis() and micros() return an unsigned long, so you should store the value in an unsigned long. Otherwise you will eventually run into problems.

Both signed and unsigned long store their values in 4 bytes. So they have the same storage capacity, but they don't haverepresent the same range of values they can store. Because unsigned long only stores positive values, it can store twice as many positive values as signed long, because half of signed long's values are negative.

A smaller scale example:
byte is an 8 bit unsigned type, so it can store any value from 0 to 255. If you try to store the value 256 in it, you will get an overflow and the actual value stored in it will be 0. If you try to store 257 in it, the actual value stored will be 1.
char is an 8 bit signed type. It stores values from -128 to to 127. It still has the same storage capacity, 256 discrete values, but a different range. However, if you have a function that returns a byte value, and you attempt to store it in a char, if that byte value is greater than 127, it will not be properly represented by the char type. The bit pattern will be stored exactly the same, but the representation will be different. Operations on the char value will likely have undesirable results.

@Arch,
You need to show how signed short b = 0xD5; gets sign extended to a negative number to -43.

jraskell:
You should make them unsigned, not signed. millis() and micros() will never return a negative value. Look at the reference of a function to see it's return type. 9 times out of 10, that's the data type you want to store the value into.

millis() and micros() return an unsigned long, so you should store the value in an unsigned long. Otherwise you will eventually run into problems.

Got it, I think! So, can I do the following; use a short for the interval, as the interval is constant at 500?

unsigned long previousMillis = 0;
const unsigned short interval = 500; // creates 500ms interval in which to update serial

So as for defining pins as ints, can I not define pins as chars, as they are between 0 and 255 - to save space? For example;

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

Or is this not seen as best practice, if not - why?

EDIT: Changed my entire code to the following, and tested - works exactly the same, but the program size is exactly the same replacing the ints with shorts. I thought a short was 1 byte, and int was 2 bytes?

/*
Uses an LM35 to sense temperature, and drive a cooling fan accordingly.
 
by Julian West http://uk.linkedin.com/pub/julian-west/26/a42/a02
*/

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

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(); // count milliseconds and assign to currentMillis
  if(currentMillis - previousMillis > interval) // decides if current millis is greater than interval
  {
    previousMillis = currentMillis;
    short 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("");
  }
}

So as for defining pins as ints, can I not define pins as chars

No, the type accepted by pinMode, digitalWrite etc for pin numbers is unsigned.

I thought a short was 1 byte, and int was 2 bytes?

No, a short is 2 bytes.

It's specifically 2 bytes on all systems regardless of word size.

On a 32-bit system an int is 4 bytes, but a short is still 2 bytes.

On an 8-bit system like the AVR an int is 2 bytes emulated as 2 individual bytes with extra code to operate on both as a single digit. A short, not surprisingly, is 2 bytes - exactly the same as an int.

As for negative numbers, you need to understand "two's complement", which is how processors and microcontrollers represent negative numbers.

Wikipedia has a page on it here: Two's complement - Wikipedia

AWOL was right, my example was "rubbish".

They should have been char or byte rather than short. The concept still stands, just didn't have the right type for my example.

Program size that is shown by Arduino is the size of the 'code' portion of the hex file. Variable declaration data is stored in the same file, but as a separate 'section' of the file, and is not included in the reported program size. The details of the hex file are a bit more complicated, but if you're feeling particularly ambitious, this page: http://www.nongnu.org/avr-libc/user-manual/mem_sections.html will give you an introduction to how it's laid out. Just be forewarned, it may only make you more confused than you currently are though. It isn't beginner material.

Ahh - that would explain perfectly why the size isn't changing! I think I'll leave studying the link too hard for a while! :smiley:

If an int (or a long or anything for that matter) is not defined as either signed, or unsigned - which does it default to? Unsigned I'd presume.

you'd presume wrong.

Some are signed, some are unsigned.

The basic types (int, char, short, etc) are usually signed by default.

Special types defined specifically by the Arduino code (byte, etc) may be unsigned. You'd have to read the documentation to be sure.

That's why I never use the arduino specific ones and always use proper named ones.

Of course, there are the explicit ones - uint16, etc, where the "u" means unsigned, and the 16 means 16-bit, or 2 bytes.

Okay, I've got what I need to know for this program at least. I can't see saving 1 or 2 bytes here or there are going to help with anything in the long run anyhow - but knowledge is king ]:slight_smile:

Thanks to all those who replied for their help!