All AVR microcontrollers have an internal watchdog timer that can be successfully used in your projects. Atmega328 and other modern AVR microcontrollers have the so-called Enhanced Watchdog Timer (WDT). It has few beneficial features, including a separate 128kHz clock source, reset the microcontroller, and generates an interrupt. The watchdog timer is nothing more than a simple counter that gives a pulse when it counts up from the hardware perspective. This pulse can either generate an interrupt or reset MCU (or do both). The watchdog timer can be reset to zero at any time with simple WDR command, and this is where the fun begins. If you enabled the watchdog timer, you have to take care and reset it before it fills up and resets MCU. Otherwise, if your program hangs or sticks in some infinite loop without a reset, watchdog counts up and resets the system. In this case, we get a pretty good program guardian who keeps an eye on program flow. In other special cases, the watchdog can serve as a simple software-based MCU reset source.
AVR microcontrollers have some amount of EEPROM memory on-chip. For instance, Atmega328 has 1K of byte-addressable EEPROM. EEPROM memory can be used to store and read variables during program execution and is nonvolatile. It means that it retains values when the power supply is off. EEPROM memory comes in handy when we need to store calibration values, remember program state before powering off (or power failure) or store constants in EEPROM memory when you are short of program memory space, especially when using smaller AVRs. Think of a simple security system – EEPROM is the ideal place to store lock combinations, code sequences, and passwords. AVR Datasheets claim that EEPROM can withhold at least 100000 writes/erase cycles.
In many cases, our embedded projects have to deal with various constants or arrays that aren’t changed during program execution. So why put them in RAM if we can store constant data in flash memory and leave RAM untouched. RAM is precious in micro-controllers, so leave it for stack and heaps. For instance, you are using an LCD in your project and want to send “Hello World” to it, you simply grab one of common LCD libraries and use commands like: By using this innocent action we end up in storing this string in flash memory during compilation and loading it to RAM during program start-up routines in the microcontroller. When LCDstring() command is executed string is read from SRAM not from FLASH. So we end up with two copies of same string (flash and SRAM), and worse – we occupy SRAM with constants. AVR flash memory locations can be read by the program, so this feature can be used to read constants directly from flash without loading them to RAM. Before doing this we need to use one special…
Until now, we used pretty simple program examples where all code fit into a single file and didn’t look very complicated. We didn’t care much about programming styles and modularizing. But due time, programs are going to grow bigger and more complex. It may become tough to maintain your code and even more complicated for other developers to read. We should follow some simple rules that make microcontroller programming more fun than scratching along. Split your programs Say you are writing a complex program that deals with LCD, USART, and even more peripherals. To make them all work, you need routines to init, read, write, and change mode. Imagine how many functions your single file would have to hold, and I am not talking about the main routine. It would end up with more scrolling than coding. So, the smart solution is to split your project into several files – libraries.
We have almost gone through main modes of AVR timers. It is impossible to review them all in more detail as there are lots of unique uses and cases. Anyway we will get back to them in future, as lots of routines are usually based on timer operations. We haven’t touched Timer/Counter2, which is another 8-bit timer of Atmega328. This is very similar to Timer0 with all pretty same features, including CTC, fast PWM and correct phase PWM modes. If you can run these modes in Timer0 then this will be easy doing on Timer2. The only difference is the naming of registers. So let’s leave this behind and get to something new and untouched. As I mentioned before, each timer has something unique, making them useful on special occasions. So this one isn’t an exception. It has a particular asynchronous timing mode which can be set to count events from an external clock source or be clocked with 32.768kHz crystal.
Atmega328 has one 16 bit timer, which is more powerful comparing to 8-bit timers. A 16-bit timer is called Timer/Counter1. Counter1 has twice more bits than 8-bit Counter0, so you get more counts leading to longer duration and more precise timings. The 16-bit timer has the same functionality as Timer0 plus more specific ones. We won’t be discussing Normal, CTC, fast PWM, and correct phase PWM modes, as these are equivalent to Timer0. But let’s focus on new things. There we have a new module called Input Capture Unit along with Input Capture Flag (ICF1) interrupt and the original waveform generating mode called Phase and Frequency Correct PWM.