Published on

Programming

Table of Contents

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:

  1. Setting up the hardware and the program variables
  2. 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.

Some extra knowledge (For assignments)

This would be reqiured to solve the Programming assignment.

TV Serial

Sometimes its really useful to see what's going on inside the brain of a microcontroller. Whilst there are many ways to send and receive information to and from a microcontroller and the computer, using the Serial port turns out to be the easiest.

Monitor

The Serial Monitor is basically a window in the Arduino IDE that allows you to send messages from your computer to an Arduino board (over USB) as well as receive messages from the Arduino.

Here's how you can access the Serial Monitor

  1. Open your Arduino IDE. Click on 'Tools' in the Menu bar, and select 'Serial Monitor'.
  2. Alternatively, you can use the hotkey Ctrl+Shift+M

This is how your Serial Monitor will typically look like

IR

Basic program to print your name

As you know whatever we do in the void setup() is only run once whereas as the part in the void loop() keeps on runing until Arduino is powered. This is an example to print your name once when the board is powered.

void setup()
{
  Serial.begin(9600);  //Begin serial communication at 9600(Baud rate)
  Serial.println("Hi, I'm Bhavya Jain");  //Print text
}

void loop(){ }

Serial.print() is used to print in a single line. Serial.println() moves to next line after printing.

Add delay to your program

delay() function is used to add some time delay to your program. For example if you want to print "1" and thenafter 1 second you want to print "2" and so on. You will need delay function.

The function takes milliseconds as input.

void setup(){
	Serial.begin(9600);
}
void loop(){
	//This will print 1,2,1,2...infinitely
	Serial.print(1);
	delay(1000); // Do nothing for 1 second
	Serial.print(2);
	delay(1000); // Do nothing for 1 second
}

Assignment 1

  1. Print a simple message on monitor "Hello World" in a loop.
  2. Write a program to print "LED on" for 1 second then "LED off" for 1 second infinitely.
  3. Design a traffic signal Red = 3 secs, Yellow = 2 secs, Green = 3 secs. Display "RED LIGHT ON", "YELLOW LIGHT ON" and "GREEN LIGHT ON" for the time mentioned in loop.

Variables and DataTypes in cpp

The Arduino microcontroller uses variables identical to cpp on most parts. Hence, we have the familiar cpp data types like int, float, double, char, bool, etc. However, beyond the cpp 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:

typenameSizeRange
char1 byte0 to 255
int8_t1 byte27-2^7 to 272^7 - 1
int16_t2 bytes215-2^{15} to 2152^{15} - 1
int32_t4 bytes231-2^{31} to 2312^{31} - 1
.........
uint8_t1 byte0 to 282^8 - 1
uint16_t2 bytes0 to 2162^{16} - 1
.........
float4 bytes...
double8 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:

  1. Arithmetic Operators:
operatoroperationExample
+addition3 + 5 = 8
-subtraction3 - 5 = -2
*multiplication3 * 5 = 15
/division5 / 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
++xprefix increment (Add 1 to the value)++a = a + 1
x--postfix decrement (Subtract 1 from the value)a-- = a - 1
--xprefix decrement (Subtract 1 from the value)--a = a - 1

% is used with integer datatypes (eg: uint8_t, int32_t, etc) only.

  1. Assignment Operations:
operatoroperationExample
=assignmenta = 5;
+=addition and assignmenta += 5;
-=subtraction and assignmenta -= 5;
*=multiplication and assignmenta *= 5;
/=division and assignmenta /= 5;
%=modulo and assignmenta %= 5;
  1. Relational operators:

int a = 7

operatoroperationExample
==equala == 5; is false
!=not equala != 5; is true
<less thana < 5; is false
>greater thana > 5; is true
<=less than or equal toa <= 5; is false
>=greater than or equal toa >= 5; is true
  1. Logical operators:

bool a = true

bool b = false

operatoroperationExample
&&ANDa && b is false
||ORa || b is true
!NOT!a is false
  1. Bitwise operators:

uint8_t a = 0b0000_1011 = 0x0B

uint8_t b = 0b0000_0010 = 0x02

operatoroperationExample
&ANDa & b = 0b0000_0010 = 0x02
|ORa | b = 0b0000_1011 = 0x0B
^XORa ^ b = 0b0000_1001 = 0x09
~NOT~a = 0b1111_0100 = 0xF4
<<LEFT SHIFTa << b = 0b0010_1100 = 0x2C
>>RIGHT SHIFTa >> b = 0b0000_0010 = 0x02

We will look at Bitwise operations in more detail further.

Assignment 2

Variables and operators

  1. Write a program to make a variable "A" and assign the value "25" to it. Print the value of "A" only once on the monitor.
  2. Write a program to print natural numbers infinitely.
  3. Write a program to print the following series infinitely- a. 1, 3 ,5, 7, 9... b. 1, ,2 ,4, 8, 16... c. 32000, 16000, 8000... d. 10, 10, 20, 20, 30, 30.... e. 10, 90, 20, 80, 30, 70...

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 over while loop.

Syntax:

do {
    // Loop Body
} while (condition);

Assignment 3

Conditional Programming

  1. Print natural numbers only till 25
  2. Make a variable and assign thevalue 0 to it. Keep adding 1 to it but print the value of variable only from 20-30
  3. Print table of 5 till 50 only
  4. From the series given in Assignment 2, print the numbers only till the 7th term.

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:

  1. A function to draw the circle
  2. 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:

  1. User-defined functions: Created by users
  2. Built-in functions: Predefined in cpp, or the compiler

User Defined Functions:

Naming A Function: In cpp, 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 with Day 1 of our workshop.