#include // this contains all the IO port definitions #include #include #define TIMER1_PRESCALE_1 1 #define TIMER1_PRESCALE_8 2 #define TIMER1_PRESCALE_64 3 #define TIMER1_PRESCALE_256 4 #define TIMER1_PRESCALE_1024 5 /* turn a numeric literal into a hex constant (avoids problems with leading zeroes) 8-bit constants max value 0x11111111, always fits in unsigned long */ #define HEX__(n) 0x##n##LU /* 8-bit conversion function */ #define B8__(x) ((x&0x0000000FLU)?1:0) \ +((x&0x000000F0LU)?2:0) \ +((x&0x00000F00LU)?4:0) \ +((x&0x0000F000LU)?8:0) \ +((x&0x000F0000LU)?16:0) \ +((x&0x00F00000LU)?32:0) \ +((x&0x0F000000LU)?64:0) \ +((x&0xF0000000LU)?128:0) #define B8(d) ((unsigned char)B8__(HEX__(d))) const static int image[] = { B8(11111111), B8(11111111), B8(00001110), B8(00111100), B8(11110000), B8(11110000), B8(00111100), B8(00001110), B8(11111111), B8(11111111), B8(00000000), B8(01100000), B8(11110100), B8(10010100), B8(10010100), B8(11111100), B8(11111000), B8(10000000), B8(00000000), B8(11111111), B8(11111111), B8(00110000), B8(01111000), B8(11111100), B8(11001100), B8(10000000), B8(00000000), B8(01111000), B8(11111100), B8(11010100), B8(11010100), B8(11011100), B8(01011000), B8(00000000), B8(00000000), B8(00000000), B8(00001110), B8(11011111), B8(11011111), B8(00001110), B8(00000000), B8(00000000), B8(00000000), B8(00000000), B8(00000000), B8(00000000), B8(00000000), B8(00000000), B8(00000000), B8(00000000), B8(00000000), B8(00000000), }; #define NUM_ELEM(x) (sizeof (x) / sizeof (*(x))) int imagesize = NUM_ELEM(image); // This function basically wastes time, in case you want to // do some other timing stuff void delay_ms(long int ms) { unsigned long int timer; while (ms != 0) { // this number is dependant on the clock frequency for (timer=0; timer <= 4200; timer++); ms--; } } // this function is called when timer1 compare matches OCR1A uint8_t j = 0; SIGNAL( SIG_TIMER1_COMPA ) { if (j >= imagesize) j = 0; PORTB = image[j]; j++; } int main(void) { DDRB = 0xFF; // set all 8 pins on port B to outputs /* the frequency of the interrupt overflow is determined by the prescaler and overflow value. freq = clock_frequency / ( 2 * prescaler * overflow_val) where prescaler can be 1, 8, 64, 256, or 1024 clock_freq is 8MHz and overflow_val is 16bit the overflow value is placed in OCR1A, the prescale is set in TCCR1B so for example: A good POV frequency is around 400Hz desired freq = 400Hz clock freq = 8MHz 8MHz / (400Hz * 2) = 10000 since 10000 is less than 655536 (largest 16 bit number) OCR1A = 10000 and the prescale is 1 */ TCCR1B = (1 << WGM12) | TIMER1_PRESCALE_1; OCR1A = (uint16_t)10000; TIMSK |= 1 << OCIE1A; // Output Compare Interrupt Enable (timer 1, OCR1A) sei(); // Set Enable Interrupts while (1); }