Hello folks,
In this post, I’ll assume you’re completely new to embedded systems and electronics. My goal is to make understanding microcontrollers as simple and enjoyable as possible, even if you’re starting from scratch.
A microcontroller is essentially an integrated circuit (IC) designed to execute tasks programmed by the user.
In contrast, a microcontroller is a complete system on a single chip. It includes a small CPU along with memories like :-
For this guide, we’ll focus on one of the most popular microcontrollers: the ATmega328P. It was originally developed by Atmel, which was later acquired by Microchip Technology in 2016.
That’s the complete system in a single chip! The ATmega328P comes in a package called DIP-28 (Dual Inline Package with 28 pins, 14 on each side). This type of package is also referred to as through-hole, as it can be mounted on a printed circuit board (PCB) with matching holes or directly placed on a breadboard. We’ll explore this in detail later.
The ATmega328P is also available in other package types, such as the TQFP-32 (Thin Quad Flat Package with 32 pins).
This package is smaller and falls under the surface-mount category, designed to be mounted on flat surfaces with the correct pad layout, no holes are needed. Despite their physical differences, both package types function identically.
The through-hole type is especially popular in the maker community because of its ease of use and convenient access to its pins, which are called GPIOs (General Purpose Input/Output pins).
Its boot time is impressively fast, under 5 milliseconds from power-up!
Next, we’ll explore the minimum barebones setup needed to get the ATmega328P running. But first, let’s take a quick detour to understand how a breadboard works.
If you’re unfamiliar with breadboards, I recommend watching this fantastic 10 minute video. It provides a simple and clear explanation of how breadboards work and how to use them. If you’re already familiar, feel free to skip ahead. Otherwise, this is a must-watch!
Now that you’re familiar with breadboards, let’s put one to use! This is the breadboard we’ll use, it is the most common type, widely available and very affordable.
Notice the two power rails at the top and bottom of the breadboard. Let’s power the bottom rail using three AA batteries connected in series. Each AA battery provides about 1.5V when fully charged, so three of them combined will supply approximately 4.5V. Since the ATmega328P is a 5V device, 4.5V is within the safe operating range. To power the rail, simply connect the positive and negative wires from the battery pack to the rails, as shown below.
With the bottom power rail now energized, let’s power the top rail. Instead of running a separate set of wires from the battery pack, we can simply connect the top rail to the bottom rail using jumper wires, as shown here.
Now that both power rails are connected, it’s time to place the ATmega328P on the breadboard. Position it in the middle.
Next, let’s connect power to the ATmega328P. But which pins should we use? The chip requires a positive supply at pin 7 and pin 20, while the negative supply goes to pin 8 and pin 22.
How do you locate these pins? Every chip has a small mark (like a dot or notch) to indicate pin 1’s location. Once you find pin 1, you can count sequentially around the chip to identify the others. Here’s the pinout diagram for the ATmega328P
Each pin on the chip has a specific name. For example, instead of referring to pin 7, we can call it the VCC pin. Similarly, AVCC also requires a positive supply, while the GND pins need a negative supply.
To wire this on the breadboard, use the nearest power rails to supply power to the corresponding pins on each side of the microcontroller.
With power connected, the microcontroller should work, right? Not quite yet. On the ATmega series, pin 1 is the RESET pin. If this pin is connected to GND (negative power supply), the microcontroller stays OFF and won’t boot. Conversely, connecting it to VCC (positive supply) allows the microcontroller to run.
However, if the RESET pin is left unconnected (or “floating”), it fluctuates between VCC (5V) and GND (0V), causing the microcontroller to rapidly turn ON and OFF, an undesirable state for any application.
Since the RESET pin is crucial, it requires some protection. To connect it to VCC, we use a resistor. While the exact value isn’t critical, a 10kΩ resistor is commonly used. This setup is called a pull-up resistor, which means the pin is “pulled up” to the VCC voltage through the resistor. Let’s add this component to the circuit.
Now the microcontroller is operational, but there’s one more step: power line filtering. Stable and clean power is essential for the ATmega328P to run reliably. While this topic is quite detailed, we’ll stick to the basic recommendations for now.
It’s recommended to place bypass capacitors near the power pins. For the ATmega328P, this means adding capacitors between pins 7 and 8 (VCC and GND) and pins 20 and 22 (AVCC and GND).
Additionally, it’s recommended to connect a capacitor between pin 21 (AREF) and GND. Although AREF isn’t a power pin, this setup is beneficial in certain applications. To keep things simple, let’s just add the capacitor without diving into the specifics.
At this point, with a resistor, some capacitors, and power connected to the VCC and GND pins, the microcontroller is powered ON. However, it’s not doing anything exciting yet. Nothing is connected to its GPIO pins, no LEDs or other components, so we can’t visibly confirm it’s running. Even if we added an LED, it wouldn’t blink because there’s no firmware (code) in the microcontroller’s FLASH memory to control it.
Official programmers use Atmel’s proprietary In-System Programming (ISP) protocol. Fortunately, this protocol has been reverse-engineered, and affordable clones are widely available. These clones work perfectly to program classic ATmega microcontrollers using the ISP protocol.
One of the most popular and budget-friendly ISP programmers is the USBASP, which looks like this:
To use the ISP protocol, you’ll need to connect six pins from the programmer to the ATmega328P. These pins are:
These will be connected to ATmega328P programming pins like this :-
The USBASP programmer also supplies 5V directly from your PC’s USB port. This means we can use it to power the ATmega328P, eliminating the need for AA batteries.
Here’s what the updated setup looks like with the USBASP connected to the ATmega328P. I’ve color-coded the wires to match the pin connections in the diagram above:
Next, let’s set up the drivers for the USBASP programmer. When you first connect the USBASP to your PC, it will appear in the Device Manager as an unrecognized device.
To install the drivers, download the Zadig application from https://zadig.akeo.ie/.
After downloading, run the application and:
Once installed, you’ll see a confirmation message.
After successful installation, check the Device Manager, it should now recognize the USBASP programmer.
With the programmer ready, let’s verify if we can communicate with the ATmega328P. To do this, download the software AVRDUDESS from this GitHub page https://github.com/ZakKemble/AVRDUDESS/releases.
Be sure to download the setup version and install it in the default directory.
Install the app in the default folder.
Let it be full installation, don't change.
After installation, launch the APP.
When you first launch AVRDUDESS, the interface may seem overwhelming with numerous options. But don’t worry, we only need to perform a basic check to ensure our ATmega328P is active and detectable by the PC.
So select the programmer to usbasp-clone.
and select the MCU to ATmega328P
and hit Detect.
If the output window confirms detection, congratulations! Your ATmega328P is alive and ready to be programmed.
To write code, we’ll use an IDE called Microchip Studio. This will be the last software installation you’ll need for programming the ATmega328P.
Download from here - https://www.microchip.com/en-us/tools-resources/develop/microchip-studio#Downloads
Be sure to choose the offline installer for a smoother installation process.
Run the installer.
Hit next
Uncheck UC3 and SAM, because we don't need support for those microcontrollers, ours is AVR so only check that and hit next.
Uncheck the advance software example projects, we don't need them. Hit next
Hit next.
During the installation, you’ll be prompted to install the XC8 C Compiler, which Microchip includes by default. Although we won’t use it in this tutorial (we’ll rely on the avr-gcc C Compiler), you must install it to proceed with the IDE installation.
Anyways just hit Install.
Hit yes on the next prompt if it asks.
Hit next.
Hit next.
Hit next.
Let it install in the default directory, hit next.
Hit next.
Hit next.
Now wait for the installation to complete.
Hit finish.
Now that the compiler is installed, now the IDE installation will continue.
Prompts like this will pop up just keep on hitting install.
At last hit close and your microchip studio will launch.
Before we start coding, we need to configure Microchip Studio to recognize our USBASP clone programmer, since we aren’t using official programming tools.
Go to Tools -> External Tools
In this window add the following details.
Title: USBASP
Command: C:\Program Files (x86)\AVRDUDESS\avrdude.exe
Arguments -c usbasp-clone -p m328p -U flash:w:$(ProjectDir)Debug\$(TargetName).hex:i
Should look like this.
Check the Use Output window -> hit apply -> hit OK
Now that everything is set up, it’s time to write some code! Before we start, let’s connect an LED to pin PB0 using a 220Ω resistor.
In microchip studio go to File -> New -> Project
Select GCC C Executable Project
Give any appropriate name.
Hit OK.
Select ATmega328P as the device
Hit OK
Now you are ready to write the code.
Let’s start with a simple C program to toggle pin PB0 between HIGH and LOW (turning it ON and OFF).
Go to Build -> Build Solution or Hit F7
In the output window you'll see Build succeeded and no errors.
To program the device go to Tools -> USBASP.
The output window will display progress as the firmware is flashed onto the device. After flashing, the firmware will be read back to confirm it matches what you wrote. If everything went smoothly, your ATmega328P is now running the program!
If you encounter an error like “cannot set SCK period”, don’t worry. This happens because the firmware on many USBASP clone programmers is outdated. While you can resolve this by updating the programmer’s firmware, it doesn’t affect the functionality. Your program will still upload to the ATmega328P without issues, which is all that matters.
And voila, Your LED should now be blinking as expected.
In the embedded world, making an LED blink is often considered the equivalent of a “Hello, World!” program, except it involves less talking and more flashing!
You’ve now completed the journey to your first LED blink! From here, you can start experimenting by writing full-fledged programs and uploading them to your microcontroller.
With an Arduino board, you don’t have to worry about setting up power, adding resistors, or using a programmer. All those steps are pre-configured for you, allowing you to focus entirely on building and coding. Still, having this background knowledge is always a plus!
The Arduino we’ll focus on is the Arduino Uno R3. This board features the same ATmega328P microcontroller we’ve been working with. The difference is that the Arduino team has already mounted it on a PCB (Printed Circuit Board), so you don’t need to use a breadboard for basic setups.
Let me explain a few key features of the Arduino Uno R3 board.
Pin Headers: All the pins on the ATmega328P are conveniently exposed through these headers. You can easily connect jumper wires for input and output tasks.
Power Section: This area includes a voltage regulator, filtering capacitors, and a DC barrel jack connector. You can supply a voltage between 7-12V, and the onboard regulator will step it down to the required 5V for the ATmega328P. Additionally, there are multiple other ways to power the board.
ISP Header: This header includes the same six programming pins we used earlier on the breadboard version (MISO, MOSI, SCK, RESET, GND, and VCC). You can connect the USBASP programmer here to program the board directly. However, with Arduino, you won’t typically need to use this header, more on that shortly.
Reset Button: This allows you to manually restart the board whenever needed.
This is the another programming section, containing:
USB Type-B Port: This connector allows you to connect the Arduino to your PC using a USB cable. It serves two purposes: powering the board and enabling programming or communication.
USB-to-Serial Converter Chip: This chip bridges the USB port and the ATmega328P’s UART interface. It enables the ATmega328P to send and receive data through the USB connection using the UART protocol, which requires only two pins.
When you connect the Arduino to a PC.
The computer doesn’t directly detect the ATmega328P. Instead, it communicates with the USB-to-Serial converter chip, which appears as a COM port in the Device Manager.
The small pin headers near the USB-to-Serial converter chip are its programming headers. These are rarely needed and can be ignored for most projects.
The bootloader is a small program stored in the microcontroller’s flash memory. Every time the Arduino powers on or resets, the bootloader runs first. Its role is to check if any device (like a PC) is trying to upload new code. If it detects an upload, the bootloader receives the firmware and writes it to the microcontroller’s flash memory. Essentially, the ATmega328P programs itself with the help of the bootloader.
When the PC begins uploading code, it signals the USB-to-Serial converter chip to pull the RESET pin of the ATmega328P LOW, forcing it into bootloader mode. The PC then sends the firmware, which the bootloader receives via the USB-to-Serial chip and writes into the flash memory of the ATmega328P.
If no new code is detected during startup or reset, the bootloader simply jumps to the existing firmware in flash memory and executes it. Importantly, the bootloader itself is never overwritten, it only programs the remaining flash memory of the ATmega328P.
On the Arduino, the USB-to-Serial chip is always connected to the ATmega328P’s UART pins. This connection allows your custom firmware to send and receive data between the microcontroller and the PC without any additional setup. The necessary hardware is already in place, your job is simply to write the code!
Power LED: Indicates that the board is receiving power.
Pin 13 LED: Connected to one of the GPIO pins (PB5 on the ATmega328P) and can be used for basic testing or debugging.
RX/TX LEDs: Blink when data is being transmitted or received over the USB connection.
By default, the ATmega328P on the Arduino Uno operates at 16MHz, thanks to an onboard crystal oscillator. This is much faster than the 1MHz default clock speed of our earlier breadboard version. You can adjust the speed to 8MHz or higher (up to 20MHz) by modifying the fuses and adding the necessary components.
It’s entirely possible to set up the breadboard version of the ATmega328P to function just like an Arduino Uno. With a few additional components and some jumper wires, you can recreate the Arduino experience without soldering. However, for beginners, using a pre-built Arduino board is much simpler and more efficient.
Functionally, there’s no difference between the original Arduino Uno and its clones. However, the original board typically uses higher-quality components and features lead-free soldering, which is more environmentally friendly. This is one reason why the original is more expensive.
While clone boards may lack these refinements, they perform just as well for most applications, so there’s no need to worry about using one.
Since the Arduino board doesn’t have a dedicated space for components, we’ll use a breadboard to hold the LED and resistor. Then, use jumper wires to connect the breadboard circuit to the Arduino.
Download Arduino IDE.
When prompted with these dialog boxes, allow/install them.
Open Arduino IDE
Select Board -> Arduino Uno.
Now, let’s write some basic code. You’ll notice the Arduino code is slightly different from what we wrote for the breadboard example. This is because the Arduino team developed an abstraction layer on top of low-level C code to make it easier to read, learn, and understand.
While the code is still in C, the use of more intuitive function names simplifies programming. Behind the scenes, this is converted into the same low-level C code during compilation.
Hit the upload button and wait for the code to be uploaded.
And just like that, your program is now running on the Arduino!
By now, you've learned how to set up, power, and program an ATmega328P microcontroller, both on a breadboard and using the Arduino Uno. You’ve also discovered how the Arduino bootloader simplifies programming by handling the code upload automatically, leaving you to focus on building your projects.
Whether you're using a breadboard setup or an Arduino board, you're well on your way to diving into the world of embedded systems. With just a little more practice, you'll be able to create all sorts of exciting electronic projects.
Happy tinkering!
In this post, I’ll assume you’re completely new to embedded systems and electronics. My goal is to make understanding microcontrollers as simple and enjoyable as possible, even if you’re starting from scratch.
A microcontroller is essentially an integrated circuit (IC) designed to execute tasks programmed by the user.
How is it different from our computers?
In computing terms, our computers use a microprocessor, not a microcontroller.What is the difference?
A microprocessor is essentially just the CPU (central processing unit) on a chip. It depends on external components such as RAM, storage, a motherboard, and input/output controllers to function. A microprocessor isn’t a complete system by itself. Moreover, because it’s designed for high-speed number crunching, it consumes more energy, generates heat under heavy loads, and often requires external cooling.In contrast, a microcontroller is a complete system on a single chip. It includes a small CPU along with memories like :-
- RAM: Temporary storage that gets erased when the power is off, just like the RAM in your computer.
- Flash Memory: Permanent storage that retains data even when power is lost. This is where firmware and bulk data are stored. It can be erased in chunks before rewriting.
- EEPROM: Similar to flash memory but allows byte-level reading and writing. It’s ideal for saving settings or other small data that must persist through power cycles and may require frequent updates.
For this guide, we’ll focus on one of the most popular microcontrollers: the ATmega328P. It was originally developed by Atmel, which was later acquired by Microchip Technology in 2016.
ATmega328P
That’s the complete system in a single chip! The ATmega328P comes in a package called DIP-28 (Dual Inline Package with 28 pins, 14 on each side). This type of package is also referred to as through-hole, as it can be mounted on a printed circuit board (PCB) with matching holes or directly placed on a breadboard. We’ll explore this in detail later.
The ATmega328P is also available in other package types, such as the TQFP-32 (Thin Quad Flat Package with 32 pins).
This package is smaller and falls under the surface-mount category, designed to be mounted on flat surfaces with the correct pad layout, no holes are needed. Despite their physical differences, both package types function identically.
The through-hole type is especially popular in the maker community because of its ease of use and convenient access to its pins, which are called GPIOs (General Purpose Input/Output pins).
ATmega328P Specs
Let's check the specs on this bad boy.- CPU - AVR 8-bit single core processor, can run up to 20MHz clock speed. Can also be overclocked but not recommended.
- RAM - 2KB of SRAM.
- FLASH - 32KB of flash memory.
- EEPROM - 1KB
- Peripherals - we might see them later, no point listing, if we don't know what they do.
How does it boot ?
Booting this microcontroller is incredibly straightforward. Unlike a microprocessor, which typically requires an operating system and multiple boot sequences, a microcontroller like the ATmega328P simply needs power. Once powered, it immediately starts executing your program.Its boot time is impressively fast, under 5 milliseconds from power-up!
Next, we’ll explore the minimum barebones setup needed to get the ATmega328P running. But first, let’s take a quick detour to understand how a breadboard works.
If you’re unfamiliar with breadboards, I recommend watching this fantastic 10 minute video. It provides a simple and clear explanation of how breadboards work and how to use them. If you’re already familiar, feel free to skip ahead. Otherwise, this is a must-watch!
Now that you’re familiar with breadboards, let’s put one to use! This is the breadboard we’ll use, it is the most common type, widely available and very affordable.
Notice the two power rails at the top and bottom of the breadboard. Let’s power the bottom rail using three AA batteries connected in series. Each AA battery provides about 1.5V when fully charged, so three of them combined will supply approximately 4.5V. Since the ATmega328P is a 5V device, 4.5V is within the safe operating range. To power the rail, simply connect the positive and negative wires from the battery pack to the rails, as shown below.
With the bottom power rail now energized, let’s power the top rail. Instead of running a separate set of wires from the battery pack, we can simply connect the top rail to the bottom rail using jumper wires, as shown here.
Now that both power rails are connected, it’s time to place the ATmega328P on the breadboard. Position it in the middle.
Next, let’s connect power to the ATmega328P. But which pins should we use? The chip requires a positive supply at pin 7 and pin 20, while the negative supply goes to pin 8 and pin 22.
How do you locate these pins? Every chip has a small mark (like a dot or notch) to indicate pin 1’s location. Once you find pin 1, you can count sequentially around the chip to identify the others. Here’s the pinout diagram for the ATmega328P
Each pin on the chip has a specific name. For example, instead of referring to pin 7, we can call it the VCC pin. Similarly, AVCC also requires a positive supply, while the GND pins need a negative supply.
To wire this on the breadboard, use the nearest power rails to supply power to the corresponding pins on each side of the microcontroller.
With power connected, the microcontroller should work, right? Not quite yet. On the ATmega series, pin 1 is the RESET pin. If this pin is connected to GND (negative power supply), the microcontroller stays OFF and won’t boot. Conversely, connecting it to VCC (positive supply) allows the microcontroller to run.
However, if the RESET pin is left unconnected (or “floating”), it fluctuates between VCC (5V) and GND (0V), causing the microcontroller to rapidly turn ON and OFF, an undesirable state for any application.
Since the RESET pin is crucial, it requires some protection. To connect it to VCC, we use a resistor. While the exact value isn’t critical, a 10kΩ resistor is commonly used. This setup is called a pull-up resistor, which means the pin is “pulled up” to the VCC voltage through the resistor. Let’s add this component to the circuit.
Now the microcontroller is operational, but there’s one more step: power line filtering. Stable and clean power is essential for the ATmega328P to run reliably. While this topic is quite detailed, we’ll stick to the basic recommendations for now.
It’s recommended to place bypass capacitors near the power pins. For the ATmega328P, this means adding capacitors between pins 7 and 8 (VCC and GND) and pins 20 and 22 (AVCC and GND).
Additionally, it’s recommended to connect a capacitor between pin 21 (AREF) and GND. Although AREF isn’t a power pin, this setup is beneficial in certain applications. To keep things simple, let’s just add the capacitor without diving into the specifics.
At this point, with a resistor, some capacitors, and power connected to the VCC and GND pins, the microcontroller is powered ON. However, it’s not doing anything exciting yet. Nothing is connected to its GPIO pins, no LEDs or other components, so we can’t visibly confirm it’s running. Even if we added an LED, it wouldn’t blink because there’s no firmware (code) in the microcontroller’s FLASH memory to control it.
How do you program the ATmega328P?
To program the ATmega328P, you’ll need a programmer. Microchip offers official programmers, with the most common being the ATMEL ICE. However, this tool is expensive because it includes advanced features like debugging, which aren’t necessary at the beginner level. For now, I wouldn’t recommend it.Official programmers use Atmel’s proprietary In-System Programming (ISP) protocol. Fortunately, this protocol has been reverse-engineered, and affordable clones are widely available. These clones work perfectly to program classic ATmega microcontrollers using the ISP protocol.
One of the most popular and budget-friendly ISP programmers is the USBASP, which looks like this:
To use the ISP protocol, you’ll need to connect six pins from the programmer to the ATmega328P. These pins are:
- 5V: Power supply
- GND: Ground
- MISO: Master-In Slave-Out
- MOSI: Master-Out Slave-In
- SCK: Serial Clock
- RESET: Resets the microcontroller
These will be connected to ATmega328P programming pins like this :-
The USBASP programmer also supplies 5V directly from your PC’s USB port. This means we can use it to power the ATmega328P, eliminating the need for AA batteries.
Here’s what the updated setup looks like with the USBASP connected to the ATmega328P. I’ve color-coded the wires to match the pin connections in the diagram above:
Next, let’s set up the drivers for the USBASP programmer. When you first connect the USBASP to your PC, it will appear in the Device Manager as an unrecognized device.
To install the drivers, download the Zadig application from https://zadig.akeo.ie/.
After downloading, run the application and:
- Select the USBASP device.
- Change the driver to libusbK (v3.1.0.0).
- Click Install Driver.
Once installed, you’ll see a confirmation message.
After successful installation, check the Device Manager, it should now recognize the USBASP programmer.
With the programmer ready, let’s verify if we can communicate with the ATmega328P. To do this, download the software AVRDUDESS from this GitHub page https://github.com/ZakKemble/AVRDUDESS/releases.
Be sure to download the setup version and install it in the default directory.
Install the app in the default folder.
Let it be full installation, don't change.
After installation, launch the APP.
When you first launch AVRDUDESS, the interface may seem overwhelming with numerous options. But don’t worry, we only need to perform a basic check to ensure our ATmega328P is active and detectable by the PC.
So select the programmer to usbasp-clone.
and select the MCU to ATmega328P
and hit Detect.
If the output window confirms detection, congratulations! Your ATmega328P is alive and ready to be programmed.
To write code, we’ll use an IDE called Microchip Studio. This will be the last software installation you’ll need for programming the ATmega328P.
Download from here - https://www.microchip.com/en-us/tools-resources/develop/microchip-studio#Downloads
Be sure to choose the offline installer for a smoother installation process.
Run the installer.
Hit next
Uncheck UC3 and SAM, because we don't need support for those microcontrollers, ours is AVR so only check that and hit next.
Uncheck the advance software example projects, we don't need them. Hit next
Hit next.
During the installation, you’ll be prompted to install the XC8 C Compiler, which Microchip includes by default. Although we won’t use it in this tutorial (we’ll rely on the avr-gcc C Compiler), you must install it to proceed with the IDE installation.
Anyways just hit Install.
Hit yes on the next prompt if it asks.
Hit next.
Hit next.
Hit next.
Let it install in the default directory, hit next.
Hit next.
Hit next.
Now wait for the installation to complete.
Hit finish.
Now that the compiler is installed, now the IDE installation will continue.
Prompts like this will pop up just keep on hitting install.
At last hit close and your microchip studio will launch.
Before we start coding, we need to configure Microchip Studio to recognize our USBASP clone programmer, since we aren’t using official programming tools.
Go to Tools -> External Tools
In this window add the following details.
Title: USBASP
Command: C:\Program Files (x86)\AVRDUDESS\avrdude.exe
Arguments -c usbasp-clone -p m328p -U flash:w:$(ProjectDir)Debug\$(TargetName).hex:i
Should look like this.
Check the Use Output window -> hit apply -> hit OK
Now that everything is set up, it’s time to write some code! Before we start, let’s connect an LED to pin PB0 using a 220Ω resistor.
In microchip studio go to File -> New -> Project
Select GCC C Executable Project
Give any appropriate name.
Hit OK.
Select ATmega328P as the device
Hit OK
Now you are ready to write the code.
Let’s start with a simple C program to toggle pin PB0 between HIGH and LOW (turning it ON and OFF).
Go to Build -> Build Solution or Hit F7
In the output window you'll see Build succeeded and no errors.
To program the device go to Tools -> USBASP.
The output window will display progress as the firmware is flashed onto the device. After flashing, the firmware will be read back to confirm it matches what you wrote. If everything went smoothly, your ATmega328P is now running the program!
If you encounter an error like “cannot set SCK period”, don’t worry. This happens because the firmware on many USBASP clone programmers is outdated. While you can resolve this by updating the programmer’s firmware, it doesn’t affect the functionality. Your program will still upload to the ATmega328P without issues, which is all that matters.
And voila, Your LED should now be blinking as expected.
In the embedded world, making an LED blink is often considered the equivalent of a “Hello, World!” program, except it involves less talking and more flashing!
You’ve now completed the journey to your first LED blink! From here, you can start experimenting by writing full-fledged programs and uploading them to your microcontroller.
What is Arduino?
Everything we’ve done so far hasn’t involved Arduino, and that was intentional. I wanted you to understand the foundational setup and programming process so you can fully appreciate what Arduino offers.With an Arduino board, you don’t have to worry about setting up power, adding resistors, or using a programmer. All those steps are pre-configured for you, allowing you to focus entirely on building and coding. Still, having this background knowledge is always a plus!
The Arduino we’ll focus on is the Arduino Uno R3. This board features the same ATmega328P microcontroller we’ve been working with. The difference is that the Arduino team has already mounted it on a PCB (Printed Circuit Board), so you don’t need to use a breadboard for basic setups.
Let me explain a few key features of the Arduino Uno R3 board.
Pin Headers: All the pins on the ATmega328P are conveniently exposed through these headers. You can easily connect jumper wires for input and output tasks.
Power Section: This area includes a voltage regulator, filtering capacitors, and a DC barrel jack connector. You can supply a voltage between 7-12V, and the onboard regulator will step it down to the required 5V for the ATmega328P. Additionally, there are multiple other ways to power the board.
ISP Header: This header includes the same six programming pins we used earlier on the breadboard version (MISO, MOSI, SCK, RESET, GND, and VCC). You can connect the USBASP programmer here to program the board directly. However, with Arduino, you won’t typically need to use this header, more on that shortly.
Reset Button: This allows you to manually restart the board whenever needed.
This is the another programming section, containing:
USB Type-B Port: This connector allows you to connect the Arduino to your PC using a USB cable. It serves two purposes: powering the board and enabling programming or communication.
USB-to-Serial Converter Chip: This chip bridges the USB port and the ATmega328P’s UART interface. It enables the ATmega328P to send and receive data through the USB connection using the UART protocol, which requires only two pins.
When you connect the Arduino to a PC.
The computer doesn’t directly detect the ATmega328P. Instead, it communicates with the USB-to-Serial converter chip, which appears as a COM port in the Device Manager.
The small pin headers near the USB-to-Serial converter chip are its programming headers. These are rarely needed and can be ignored for most projects.
How does programming work?
Here’s where the magic of Arduino comes into play, the ATmega328P on the Arduino Uno comes pre-programmed with a bootloader firmware.The bootloader is a small program stored in the microcontroller’s flash memory. Every time the Arduino powers on or resets, the bootloader runs first. Its role is to check if any device (like a PC) is trying to upload new code. If it detects an upload, the bootloader receives the firmware and writes it to the microcontroller’s flash memory. Essentially, the ATmega328P programs itself with the help of the bootloader.
When the PC begins uploading code, it signals the USB-to-Serial converter chip to pull the RESET pin of the ATmega328P LOW, forcing it into bootloader mode. The PC then sends the firmware, which the bootloader receives via the USB-to-Serial chip and writes into the flash memory of the ATmega328P.
If no new code is detected during startup or reset, the bootloader simply jumps to the existing firmware in flash memory and executes it. Importantly, the bootloader itself is never overwritten, it only programs the remaining flash memory of the ATmega328P.
On the Arduino, the USB-to-Serial chip is always connected to the ATmega328P’s UART pins. This connection allows your custom firmware to send and receive data between the microcontroller and the PC without any additional setup. The necessary hardware is already in place, your job is simply to write the code!
What else does the Arduino Uno have?
The Arduino Uno comes with several built-in LEDs:Power LED: Indicates that the board is receiving power.
Pin 13 LED: Connected to one of the GPIO pins (PB5 on the ATmega328P) and can be used for basic testing or debugging.
RX/TX LEDs: Blink when data is being transmitted or received over the USB connection.
By default, the ATmega328P on the Arduino Uno operates at 16MHz, thanks to an onboard crystal oscillator. This is much faster than the 1MHz default clock speed of our earlier breadboard version. You can adjust the speed to 8MHz or higher (up to 20MHz) by modifying the fuses and adding the necessary components.
It’s entirely possible to set up the breadboard version of the ATmega328P to function just like an Arduino Uno. With a few additional components and some jumper wires, you can recreate the Arduino experience without soldering. However, for beginners, using a pre-built Arduino board is much simpler and more efficient.
Is there any difference between original and clone Arduino Uno boards?
Functionally, there’s no difference between the original Arduino Uno and its clones. However, the original board typically uses higher-quality components and features lead-free soldering, which is more environmentally friendly. This is one reason why the original is more expensive.
While clone boards may lack these refinements, they perform just as well for most applications, so there’s no need to worry about using one.
How to program an Arduino?
Before programming, let’s connect an LED to the Arduino. We’ll use the same LED and 220Ω resistor from the breadboard example and connect it to pin 12 on the Arduino Uno.Since the Arduino board doesn’t have a dedicated space for components, we’ll use a breadboard to hold the LED and resistor. Then, use jumper wires to connect the breadboard circuit to the Arduino.
Download Arduino IDE.
When prompted with these dialog boxes, allow/install them.
Open Arduino IDE
Select Board -> Arduino Uno.
Now, let’s write some basic code. You’ll notice the Arduino code is slightly different from what we wrote for the breadboard example. This is because the Arduino team developed an abstraction layer on top of low-level C code to make it easier to read, learn, and understand.
While the code is still in C, the use of more intuitive function names simplifies programming. Behind the scenes, this is converted into the same low-level C code during compilation.
Hit the upload button and wait for the code to be uploaded.
And just like that, your program is now running on the Arduino!
By now, you've learned how to set up, power, and program an ATmega328P microcontroller, both on a breadboard and using the Arduino Uno. You’ve also discovered how the Arduino bootloader simplifies programming by handling the code upload automatically, leaving you to focus on building your projects.
Whether you're using a breadboard setup or an Arduino board, you're well on your way to diving into the world of embedded systems. With just a little more practice, you'll be able to create all sorts of exciting electronic projects.
Happy tinkering!
Last edited: