Show Posts
|
|
Pages: [1]
|
|
3
|
Forum 2005-2010 (read only) / Exhibition / Re: Arduino Pong
|
on: August 23, 2007, 05:59:06 pm
|
Heres what I get (on the 168) when I don't disable the interrupt  And this is what I get when i put 'cli();' as the first line in setup()  So it seems that cli(); works just as well as changing wiring.c, and it's easier! Thanks agent_orange. If your getting something similar to the first img, try the cli(); method. Al
|
|
|
|
|
4
|
Forum 2005-2010 (read only) / Exhibition / Re: Arduino Pong
|
on: August 23, 2007, 05:43:36 pm
|
|
disabling the timer is quite important, each scan line in the signal must take 63( +/- 0.5)us, if the interrupt fires during the line generation, it will blow out the timing significantly, I will try to take a picture of what I get when the timer is NOT disabled, then you can compare what you're getting.
I'm not too sure how to disable it on the amtega8, but try using agent_orange's solution of 'cli();' somewhere in the setup() routine.
with regards to the 75ohm resistor, I can't be sure how critical it is, the most important thing is that you can generate 4 distinct voltages wrt the tv signal pin.
the voltages that you are aiming for are close to: sync = 0.0v black = 0.33v gray = 0.66 white 1v
I was able to generate approx: sync = 0v black= 0.30 gray = 0.64 white = 0.95
Check your results with a multimeter first, to see what you get.
Good luck!
Oh, on a side note, I can't verify how correct the PAL signal is, (I don't have an oscilloscope) so I only know that this works on the 2 tvs that I have (which are both pal, but quite new). If anyone has actually got this working, maybe they could post back with their resistor values and geographical location.
Al
|
|
|
|
|
6
|
Forum 2005-2010 (read only) / Exhibition / Re: Arduino Pong
|
on: August 22, 2007, 04:44:57 pm
|
Heres some info that I forgot about, which is important if you guys are actually going to run pong! In order to get the timings exact, you will need to disable the timer interrupt on the atmega168 Edit the file lib/targets/arduino/wiring.c and block comment out the following // enable timer 0 overflow interrupt #if defined(__AVR_ATmega168__) sbi(TIMSK0, TOIE0); #else sbi(TIMSK, TOIE0); #endif ie: make it look like this /* // enable timer 0 overflow interrupt #if defined(__AVR_ATmega168__) sbi(TIMSK0, TOIE0); #else sbi(TIMSK, TOIE0); #endif */ Getting nstc to work. According to http://www.amazon.com/Black-Video-Game-Console-Design/dp/0672328208pal has 625 total lines (about 575 visible) and ntsc has 525(about 480 visible), because arduino pong ignores interlacing, the effective number of lines is cut in half. If someone were to try to get it to work on ntsc, I would start by decreasing the number of displayed lines, which will probably mess up the timing, so some experimentation would be needed with the remainder of the delays after vsync. Perhaps someone with an ntsc tv can have a go at hacking the code and then sharing the results so other ntsc hackers can enjoy pong aswell. Sorry I can't be more help right now, I will try to look into it, but without an ntsc tv, testing is hard  Alastair
|
|
|
|
|
8
|
Forum 2005-2010 (read only) / Exhibition / Re: Arduino Pong
|
on: August 20, 2007, 08:21:56 pm
|
last chunk o' code 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); // klugdge to correct timings PORTB = frameBuffer[36][newLine]; PORTB=PORTB; PORTB=PORTB; PORTB=PORTB; delayMicroseconds(3); } //vsync PORTB = _SYNC;
// if delaying for some reason if(waiting) { // increment the waiting counter waitingCount++; // if waiting is over for a new game if(waitingCount==DONE_WAITING & !justScored) { waitingCount=0; // if on title screen if(showingTitle) { // draw the loading bar grayPixel(loadingBar,BASE_BAR); loadingBar+=2; // done loading if (loadingBar > 37) { showingTitle=false; clearScreen(); initGame(); initScreen(); waiting=false; } } } // waiting because someone scored if(waitingCount==SCORE_WAITING & justScored) { justScored=false; waitingCount=0; waiting=false; } // wait for the remainder of the sync period delayMicroseconds(305); } // not waiting else { // increment the update delay counter updateCounter++; if( updateCounter >= UPDATE_INTERVAL) { //player movement if(playerLeftTurn) { drawPaddle(PLAYER_LEFT_X,playerLeftOld,_BLACK); playerLeft = analogRead(PLAYER_LEFT_PIN)>>6; if(playerLeft<SCORE_BAR) playerLeft=SCORE_BAR; if(playerLeft>BASE_BAR) playerLeft=BASE_BAR; drawPaddle(PLAYER_LEFT_X,playerLeft,_WHITE); playerLeftOld=playerLeft; playerLeftTurn=false; } else { drawPaddle(PLAYER_RIGHT_X,playerRightOld,_BLACK); playerRight = analogRead(PLAYER_RIGHT_PIN)>>6; if(playerRight<SCORE_BAR) playerRight=SCORE_BAR; if(playerRight>BASE_BAR) playerRight=BASE_BAR; drawPaddle(PLAYER_RIGHT_X,playerRight,_WHITE); playerRightOld=playerRight; playerLeftTurn=true; } // remainder of sync period delayMicroseconds(10); updateCounter=0; } else // remainder of sync period delayMicroseconds(250);
// perform ball x velocity delay ballXLoop--; if(ballXLoop <= abs(ballXVel) and ballXVel != 0) { //ball movement; drawBall(_BLACK); updateBall(true); ballXLoop=MAX_VEL; } // perform ball y velocity delay ballYLoop--; if(ballYLoop <= abs(ballYVel) and ballYVel != 0) { //ball movement; drawBall(_BLACK); updateBall(false); ballYLoop=MAX_VEL; } // draw new ball drawBall(_GRAY); } }
The pong code needs some work to make it better, but at least it works (for me anyway) as a proof of concept. Alastair
|
|
|
|
|
9
|
Forum 2005-2010 (read only) / Exhibition / Re: Arduino Pong
|
on: August 20, 2007, 08:21:19 pm
|
next chunk o' code // do the main game logic regarding the ball and collisions void updateBall(boolean xEvent) { // if checking the x coords of the ball if(xEvent) { /* TODO have the yvel start 1t 1 */ //check for collision with left player if(ballXPos <PLAYER_LEFT_X+2 & (playerLeft == ballYPos or playerLeft+1 == ballYPos)) { ballXVel = -1 * ballXVel; ballXPos=PLAYER_LEFT_X+1; } //check for collision with right player if(ballXPos > PLAYER_RIGHT_X-2 & (playerRight == ballYPos or playerRight+1 == ballYPos)) { ballXVel = -1 * ballXVel; ballXPos=PLAYER_RIGHT_X-1; } //move the ball in the x direction if(ballXVel < 1) { ballXPos--; } else { ballXPos++; } } //if checking the y coords if(!xEvent) { //check for top of screen hit if( ballYPos <= SCORE_BAR ) { ballYVel = -1 * ballYVel; ballYPos = SCORE_BAR; } //check for bottom of screen hit if( ballYPos>BASE_BAR ) { ballYVel = -1 * ballYVel; ballYPos = BASE_BAR+1; } // move the ball in the y direction if(ballYVel < 1) { ballYPos--; } else { ballYPos++; } } //always check for scoring of points //right player scores if(ballXPos==PLAYER_LEFT_X)//0 { //reset the position of the ball ballXPos = PLAYER_RIGHT_X - 5; ballYPos=7; // change the other players life clearPixel(PLAYER_LEFT_LIFE+2*playerLeftLife-2,SCORE_BAR-1); playerLeftLife--; // indicate that someone scored so the wait doesn't start a new game justScored=true; // indicate that we should wait next loop waiting=true;
// check if game is over if(playerLeftLife==0) justScored=false; } //left player scores if(ballXPos==PLAYER_RIGHT_X)//38 { //reset position of ball ballXPos = PLAYER_LEFT_X + 5; ballYPos=7; //update other players score clearPixel(PLAYER_RIGHT_LIFE+2*(MAX_LIFE-playerRightLife)+2,SCORE_BAR-1); playerRightLife--; // indicate that someone scored so the wain doesn't start a new game justScored=true; // indicate that we should wait next loop waiting=true;
// check for game over if(playerRightLife==0) justScored=false; } }
// draw the player life bars void initScreen() { for(index=1;index<=MAX_LIFE;++index) { grayPixel(index*2,SCORE_BAR-1); grayPixel(index*2+PLAYER_RIGHT_LIFE,SCORE_BAR-1); } }
// draw the ball void drawBall(byte col) { frameBuffer[ballXPos][ballYPos]=col; }
// clear the screen void clearScreen() { for (index = 0; index < WIDTH; index++) for (index2=0;index2<=HEIGHT;++index2) { frameBuffer[index][index2] = _BLACK; } }
// the setup routine void setup() { pinMode (SYNC_PIN, OUTPUT); pinMode (DATA_PIN, OUTPUT); digitalWrite (SYNC_PIN, HIGH); digitalWrite (DATA_PIN, HIGH); clearScreen(); drawArduinoPong(); }
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; delayMicroseconds(0.6+2.5+1.6);
//calculate which line to draw to newLine = line >>4; delayMicroseconds(1); //display the array for this line // a loop would have been smaller, but it messes the timing up PORTB = frameBuffer[0][newLine]; delayMicroseconds(1); PORTB = frameBuffer[1][newLine]; delayMicroseconds(1); PORTB = frameBuffer[2][newLine]; delayMicroseconds(1); PORTB = frameBuffer[3][newLine]; delayMicroseconds(1); PORTB = frameBuffer[4][newLine]; delayMicroseconds(1); PORTB = frameBuffer[5][newLine]; delayMicroseconds(1); PORTB = frameBuffer[6][newLine]; delayMicroseconds(1); PORTB = frameBuffer[7][newLine]; delayMicroseconds(1); PORTB = frameBuffer[8][newLine]; delayMicroseconds(1); PORTB = frameBuffer[9][newLine]; delayMicroseconds(1); PORTB = frameBuffer[10][newLine]; delayMicroseconds(1); PORTB = frameBuffer[11][newLine]; delayMicroseconds(1); PORTB = frameBuffer[12][newLine]; delayMicroseconds(1); PORTB = frameBuffer[13][newLine]; delayMicroseconds(1); PORTB = frameBuffer[14][newLine]; delayMicroseconds(1); PORTB = frameBuffer[15][newLine]; delayMicroseconds(1); PORTB = frameBuffer[16][newLine]; delayMicroseconds(1); PORTB = frameBuffer[17][newLine]; delayMicroseconds(1); PORTB = frameBuffer[18][newLine]; delayMicroseconds(1); PORTB = frameBuffer[19][newLine]; delayMicroseconds(1); PORTB = frameBuffer[20][newLine]; delayMicroseconds(1); PORTB = frameBuffer[21][newLine]; delayMicroseconds(1); PORTB = frameBuffer[22][newLine]; delayMicroseconds(1);
|
|
|
|
|
10
|
Forum 2005-2010 (read only) / Exhibition / Arduino Pong
|
on: August 20, 2007, 08:19:56 pm
|
Hello all, I have been playing with pal signal generation, and decided to make pong as an example. I based my video code on work by Benoît ROUSSEAU, found at http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1176757335. But it didn't work for me, so I rewrote it using information found in. http://www.amazon.com/Black-Video-Game-Console-Design/dp/0672328208This code works for both of my (Australian) pal tvs. All the source on one page http://alastair.parker.googlepages.com/arduinopong Title screen  during play  schematic //Arduino Tv framebuffer //Alastair Parker //2007
// Video out voltage levels #define _SYNC 0x00 #define _BLACK 0x01 #define _GRAY 0x02 #define _WHITE 0x03
// dimensions of the screen #define WIDTH 38 #define HEIGHT 14
//number of lines to display #define DISPLAY_LINES 240
// update speed for the main loop of the game #define UPDATE_INTERVAL 1
// positions of the player paddles #define PLAYER_RIGHT_X 35 #define PLAYER_LEFT_X 2
// maximum velocity of the ball #define MAX_VEL 10
// locations of the top and bottom virtual bars #define SCORE_BAR 3 #define BASE_BAR 13
// time to wait while paused #define DONE_WAITING 30 #define SCORE_WAITING 30
// max player life #define MAX_LIFE 6
//positions of player life bars #define PLAYER_LEFT_LIFE 2 #define PLAYER_RIGHT_LIFE 23
// input pins for the player pots #define PLAYER_LEFT_PIN 2 // currently the same pin #define PLAYER_RIGHT_PIN 2
//video pins #define DATA_PIN 9 #define SYNC_PIN 8
// the video frameBuffer byte frameBuffer[WIDTH][HEIGHT];
// loop indices byte index, index2;
// pal video line loop byte line; // current drawing line in framebuffer byte newLine;
// flag used in wait loop to indicate that player just scored boolean justScored=false;
// positions for the left paddle byte playerLeft; byte playerLeftOld=-1; // life for the left player byte playerLeftLife = MAX_LIFE;
// positions of the right paddle byte playerRight; byte playerRightOld=-1; // life for the right player byte playerRightLife = MAX_LIFE;
// positions and velocity of the ball int ballXVel = -1; int ballYVel = -5; byte ballXPos = 14; byte ballYPos = 7;
// loop counters to control the velocity of the ball byte ballXLoop =MAX_VEL; byte ballYLoop =MAX_VEL;
// loop counter to for the main loop delay int waitingCount = 0;
// start postion of the loading bar byte loadingBar = 2;
// if the left player should be updated or the right boolean playerLeftTurn=true;
// if we should be waiting for something to happen boolean waiting=true; // if displaying the title boolean showingTitle = true;
// value of the counter controlling the freq of updates byte updateCounter=0;
// init the variables void initGame() { playerLeftOld=-1; playerLeftLife = MAX_LIFE; playerRightOld=-1; playerRightLife = MAX_LIFE; ballXVel = -1; ballYVel = -5; ballXPos = 14; ballYPos = 7; ballXLoop =MAX_VEL; ballYLoop =MAX_VEL; waitingCount = 0; loadingBar = 2; playerLeftTurn=true; waiting=true; showingTitle = true; justScored=false; updateCounter=0; }
// draw a pixel to the buffer void setPixel(byte x,byte y) { frameBuffer[x][y]= _WHITE; }
void grayPixel(byte x, byte y) { frameBuffer[x][y]= _GRAY; }
// draw a black pixel to the buffer void clearPixel(byte x,byte y) { frameBuffer[x][y]= _BLACK; }
// draw a paddle void drawPaddle(byte x,byte y,byte col) { frameBuffer[x][y]= col; frameBuffer[x][y+1]= col; }
//draw the title message void drawArduinoPong() { //arduino setPixel(7,3); setPixel(8,3); setPixel(15,3); setPixel(21,3); setPixel(6,4); setPixel(8,4); setPixel(14,4); setPixel(15,4); setPixel(28,4); setPixel(6,5); setPixel(7,5); setPixel(8,5); setPixel(10,5); setPixel(11,5); setPixel(13,5); setPixel(15,5); setPixel(17,5); setPixel(19,5); setPixel(21,5); setPixel(23,5); 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); }
|
|
|
|
|