A microcontroller is basically a small computer, whose main job is to control electronics. Just like your normal computers, it has a CPU, some RAM and some flash memory to store your program. It also has programmable IO (Input/Ouput) pins. These pins are what helps them ‘control’ your electronics. There are tons of microcontrollers available in the market. The most popular one being the Arduino UNO. Now just to clarify, Arduino UNO is not actually the microcontroller, rather, it is just a ‘development board’ built around the ATmega328P microcontroller. Development boards make it easy for us to work with microcontrollers, as they have additional circuits designed to help run and program them.
The Arduino IDE is the most common program that you will be using while working with an Arduino (and many other microcontrollers). You can download it from here.
We will be using Tinkercad throughout this module for easy simulations. Go here and make an account if you don’t have one already.
Let’s start with the ‘Hello World’ of microcontrollers, ie, blinking an LED. Go to this example. Click on ‘Tinker this’ and then ‘Start Simulation’. Click on ‘Code’ to see the magic behind all of it. As you can see, the code is made up of two ‘functions’, namely void setup()
and void loop()
. The important part:
void setup()
: Runs once at the start.void loop()
: Obviously, keeps running in a loop.
Now, a very important reference image:
I would suggest you to always keep this handy while working with your Arduino UNO.
Each pin on your microcontroller serves a purpose, and majority of them, can be used in a variety of ways. As you can see in the image, D8
is our pin number 8, which has been marked as a Digital Pin
, which means you can turn it HIGH
or LOW
. Now, as Arduino UNO runs on 5V:
HIGH
/ON
means 5VLOW
/OFF
means Ground
Before you start using a pin, you need set the mode of the pin to tell the microcontroller how you intend on using it.
void setup()
{
pinMode(8, OUTPUT);
}
This, at the start, sets the mode of pin 8 to OUTPUT
, ie, you can turn it on or off.
void loop()
{
digitalWrite(8, HIGH);
delay(1000);
digitalWrite(8, LOW);
delay(1000);
}
This first turns the pin 8 HIGH
and then waits for 1000 miliseconds, ie, 1 second. Then it turns the pin LOW
and again waits 1 second. After that, the cycle continues indefinitely, and we get a blinking LED!
(Notice that we have a current limiting resistor in series with our LED so that it does not burn up).
Let’s try to vary the brightness of the LED. Arduino UNO doesn’t have a Digtal-to-Analog Converter (DAC), so we cannot get a true analog output. Look up the difference between digital and analog if you do not know. Arduino UNO can produce a PWM signal, which in most cases can be used as an alternative to true analog output. Pins that support PWM output are marked with a tilde (~) before their number. Looking at the pinout diagram, we see that pin 6 is one of such pins. Look at this simulation.
#define LED_PIN 6
byte brightness = 0;
The first line basically means - “replace every occurence of LED_PIN
with the number 6.”
Next, we define a variable of the type byte
, and initialize it to zero. Go here to see all the datatypes available to you. As you can see from the documentation, a byte
stores values from 0 to 255.
void setup()
{
pinMode(LED_PIN, OUTPUT);
}
This is the same as before.
void loop()
{
analogWrite(LED_PIN, brightness);
delay(10);
brightness++;
}
Now, for the analogWrite
function, a value of 0 corresponds to a PWM signal with 0% duty cycle (ie completely off) and it linearly goes up to 255, which corresponds to a PWM signal with 100% duty cycle (ie fully on). The last line simply means ‘add 1 to the brightness
variable’.
As a result, the brightness of the LED increases with time. Note that brightness suddenly drops to zero. This is due to something called the ‘Integer Overflow’. Basically, when the value of brightness
is 255, and we try to add 1 to it, the result comes out to be 256, but as a byte can only store values upto 255, it loops around to 0. Therefore, the value of brightness
becomes 0, and hence the LED also turns off momentarily. Then the cycle continues.
Let’s say you want to toggle the LED using a push button. When you press the push button once, the LED turns on, and when you push it again, it turns off. Take a look at this simulation. Try to push the button a few times.
#define LED_PIN 4
#define BUTTON_PIN 2
void setup()
{
pinMode(LED_PIN, OUTPUT);
pinMode(BUTTON_PIN, INPUT);
}
General setup. Note that the pinMode
of BUTTON_PIN
has been set to INPUT
.
bool led_state = false;
bool prev_button_state = false;
We create two variables of type bool
(check the official reference provided earlier if you don’t know what that means).
void loop()
{
bool button_state = !digitalRead(BUTTON_PIN);
if(prev_button_state == false && button_state == true)
{
led_state = !led_state;
digitalWrite(LED_PIN, led_state);
}
prev_button_state = button_state;
}
OK, we have a lot going on here. So first we use the digitalRead
function to read the state of the button. The function returns true
(or 1) if the BUTTON_PIN
is connected to 5V, and false
(or 0) if it is connected to ground. Note that when we press the button, the pin gets connected to ground, whereas by default it is connected to 5V (using the pull-up resistor). As this would give us false
when we press the button, we have added an exclamation mark in front of the function call, which simply inverts the output. Therefore, now when we press the button, button_state
will be set to true
.
prev_button_state
corresponds to the state of the button during the previous iteration of the loop. button_state
corresponds to the current state. We set prev_button_state
equal to button_state
at the end of the loop.
Now, if the previous state of the button was false
(unpressed), but now is true
(pressed), we have detected a button press. Then, we toggle the led_state
variable (set to its opposite using the exclamation mark). Then we write the led_state
to LED_PIN
. As you can see, you can use true
/ false
instead of HIGH
/ LOW
. HIGH
is basically the number 1 and LOW
is the number 0. You can use any non-zero number for the HIGH
state, as anything non-zero is true
, whereas zero is false
.
Note that we can remove the pull-up resistor as Arduino also comes with a builtin one. To use the builtin pull-up resistor, set the pinMode
of BUTTON_PIN
to INPUT_PULLUP
. Go here to learn about floating-pins and pull-up/pull-down resistors.
What we saw previously was an example of digital input. It can have only two states - on or off. Now we’ll look at analog input. Let’s control the speed of blinking of an LED using a dial. We use a potentiometer as the dial. Here is the simulation. The code, now should be self-explanatory.
Let’s send and receive messages from our Arduino. There are a number of communication protocols popular in the world of microcontrollers, such as UART, I2C, SPI, etc. Arduino uses UART (generally called serial communication) to talk to your system. Go to this simulation. Go to the code section and click on the ‘Serial Monitor’ below. Now, enter values from 0 to 255 to change the brightness of the LED. You will also see those values printed back to you.
#define LED_PIN 9
void setup()
{
pinMode(LED_PIN, OUTPUT);
Serial.begin(9600);
Serial.setTimeout(10);
}
Serial.begin
function begins the serial communication at a certain baud-rate (9600 in this case). You can learn about baud-rate online, but in general, it’s good enough to know that the baud-rate of your Arduino and that of you serial monitor should match (you have to choose a baud-rate in the Arduino IDE). Our serial monitor sends data to the Arduino sequentially. Therefore, we need to set a timeout for the Arduino to know that it can safely end the interpretation of the bytes. It is necessary only for the functions that parse the incoming bytes to a value (such as parseFloat
and parseInt
).
byte brightness = 0;
void loop()
{
if(Serial.available() > 0)
{
brightness = Serial.parseInt();
Serial.println(brightness);
analogWrite(LED_PIN, brightness);
}
}
if Serial.available
is greater than 0, it means that we have received some input. Then we parse the input stream (which is in form of bytes) into an integer, and store it in our brightness value. Using Serial.println
, we print the value back to the user. Then, we simply set the brightness of the LED.
I highly suggest you to go through the official documentation of the serial communication here to learn about all the different functions available to you. Also, you can look up a tutorial about this.
Everything till now has just given you an idea of what using a microcontroller looks like. Here are some links that will help you move forward in your journey of microcontrollers.
- Learning the IDE
- General mistakes
- Our program for digital input is WRONG
- Types of sensors
- Interrupts
- Registers
Arduino UNO, although being very popular, is not the perfect fit for every project. There are tons of other microcontrollers that you should consider. Most important in our case would be the esp32. It has a faster processor, and builtin wifi and bluetooth support, being cheap at the same time. Be sure to take a look at it, as it is probably the microcontroller you would be using in your projects. Other microcontrollers are the Arduino Mega, Arduino Nano, etc.