- Published on
Level 0
Table of Contents
- Note
- Variables and DataTypes in C++
- Bonus: Implicit and Explicit Type Casting
- Operators
- Conditionals
- The ternary Operator
- Loops
- while loop
- for loop
- The unspoken Brother
- Functions
- User Defined Functions:
- C for Arduino Microcontrollers
- Programming the Arduino Microcontrollers
- Control Structure of a simple Arduino Program
- The setup() function
- The loop() function
Note
If you have done CS F111, you can cruise through this level as it covers the basics of C/C++ programming. Even if you don't have knowledge of CS F111, you will be able to do this level as it is beginner-friendly.
Variables and DataTypes in C++
The Arduino microcontroller uses variables identical to C++ on most parts. Hence, we have the familiar C++ data types like int
, float
, double
, char
, bool
, etc. However, beyond the C++ data types, we have the string
datatype, which is used to store a sequence of characters.
// TODO: Variable Naming Conventions
Example:
int32_t myverylongvariable; // Bad Naming, Extremely Unreadable
int32_t my_very_long_variable; // Good, but unconvetional
int32_t MyVeryLongVariable; // Good, but unconventional. Pascal case is used with Classes
int32_t myVeryLongVariable; // Good
Most of these datatypes have sizes that depend on the compiler architecture being used (x32 or x64), and is often unreliable. To counteract this problem, we have integer datatypes that specify the size (in bytes) explicitly. For Example, int8_t
has a fixed size of 8 bits, int32_t
has a size of 32 bits or 4 bytes. Similarly, there are unsigned variations of the same types availabel as well. For example, uint8_t
, uint64_t
. We strongly recommend that you use these fixed-size integer datatypes whenever possible.
Size and Range of Some Standard Data Types:
typename | Size | Range |
---|---|---|
char | 1 byte | 0 to 255 |
int8_t | 1 byte | to - 1 |
int16_t | 2 bytes | to - 1 |
int32_t | 4 bytes | to - 1 |
... | ... | ... |
uint8_t | 1 byte | 0 to - 1 |
uint16_t | 2 bytes | 0 to - 1 |
... | ... | ... |
float | 4 bytes | ... |
double | 8 bytes | ... |
Examples:
int a = 5;
int32_t b = 7; // Equicvalent to int in x64 compilers
unsigned int mask = 1234;
uint8_t mask = 0x11; // 8 bit unsigned integers most frequently used as bit masks
float f = 2.5f; // the f at the end of 2.5 signifies explicitly that this is a float
double d = 3.5; // floating point numbers are double precision by default
Bonus: Implicit and Explicit Type Casting
Please refer to this source for information on this topic
Operators
Operators may be unary (single operand) or binary (two operands). We look at the following types of operators:
- Arithmetic Operators:
operator | operation | Example |
---|---|---|
+ | addition | 3 + 5 = 8 |
- | subtraction | 3 - 5 = -2 |
* | multiplication | 3 * 5 = 15 |
/ | division | 5 / 3 = 1, 3.0 / 2.0 = 1.5 |
% | modulo (Remainder after integer division) | 5 % 3 = 2 |
x++ | postfix increment (Add 1 to the value) | a++ = a + 1 |
++x | prefix increment (Add 1 to the value) | ++a = a + 1 |
x-- | postfix decrement (Subtract 1 from the value) | a-- = a - 1 |
--x | prefix decrement (Subtract 1 from the value) | --a = a - 1 |
%
is used with integer datatypes (eg:uint8_t
,int32_t
, etc) only.
- Assignment Operations:
operator | operation | Example |
---|---|---|
= | assignment | a = 5; |
+= | addition and assignment | a += 5; |
-= | subtraction and assignment | a -= 5; |
*= | multiplication and assignment | a *= 5; |
/= | division and assignment | a /= 5; |
%= | modulo and assignment | a %= 5; |
- Relational operators:
int a = 7
operator | operation | Example |
---|---|---|
== | equal | a == 5; is false |
!= | not equal | a != 5; is true |
< | less than | a < 5; is false |
> | greater than | a > 5; is true |
<= | less than or equal to | a <= 5; is false |
>= | greater than or equal to | a >= 5; is true |
- Logical operators:
bool a = true
bool b = false
operator | operation | Example |
---|---|---|
&& | AND | a && b is false |
|| | OR | a || b is true |
! | NOT | !a is false |
- Bitwise operators:
uint8_t a = 0b0000_1011 = 0x0B
uint8_t b = 0b0000_0010 = 0x02
operator | operation | Example |
---|---|---|
& | AND | a & b = 0b0000_0010 = 0x02 |
| | OR | a | b = 0b0000_1011 = 0x0B |
^ | XOR | a ^ b = 0b0000_1001 = 0x09 |
~ | NOT | ~a = 0b1111_0100 = 0xF4 |
<< | LEFT SHIFT | a << b = 0b0010_1100 = 0x2C |
>> | RIGHT SHIFT | a >> b = 0b0000_0010 = 0x02 |
We will look at Bitwise operations in more detail further.
Conditionals
We now look at how to control the flow of execution of the program. Typically, every statement is executed line by line. However, there are times when we want to execute a statement only when a condition is true. This is where conditionals come in.
We have the following structure of Programs:
if (condition1) {
// do something when condition1 is true
} else if (condition2) {
// do something when condition2 is true
} else {
// do something when neither condition is true
}
The ternary Operator
Ternary operator provides a simple way to execute a statement when a condition is true or false.
variable = condition ? value when condition is true : value when condition is false;
This is equivalent to:
if (condition) {
variable = value when condition is true;
} else {
variable = value when condition is false;
}
Example:
int32_t a = 5, b = 7;
int32_t maxAB = (a > b) ? a : b; // maxAB = 7
Loops
Loops are commands that execute a set of statements multiple times. There are two types of loops: while
and for
.
while loop
These loops execute a set of statements as long as a condition is true. The condition is checked at the beginning of each loop iteration. The loop is exited when the condition becomes false.
Syntax:
while (condition) {
// Loop body
}
Example:
int32_t i = 0;
while (i < 10) {
i++;
}
// Value of i after loop exits: 10 (Why not 9?)
for loop
These loops execute a set of statements once for each element in a collection. The collection is specified by the loop variable. This collection is defined by the loop variable.
Syntax:
for (variable = initial value; condition; increment variable) {
// Loop Body
}
Example:
int32_t i;
for (i = 0; i < 10; i++) {
// do something
}
The unspoken Brother
The third kind of Loops are the do while
loops. These loops execute a set of statements as long as a condition is true. The condition is checked at the end of each loop iteration. The loop is exited when the condition becomes false.
Point out a case where
do while
loop is preferred overwhile
loop.
Syntax:
do {
// Loop Body
} while (condition);
Functions
A function is a named sequence of statements that perform a specific task. It is a block of code that performs a specific task.
Suppose we need to create a program to create a circle and color it. We can create two functions to solve this problem:
- A function to draw the circle
- A function to color the circle
Dividing a complex problem into smaller chunks makes our program easy to understand and reusable.
There are two types of function:
- User-defined functions: Created by users
- Built-in functions: Predefined in C++, or the compiler
User Defined Functions:
Naming A Function: In C++, the conventional practive is to use Camel Case for naming functions. This is similar to how variables are named.
Example:
int32_t myverylongfunction(); // Bad Naming, Extremely Unreadable
int32_t my_very_long_function(); // Good, but unconvetional
int32_t MyVeryLongFunction(); // Good, but unconventional. Pascal case is used with Classes
int32_t myVeryLongFunction(); // Good
Every function has a protype (or its signature/declaration) and a definition. The protype contains the return type of the function, the function name, and its parameters. The function definition contains the statements that the function performs.
Syntax:
returnType functionName (parameter1, parameter2, ...); // Function Protype
returnType functionName (parameter1, parameter2, ...) { // Function Definition
// Function Body
}
The protype may exists independantly of the definition, but the definition always includes the protype.
Example:
bool isOdd(int32_t n) {
/*
Check if the number passed is odd
Args:
int32_t n: The number to check
Returns:
bool: True if the number is odd, false otherwise
*/
return (n & 1);
}
Now that you've finished this section, you have all the programming knowledge required to get started.
C for Arduino Microcontrollers
Programming the Arduino Microcontrollers
Note: This doc assumes some basic familiarity with programming concepts as covered in CS F111: Computer Programming at BITS. Although some pre-requisite knowledge of programming structures is recommended, it is not requried.
Control Structure of a simple Arduino Program
Almost any arduino program consists of two important functions: setup()
and loop()
. These two functions are the building blocks of any arduino program. Most programs that you need to run on a microcontroller device have two major components:
- Setting up the hardware and the program variables
- Recurring tasks like collecting data or sending some data
These tasks are handled by the following two functions:
The setup() function
This function is called when your Arduino Board starts up. It is used to initalize any variables that you have to use in your program. It can also be used to set up any hardware that you need to use. The crucial part to remember is that this function is called exactly once. Anything, and everyhting that you don't need to run more than once, should be within this function.
The loop() function
This function is called repeatedly. It is the main function of your program. It is where you should put all the code that you want to run repeatedly. The loop function is called repeatedly until the program is stopped. (How is a program stopped?)
Sample Code Structure:
// Define Global Variables
void setup() {
// Set up your microcontroller here
// Initialize Variables
}
void loop() {
// Collect some data
// Send some data back
}
Once we understand the strucutre of a program, we can start writing the code. Let us look at the building blocks.