In this example, I’ll switch over to using the ATtiny2313’s 8-bit timer module for toggling the LEDs. Everything is still connected exactly as it was in the last example.
Before I get too far along with my examples, I’m going to introduce a new section. Ideally people with little experience in microcontrollers should be able to follow along and pick up useful tips (if not just able to take and compile my code). So, I’ll be introducing the new pieces as I understand it.
Timer module - The ATtiny2313 has many modules that will do a lot of the hard work for you, one set of these is the 8-bit timer and the 16-bit timer. The most basic operation involves setting up a prescaler
Prescaler - The prescaler effectively divides the clock. So, with a prescaler setting of /64 on the timer module, the timer will not tick on every clock cycle, but only every 64 cycles.
Interrupts - One of the more powerful features of working at a low level, interrupts allow modules to stop all code execution and jump to their own interrupt subroutine (ISR). When the ISR returns, everything will pick up as it left off. More precautions have to be taken with interrupts in assembly than in C, such as making sure registers, especially the status register, are preserved. If the status register isn’t preserved, then an interrupt could potentially foul up the results of a simple statement such as “if (foo==3)”.
I’ll be using the 8-bit timer module and interrupts to count off the 1 second LED changes.
The other major change from the previous example is that I decided that one of the LEDs should flash twice as slow. To do this, I’m going to simply XOR its current state with the other LEDs new state. No seperate counters required.
One of the main concerns with using the 8-bit timer to count off seconds is getting it to divide evenly into the clock frequency. The clock frequency is a power of 10, but the prescalers and various division methods are powers of 2.
As you can see in the code comments, I set the timer up to have a prescaler of 64 and interrupt on overflow (256) as well as only toggling the LEDs when another counter hit 61. All told, this gets to 1 second with .06% error. One thing I could have done differently was to change the value the timer would interrupt on. Keeping the prescaler the same (64), the factorization of 1000000/64 is 5^6. If you split that into 5^3*5^3, then you can have the timer interrupt at 125 and toggle when the counter in the code equals 125. That equals exactly 1000000, so it should be as close to 1 second as you can get.
Some improvements I’ve noticed so far using C over assembly? Control flow is much less effort. I don’t need to figure out what label I’m going to use or how I’m going to set up a loop or if statement. Setting bits in registers is more concise and using the
>> syntax, I can easily determine which bits are being set/cleared.