First Look At A Microcontroller
Introduction
What exactly is a microcontroller?
To put it simply, it is the computing brains of any device that takes decisions based on certain inputs.
Think of a handheld calculator. Each key is mapped to a certain command, whether it’s printing out a number to the screen (and storing it somewhere), performing calculations, clearing the screen, or storing and restoring values to and from memory. That leads us to the conclusion that the calculator has a brain that decides what to do, based on the pressed key. You can scale that concept up to space rockets, and down to smart watches.
So let’s dive a little deeper into this component, and figure out how to work with it.
Components
In its simplest form, a micro-controller includes:
A central processing unit (a.k.a the processor) that handles the decoding and execution of the commands
Memory: Random Access Memory (RAM) and Read-Only Memory (ROM)
An arithmetic logic units (ALU) that takes care of integer computations
Registers: specialized storage areas that are used for information needed by the processor, control information that are supplied by the programmer, or status information that are toggled by the processor
Input and output pins to communicate with the controller
These components are connected via buses, which are really tiny wires
So the components really emphasize what the microcontroller can do for us. We can write some instructions into the ROM, telling the controller to expect some sort of data from us using the input pins , be that connected to a sensor or a push button. We can also tell it to send out some feedback using the output pins, which could be connected to an LED pin or an LCD display. Since microcontrollers are also equipped with an ALU, it can execute math operations pretty quickly, so we can have it calculate its distance from an object it senses using an ultrasonic sensor, then calculate the number of rotations the wheels need to turn in order to get there.
Registers
One of the important concepts to grasp about microcontrollers is how the physical pins are connected to the registers, and how we can read from and write to them. For starters, each microcontroller has a certain register size: 8 bits (1 byte), 16 bits (2 bytes), or 32 bits (4 bytes). This means that each register will either have 8 slots of data, 16 slots of data, or 32 slots of data. Remembering that we are dealing with a digital system, this data will either be a 0 or a 1 (off or on). The following diagram features an 8-bit controller, where one of the many registers, Port A’s register, has 8 slots for a 1 or a 0.
For example: Port A’s register might hold the following information:
But what does this mean?
If the pin corresponding to that bit is connected to an input device, then we are either receiving voltage on that pin, which is writing a 1 to that bit, or we are NOT receiving voltage to that pin, which is writing a 0 to that bit.
If the pin corresponding to that bit is connected to an output device, then we are either sending voltage to that device by writing a 1 to that bit, or we are NOT sending voltage to that device by writing a 0 to that bit.
Practical Example
Below we have a simple circuit (hover over it for more info):
In this example, we want our LEDs to take turns turning on when we press the push button. The first time we press it, LED 1 will turn on. The second time, LED 2 will turn on, the third time, LED3 will turn on, the fourth time they will all turn off. Then we repeat the pattern.
Every problem has multiple ways of solving. And this is no exception. Technically, I can think of at least 3 different ways of achieving this behaviour. I will demonstrate one of them here, emphasizing that this may not be the best or only way to do it, it’s just the easiest to get started with. I will also be covering the actual code for this example in a later post, because it takes a bit of preliminary work to get that circuit set up. The following will only be pseudo-code (code description).
First of all, let’s analyze the problem a bit more thoroughly. We want to press a button, and with certain logic, should loop through LEDs or turn them all off. Typically, a task like that requires a counter, and that value should determine where we’re at in the LED cycling.
declare counter variable
Cool! We now need to increment that value every time we press that push button. Sounds like a conditional statement right? If push button is pressed, increment the counter variable. But how do we know if the button has been pushed? Well, since we’ve wired the push button in an active-high connection to bit 3, we will receive a 1 on Port B’s 3rd bit if we press the button, allowing current to flow from the source down to the pin.
if Port B's bit 3 is pressed
increment counter
Counter value | Corresponding LED |
---|---|
0 | All Off |
1 | LED 1 on |
2 | LED 2 on |
3 | LED 3 on |
Now we need to figure out how to cycle through our LEDs. One way to plan this is to assign each counter value to an LED, and based on that, turn the corresponding light on or off. But how do we toggle the LEDs? Well, they’re connected to Port B’s bits 1, 2, and 3. If we write a 1 to that register bit, we essentially give them power, and the corresponding LED will light up. (We have also set up our LEDs as active-high logic).
if counter is 0
Port B's bit 0 = 0
Port B's bit 1 = 0
Port B's bit 2 = 0
else if counter is 1
Port B's bit 0 = 0
Port B's bit 1 = 0
Port B's bit 2 = 1
else if counter is 2
Port B's bit 0 = 0
Port B's bit 1 = 1
Port B's bit 2 = 0
else if counter is 3
Port B's bit 0 = 1
Port B's bit 1 = 0
Port B's bit 2 = 0
The real question now is, what happens when the counter increments to 4? Based on the previous pseudo-code, nothing will happen anymore. That’s no good. The easiest way to fix that is to reset the counter when we reach 4, and before we check the value of the counter.
The complete logic for this program would look something like this:
configure ports
declare counter variable
loop indefinitely
if Port B's bit 3 is pressed
increment counter
if counter is 4
reset counter to 0
if counter is 0
Port B's bit 0 = 0
Port B's bit 1 = 0
Port B's bit 2 = 0
else if counter is 1
Port B's bit 0 = 0
Port B's bit 1 = 0
Port B's bit 2 = 1
else if counter is 2
Port B's bit 0 = 0
Port B's bit 1 = 1
Port B's bit 2 = 0
else if counter is 3
Port B's bit 0 = 1
Port B's bit 1 = 0
Port B's bit 2 = 0
Note that the logic for checking the counter is embedded inside the if block, meaning we will only check the value of the counter if we know it has been changed (when the button is pressed). That would give our microprocessor some rest.