ATmega168

Best Way to Use the ATmega168 ‘s Interrupts

atmega168

The ATmega168 microcontroller has three interrupt sources: external, timer, and serial. In this article, we’ll discuss the best way to use the ATmega168’s interrupts. We’ll also provide some code examples to help you get started.

Learn about common sources of interruption and how they may be applied for your next AVR microcontroller implementation!

HARDWARE

  • ATmega168
  • 680R Resistor(R2)
  • 5.6K Resistor (R1) 
  • 20pF Capacitor (C1, C2)
  • 100nF Capacitor (C4, C5)
  • 100uF Capacitor (C3)
  • 7805 Regulator (U2 – Optional if not using USBasp power)

SOFTWARE

  • Atmel Studio 7
  • WinAVR
  • USBasp

Thus far, we’ve learned how to use peripheral components on the Atmega168, such as the I/O port with an address, the A/D converter, and the timer. In this guide, we’ll learn about interruptions and how they can be used to produce real-time programs.

SCHEMATIC

Best Way to Use the ATmega168 's Interrupts O6SwYaq6wsTJcU EFU0ROi 6 Sw9vz1Z5U4U1fAub648enYYpNrbirpdGSxUq1QME4eWg

What Are Interrupts and How Do They Work?

Simple microcontroller programs can usually be completed entirely within the main function, with minimal use of peripherals. Most other microcontroller applications, on the other hand, are more complicated and need a huge amount of code. Interrupts can be very useful in this situation, but what precisely are interrupts?

Interrupts helps you take control of your time by allowing you to instantly schedule and manage your time in a more efficient way

Imagine that our microcontroller needs to have two functions operating at once: keep track of time accurately and blink an LED. Our program could first reset a timer, increment a counter, and then wait until the timer overflows, at which point the code could use the counter to blink the LED. However, while we find that our program accomplishes these tasks, it’s inherently inefficient by reason of how to use counters.

How can we fix this situation? We can use an interrupt on the timer! So instead of incrementing a counter in the main code, we shift the code to an interrupt service routine, which handles timing.

Typically, a microcontroller runs the LED blink code, but when the timer instantiates an interrupt, the microcontroller stops this loop, follows the timer interrupt procedure, then returns to executing the LED blink code. This allows our timer mission-critical code to execute efficiently without interference from the LED blink code, and this allows our LED blink code to more fluidly track time.

AVR Core Interrupts

The AVR table contains a vector table for each interrupt source, with each jump to a unique address. This is extremely beneficial, as it helps eliminate the need to individually compare the address of one interrupt source to the address of another, and could consequently save time.

Interrupts have accessible as the property address of the Atmega168. Interrupt attributes have to be configured prerequisite to use.

Best Way to Use the ATmega168 's Interrupts

Table Location

The Atmega168 has a memory area that can be used to update its firmware. Therefore, where the table of interrupt vector lines will be located on the board is considered important. If the table of memory lines is located in the area occupied by the bootloader, the update cannot be performed (don’t do this) if the bootloader is enabled.

Therefore, if you don’t use the bootloader, you should put the vector table at the bottom of the memory (near address 0x0000). If you do use the bootloader and you should put the vector table above the bootloader, this can be achieved by changing a few bits in the MCUCR register.

Best Way to Use the ATmega168 's Interrupts 9EoY9TiOZLAjmOV8i2Own632AwP Mdz8Ev fHuEN4X9Hr50cM7q3BEKyN4VuS 3UGDKB9ZbMfwq5nDZIEeRmWokMcaWBwYxUOrqD8SWd59AhYFHU6

Best Way to Use the ATmega168 's Interrupts yOsyJr30zc2CJs5J2zL2Mn4UpuYOyz595Xn3XLKwRHWCnAkWtLVWOd 8XdpSz8apG5xiMcE8NPt7rJhifYUaZMmu7n25gj3T5ezJd OhJTObhFBpmUcyFH8cQZfi4c VLyTvi7Xj

If IISEL = 0, then ISR is at the start of the vector table otherwise ISR is located in the boot loader. For the time being, leave this setting at zero.

Interrupt Enable Bits

The IVCE negotiation is equal to 1, so the ISR switchover is performed. Leave this with no 0 for now.

For each interrupt source, there is a bit that needs to be set to enable interrupts. Just like the PIC, there is a global enable bit in the STATUS register you will need to be all set to receive. To check where these flags are placed, you’ve got to read the documentation for the relevant peripheral.

Using WinAVR to write an ISR

We now know that interrupting routines is essential, which requires the C -language and the WINAVR compiler. It’s a simple matter in this regard. You just have to instruct the compiler to use the special reserved word ISR and to pass the interrupt name argument to the function. Remember that without an interrupt header file, you will have no chance of using an interrupt function.

#include <avr/interrupt.h>

ISR(TIMER0_OVF_vect)
{
	// Interestingly, the AVR automatically clears interrupt flags....unlike the PIC
	// Put your code here
}

Example of a Simple Blink

The ATmega168 will flash an LED attached to PD0 every so often in this example, with the rate of blinking regulated by timer 0. However, inside the timer overflow interrupt service routine, you may detect that the main function is empty and the LED is blinking (ISR). This means that we can put whatever code we want in the while loop and the interrupt will not be stopped.

/* * AVR Interrupt.c * * Created: 09/01/2018 * Author : RobinLaptop */ // These are really useful macros that help to get rid of unreadable bit masking code #define setBit(reg, bit) (reg = reg | (1 << bit)) #define clearBit(reg, bit) (reg = reg & ~(1 << bit)) #define toggleBit(reg, bit) (reg = reg ^ (1 << bit)) #define clearFlag(reg, bit) (reg = reg | (1 << bit)) #include #include ISR(TIMER0_OVF_vect) { // Interestingly, the AVR automatically clears interrupt flags =) ….unlike the PIC =( // Toggle the LED (PD0 , Pin 2) toggleBit(PORTD, PD0); } int main(void) { // Initialize Registers clearBit(TCCR0A, WGM00); // Configure WGM to be 0x00 for normal mode clearBit(TCCR0A, WGM01); clearBit(TCCR0B, WGM02); setBit(TCCR0B, CS00); // Configure clock source to be clock io at 1024 pre-scale clearBit(TCCR0B, CS01); setBit(TCCR0B, CS02); DDRD = 0xFF; // Make PORT D and output sei(); // Enable interrupts setBit(TIMSK0, TOIE0); // Enable the timer interrupt while (1) { // Put any code you want here // It should not affect the interrupt service routine! } }

Conclusion

This lesson will just demonstrate the 0 overflow interrupt, but it reveals just how interruptions are very fulfilling. If utilized properly, you can bring about a processor that can deal with signals instantly, and it can stop running the code. This can be used to do many things, including multitasking, handling various peripherals, and performing similar operations simultaneously.

video resource on youtube is available.