#include <avr/io.h> #include <avr/interrupt.h> #include <avr/signal.h> #include "font.h" int pong_mode; /***************************************\ * Ports: * A0-6: Dot matrix rows * D0-4: Dot matrix columns * B0: Player 2 UP * B1: Player 2 DOWN * B2: Player 1 UP * B3: Player 1 DOWN * B4: Player 2 score LED * B5: Player 1 score LED \***************************************/ /***************************************\ * Framebuffer(5x7 dot matrix): * 6 x x x x O * x x x x O <- p2_pos = 5 * x x x x x * x x x x x * x x x x x * x x x x O * 0 x x x x O <- p2_pos = 0 * 0 4 \***************************************/ volatile unsigned char framebuffer[5]; volatile unsigned char framebuffer_pos = 0x00; volatile char ball_x; volatile char ball_y; volatile char ball_dx; volatile char ball_dy; volatile char p1_pos; /* Position of player 1 paddle */ volatile char p2_pos; /* Position of player 2 paddle */ volatile char ballClock; /* Move ball only every to tick */ volatile char redraw_needed; volatile char speed_counter; /* increase speed as game goes on */ const char speed_bumper = 10; /* increase speed after this many movement_timer ticks */ volatile char current_speed; volatile char score; const unsigned char d1[] = {0x00, 0x10, 0x20, 0x7f, 0x00}; /* the number 1 */ const unsigned char d2[] = {0x47, 0x49, 0x49, 0x49, 0x31}; /* the number 2 */ /* Draw paddles and ball */ void drawScene() { framebuffer[0] = BV(p1_pos) | BV(p1_pos+1); framebuffer[1] = 0; framebuffer[2] = 0; framebuffer[3] = 0; framebuffer[4] = BV(p2_pos) | BV(p2_pos+1); framebuffer[(unsigned char)ball_x] |= BV(ball_y); } void variable_init(void) { ball_x = 2; ball_y = 3; ball_dx = 1; ball_dy = 0; p1_pos = 2; p2_pos = 2; ballClock = 0; redraw_needed = 1; speed_counter = 0; current_speed = 3; outw(OCR1A,40000); } void ioinit(void) { /* Set port C and B0-3, B6-7, to internal pullup, B4-5 output */ outp(0x30, DDRB); outp(0x00, DDRC); outp(0xcf, PORTB); outp(0xff, PORTC); /* Set port A and D to output */ outp(0xff, DDRA); outp(0xff, DDRD); /* Enable 8-bit counter1, running on clk speed */ outp(BV(CS01), TCCR0); /* Set OCR1A as max value and Enable 16-bit counter, * running on clk/8 speed */ outp(BV(WGM12)|BV(CS11), TCCR1B); /* */ outw(OCR1A,40000); /* Enable overlow when counter1 reaches OCR1A */ /*outp(BV(TOV1), TIFR);*/ /* Enable overflow interrupt for counter 0 and counter 1*/ timer_enable_int(BV(TOIE0)|BV(OCIE1A)); /* Enable interrupts */ sei(); } /* Switch leds to indicate who's leading */ void update_score_output(void) { if (score == 1) { outp(0xef, PORTB); /* turn on led for player 1 */ } else if(score == -1) { outp(0xdf, PORTB); /* turn on led for player 2 */ } else { outp(0xcf, PORTB); /* turn off leds */ } } void victory(void) { unsigned char buttons; int i; int j; /* turn off counter */ outp(0x00, TCCR1B); /* turn on both leds */ /* outp(0xff, PORTB); */ /* Display winner */ if (score == 1) { framebuffer[0] = d1[0]; framebuffer[1] = d1[1]; framebuffer[2] = d1[2]; framebuffer[3] = d1[3]; framebuffer[4] = d1[4]; } else { framebuffer[0] = d2[0]; framebuffer[1] = d2[1]; framebuffer[2] = d2[2]; framebuffer[3] = d2[3]; framebuffer[4] = d2[4]; } sei(); /* wait a little */ for (i = 0; i < 5000; i++) for (j = 0; j < 1000; j++) j=j; /* wait for buttonpress to start again */ buttons = ~inp(PINB); while( (buttons & 0x0f) == 0x00 ) { unsigned char wait_count; for (wait_count = 0; wait_count < 0xff; ++wait_count); buttons = ~inp(PINB); } cli(); /* Reinit */ variable_init(); ioinit(); score = 0; speed_counter = 0; } /* Movement */ void timer_movement(unsigned char portB) { unsigned char p1_up; /* Player 1 up button pressed */ unsigned char p1_dn; /* Player 1 down button pressed */ unsigned char p2_up; /* Player 2 up button pressed */ unsigned char p2_dn; /* Player 2 down button pressed */ char pos; char loose; char paddle_bounce; int i; int j; /* Read buttons */ p1_up = portB & 0x04; /* Pin B2 */ p1_dn = portB & 0x08; /* Pin B3 */ p2_up = portB & 0x01; /* Pin B0 */ p2_dn = portB & 0x02; /* Pin B1 */ /* Stop paddle movement at wall */ p1_up = (p1_up && p1_pos < 5); p1_dn = (p1_dn && p1_pos > 0); p2_up = (p2_up && p2_pos < 5); p2_dn = (p2_dn && p2_pos > 0); /* Move paddles */ if (p1_up) p1_pos++; if (p1_dn) p1_pos--; if (p2_up) p2_pos++; if (p2_dn) p2_pos--; /* Move ball only every two clock tick */ if ((ballClock = !ballClock)) { /* Bounce ball on wall */ if (ball_y == 0) ball_dy = -ball_dy; if (ball_y == 6) ball_dy = -ball_dy; /* Bounce ball on paddle */ loose = 0; paddle_bounce = 0; pos = (ball_x == 1)?p1_pos:p2_pos; if (ball_x == 1 || ball_x == 3) { loose = 1; if (ball_y == pos || ball_y == pos+1) { ball_dx = -ball_dx; loose = 0; paddle_bounce = 1; } else if (ball_y == pos-1 && ball_dy == 1) { ball_dx = -ball_dx; ball_dy = -ball_dy; loose = 0; paddle_bounce = 1; } else if (ball_y == pos+2 && ball_dy == -1) { ball_dx = -ball_dx; ball_dy = -ball_dy; loose = 0; paddle_bounce = 1; } } if (loose) { if (ball_x == 1) /* player 2 won */ { if (score == -1) /* total victory! */ { victory(); return; } else { score--; update_score_output(); ball_x += ball_dx; ball_y += ball_dy; redraw_needed = 1; outp(0x00, TCCR1B); /* turn off counter */ sei(); /* Re-enable interrupts */ /* Wait a little */ for (i = 0; i < 5000; i++) for (j = 0; j < 1000; j++) j=j; cli(); /* Disable interrupts again */ outp(BV(WGM12)|BV(CS11), TCCR1B); /* turn on counter */ } } else { /* player 1 won */ if (score == 1) /* total victory! */ { victory(); return; } else { score++; update_score_output(); ball_x += ball_dx; ball_y += ball_dy; redraw_needed = 1; outp(0x00, TCCR1B); /* turn off counter */ sei(); /* Re-enable interrupts */ /* Wait a little */ for (i = 0; i < 5000; i++) for (j = 0; j < 1000; j++) j=j; cli(); /* Disable interrupts again */ outp(BV(WGM12)|BV(CS11), TCCR1B); /* turn on counter */ } } variable_init(); update_score_output(); } /* Change vertical speed of ball according to paddle speed */ if (paddle_bounce) { if (ball_x == 1 && p1_up && ball_dy < 1) ball_dy++; if (ball_x == 1 && p1_dn && ball_dy > -1) ball_dy--; if (ball_x == 3 && p2_up && ball_dy < 1) ball_dy++; if (ball_x == 3 && p2_dn && ball_dy > -1) ball_dy--; } /* Wall bounce after paddle bounce */ if (ball_y == 0 && ball_dy == -1) ball_dy = -ball_dy; if (ball_y == 6 && ball_dy == 1) ball_dy = -ball_dy; /* Move ball */ ball_x += ball_dx; ball_y += ball_dy; } redraw_needed = 1; } /* Framebuffer output to led matrix */ SIGNAL(SIG_OVERFLOW0) { if (++framebuffer_pos > 4) framebuffer_pos = 0; /* Change output to dot matrix */ outp(0xff, PORTA); /* Avoid ghosting */ outp(BV(framebuffer_pos), PORTD); outp(~framebuffer[framebuffer_pos], PORTA); if (!pong_mode) return; /* Redraw scene during "vertical retrace" */ if (framebuffer_pos == 4 && redraw_needed) { drawScene(); redraw_needed = 0; } } /* Movement */ SIGNAL(SIG_OUTPUT_COMPARE1A) { if (!pong_mode) return; if (++speed_counter == speed_bumper) { speed_counter = 0; outw(OCR1A, (40000 / ++current_speed) * 3); if (current_speed > 100) current_speed = 100; } timer_movement(~inp(PINB)); } int main_pong(void) { score = 0; variable_init(); ioinit(); for(;;); } int main_font(void) { unsigned char portB; unsigned char nextPressed; unsigned char prevPressed; int cf; /* Current font */ nextPressed = 0; prevPressed = 0; cf = 0; framebuffer[0] = font[cf][0]; framebuffer[1] = font[cf][1]; framebuffer[2] = font[cf][2]; framebuffer[3] = font[cf][3]; framebuffer[4] = font[cf][4]; ioinit(); for(;;) { portB = ~inp(PINB); /* Prev button */ if (portB & 0x01) { if (!prevPressed) { cf--; if (cf < 0) cf = 0; framebuffer[0] = font[cf][0]; framebuffer[1] = font[cf][1]; framebuffer[2] = font[cf][2]; framebuffer[3] = font[cf][3]; framebuffer[4] = font[cf][4]; } prevPressed = 1; } else prevPressed = 0; /* Next button */ if (portB & 0x02) { if (!nextPressed) { cf++; if (cf >= font_count) cf = font_count - 1; framebuffer[0] = font[cf][0]; framebuffer[1] = font[cf][1]; framebuffer[2] = font[cf][2]; framebuffer[3] = font[cf][3]; framebuffer[4] = font[cf][4]; } nextPressed = 1; } else nextPressed = 0; } } int main(void) { unsigned char portB; framebuffer[0] = 0; framebuffer[1] = 0; framebuffer[2] = 0; framebuffer[3] = 0; framebuffer[4] = 0; pong_mode = 0; ioinit(); for (;;) { portB = ~inp(PINB); if (portB & 0x01) {pong_mode = 1; main_pong();} if (portB & 0x02) {pong_mode = 0; main_font();} } }