Paul covered the most important points. This answer is intended to be a
complement to his.
First, you should keep in mind the general rules, which are more
important than the more specific ones. The general rule for saving RAM
is: be aware of what you are storing, and do not store anything you do
not really need. The general rule for saving flash is: be aware of what
you are doing, and do not do anything you do not really need.
Now, a few specific tips:
Use the const
qualifier for declaring constants (e.g.
const int ledPin = 13;
). The compiler will optimize-out the storage of
the constant and use immediate addressing instead.
Use PROGMEM
for arrays of constants.
Whenever possible, use static memory (globals and static
locals)
rather than heap allocation (malloc()
and new
). This will prevent
memory fragmentation and make the memory usage more predictable (only
the stack holds dynamic memory): you know at compile time, rather than
run time, whether you are low in RAM.
For the same reason, prefer C strings (char *
) over String
objects.
Use the C99 types int8_t
and uint8_t
whenever 8 bits are enough for
your integer variables.
Use the static
qualifier for functions that will be used only in the
same source file, especially for functions that are called only from one
place. This gives the compiler more optimization opportunities.
If you need to optimize,
use avr-nm
to know what is
consuming your precious RAM.