3 Variables
3 Variables
Variables
Created by: Dr. Daniel van Niekerk
Constants
• Description
̶ Constants are predefined expressions in the Arduino language.
̶ Constants are used to make programs easier to read.
̶ Constants are classify in the following groups:
> Logical Levels: true and false (Boolean Constants)
> Pin Levels: HIGH and LOW
> Digital Pin modes: INPUT, INPUT_PULLUP and OUTPUT
> Built-in LED constant: LED_BUILTIN
Logical Levels: true and false
• Description
̶ There are two constants used to represent true and false in the Arduino language.
• false
̶ false is always defined as “0” (zero).
• true
̶ true is often defined as “1” which is correct, but it has a wider definition.
̶ In the boolean sense any integer which is non-zero is true.
̶ For example: -3, -1, 4 and 250 are all defined as true.
̶ Note that true and false constants are typed in lowercase unlike HIGH, LOW, INPUT,
INPUT_PULLUP, OUTPUT and LED_BUILTIN.
Pin Levels: HIGH and LOW
• Description
̶ When reading or writing to a digital pin there are only two possible values a digital pin
can be at or set to, either HIGH or LOW.
• HIGH
̶ The meaning of HIGH in reference to a port pin is different depending on whether it is
configured to an INPUT or OUTPUT port pin.
̶ When a port pin is configured as an INPUT with pinMode() and read with digitalRead(),
the Arduino port pin will report HIGH if:
> a voltage > 3 volts is present at the input pin (5 V Arduino boards).
> a voltage > 2 volts is present at the input pin (3.3 V Arduino boards).
̶ When a port pin is configured as an OUTPUT with pinMode() and set to HIGH with
digitalWrite(), the Arduino port pin is set to:
> 5 volts for 5 V boards, or 3.3 volts for 3.3 V boards.
> In this state the port pin can source current.
> For example, light an LED that is connected through a series resistor to ground.
Pin Levels: HIGH and LOW
• LOW
̶ The meaning of LOW in reference to a port pin is also different depending on whether it
is configured as an INPUT or OUTPUT port pin.
̶ When a port pin is configured as an INPUT with pinMode() and read with digitalRead(),
the Arduino port pin will report LOW if:
> a voltage < 1.5 volts is present at the input pin (5 V Arduino boards).
> a voltage < 1 volts is present at the input pin (3.3 V Arduino boards).
̶ When a port pin is configured as an OUTPUT with pinMode() and set to LOW with
digitalWrite(), the Arduino port pin is set to:
> 0 volts for 5 V boards, or 3.3 V boards.
> In this state the port pin can sink current.
> For example, light an LED that is connected through a series resistor to +5 volts or
+3.3 volts.
• Internal pull-up
̶ To enable the internal 20 KΩ pull-up resistor on the Atmega chip, a port pin can be
configured as an INPUT with pinMode() and then made HIGH with digitalWrite().
̶ Or a port pin can also be configured as an INPUT_PULLUP with pinMode() to enable
the internal 20 KΩ pull-up resistor on the Atmega chip.
̶ The internal 20 KΩ will pull-up the configured input pin to a HIGH level, unless it is
pulled LOW by external circuitry.
Digital Pin modes: INPUT, INPUT_PULLUP & OUTPUT
• Description
̶ Digital pins can be used as INPUT, INPUT_PULLUP or OUTPUT.
̶ Changing a pin with pinMode() changes the electrical behavior of the pin.
̶ When an INPUT pin is reading a switch and it is in an open state, the input pin voltage
will be "floating", resulting in unpredictable results.
̶ In order to assure a proper reading when the switch is open, a pull-up or pull-down
resistor must be used to pull the pin to a known state when the switch is open.
̶ A 10 to 20 kΩ resistor is usually chosen, as it has a low enough value to reliably prevent
a floating input and at the same time it has a high enough value not to draw too much
current when the switch is closed (5 V / 10 kΩ = 0.5 mA).
̶ If a pull-down resistor is used with the switch connected to 5 V or 3.3 V, the input pin
will be LOW when the switch is open and HIGH when the switch is closed.
̶ If a pull-up resistor is used with the switch connected to ground, the input pin will be
HIGH when the switch is open and LOW when the switch is closed.
Digital Pin modes: INPUT, INPUT_PULLUP & OUTPUT
• Pins Configured as INPUT with PULLUP enabled
̶ The Arduino microcontroller has internal pull-up resistors that are connect to Vcc which
is either 5 V or 3.3 V, depending on which Arduino board is used.
̶ To use these internal resistors instead of connecting external pull-up resistors, use the
INPUT_PULLUP argument in pinMode().
̶ Note that pins configured as inputs with either INPUT or INPUT_PULLUP can be
damaged or destroyed if they are connected to voltages below ground (negative
voltages) or above the positive power rail (5 V or 3.3 V).
̶ The input voltage range must be between: -0.5 V to Vcc + 0.5 V
• Decimal
̶ Decimal (base 10) is the common-sense math we are acquainted with.
̶ Constants without other prefixes are assumed to be in decimal format such as:
Var = 101; // same as 101 decimal -> ((1*10^2) + (0*10^1) + 1)
Integer constants
• Binary
̶ For binary (base two) only characters 0 and 1 are valid:
Var = B101; // same as 5 decimal -> ((1*2^2) + (0*2^1) + 1)
̶ Binary values are indicated by the prefix "B“ and this binary formatter only works on
bytes (8 bits), between 0 (B0) and 255 (B11111111).
̶ If it is convenient to input an integer (16 bits) in binary form, use the following:
myInt = (B11001100 * 256) + B10101010; //B11001100 is the high byte
• Octal
̶ For octal (base eight) only characters 0 through 7 are valid.
̶ Octal values are indicated by the prefix "0" such as:
Var = 0101; // same as 65 decimal -> ((1*8^2) + (0*8^1) + 1)
̶ Note that it is possible to generate a hard-to-find bug by unintentionally including a
leading zero before any integer constant.
̶ Therefore, the compiler will unintentionally interpret the constant as an octal number.
• Hexadecimal
̶ For hexadecimal or hex (base sixteen), valid characters are 0 to 9 and letters A to F.
̶ Note that: ‘A’ = 10, ‘B’ = 11, ‘C’ = 12, ‘D’ = 13, ‘E’ = 14 and ‘F’ = 15.
̶ Hex values are indicated by the prefix "0x" and "A-F" may be upper or lower case (“a-f”):
Var = 0x101; // same as 257 decimal -> ((1*16^2) + (0*16^1) + 1)
Integer constants
• U & L formatters
̶ By default, an integer constant is treated as an int, with intended limitations in values.
̶ To specify an integer constant with another data type, follow it with:
> a 'u' or 'U' to force the constant into an unsigned data format (example: 33u).
> a 'l' or 'L' to force the constant into a long data format (example: 100000L).
> a 'ul' or 'UL' to force the constant into an unsigned long data format
(example: 65537UL).
Floating point constants
• Description
̶ Similar to integer constants, floating point constants can also be used.
̶ Floating point constants can be expressed in a variety of scientific notation.
̶ 'E' and 'e' are both accepted as valid exponent indicators.
10.0 10 10
2.34E5 2.34 * 10^5 234000
67e-4 67.0 * 10^-4 0.000067
Data Type: void
• Description
̶ The void keyword is used only in function declarations.
̶ It indicates that the function is expected to return nothing to the calling function.
̶ It can also indicate that it receives no information in the parameters to process.
• Example:
// actions are performed in the functions "setup" and "loop"
// but no information is reported back to the C control program
// and no information is received in the parameters to process.
void setup() // or void setup(void)
{
// statements...
}
void setup(){
pinMode(pinLED, OUTPUT);
// next two lines same as: pinMode(pinSwitch, INPUT_PULLUP)
pinMode(pinSwitch, INPUT); // make the pin an input
digitalWrite(pinSwitch, HIGH); // turn on internal 20 kΩ pull-up
}
void loop(){
if(digitalRead(pinSwitch) == LOW){ // check if switch pressed
delay(10); // delay to debounce switch
if(digitalRead(pinSwitch) == LOW){ // check switch again
bRunning = !bRunning; // toggle bRunning variable
digitalWrite(pinLED, bRunning); // indicate state via LED
}
}
}
Data Type: char
• Description
̶ A char takes up one byte of memory and is used to store a character value.
̶ Character literals are written in single quotes: 'A'
̶ For multiple characters such as in strings use double quotes: "ABC".
̶ Characters are stored as numbers and have a specific encoding as listed on ASCII chart.
̶ It is possible to do arithmetic calculations with characters, where ASCII code number
value of the character is used.
̶ For example: 'A' + 1 = 66, because the ASCII code value of capital letter A is 65.
̶ char data type is a signed type and encodes numbers from -128 to 127.
̶ For an unsigned or one-byte (8 bit) data type, use the byte data type.
• Example
char cMyChar = 'A';
char cMyChar = 65;
̶ both are equivalent.
Data Type: unsigned char
• Description
̶ An unsigned char occupies one byte of memory, same as the byte data type.
̶ The unsigned char data type encodes numbers from 0 to 255.
̶ Note that for consistency with the Arduino programming style, the byte data type is
preferred.
• Example
unsigned char ucMyChar = 240;
0 0
255 -1
0
255
byte range:
192 0 to 2^8-1 = 0 to 255 63
127
Data Type: int
• Description
̶ Integers are the most often used data type for number storage.
̶ On the Arduino ATmega based boards, an int stores a 16-bit (2-byte) value.
̶ This yields a range of -32,768 to 32,767.
̶ Minimum value of (-2^15) and a maximum value of ((2^15) - 1).
̶ On the Arduino Due, an int stores a 32-bit (4-byte) value.
̶ This yields a range of -2,147,483,648 to 2,147,483,647
̶ Minimum value of (-2^31) and a maximum value of ((2^31) - 1).
̶ Integers store negative numbers with a technique called 2's complement math.
̶ The highest bit is called the "sign" bit, if set to one the number store is negative.
̶ If negative, inverted all bits and add 1, the resulting value is the negative number.
̶ Note that the Arduino compiler takes care of dealing with negative numbers.
̶ Therefore, code arithmetic operations work transparently in the expected manner.
̶ However, there can be an unexpected complication when dealing with bit-shift right “>>”.
• Example
int iData = 32767;
• Syntax
̶ int iVar = value;
• Note
̶ iVar - is the integer variable name.
̶ value - is the value assigned to the integer variable name.
Data Type: int
• Note
̶ When variables exceed maximum capacity, "roll over" back to minimum occurs.
̶ This happens in both increment and decrement directions.
• Example
int iVar; // declare 16-bit integer variable
iVar = -32768; // iVar = B1000 0000 0000 0000
iVar = iVar - 1; // iVar now contains +32,767 roll-over occurred
... // now iVar = B0111 1111 1111 1111
iVar = 32767; // iVar = B0111 1111 1111 1111
iVar = iVar + 1; // iVar now contains -32,768 roll-over occurred
// now iVar = B1000 0000 0000 0000
0
-1
32767 (2^15-1)
-32768
(-2^15)
Data Type: short
• Description
̶ A short is a 16-bit data-type, same as an int.
̶ On all Arduino ATmega based boards, a short stores a 16-bit (2-byte) value.
̶ This yields a range of -32,768 to 32,767.
̶ Minimum value of -2^15 and a maximum value of (2^15) - 1.
• Example
short sData = -32768;
• Syntax
̶ short sVar = value;
• Note
̶ sVar - is the short variable name.
̶ value - is the value assigned to short variable name.
Data Type: unsigned int
• Description
̶ An unsigned int stores only a positive 16-bit (2 byte) value.
̶ An unsigned int yields a range of 0 to 65,535 (or 0 to (2^16) - 1).
̶ The Arduino Due stores a 4 byte (32-bit) value, ranging 0 to 4,294,967,295 (2^32 - 1).
̶ The difference between unsigned int and (signed) int, lies in the way the highest bit
called the "sign" bit, is interpreted.
̶ For an int type, if the highest bit is a "1", the number is interpreted as a negative
number and the bits are interpreted by using 2's complement math.
• Example
unsigned int uiData = 65535; // or iVar = B1111 1111 1111 1111
• Syntax
̶ unsigned int uiVar = value;
• Note
̶ uiVar - is the unsigned int variable name.
̶ value - is the value assigned to the unsigned int variable name.
Data Type: unsigned int
• Coding Tip
̶ When variables exceed maximum capacity, "roll over" back to minimum occurs.
̶ This happens in both increment and decrement directions.
• Example
unsigned int uiVar;
...
uiVar = 0;
uiVar = uiVar - 1; // uiVar now contains 65535 - rolls over
uiVar = uiVar + 1; // uiVar now contains 0 - rolls over
0
65535
32767
Data Type: word
• Description
̶ A word stores a 16-bit unsigned number from 0 to 65535, same as an unsigned int.
• Example
word wMyWord = 0xFFFF; // same as 65535 decimal
0
65535
word range:
49150 0 to 2^16-1 = 0 to 65535 16383
32767
Data Type: long
• Description
̶ A long variable is an extended size variable for number storage.
̶ It stores 32 bits (4 bytes), from -2,147,483,648 (-2^31) to 2,147,483,647 ((2^31) - 1).
̶ When doing math with integers or literals, at least one of the integers must be type case
as a long or the literal must be followed by an L, if the result is to be saved into a long
variable.
• Example
// 'L' forces constant into a long data format
long lspeed = 200000000L;
• Syntax
̶ long lVar = value;
• Note
̶ lVar - is the long variable name.
̶ value - is the value assigned to the long variable name.
Data Type: unsigned long
• Description
̶ An unsigned long stores only a positive 32-bit (4 byte) value.
̶ An unsigned long yields a range of 0 to 4,294,967,295 (2^32 - 1).
• Example
// ‘UL' forces constant into an unsigned long data format
unsigned long ulspeed = 4000000000UL;
• Syntax
̶ unsigned long ulVar = value;
• Note
̶ ulVar - is the unsigned long variable name.
̶ value - is the value assigned to unsigned long variable name.
Example: unsigned long
// tip: use “ul” in front of variable name to indicate the data size
unsigned long ulTime;
void setup()
{
Serial.begin(9600);
}
void loop()
{
Serial.print("Time: ");
ulTime = millis();
// prints time since program started, then moves to the next line
Serial.println(ulTime);
// wait a second, limits the amount of transmitted serial data
delay(1000);
}
Data Type: float
• Description
̶ A number that has a decimal point is a floating-point data type number.
̶ Floating-point numbers are often used to approximate analog or continuous real
number values because they have greater resolution than integers.
̶ Floats can be as large as 3.4028235E+38 and as small as -3.4028235E+38.
̶ They are stored as 32 bits (4 bytes) of information.
̶ Floats only have a total number of 6 to 7 digits of precision after the decimal point.
̶ Unlike other platforms where you can get more precision by using a double data type
(e.g. up to 15 digits after decimal point), on the Arduino Uno the double is the same
size as a float.
̶ Floating point numbers are not always exact and may yield strange results.
̶ Floating point math is also much slower than integer math in performing calculations.
̶ Avoid using float math, if a loop has to run at top speed for a critical timing function.
̶ Programmers often go to some lengths to convert floating point calculations into integer
math to increase speed.
̶ When doing math with a float, add a decimal point to the literal constant number
otherwise it will be treated as an integer.
Data Type: float
• Examples
float fMyfloat;
float fSensCalbrate = 1.117;
• Syntax
̶ float fVar = value;
• Note
̶ fvar - is the float variable name.
̶ value - the value assign to the float variable name.
• Example Code
int iX;
int iY;
float fZ;
iX = 1;
iY = iX / 2; // iY now contains 0, can't hold fractions
fZ = (float)iX / 2.0; // fZ now contains 0.5 (must use 2.0 & not 2)
// also type case integer ‘iX’ to a float
Data Type: double
• Description
̶ A double is a double precision floating point number.
̶ However, on Arduino ATmega based boards a double still occupies only 4 bytes.
̶ Therefore, double is exactly the same as the float with no gain in precision.
̶ However, on the Arduino Due a double is a 8 bytes (64-bit) resulting in double precision.
• Tip
̶ Borrowed code from other sources that includes double variables may require further
examination.
̶ See if the implied precision is different from what can actually be achieved on the
Arduino ATmega based boards.
Data Type Summary
̶ When declaring variables, “typedef” can also be used instead of typing full data type.
Data type typedef Size Numeric range
boolean or None 8-bits or false (0) and
bool 1-byte true (1 to 255)
signed char or int8_t 8-bits or -128 to 127 or
char 1-byte -2^7 to 2^7 - 1
unsigned char or uint8_t 8-bits or 0 to 255 or
byte 1-byte 0 to 2^8 - 1
signed int or int16_t 16-bits or -32768 to 32767 or
int or short 2-bytes -2^15 to 2^15 – 1
unsigned int or uint16_t 16-bits or 0 to 65535 or
word 2-bytes 0 to 2^16 – 1
signed long or int32_t 32-bits or -2147483648 to 2147483647 or
long 4-bytes -2^31 to 2^31 – 1
unsigned long uint32_t 32-bits or 0 to 4294967295 or
4-bytes 0 to 2^32 -1
float or none 32-bits or -3.4028235E+38 to 3.4028235E+38
double 4-bytes
Data Type: array
• Description
̶ An array is a collection of variables that are accessed with an index number.
• Creating or Declaring an Array
̶ All of the methods below are valid ways to create or declare an array:
int iData[7];
int iPins[] = {2, 4, 8, 3, 6};
int iSensVals[5] = {2, 4, -8, 3, 2};
char cMsg[6] = "hello"; //5 characters plus a NULL ('\0')
• Note
̶ You can declare an array without initializing it (iData).
̶ You can declare an array without explicitly choosing a size (iPins).
̶ The compiler counts the elements and creates an array of the appropriate size.
̶ Finally you can both initialize and size an array (iSensVals).
̶ Note that when declaring an array of type char to store a string, one more element is
required to hold the null character or '\0' (cMsg).
• Accessing an Array
̶ Arrays are zero indexed, that is the first element of the array is at index 0, therefore:
iSensVals[0] == 2,
iSensVals[1] == 4,
iSensVals[2] == -8, and so on.
Data Type: array
• To assign a value to an array:
iSensVals[0] = 10;
• To retrieve a value from an array:
iValue = iSensVals[4];
• Arrays in loops
̶ Arrays are often manipulated inside for or while loops, where the loop counter is used
as the index for each array element.
• Example
// code to print the elements of an array via the serial port
char cMsg[6] = "hello";
...
for(int i=0; i<5; i++)
{
Serial.write(cMsg[i]); // serially send array elements
delay(250); // send each char every 250 ms
}
...
Data Type: array
̶ Index nine is the last element in an array with ten elements, therefore in:
void setup()
{
Serial.begin(9600); // enable serial port at 9600 bits per second
}
void loop()
{
for(int i = 0; i < 4; i++)
{
Serial.println(strArray[i]); // print each string on a new line
delay(500); // every 500 ms
}
while(1); // loop continuously, stops repeating the code above
}
Conversion: char()
• Description
̶ Converts a value to the char data type.
• Syntax
̶ char(val)
• Parameters
̶ val: a value of any data type.
• Returns
̶ A char
Conversion: byte()
• Description
̶ Converts a value to the byte data type.
• Syntax
̶ byte(val)
• Parameters
̶ val: a value of any data type.
• Returns
̶ A byte
Conversion: int()
• Description
̶ Converts a value to the int data type.
• Syntax
̶ int(val)
• Parameters
̶ val: a value of any data type.
• Returns
̶ An int
Conversion: word()
• Description
̶ Convert a value to the word data type or creates a word from two bytes.
• Syntax
̶ word(val)
̶ word(high, low)
• Parameters
̶ val: a value of any data type.
̶ high: the high-order (leftmost) byte of the word.
̶ low: the low-order (rightmost) byte of the word.
• Returns
̶ A word
Conversion: long()
• Description
̶ Converts a value to the long data type.
• Syntax
̶ long(val)
• Parameters
̶ val: a value of any data type.
• Returns
̶ A long
Conversion: float()
• Description
̶ Converts a value to the float data type.
• Syntax
̶ float(val)
• Parameters
̶ val: a value of any data type.
• Returns
̶ A float
Variable Scope
• Description
̶ Variables in the C programming language have a property called scope.
̶ In contrast to early versions of languages such as BASIC where every variable is a global.
̶ A global variable is one that can be seen by every function in a C program.
̶ Local variables are only visible to the function in which they are declared.
̶ In the Arduino C programing environment any variable declared outside of a function
such as setup(), loop(), etc…, is a global variable.
̶ When programs start to get larger and more complex, local variables are a useful way
to insure that only one function has access to its own variables.
̶ This prevents one function inadvertently modifies variables used by another function
thereby avoiding programming errors.
̶ It is also sometimes handy to declare and initialize a variable inside a for loop.
̶ This creates a variable that can only be accessed from inside the for loop brackets.
Example: Variable Scope
int giPWMval; // any function will see this global variable
void setup()
{
giPWMval = 20; // can use “giPWMval” in setup()function
}
void loop()
{
int iData; // "iData" is only "visible" inside of loop()function
float fData; // "fData" is only "visible" inside of loop()function
void setup(){
Serial.begin(9600);
}
void loop() {
if(iNum <= 60)
{
iNum = UpdateCnt();
Serial.print(":");
Serial.print(iNum); // only prints ":10:20:30:40:50:60"
}
}
// iCnt declared as static, value is preserved between function calls.
// Without static keyword, value of iCnt would be reset to 0 each time,
// and when UpdateCnt() is called, return value will always be 10.
int UpdateCnt()
{
static int iCnt = 0;
iCnt += 10;
return count;
}
Qualifier: volatile
• Description
̶ The volatile keyword is known as a variable qualifier.
̶ It is used before the data type of a variable, in order to modify the way in which the
compiler and subsequent program treats the variable.
̶ Declaring a variable volatile is a instruction or directive to the compiler.
̶ A compiler is software that translates C/C++ code into machine code which is the real
executable machine instructions of the Atmega microcontroller on the Arduino board.
̶ The volatile keyword directs the compiler to load the variable from RAM and not from
a storage stack register, which is a temporary memory location where program and
function variables are stored and manipulated.
̶ Under certain conditions the value for a variable stored in registers can be inaccurate.
̶ A variable should be declared volatile whenever its value can be changed by something
beyond the control of normal code execution in which it appears, such as a
concurrently executing thread or an interrupt routine.
̶ In the Arduino the only place that this is likely to occur is in sections of code associated
with interrupts, called an interrupt service routine (ISR).
Example: volatile
// toggles LED when interrupt pin changes state
const int pinLED = 10;
volatile bool vbState = LOW;
void setup()
{
pinMode(pinLED, OUTPUT);
attachInterrupt(0, blink, CHANGE); // attach to interrupt 0 pin
} // this is pin 2 of Arduino UNO
void loop()
{
digitalWrite(pinLED, vbState); // update LED with current state
delay(20);
}
void blink()
{
vbState = !vbState; // change state when interrupt 0 state changes
}
Qualifier: const
• Description
̶ The const keyword stands for constant and is a variable qualifier that modifies the
behavior of the variable by making it "read-only".
̶ This means that a variable can be used just as any other variable of its data type but its
value cannot be changed.
̶ A compiler error occurs if a value is assigned to a const declared variable data type.
̶ The benefit of using const variables is that they obey the rules of variable scoping that
govern other variables.
̶ The pitfalls of using #define, makes the const keyword a superior method for defining
constants which is generally preferred over using #define.
• Example
const float pi = 3.14;
float fx;
float fy = pi; //not allowed when initializing declared variables
...
fx = pi * 2; //it's fine to use const's in math
pi = 7; //illegal, can't write to or modify a constant
• #define or const?
̶ Either const or #define can be used for creating numeric or string constants.
̶ However, for arrays you will need to use const.
Utilities: PROGMEM
• Description
̶ Stores data in flash (program) memory instead of SRAM.
̶ The PROGMEM keyword is a variable modifier used only with the data types defined in
“avr/pgmspace.h”.
̶ It tells the compiler “to put this information into flash memory" instead of into SRAM,
where it would normally be stored.
̶ PROGMEM is part of the “avr/pgmspace.h” library.
̶ So to use PROGMEM, include the following library at the top of the sketch, as follows:
#include <avr/pgmspace.h>
̶ While PROGMEM can be used on a single variable, it is really only worth the fuss if a
larger block of data needs to be stored, which is usually in an array.
̶ Using PROGMEM is a two-step procedure because after saving data into Flash memory,
it requires special methods (functions) defined in the “avr/pgmspace.h” library, to read
the data from program memory back into SRAM, so that it can be used.
• Syntax
̶ const dataType variableName[] PROGMEM = {data0, data1, data3...};
̶ dataType - any valid variable data type
̶ variableName - the name to identify the array of data
Utilities: PROGMEM
̶ Note that because PROGMEM is a variable modifier there is no hard and fast rule about
where it should go.
̶ However, experiments have indicated that in various versions of Arduino (having to do
with GCC version), PROGMEM may work in one location and not in another.
̶ Earlier versions of IDE work better if PROGMEM is included after the variable name.
• Example
const dataType variableName[] PROGMEM = {}; //use this form
const PROGMEM dataType variableName[] = {}; //or this form
const dataType PROGMEM variableName[] = {}; //not this one
• Note
̶ Please note that variables must be either globally defined, or defined with the static
keyword in order to work with PROGMEM variable modifier.
̶ The following code WILL work, even if locally defined within a function:
const static char Str[] PROGMEM = "Hi, let us talk.\n";
Utilities: PROGMEM
// Code to read and write bytes and integers from flash (program) memory.
#include <avr/pgmspace.h>
const unsigned int Nums[] PROGMEM = {65000, 32796, 512}; // save ints to flash
const char Msg[] PROGMEM = "I am a hard working student"; // save chars to flash
unsigned int uiDisplay;
char cByte;
void setup(){
Serial.begin(9600);
}
void loop(){
for(int i=0; i<3; i++)
{
uiDisplay = pgm_read_word_near(Nums + i); // read unsigned int from PROGMEM
Serial.println(uiDisplay); // print each number on new line
}
void setup()
{
Serial.begin(9600);
// Using string table in program memory requires the use of "strcpy_P" function
// to copy a string from program space to a string in RAM (“cStrBuf").
for(int i=0; i<4; i++)
{
//necessary casts and dereferencing, just use as is
strcpy_P( cStrBuf, (char*)pgm_read_byte_near( &(StrTable[i]) ) );
Serial.println(StrBuf); // print each string on a new line
delay(1000);
}
}
void loop(){}
EXERCISE
1. Explain the meaning of a “HIGH” in reference to a port pin when it is configured as an
“INPUT” or an “OUTPUT” on the Arduino board?
2. Explain the meaning of a “LOW” in reference to a port pin when it is configured as an
“INPUT” or an “OUTPUT” on the Arduino board?
3. Describe how the internal 20 KΩ pull-up resistor on the Atmega port pins, can be enabled
and explain what will it do to an input port pin?
4. Elaborate on what makes an Arduino port pin configured as an INPUT, useful in reading an
input sensor?
5. Discuss why an input port pin should use an external 10 KΩ pull-up or pull-down resistor
when reading the state of a connected open switch?
6. Explain the difference between using an external pull-up or pull-down resistor?
7. What is the state of Arduino configured output port pins and what can they provide to
other external circuits?
8. Explain what the Arduino constant “LED_BUILTIN” represents.
9. Generate a table showing the base, special notation or formatters, example and character
range for a decimal, a binary and a hexadecimal integer constant.
10. Where is the “void” keyword used and what does it indicate?
11. Generate a table showing the bit size and numeric value range of both a signed and
unsigned “char”, “int” and “long” data type.
EXERCISE
12. Generate a table showing the bit size and numeric value range of a Boolean, byte, word
and short data type.
13. Design an Arduino C program without comments to serially print continuously every half
second on each line the following strings: “First line”, “Second line” and “Third line”. Use
serial function at 9600 bit/s, an array of strings and a for-loop to iterate through the array.
14. Describe and show the syntax with associated function parameters and return value of
the “word()” conversion function.
15. Explain what the difference is between a global and local declared variable in C?
16. Discuss why local variables are useful and how they can prevent programing errors?
17. What does the “static” keyword create and how it is different to a function local variable?
18. Describe the “volatile” keyword, what it does and when it should be use?
19. Describe the “const” keyword, what it does and the benefit of using it?
20. Create an Arduino C program to serially print out on each line, the array index equal to the
associated character of an unknown string by using the “sizeof()” operator at 19200 bit/s.
21. Develop an Arduino C program that initially saves the follow string data to the flash
program memory, “I love to program an Arduino UNO” and then serially prints out the
string data once at 9600 bits/s.
22. Design an Arduino C program that initially saves the follow data strings to the flash
program memory, “Hello, I love to program”, “Do you love to program?”, “I use a table to
refer to strings”. Then serially print out every half second on each line the data strings
once at 9600 bits/s.