Professional Documents
Culture Documents
Arduino Pong
After playing with composite video signal generation, the next step was to use if for something
'useful'.
Programming was not difficult, but there were some challenges.
Given that so much time is spent on generating the correct video signals, any major delays (1-5us)
would cause the video to lose sync and nothing would be displayed.
Essentially the code is multi-threaded, with the left players position being updated in one loop, and
the right updated in another.
Due to the timing constraints, I decided not to use any floating point arithmetic for the velocity of the
ball. This meant that I needed to have some other way of controlling how often the ball would change
positions. In the end I used a delay loop to limit how often the balls position would be updated,
changing the number of main loops to skip would effectively change the velocity of the ball.
The video resolution is 35*14, the arduino is capable of generating video lines of about 100-105
pixels, but the real killer is the amount of ram available, 1024/100 = 10 lines of 100 pixels, with 24
bytes of memory available for general use. This would have been ok, but it wouldn't have looked very
nice having a ball that is 1/10 of the screen height and 1/100 of the screen width.
The code still isn't completely finished, presently the ball moves with a constant velocity. This can be
easily changed by varying the ballXVel and ballYVel values whenever there is a collision with the ball
I only had 1 10k pot lying around, so I tied both players inputs to the same pin (analogIn #2), adding
a second player is as simple as adding another pot to another pin (say analogIn #3) and changing the
constant PLAYER_RIGHT_PIN to that pin (again 3).
1 of 14
arduinopong - alastairparker
Setup
In order to get the timings exact, you will need to disable the timer interrupt on the atmega168
ie:
/*
// enable timer 0 overflow interrupt
#if defined(__AVR_ATmega168__)
sbi(TIMSK0, TOIE0);
#else
sbi(TIMSK, TOIE0);
#endif
*/
The 75ohm is required, but the 450 and 900 arent so critical, more common values like 430 and 1k
could probably be used instead, just remember to check the volatges before you plug anthing into the
tv !
Code
//Arduino Tv framebuffer
//Alastair Parker
//2007
2 of 14
arduinopong - alastairparker
//video pins
#define DATA_PIN 9
#define SYNC_PIN 8
// loop indices
byte index, index2;
3 of 14
arduinopong - alastairparker
byte playerLeftOld=-1;
// life for the left player
byte playerLeftLife = MAX_LIFE;
4 of 14
arduinopong - alastairparker
showingTitle = true;
justScored=false;
updateCounter=0;
}
// draw a paddle
void drawPaddle(byte x,byte y,byte col)
{
frameBuffer[x][y]= col;
frameBuffer[x][y+1]= col;
}
5 of 14
arduinopong - alastairparker
setPixel(24,5);
setPixel(27,5);
setPixel(29,5);
setPixel(6,6);
setPixel(8,6);
setPixel(10,6);
setPixel(14,6);
setPixel(15,6);
setPixel(18,6);
setPixel(19,6);
setPixel(21,6);
setPixel(23,6);
setPixel(25,6);
setPixel(28,6);
//pong
setPixel(10,8);
setPixel(11,8);
setPixel(15,8);
setPixel(16,8);
setPixel(19,8);
setPixel(22,8);
setPixel(24,8);
setPixel(25,8);
setPixel(26,8);
setPixel(10,9);
setPixel(12,9);
setPixel(14,9);
setPixel(17,9);
setPixel(19,9);
setPixel(20,9);
setPixel(22,9);
setPixel(24,9);
setPixel(10,10);
setPixel(11,10);
setPixel(14,10);
setPixel(17,10);
setPixel(19,10);
setPixel(21,10);
setPixel(22,10);
setPixel(24,10);
setPixel(26,10);
setPixel(10,11);
setPixel(15,11);
setPixel(16,11);
setPixel(19,11);
setPixel(22,11);
setPixel(24,11);
setPixel(25,11);
setPixel(26,11);
}
6 of 14
arduinopong - alastairparker
{
// if checking the x coords of the ball
if(xEvent)
{
/*
TODO
*/
7 of 14
arduinopong - alastairparker
ballYPos--;
}
else
{
ballYPos++;
}
}
// indicate that someone scored so the wait doesn't start a new game
justScored=true;
// indicate that we should wait next loop
waiting=true;
// indicate that someone scored so the wain doesn't start a new game
justScored=true;
// indicate that we should wait next loop
waiting=true;
8 of 14
arduinopong - alastairparker
void loop()
{
// iterate over the lines on the tv
for ( line =0;line< DISPLAY_LINES;++line)
{
// HSync
// front porch (1.5 us)
PORTB = _BLACK;
delayMicroseconds(1.5);
//sync (4.7 us)
PORTB = _SYNC;
delayMicroseconds(4.7);
// breezeway (.6us) + burst (2.5us) + colour back borch (1.6 us)
PORTB = _BLACK;
9 of 14
arduinopong - alastairparker
delayMicroseconds(0.6+2.5+1.6);
10 of 14
arduinopong - alastairparker
delayMicroseconds(1);
PORTB = frameBuffer[23][newLine];
delayMicroseconds(1);
PORTB = frameBuffer[24][newLine];
delayMicroseconds(1);
PORTB = frameBuffer[25][newLine];
delayMicroseconds(1);
PORTB = frameBuffer[26][newLine];
delayMicroseconds(1);
PORTB = frameBuffer[27][newLine];
delayMicroseconds(1);
PORTB = frameBuffer[28][newLine];
delayMicroseconds(1);
PORTB = frameBuffer[29][newLine];
delayMicroseconds(1);
PORTB = frameBuffer[30][newLine];
delayMicroseconds(1);
PORTB = frameBuffer[31][newLine];
delayMicroseconds(1);
PORTB = frameBuffer[32][newLine];
delayMicroseconds(1);
PORTB = frameBuffer[33][newLine];
delayMicroseconds(1);
PORTB = frameBuffer[34][newLine];
delayMicroseconds(1);
PORTB = frameBuffer[35][newLine];
delayMicroseconds(1);
//vsync
PORTB = _SYNC;
11 of 14
arduinopong - alastairparker
grayPixel(loadingBar,BASE_BAR);
loadingBar+=2;
// done loading
if (loadingBar > 37)
{
showingTitle=false;
clearScreen();
initGame();
initScreen();
waiting=false;
}
}
}
12 of 14
arduinopong - alastairparker
playerRightOld=playerRight;
playerLeftTurn=true;
}
// remainder of sync period
delayMicroseconds(10);
updateCounter=0;
}
else
// remainder of sync period
delayMicroseconds(250);
Schematic
13 of 14
arduinopong - alastairparker
Action Shot
Σύνδεση σε Πρόσφατη δραστηριότητα ιστοτόπου Όροι Αναφορά κατάχρησης Εκτύπωση σελίδας | Με την
υποστήριξη των Ιστότοπων Google
14 of 14