Articles Tagged blog, page 1
The importance of a good library
Posted on March 30th, 2012 00:26:19
by landon
Comments
Introducing the Keypad
Posted on March 1st, 2012 22:18:54
by landon
Comments
For this project, I'm going to introduce a 4x3 (3x4?) keypad. The 0-9 keys will determine the frequency of the flashing LED, from 0Hz to 9Hz. In addition, the * and # keys will determine which LED I'm setting the frequency for.
The Terminology
State Machine - A state machine is a collection of different states. For example, you could have two states IN_WORD and OUT_OF_WORD, which both process a string. While in the IN_WORD state, you could, for example, increment a word length counter. When a space appears, you'll set the state to OUT_OF_WORD. While you're in the OUT_OF_WORD state, you could set the word length counter to 0, but when you encounter something that's not a space, you switch to the state IN_WORD.

Debounce - One annoying feature of keypads and switches in general is that when they're pressed they will bounce from open to closed. To account for this, my code has a built in delay in the state machine to filter out rapid changes that would come from debouncing.
Design Considerations
There are two main parts to this project:
- Keypad Entry
- LED Flashing
There's a fairly simple state machine that I can implement to decode the key presses. (The one in the code has been modified a bit from the picture to loop in decode_state a bit to debounce the keypad, but is basically the same.)

Once a key is decoded, I'll stick it in a buffer so it can be processed in the main loop.
To get LED flashing correct, the timer will be set to interrupt so all of the toggle frequencies are multiples of the interrupt frequency. The exact multiples will be stored in a lookup table indexed by the keypad numbers.
Working With the Keypad
The 3x4 keypad has 8 pins. 4 pins are for the rows and 3 for the columns, along with one pin that won't be connected. There are a couple of ways to decode it, but since I have plenty of free pins, I'll hook them all up to a port and continuously poll that for changes and then scan it for the row/column combination. When a button on the keypad is pressed, it connects the corresponding row and column lines. So what I'll do is set the pins connected to the row lines as inputs with the pullup resistor enabled (this sets them high when there's no other signal). The pins connected to the column lines will be set as outputs and all will be set low. When a button is pressed, a single one of the row inputs will also go low. Once this change is detected, then for each column I toggle the output high until I find one that makes all of the rows read high. Then I use the column number as an index into a short lookup table to determine which button was pressed. The code should make the process clear!
Getting the Right LED Frequency
To simplify matters, I'm going to use a separate timer for LED flashing interrupts. I've decided the interrupt should trigger every millisecond. This isn't perfect for all frequencies. However, the greatest calculated error is only .2% for 6Hz, which is acceptable because I won't be able to tell the difference with my eye. (For reference, the errors from 1Hz to 9Hz are: 0%, 0%, .1%, 0%, 0%, .2%, .1%, 0%, .1%).
Hooking It Up




The Code
Unfortunately code length is quickly growing larger than I want to keep directly in the blog post. If you want syntax highlighting, you'll have to open it into the editor of your choice.
The Video
Coming soon!
Blinking an LED - This time with interrupts
Posted on March 1st, 2012 01:12:02
by landon
Comments
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.
The Terminology
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)".
What's new
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.
Design Considerations
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.
The Code
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 1000000UL // Running at 1 MHz
char counter;
int main(void)
{
DDRA = 0x03; // Set PA0 and PA1 to be outputs
TCCR0B |= (1<<CS01)|(1<<CS00); //set prescaler to /64, which divides evenly into 1MHz
TIMSK |= (1<<TOIE0); // Enable timer 0 interrupts
counter = 0;
sei(); // Enable interrupts
while (1)
{
// Do nothing. Alternatively, a sleep instruction could be used so the CPU only wakes
// on interrupts and immediately goes back to sleep.
}
}
// Set an interrupt on the Timer0 Overflow vector
ISR(TIMER0_OVF_vect)
{
counter++;
if (counter == 61) // This gets VERY close to 1 second
// The timer prescaler (64) * 8 bit overflow (256) * 61 = .999424 seconds
// .06% error should be close enough for this application
{
char led1, led2;
led1 = PINA & 0x01; // Get PA0's pin value
led1 ^= 0x01; // Toggle PA0
led2 = (PINA>>1) & 0x01; // Get PA1's pin value
led2 ^= led1; // Xor PA1 with the current state of PA0, effectively doubling the period
PORTA = (led2 << 1) | led1;
counter = 0;
}
}
Closing Thoughts
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 << and >> syntax, I can easily determine which bits are being set/cleared.
Another blog change
Posted on October 8th, 2011 17:08:25
by landon
Comments
I changed my blog yet again and spent all day copying over posts (hopefully for the last time!)
I'm now using django-articles and have an awesome disqus comment system set up, so have at!
Hard drive replacement
Posted on November 1st, 2009 13:57:51
by landon
Comments
Over the past year I've put off replacing some dying drives (2*750gb) I have. Lately they've started to have a lot of problems so I went ahead and bought some replacements. For future reference, if you don't plan on using dd to copy over the drive then rsync -avP -H --numeric-ids /mnt/src /mnt/dst should work just as well. (I need the hard links especially for my backups drive, which is where Dirvish dumps everything to. Without the hard link copying, rsync would try to copy many many many more terabytes of backups than I can reasonably hold!
