0% found this document useful (0 votes)
7 views50 pages

Basic Programming Knowledge

Uploaded by

tanzimatahrin0
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
0% found this document useful (0 votes)
7 views50 pages

Basic Programming Knowledge

Uploaded by

tanzimatahrin0
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
Download as pdf or txt
You are on page 1/ 50

Part A

Introduction on Embedded C
Embedded C programming is crucial for developing firmware in various systems such as IoT
devices and industrial controllers. As we progress through 2024, it’s important to refine our
approach to mastering this skill. This guide explores core concepts, modern practices, and
advanced topics relevant to embedded C programming this year.

Embedded C programming involves utilizing the C language to develop firmware for


microcontrollers, the brains of embedded systems. These microcontrollers operate within a
constrained environment with limited resources (memory, processing power). Embedded C
provides a powerful yet efficient language for manipulating hardware registers, interfacing with
peripherals, and implementing real-time control logic.

The continued relevance of embedded C in 2024 can be attributed to several factors:

• Growth of the IoT: The proliferation of connected devices necessitates compact, low-
power firmware, making embedded C an ideal choice for resource-constrained IoT nodes.
• Focus on Security: As embedded systems become more interconnected, security
vulnerabilities pose a significant threat. Understanding secure coding practices in
embedded C is paramount.
• Hardware Advancements: Modern microcontrollers offer a plethora of new features
like hardware accelerators and security modules. Effective embedded C code leverages
these features for improved performance and security.

Core Concepts
A solid foundation in C programming fundamentals is crucial for mastering embedded C. This
section revisits essential concepts with an embedded systems perspective:

• Data Types: Grasping the nuances of data types like char, int, long, and structures is vital
for memory management and efficient data manipulation.
• Operators: Operators like bitwise operators (&, |, ^), arithmetic operators (+, -, *, /), and
comparison operators (==, !=, <, >) are fundamental for interacting with hardware
registers and performing calculations.
• Control Flow: Control flow statements like if, else, for, while, and switch enable
decision-making and program execution flow control, essential for implementing control
algorithms.
• Functions: Functions promote code modularity, reusability, and maintainability.
Understanding function prototypes, arguments, return values, and recursion is crucial.
• Pointers: Pointers provide a powerful mechanism for memory management and low-
level hardware interaction. Mastering pointer arithmetic and avoiding dangling pointers is
essential for safe and efficient code.

Memory Management in Embedded Systems

Memory management in embedded systems is a critical aspect distinct from traditional C


programming. This section dives deeper:

• Memory Organization: Embedded systems typically have segmented memory with


distinct regions for program, data, stack, and heap. Understanding these segments and
their usage patterns is crucial.
• Memory Allocation Strategies: Techniques like static allocation, dynamic allocation
using malloc and free, and memory pool management are explored for efficient memory
usage.
• Bit Manipulation: Embedded systems often require bit-level operations. Bit fields and
bitwise operations are crucial for interacting with hardware registers.

Input/Output (I/O) Programming

Interfacing with the physical world is a core function of embedded systems. This section covers
various I/O mechanisms and their C programming aspects:

• General Purpose Input/Output (GPIO): Configuring GPIO pins as inputs or outputs,


reading digital data, and driving output signals are fundamental for sensor interfacing and
actuator control.
• Timers and Counters: Timers and counters are essential for real-time operations.
Programming timers for periodic tasks, pulse-width modulation (PWM), and delay
generation is covered.
• Analog-to-Digital Converters (ADCs) and Digital-to-Analog Converters (DACs):
Interfacing with analog sensors and actuators using ADCs and DACs requires
understanding conversion techniques and programming considerations.
• Communication Protocols: Mastering serial communication protocols like I2C, SPI,
and UART is essential for interfacing with external devices and modules.

Interrupts and Real-Time Programming

Embedded systems often respond to external events. This section explores interrupts and real-
time concepts:

• Interrupt Handling Mechanisms: Understanding interrupt service routines (ISRs),


interrupt priority levels, and interrupt nesting is crucial for real-time response.
• Real-Time Concepts: Concepts like latency (time between event and response) and jitter
(variation in latency) are critical for real-time systems. Techniques for minimizing these
factors are explored.
• Efficient ISR Routines: Writing concise and efficient ISRs that minimize interrupt
latency is essential for maintaining real-time performance.

Embedded Development Tools

The selection of development tools significantly impacts the embedded C development


experience. Here’s a breakdown of essential tools:

• Debuggers: Debuggers allow for step-by-step code execution, variable inspection, and
breakpoint setting, crucial for troubleshooting and code optimization.
• Emulators and Simulators: Emulators mimic the behavior of a microcontroller on a
host computer, while simulators model the microcontroller’s instruction set. These tools
are valuable for pre-silicon development and testing.
• Integrated Development Environments (IDEs): IDEs combine editing, compiling,
debugging, and project management functionalities in a single interface, streamlining the
development workflow. Popular embedded C IDEs include Keil MDK-ARM, IAR
Embedded Workbench, and Eclipse with CDT plugin.

Modern Practices and Considerations


As the embedded systems landscape evolves, best practices and considerations need to be
adapted. Here are key areas to focus on in 2024:

• Security in Embedded Systems: Security vulnerabilities in embedded C code can have


catastrophic consequences.
o Secure coding practices like input validation, buffer overflow protection, and
memory access control are crucial.
o Static code analysis tools can help identify potential security risks in the code.
• Power Efficiency: With the rise of battery-powered IoT devices, optimizing code for low
power consumption is essential.
o Techniques like clock gating, peripheral power management, and low-power
sleep modes need to be carefully considered during development.
• Leveraging Hardware Features: Modern microcontrollers offer a plethora of new
features:
o Hardware accelerators for tasks like cryptography or signal processing can
significantly improve performance when utilized effectively in C code.
o Security modules like secure boot and hardware encryption engines can enhance
system security.
• Integration with IoT and Cloud Platforms (if applicable): For embedded systems
participating in the IoT ecosystem:
o Understanding data serialization formats like JSON or message queuing protocols
(MQTT) is necessary for communication with cloud platforms.
o Security considerations for data transmission over networks become paramount.

Advanced Topics

This section explores advanced concepts for those seeking to delve deeper:

• Embedded Linux Programming: Embedded Linux offers a rich operating system


environment for complex embedded systems. Understanding how C code interacts with
the Linux kernel and device drivers is valuable for certain applications.
• Real-Time Operating Systems (RTOS): Real-time operating systems (RTOS) provide a
layer of abstraction for managing tasks, resources, and communication in complex
embedded systems. Familiarity with concepts like threads, semaphores, and mutexes is
beneficial for RTOS-based development.
• Bare-Metal vs. RTOS Development: Choosing between bare-metal programming
(direct hardware interaction) and using an RTOS depends on project requirements.
Understanding the trade-offs between control, complexity, and development time is
crucial.
Part B
Embedded C/C

Introduction

Embedded C Course is a set of language extensions for the C programming language by the C
Standards Committee to statement commonality issues that exist between C extensions for
different embedded systems. It is used to develop microcontroller programming applications.

It includes features not available in standard C like fixed-point arithmetic, named address spaces,
and necessary I/O hardware addressing. Cell phones, MP3 players are some examples of
embedded systems in which embedded C is used to program and control these devices.
What is a program in C?

A computer program written in C is a human readable and ordered set of instructions that a
computer executes. It aims to provide a solution to a specific computing problem and tell the
computer to perform a certain task with a sequence of instructions that it needs to follow.

Essentially all programs are just plain text files stored on your computer’s hard drive that use a
special syntax which is defined by the programming language you're using.

Each language has its own rules that dictate what you can write and what's considered valid, and
what is not.

A program has keywords, which are specific words that are reserved and are part of the
language. It also has literal pieces of data like strings and numbers. And it has words that follow
the language’s rules, which we define and introduce to the language that don’t already exist (like
variables or methods).

What is a compiler?

Programs are written by us and for us. They are meant to be understood by humans.

When we write programs in human readable form, we can understand them – but the computer
may not be able to. Computers don’t directly understand programming languages, they only
understand binary. So programs need to be translated into this other form so the computer can
actually understand our program's instructions.

Programs in high level languages can be either compiled or interpreted. They use special pieces
of software called compilers and interpreters, respectively.

What's the difference between a compiler and an interpreter?

Both compilers and interpreters are programs, but they're far more complex ones, and they act as
translators. They take a program that's written in a human readable form and turn it into
something that computers can make sense of. And they make it possible to run and execute
programs on different computer systems.

Compiled programs are first converted into machine-readable form which means they are
translated into machine code before they run. Machine code is a numerical language – binary
instructions composed of sequences of 0s and 1s.

This compilation produces an executable program, that is a file containing the code in the
machine language that the CPU (Central Processing Unit) will be able to read, understand, and
execute directly.
After this, the program can run and the computer does what the program tells it to do. Compiled
programs have a stronger correspondence with the underlying hardware and can more easily
manipulate the computer's CPU and memory.

Interpreted programs, on the other hand, are not directly executed by the machine nor do they
need to be translated into a machine language program. Instead, they use an interpreter that
automatically and directly translates and executes each statement and instruction in the code line
by line during run time.

C is a compiled programming language. This means that it uses a compiler to analyse the source
code written in C and then turns it into a binary file that the computer's hardware can directly
execute. This will be specific for each particular machine.

Structure of Embedded C Program


With these data types in mind, let's take a look at the structure of a program in Embedded C.

Preprocessor Directives

Preprocessor directives are not normal code statements. They are lines of code that begin with
the character "#" and appear in Embedded C programming before the main function. At runtime,
the compiler looks for preprocessor directives within the code and resolves them completely
before resolving any of the functions within the code itself. Some preprocessor directives can
skip part of the main code based on certain conditions, while others may ask the preprocessor to
replace the directive with information from a separate file before executing the main code or to
behave differently based on the hardware resources available. Many types of preprocessor
directives are available in the Embedded C language.

Global Variable Declaration

Global declarations happen before the main function of the source code. Engineers can declare
global variables that may be called by the main program or any additional functions or sub-
programs within the code. Engineers may also define functions here that will be accessible
anywhere in the code.

Main Program

The main part of the program begins with main(). If the main function is expected to return an
integer value, we would write int main(). If no return is expected, convention dictates that we
should write void main(void).

• Declaration of local variables - Unlike global variables, these ones can only be called
by the function in which they are declared.
• Initializing variables/devices - A portion of code that includes instructions for
initializating variables, I/O ports, devices, function registers, and anything else needed for
the program to execute
• Program body - Includes the functions, structures, and operations needed to do
something useful with our embedded system

Subprograms

An embedded C program file is not limited to a single function. Beyond the main() function,
programmers can define additional functions that will execute following the main function when
the code is compiled.

Variables and Types

Variables are containers for storing data values, like numbers and characters.

In C, there are different types of variables (defined with different keywords), for example:

• int - stores integers (whole numbers), without decimals, such as 123 or -123
• float - stores floating point numbers, with decimals, such as 19.99 or -19.99
• char - stores single characters, such as 'a' or 'B'. Char values are surrounded by single quotes

Declaring (Creating) Variables

To create a variable, specify the type and assign it a value:

Syntax

type variableName = value;

Where type is one of C types (such as int), and variableName is the name of the variable (such
as x or myName). The equal sign is used to assign a value to the variable.

So, to create a variable that should store a number, look at the following example:

Example

Create a variable called myNum of type int and assign the value 15 to it:

int myNum = 15;

You can also declare a variable without assigning the value, and assign the value later:
Example

// Declare a variable
int myNum;

// Assign a value to the variable


myNum = 15;

Output Variables

Example

int myNum = 15;


Serial.print(myNum); // Outputs 15

To print other types, use %c for char and %f for float:

Example

// Create variables
int myNum = 15; // Integer (whole number)
float myFloatNum = 5.99; // Floating point number
char myLetter = 'D'; // Character

// Print variables
Serial.print("%d\n", myNum);
Serial.print("%f\n", myFloatNum);
Serial.print("%c\n", myLetter);

To combine both text and a variable, separate them with a comma inside the Serial.print()
function:

Example

int myNum = 15;


Serial.print("My favorite number is: “ , myNum);

To print different types in a single Serial.print() function, you can use the following:

Example

int myNum = 15;


char myLetter = 'D';
Change Variable Values

Note: If you assign a new value to an existing variable, it will overwrite the previous value:

Example

int myNum = 15; // myNum is 15


myNum = 10; // Now myNum is 10

You can also assign the value of one variable to another:

Example

int myNum = 15;

int myOtherNum = 23;

// Assign the value of myOtherNum (23) to myNum


myNum = myOtherNum;

// myNum is now 23, instead of 15


Serial.print(myNum);

Or copy values to empty variables:

Example

// Create a variable and assign the value 15 to it


int myNum = 15;

// Declare a variable without assigning it a value


int myOtherNum;

// Assign the value of myNum to myOtherNum


myOtherNum = myNum;

// myOtherNum now has 15 as a value


Serial.print(myOtherNum);
Add Variables Together

To add a variable to another variable, you can use the + operator:

Example

int x = 5;
int y = 6;
int sum = x + y;
Serial.println(sum);

Declare Multiple Variables

To declare more than one variable of the same type, use a comma-separated list:

Example

int x = 5, y = 6, z = 50;

You can also assign the same value to multiple variables of the same type:

Example

int x, y, z;
x = y = z = 50;

C Variable Names

All C variables must be identified with unique names.

These unique names are called identifiers.

Identifiers can be short names (like x and y) or more descriptive names (age, sum, totalVolume).

Note: It is recommended to use descriptive names in order to create understandable and


maintainable code:
Example

// Good
int minutesPerHour = 60;

// OK, but not so easy to understand what m actually is


int m = 60;

The general rules for naming variables are:

• Names can contain letters, digits and underscores


• Names must begin with a letter or an underscore (_)
• Names are case sensitive (myVar and myvar are different variables)
• Names cannot contain whitespaces or special characters like !, #, %, etc.
• Reserved words (such as int) cannot be used as names

Real-Life Example

Often in our examples, we simplify variable names to match their data type (myInt or myNum
for int types, myChar for char types etc). This is done to avoid confusion.

However, if you want a real-life example on how variables can be used, take a look at the
following, where we have made a program that stores different data of a college student:

Example

// Student data
int studentID = 15;
int studentAge = 23;
float studentFee = 75.25;
char studentGrade = 'B';

// Print variables
Serial.print(“ Student ID: “);
Serial.println(studentID);
Serial.print(“ Student Age: “);
Serial.println(studentAge);

Serial.print(“ Student Fee: “);


Serial.println(studentFee);

Serial.print(“ Student Grade: “);


Serial.println(studentGrade);

Basic Data Types

The data type specifies the size and type of information the variable will store.

Data Type Size Description

int 2 or 4 bytes Stores whole numbers, without decimals

Stores fractional numbers, containing one or more decimals. Sufficient


float 4 bytes
for storing 6-7 decimal digits

Stores fractional numbers, containing one or more decimals. Sufficient


double 8 bytes
for storing 15 decimal digits

char 1 byte Stores a single character/letter/number, or ASCII values

Set Decimal Precision

You have probably already noticed that if you print a floating-point number, the output will show
many digits after the decimal point:

Example

float myFloatNum = 3.5;


double myDoubleNum = 19.99;

Serial.print(myFloatNum); // Outputs 3.500000


Serial.print(myDoubleNum); // Outputs 19.990000

If you want to remove the extra zeros (set decimal precision),


Example

float myFloatNum = 3.5;

Serial.print(myFloatNum); // Default will show 6 digits after the decimal point


Serial.print(myFloatNum, 1); // Only show 1 digit
Serial.print(myFloatNum, 2); // Only show 2 digits
Serial.print(myFloatNum, 4); // Only show 4 digits

Constants
If you don't want others (or yourself) to change existing variable values, you can use the const
keyword.

This will declare the variable as "constant", which means unchangeable and read-only:

Example
const int myNum = 15; // myNum will always be 15
myNum = 10; // error: assignment of read-only variable 'myNum'

You should always declare the variable as constant when you have values that are unlikely to
change:

Example
const int minutesPerHour = 60;
const float PI = 3.14;

Notes On Constants

When you declare a constant variable, it must be assigned with a value:

Example

Like this:
const int minutesPerHour = 60;

This however, will not work:


const int minutesPerHour;
minutesPerHour = 60; // error
Good Practice

Another thing about constant variables, is that it is considered good practice to declare them with
uppercase. It is not required, but useful for code readability and common for C programmers:

Example
const int BIRTHYEAR = 1980;

➢ Operators
Operators are used to perform operations on variables and values.

In the example below, we use the + operator to add together two values:

Example

int myNum = 100 + 50;

Although the + operator is often used to add together two values, like in the example above, it
can also be used to add together a variable and a value, or a variable and another variable:

Example

int sum1 = 100 + 50; // 150 (100 + 50)


int sum2 = sum1 + 250; // 400 (150 + 250)
int sum3 = sum2 + sum2; // 800 (400 + 400)

C divides the operators into the following groups:

• Arithmetic operators
• Assignment operators
• Comparison operators
• Logical operators
• Bitwise operators

Arithmetic Operators

Arithmetic operators are used to perform common mathematical operations.


Operator Name Description Example Try it

+ Addition Adds together two values x+y

- Subtraction Subtracts one value from another x-y

* Multiplication Multiplies two values x*y

/ Division Divides one value by another x/y

% Modulus Returns the division remainder x%y

++ Increment Increases the value of a variable by 1 ++x

-- Decrement Decreases the value of a variable by 1 --x

Assignment Operators
Assignment operators are used to assign values to variables.

In the example below, we use the assignment operator (=) to assign the value 10 to a variable
called x:

Example

int x = 10;

The addition assignment operator (+=) adds a value to a variable:

Example

int x = 10;
x += 5;
A list of all assignment operators:

Operator Example Same As

= x=5 x=5

+= x += 3 x=x+3

-= x -= 3 x=x-3

*= x *= 3 x=x*3

/= x /= 3 x=x/3

%= x %= 3 x=x%3

&= x &= 3 x=x&3

|= x |= 3 x=x|3

^= x ^= 3 x=x^3

>>= x >>= 3 x = x >> 3

<<= x <<= 3 x = x << 3

Comparison Operators

Comparison operators are used to compare two values (or variables). This is important in
programming, because it helps us to find answers and make decisions.

The return value of a comparison is either 1 or 0, which means true (1) or false (0). These values
are known as Boolean values, and you will learn more about them in the Booleans and If..Else
chapter.

In the following example, we use the greater than operator (>) to find out if 5 is greater than 3:

Example

int x = 5;
int y = 3;
Serial.print("%d", x > y); // returns 1 (true) because 5 is greater than 3
A list of all comparison operators:

Operator Name Example Try it

== Equal to x == y

!= Not equal x != y

> Greater than x > y

< Less than x<y

Greater than
>= x >= y
or equal to

Less than or
<= x <= y
equal to

Logical Operators
You can also test for true or false values with logical operators.

Logical operators are used to determine the logic between variables or values:

Operator Name Description Example

Returns true if both statements are


&& Logical and x < 5 && x < 10
true

|| Logical or Returns true if one of the statements is true x < 5 || x < 4

! Logical not Reverse the result, returns false if the result is true !(x < 5 && x < 10)

Sizeof Operator

The memory size (in bytes) of a data type or a variable can be found with the sizeof operator:

Example

int myInt;
float myFloat;
double myDouble;
char myChar;

Serial.print(sizeof(myInt));
Serial.print("%lu\n", sizeof(myFloat));
Serial.print(sizeof(myDouble));
Serial.print(sizeof(myChar));

➢ Booleans
Very often, in programming, you will need a data type that can only have one of two values, like:

• YES / NO
• ON / OFF
• TRUE / FALSE

For this, C has a bool data type, which is known as booleans.

Booleans represent values that are either true or false.

Boolean Variables
In C, the bool type is not a built-in data type, like int or char.

It was introduced in C99, and you must import the following header file to use it:

#include <stdbool.h>

A boolean variable is declared with the bool keyword and can only take the values true or
false:

bool isProgrammingFun = true;


bool isFishTasty = false;

Before trying to print the boolean variables, you should know that boolean values are returned as
integers:

• 1 (or any other number that is not 0) represents true


• 0 represents false
Therefore, you must use the %d format specifier to print a boolean value:

Example

// Create boolean variables


bool isProgrammingFun = true;
bool isFishTasty = false;

// Return boolean values


Serial.print("%d", isProgrammingFun); // Returns 1 (true)
Serial.print("%d", isFishTasty); // Returns 0 (false)

However, it is more common to return a boolean value by comparing values and variables.

Comparing Values and Variables

Comparing values are useful in programming, because it helps us to find answers and make
decisions.

For example, you can use a comparison operator, such as the greater than (>) operator, to
compare two values:

Example

Serial.print("%d", 10 > 9); // Returns 1 (true) because 10 is greater than 9

From the example above, you can see that the return value is a boolean value (1).

You can also compare two variables:

Example

int x = 10;
int y = 9;
Serial.print("%d", x > y);

In the example below, we use the equal to (==) operator to compare different values:

Example

Serial.print("%d", 10 == 10); // Returns 1 (true), because 10 is equal to 10


Serial.print("%d", 10 == 15); // Returns 0 (false), because 10 is not equal to 15
Serial.print("%d", 5 == 55); // Returns 0 (false) because 5 is not equal to 55
You are not limited to only compare numbers. You can also compare boolean variables, or even
special structures, like arrays (which you will learn more about in a later chapter):

Example

bool isHamburgerTasty = true;


bool isPizzaTasty = true;

// Find out if both hamburger and pizza is tasty


Serial.print("%d", isHamburgerTasty == isPizzaTasty);

Remember to include the <stdbool.h> header file when working with bool variables.

Real Life Example


Let's think of a "real life example" where we need to find out if a person is old enough to vote.

In the example below, we use the >= comparison operator to find out if the age (25) is greater
than OR equal to the voting age limit, which is set to 18:

Example

int myAge = 25;


int votingAge = 18;

Serial.print("%d", myAge >= votingAge); // Returns 1 (true), meaning 25 year olds are allowed to vote!

Cool, right? An even better approach (since we are on a roll now), would be to wrap the code
above in an if...else statement, so we can perform different actions depending on the result:

Example

Output "Old enough to vote!" if myAge is greater than or equal to 18. Otherwise output "Not
old enough to vote.":

int myAge = 25;


int votingAge = 18;

if (myAge >= votingAge) {


Serial.print("Old enough to vote!");
} else {
Serial.print("Not old enough to vote.");
}
C If ... Else

Conditions and If Statements

You have already learned that C supports the usual logical conditions from mathematics:

• Less than: a < b


• Less than or equal to: a <= b
• Greater than: a > b
• Greater than or equal to: a >= b
• Equal to a == b
• Not Equal to: a != b

You can use these conditions to perform different actions for different decisions.

C has the following conditional statements:

• Use if to specify a block of code to be executed, if a specified condition is true


• Use else to specify a block of code to be executed, if the same condition is false
• Use else if to specify a new condition to test, if the first condition is false
• Use switch to specify many alternative blocks of code to be executed

The if Statement

Use the if statement to specify a block of code to be executed if a condition is true.

Syntax

if (condition) {
// block of code to be executed if the condition is true
}

Note that if is in lowercase letters. Uppercase letters (If or IF) will generate an error.

In the example below, we test two values to find out if 20 is greater than 18. If the condition is
true, print some text:

Example
if (20 > 18) {
Serial.print("20 is greater than 18");
}

We can also test variables:

Example

int x = 20;
int y = 18;
if (x > y) {
Serial.print("x is greater than y");
}

Example explained

In the example above we use two variables, x and y, to test whether x is greater than y (using the
> operator). As x is 20, and y is 18, and we know that 20 is greater than 18, we print to the screen
that "x is greater than y".

The else Statement

Use the else statement to specify a block of code to be executed if the condition is false.

Syntax

if (condition) {
// block of code to be executed if the condition is true
} else {
// block of code to be executed if the condition is false
}

Example

int time = 20;


if (time < 18) {
Serial.print("Good day.");
} else {
Serial.print("Good evening.");
}
// Outputs "Good evening."
Example explained

In the example above, time (20) is greater than 18, so the condition is false. Because of this, we
move on to the else condition and print to the screen "Good evening". If the time was less than
18, the program would print "Good day".

The else if Statement

Use the else if statement to specify a new condition if the first condition is false.

Syntax

if (condition1) {
// block of code to be executed if condition1 is true
} else if (condition2) {
// block of code to be executed if the condition1 is false and condition2 is true
} else {
// block of code to be executed if the condition1 is false and condition2 is false
}

Example

int time = 22;


if (time < 10) {
Serial.print("Good morning.");
} else if (time < 20) {
Serial.print("Good day.");
} else {
Serial.print("Good evening.");
}
// Outputs "Good evening."

Example explained

In the example above, time (22) is greater than 10, so the first condition is false. The next
condition, in the else if statement, is also false, so we move on to the else condition since
condition1 and condition2 is both false - and print to the screen "Good evening".

However, if the time was 14, our program would print "Good day."
Another Example

This example shows how you can use if..else to find out if a number is positive or negative:

Example

int myNum = 10; // Is this a positive or negative number?

if (myNum > 0) {
Serial.print("The value is a positive number.");
} else if (myNum < 0) {
Serial.print("The value is a negative number.");
} else {
Serial.print("The value is 0.");
}

Switch Statement
Instead of writing many if..else statements, you can use the switch statement.

The switch statement selects one of many code blocks to be executed:

Syntax

switch(expression) {
case x:
// code block
break;
case y:
// code block
break;
default:
// code block
}

This is how it works:

• The switch expression is evaluated once


• The value of the expression is compared with the values of each case
• If there is a match, the associated block of code is executed
• The break statement breaks out of the switch block and stops the execution
• The default statement is optional, and specifies some code to run if there is no case match

The example below uses the weekday number to calculate the weekday name:

Example

int day = 4;

switch (day) {
case 1:
Serial.print("Monday");
break;
case 2:
Serial.print("Tuesday");
break;
case 3:
Serial.print("Wednesday");
break;
case 4:
Serial.print("Thursday");
break;
case 5:
Serial.print("Friday");
break;
case 6:
Serial.print("Saturday");
break;
case 7:
Serial.print("Sunday");
break;
}

// Outputs "Thursday" (day 4)

The break Keyword

When C reaches a break keyword, it breaks out of the switch block.

This will stop the execution of more code and case testing inside the block.
When a match is found, and the job is done, it's time for a break. There is no need for more
testing.

A break can save a lot of execution time because it "ignores" the execution of all the rest of the
code in the switch block.

The default Keyword

The default keyword specifies some code to run if there is no case match:

Example

int day = 4;

switch (day) {
case 6:
Serial.print("Today is Saturday");
break;
case 7:
Serial.print("Today is Sunday");
break;
default:
Serial.print("Looking forward to the Weekend");
}

// Outputs "Looking forward to the Weekend"

Note: The default keyword must be used as the last statement in the switch, and it does not need
a break.

C While Loop

Loops

Loops can execute a block of code as long as a specified condition is reached.

Loops are handy because they save time, reduce errors, and they make code more readable.
While Loop

The while loop loops through a block of code as long as a specified condition is true:

Syntax

while (condition) {
// code block to be executed
}

In the example below, the code in the loop will run, over and over again, as long as a variable (i)
is less than 5:

Example

int i = 0;

while (i < 5) {
Serial.print("%d\n", i);
i++;
}

Note: Do not forget to increase the variable used in the condition (i++), otherwise the loop will
never end!

The Do/While Loop

The do/while loop is a variant of the while loop. This loop will execute the code block once,
before checking if the condition is true, then it will repeat the loop as long as the condition is
true.

Syntax

do {
// code block to be executed
}
while (condition);

The example below uses a do/while loop. The loop will always be executed at least once, even
if the condition is false, because the code block is executed before the condition is tested:

Example
int i = 0;

do {
Serial.print( i);
i++;
}
while (i < 5);

Do not forget to increase the variable used in the condition, otherwise the loop will never end!

C For Loop

For Loop

When you know exactly how many times you want to loop through a block of code, use the for
loop instead of a while loop:

Syntax

for (statement 1; statement 2; statement 3) {


// code block to be executed
}

Statement 1 is executed (one time) before the execution of the code block.

Statement 2 defines the condition for executing the code block.

Statement 3 is executed (every time) after the code block has been executed.

The example below will print the numbers 0 to 4:

Example

int i;

for (i = 0; i < 5; i++) {


Serial.print("%d\n", i);
}

Example explained

Statement 1 sets a variable before the loop starts (int i = 0).


Statement 2 defines the condition for the loop to run (i must be less than 5). If the condition is
true, the loop will start over again, if it is false, the loop will end.

Statement 3 increases a value (i++) each time the code block in the loop has been executed.

Another Example

This example will only print even values between 0 and 10:

Example

for (i = 0; i <= 10; i = i + 2) {


Serial.print("%d\n", i);
}

Nested Loops

It is also possible to place a loop inside another loop. This is called a nested loop.

The "inner loop" will be executed one time for each iteration of the "outer loop":

Example

int i, j;

// Outer loop
for (i = 1; i <= 2; ++i) {
Serial.print( i); // Executes 2 times

// Inner loop
for (j = 1; j <= 3; ++j) {
Serial.print(" Inner: %d\n", j); // Executes 6 times (2 * 3)
}
}

C Arrays
Arrays

Arrays are used to store multiple values in a single variable, instead of declaring separate
variables for each value.

To create an array, define the data type (like int) and specify the name of the array followed by
square brackets [].

To insert values to it, use a comma-separated list, inside curly braces:

int myNumbers[] = {25, 50, 75, 100};

We have now created a variable that holds an array of four integers.

Access the Elements of an Array

To access an array element, refer to its index number.

Array indexes start with 0: [0] is the first element. [1] is the second element, etc.

This statement accesses the value of the first element [0] in myNumbers:

Example

int myNumbers[] = {25, 50, 75, 100};


printf("%d", myNumbers[0]);

// Outputs 25

Change an Array Element

To change the value of a specific element, refer to the index number:

Example

myNumbers[0] = 33;

Example

int myNumbers[] = {25, 50, 75, 100};


myNumbers[0] = 33;
printf("%d", myNumbers[0]);

// Now outputs 33 instead of 25

Set Array Size

Another common way to create arrays, is to specify the size of the array, and add elements later:

Example

// Declare an array of four integers:


int myNumbers[4];

// Add elements
myNumbers[0] = 25;
myNumbers[1] = 50;
myNumbers[2] = 75;
myNumbers[3] = 100;

Using this method, you should know the size of the array, in order for the program to store
enough memory.

You are not able to change the size of the array after creation.

C Strings

Strings

Strings are used for storing text/characters.

For example, "Hello World" is a string of characters.

Unlike many other programming languages, C does not have a String type to easily create string
variables. Instead, you must use the char type and create an array of characters to make a string
in C:

char greetings[] = "Hello World!";


Note that you have to use double quotes ("").

To output the string, you can use the printf() function together with the format specifier %s to
tell C that we are now working with strings:

Example

char greetings[] = "Hello World!";


printf("%s", greetings);

Access Strings

Since strings are actually arrays in C, you can access a string by referring to its index number
inside square brackets [].

This example prints the first character (0) in greetings:

Example

char greetings[] = "Hello World!";


printf("%c", greetings[0]);

Note that we have to use the %c format specifier to print a single character.

Modify Strings

To change the value of a specific character in a string, refer to the index number, and use single
quotes:

Example

char greetings[] = "Hello World!";


greetings[0] = 'J';
printf("%s", greetings);
// Outputs Jello World! instead of Hello World!

C Functions

A function is a block of code which only runs when it is called.

You can pass data, known as parameters, into a function.


Functions are used to perform certain actions, and they are important for reusing code: Define
the code once, and use it many times.

Predefined Functions

So it turns out you already know what a function is. You have been using it the whole time while
studying this tutorial!

For example, main() is a function, which is used to execute code, and printf() is a function;
used to output/print text to the screen:

Example

int main() {
printf("Hello World!");
return 0;
}

Create a Function

To create (often referred to as declare) your own function, specify the name of the function,
followed by parentheses () and curly brackets {}:

Syntax

void myFunction() {
// code to be executed
}

Example Explained

• myFunction() is the name of the function


• void means that the function does not have a return value. You will learn more about return
values later in the next chapter
• Inside the function (the body), add code that defines what the function should do

Call a Function

Declared functions are not executed immediately. They are "saved for later use", and will be
executed when they are called.
To call a function, write the function's name followed by two parentheses () and a semicolon ;

In the following example, myFunction() is used to print a text (the action), when it is called:

Example

Inside main, call myFunction():

// Create a function
void myFunction() {
printf("I just got executed!");
}

int main() {
myFunction(); // call the function
return 0;
}

// Outputs "I just got executed!"

A function can be called multiple times:

Example

void myFunction() {
printf("I just got executed!");
}

int main() {
myFunction();
myFunction();
myFunction();
return 0;
}

// I just got executed!


// I just got executed!
// I just got executed!

C Function Declaration and Definition


Function Declaration and Definition

You just learned from the previous chapters that you can create and call a function in the
following way:

Example

// Create a function
void myFunction() {
printf("I just got executed!");
}

int main() {
myFunction(); // call the function
return 0;
}

A function consist of two parts:

• Declaration: the function's name, return type, and parameters (if any)
• Definition: the body of the function (code to be executed)

void myFunction() { // declaration


// the body of the function (definition)
}

For code optimization, it is recommended to separate the declaration and the definition of the
function.

You will often see C programs that have function declaration above main(), and function
definition below main(). This will make the code better organized and easier to read:

Example

// Function declaration
void myFunction();

// The main method


int main() {
myFunction(); // call the function
return 0;
}

// Function definition
void myFunction() {
printf("I just got executed!");
}

Another Example

If we use the example from the previous chapter regarding function parameters and return
values:

Example

int myFunction(int x, int y) {


return x + y;
}

int main() {
int result = myFunction(5, 3);
printf("Result is = %d", result);
return 0;
}
// Outputs 8 (5 + 3)

It is considered good practice to write it like this instead:

Example

// Function declaration
int myFunction(int, int);

// The main method


int main() {
int result = myFunction(5, 3); // call the function
printf("Result is = %d", result);
return 0;
}

// Function definition
int myFunction(int x, int y) {
return x + y;
}
C Comments

Comments in C

Comments can be used to explain code, and to make it more readable. It can also be used to
prevent execution when testing alternative code.

Comments can be singled-lined or multi-lined.

Single-line Comments

Single-line comments start with two forward slashes (//).

Any text between // and the end of the line is ignored by the compiler (will not be executed).

This example uses a single-line comment before a line of code:

Example

// This is a comment
printf("Hello World!");

This example uses a single-line comment at the end of a line of code:

Example

printf("Hello World!"); // This is a comment

C Multi-line Comments

Multi-line comments start with /* and ends with */.

Any text between /* and */ will be ignored by the compiler:

Example

/* The code below will print the words Hello World!


to the screen, and it is amazing */
printf("Hello World!");
PART C
Introduction to C Programming Language with Arduino
Examples

1.1 Syntax and Structure

1.1.1 Basic Syntax


Arduino Sketch Structure:

// Include necessary libraries


#include <Arduino.h>

// Setup function: runs once at the start

void setup() {

// Initialization code here

// Loop function: runs repeatedly

void loop() {

// Code to execute repeatedly

#include <Arduino.h> includes Arduino core functions.


void setup() initializes settings, runs once.
void loop() runs continuously.

Comments:

// Single line comment

/* Multi-line
comment */

1.1.2 Data Types

Basic Data Types:

int: Integer numbers


int ledPin = 13; // Pin number for an LED

float: Floating-point numbers

float temperature = 25.6;

double: Double-precision floating-point numbers (same as float in Arduino)

double temperature = 25.62789;

char: Single characters

char mode = 'A';

Modifiers:

unsigned int: Positive integers

unsigned int count = 0;

long: Larger integers

long bigNumber = 1000000L;

1.1.3 Operators

Arithmetic Operators:

int sum = 5 + 3; // 8

int product = 5 * 3; // 15
Relational Operators:

if (sensorValue > 500)

// Code if sensorValue is greater than 500

Logical Operators:

if (temperature > 20.0 && humidity < 50.0)

// Code if both conditions are true

Assignment Operators:

ledState = !ledState; // Toggle the state of ledState

1.2 Control Structures

1.2.1 if-else Statement

Example:

void setup() {

pinMode(LED_BUILTIN, OUTPUT); // Set LED pin as output

}
void loop() {

int sensorValue = analogRead(A0); // Read sensor value

if (sensorValue > 512) {

digitalWrite(LED_BUILTIN, HIGH); // Turn LED on

} else {

digitalWrite(LED_BUILTIN, LOW); // Turn LED off

delay(1000); // Wait for 1 second

1.2.2 switch-case Statement

Example:

void setup() {

pinMode(LED_BUILTIN, OUTPUT); // Set LED pin as output

void loop() {

int sensorValue = analogRead(A0); // Read sensor value

switch (sensorValue / 256) {

case 0:

digitalWrite(LED_BUILTIN, LOW); // Low light level

break;
case 1:

digitalWrite(LED_BUILTIN, HIGH); // High light level

break;

default:

digitalWrite(LED_BUILTIN, LOW); // Default case

delay(1000); // Wait for 1 second

1.2.3 Loops

for Loop:

Example:

void setup() {

pinMode(LED_BUILTIN, OUTPUT); // Set LED pin as output

void loop() {

for (int i = 0; i < 10; i++) {

digitalWrite(LED_BUILTIN, HIGH); // Turn LED on

delay(500); // Wait for 500 milliseconds

digitalWrite(LED_BUILTIN, LOW); // Turn LED off

delay(500); // Wait for 500 milliseconds

}
delay(2000); // Wait for 2 seconds before repeating

while Loop:

Example:

void setup()

pinMode(LED_BUILTIN, OUTPUT); // Set LED pin as output

void loop() {

int count = 0;

while (count < 10) {

digitalWrite(LED_BUILTIN, HIGH); // Turn LED on

delay(500); // Wait for 500 milliseconds

digitalWrite(LED_BUILTIN, LOW); // Turn LED off

delay(500); // Wait for 500 milliseconds

count++;

delay(2000); // Wait for 2 seconds before repeating

do-while Loop:
Example:

void setup() {

pinMode(LED_BUILTIN, OUTPUT); // Set LED pin as output

void loop() {

int count = 0;

do {

digitalWrite(LED_BUILTIN, HIGH); // Turn LED on

delay(500); // Wait for 500 milliseconds

digitalWrite(LED_BUILTIN, LOW); // Turn LED off

delay(500); // Wait for 500 milliseconds

count++;

} while (count < 10);

delay(2000); // Wait for 2 seconds before repeating

1.3 Functions

1.3.1 Declaration

Syntax:

return_type function_name(parameters);
Example: int calculateSum(int a, int b);

1.3.2 Definition

Syntax:

return_type function_name(parameters) {
// Code
return value;
}

Example:

int calculateSum(int a, int b) {


return a + b;
}

1.3.3 Usage

Example:

void setup() {

Serial.begin(9600); // Initialize serial communication

void loop() {

int result = calculateSum(5, 3); // Call function

Serial.println(result); // Print result to Serial Monitor

delay(1000); // Wait for 1 second

}
int calculateSum(int a, int b) {

return a + b;

1.4 Pointers
1.4.1 Basics

Definition:

A pointer is a variable that stores the address of another variable.

Syntax:

type *pointer_name;

Example:

int value = 10;

int *ptr = &value; // Pointer to an integer

1.4.2 Usage

Dereferencing a Pointer:

Access the value at the address pointed to by the pointer.

Example:

void setup() {

Serial.begin(9600);

int value = 42;


int *ptr = &value;

Serial.println(*ptr); // Print value (42)

void loop() {

// Nothing to do here

Pointer Arithmetic:

Incrementing a pointer to point to the next memory location.

Example:

void setup() {

Serial.begin(9600);

int arr[] = {10, 20, 30, 40, 50};

int *p = arr;

Serial.println(*(p + 2)); // Access third element (30)

void loop() {

// Nothing to do here

}
Passing Pointers to Functions:

Syntax:

void function_name(type *param);

Example:

void increment(int *p) {

(*p)++;

void setup() {

Serial.begin(9600);

int num = 10;

increment(&num); // Pass address of num

Serial.println(num); // Print incremented value (11)

void loop() {

// Nothing to do here

This detailed context integrates the basic concepts of C programming with practical
Arduino examples, illustrating how these concepts apply in an embedded environment.

………………………………………………………………………………………………

You might also like