#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();}
}
}