ATtiny2313 ledbar

ATtiny26 controlling 12 leds with 4 IO-lines with charlieplexing

attinyled.c

Source code for blinking leds

/*
  cycle 12 leds with attiny2313
  Tomi Leppikangas 25.5.2010
*/

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <avr/pgmspace.h>

typedef struct {
   uint8_t ddr;
   uint8_t bits;
} leds_t;

/* bit values for 12 leds */
const leds_t led_values [] PROGMEM = {
   //      3210        3210
   { 0b00001100, 0b00000100 }, // 1
   { 0b00000110, 0b00000010 }, // 2
   { 0b00000011, 0b00000001 }, // 3
   { 0b00000011, 0b00000010 }, // 4
   { 0b00000110, 0b00000100 }, // 5
   { 0b00001100, 0b00001000 }, // 6
   { 0b00001010, 0b00001000 }, // 7
   { 0b00001010, 0b00000010 }, // 8
   { 0b00001001, 0b00000001 }, // 9
   { 0b00001001, 0b00001000 }, // 10
   { 0b00000101, 0b00000100 }, // 11
   { 0b00000101, 0b00000001 }, // 12
};
  

volatile uint8_t current = 0;  // current led
volatile uint8_t old[3] = {0}; // old leds


/* timer/counter0 compare interrupt */
ISR(TIMER0_COMPA_vect)
{
   static uint8_t count = 0;
   if(count <20) {
      DDRB  = pgm_read_byte(&led_values[current].ddr);
      PORTB = pgm_read_byte(&led_values[current].bits);
   } else if(count < 30) {
      DDRB  = pgm_read_byte(&led_values[old[0]].ddr);
      PORTB = pgm_read_byte(&led_values[old[0]].bits);
   } else if(count < 35) {
      DDRB  = pgm_read_byte(&led_values[old[1]].ddr);
      PORTB = pgm_read_byte(&led_values[old[1]].bits);
   } else {
      DDRB  = pgm_read_byte(&led_values[old[2]].ddr);
      PORTB = pgm_read_byte(&led_values[old[2]].bits);
   }
   count ++;
   if(count == 36) count = 0;
}
/* timer/counter1 compare interrupt */
ISR(TIMER1_COMPA_vect)
{
   static int8_t direction = 1; 
   old[2] = old[1];  // remember old leds
   old[1] = old[0];
   old[0] = current;
   current = current + direction;
   if(current == 11) direction = -1;
   else if (current == 0) direction = 1;

}
int main(void)
{
   // init timer 0
   TCCR0A |= (1<<WGM01); // CTC
   TCCR0B |= (1<<CS02 | 1<<CS00); // scale 1024
   TIMSK  |= (1<<OCIE0A); // enable output compare int a
   OCR0A =  1;

   // init timer 1 t
   TCCR1A &= ~(1<<WGM11 | 1<<WGM10); // CTC
   TCCR1B &= ~(1<<WGM13);
   TCCR1B |=  (1<<WGM12 | 1<<CS12 ); // CTC + scale 256
   TIMSK  |= (1<<OCIE1A); // enable output compare int a
   OCR1A =  F_CPU/256/20;
   //OCR1AL = 1000;

   DDRB  |= (1 << PB0); // port B0 out
   DDRB  |= (1 << PB1); // port B1 out
   PORTB |= (1 << PB0); // BO = 1 

   set_sleep_mode(SLEEP_MODE_IDLE);
   sleep_enable();
   sei();  
   while(1) {
      sleep_cpu();
   }
   return 0;
}
Tomi Leppikangas 27.5.2010 [home]