Tuesday, May 1, 2012

Arduino Composite TV out

I've been wanting to interface my Arduino with a monitor of some sort with RGB, but it didn't seem to be much of a possibility for such a memory limited device. But then i found this tvout library that uses composite video! It is only in black and white, but still pretty awesome. The first thing i thought of to do was make a space invaders type game with that Parallax joystick from some time ago...and its coming along quite well.

I have created a "starry" background and a ship bitmap so far(its a simple monochrome bitmap made in paint that can be converted to code and displayed using the library). Basically how it works: the loop reads the stick values, changes the X/Y coordinates of where the ship will be, then draws the "stars" and then the ship. This obviously happens many times a second so it looks fairly fluid on screen. So, currently I can move the ship around on a starry background and i'm starting to work on projectiles.

Here's some code in progress.
////////////////////BITMAPS!/////////////////////////////////////
//120 pixels wide,96 pixels high
PROGMEM const unsigned char BckGnd[] = {
  120,96,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x20,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x10,0x10,0x00,0x00,0x00,0x40,0x00,0x40,0x20,0x04,0x08,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x20,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x40,0x00,0x00,0x00,
  0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x08,0x00,0x00,0x00,0x40,0x00,
  0x04,0x02,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,
  0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,
  0x00,0x00,0x00,0x80,0x00,0x04,0x00,0x08,0x00,0x00,0x00,0x00,0x40,0x00,0x00,
  0x20,0x02,0x00,0x00,0x10,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x10,
  0x00,0x40,0x00,0x80,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x40,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,
  0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,
  0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,
  0x20,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x10,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x02,0x00,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x10,
  0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,
  0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,
  0x00,0x40,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,
  0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,
  0x20,0x00,0x40,0x00,0x08,0x10,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x02,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,
  0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x04,0x00,0x00,0x80,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x08,0x10,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x04,0x00,
  0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x10,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x04,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x04,
  0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x02,0x00,
  0x10,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x80,
  0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x02,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,
  0x04,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
  0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x08,0x00,
  0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x40,0x00,0x00,0x10,
  0x00,0x00,0x00,0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,
  0x10,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x80,0x04,0x00,0x00,0x08,0x00,0x01,0x00,
  0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};

PROGMEM const unsigned char Ship[] = {
  8,7,
  0x18,
  0x18,
  0x3C,
  0xBD,
  0xBD,
  0xFF,
  0xFF};

////////////////////END OF BITMAPS!/////////////////////////////////////

/*
RCA video plug:
 Sync(Pin 9) -> 1k -> center prong
 Video(pin 7) -> 470ohm -> center prong
 Gnd -> outside casing
 */

#include <TVout.h>
#include <fontALL.h>

TVout TV; //init the TV object

//resolution of output
#define TVresW 120
#define TVresH 96

// x/y limits for ship
#define MaxRight (TVresW-8)
#define MaxDown (TVresH -7)

//this program uses a lot of memory, so i use bytes here because they are large enough for this purpose.
//where the ship is on screen
byte CurXPos = (TVresW-8)/2; //centers ship horizontally
byte CurYPos = TVresH -7; //(total height) - 7(ship height), moves ship to bottom

#define XaxisPin A2
int Xval=0; //raw stick data, x axis
#define YaxisPin A1
int Yval=0; //raw stick data, y axis

#define FireBtn 0 //aka digital 2 interrupt
volatile long lastDebounceTime = 0;   // the last time the interrupt was triggered
#define debounceDelay  10    // the debounce time; decrease if quick button presses are ignored
volatile int fireState = LOW; //initial button state
volatile long lastFire = 0;
byte FireY =0;
byte FireX = 0;

void setup()
{
  //Serial.begin(115200);

  attachInterrupt(FireBtn,FireEvent, RISING); //fire button interrupt

  TV.begin(NTSC,TVresW,TVresH); //initialize TV
  delay(1000); //wait for TV to detect input

  TV.bitmap(0,0,BckGnd); //displays the "stars"
  TV.select_font(font8x8); //each char is 8x8 pixels
  TV.print((TVresW-80)/2,(TVresH-8)/2,"Ship Test!"); //80 pixel long message, 8 tall
  TV.bitmap(CurXPos,CurYPos,Ship); //displays the ship

  delay(250);
}
void loop()
{
  GetSticks(); //get raw data
  MoveShip(); //move ship accordingly on screen
  CheckFire(); //testing
}

void GetSticks()
{
  Yval = analogRead(YaxisPin);
  Xval = analogRead(XaxisPin);
  /*
  Serial.print(Xval);
   Serial.print(" ");
   Serial.println(Yval);
   */
  if(Xval < 512) //move left
  {
    Xval = map(Xval,512,0,0,-4);
  }
  else//its >= 512
  {
    Xval = map(Xval,512,1023,0,4); //move right
  }

  if(Yval < 512) //move down
  {
    Yval = map(Yval,512,0,0,4);
  }
  else//its >= 512 //move up
  {
    Yval = map(Yval,512,1023,0,-4);
  }
}

void MoveShip()
{
  //get new pos
  CurXPos += Xval;
  CurYPos += Yval;

  if (CurXPos > MaxRight) //check horizontal limits
  {
    CurXPos = 0;
  }
  else if(CurXPos <= 0)
  {
    CurXPos = MaxRight;
  }

  if (CurYPos > MaxDown) //check vertical limits
  {
    CurYPos = 0;
  }
  else if(CurYPos <= 0)
  {
    CurYPos = MaxDown;
  }
  //clear screen + display new ship
  TV.bitmap(0,0,BckGnd); // used to be "TV.clear_screen();", but the BckGnd bitmap covers the enite screen, so not needed.
  TV.bitmap(CurXPos,CurYPos,Ship);
  /*
  Serial.print(CurXPos);
   Serial.print(",");
   Serial.println(CurYPos);
   */
}
/*
void DrawFire() //works well at drawing a bullet, but stops the program whiles its doing it because of the for loop.
{
  byte FireX = CurXPos + 4;
  byte FireY = CurYPos;

  for(byte i = FireY; i>=0; i--)
  {
    TV.set_pixel(FireX,i+1,0);
    delay(2);
    TV.set_pixel(FireX,i,1);
    delay(2);
  }
}
*/


//untested attempt at "drawing" fire(a bullet)
void FireEvent()
{
  if ((millis() - lastDebounceTime) > debounceDelay)
  {
    lastDebounceTime = millis();
 
    FireX = CurXPos + 4;
    FireY = CurYPos;
    fireState = true;
 
    TV.set_pixel(FireX,FireY+1,0);
    TV.set_pixel(FireX,FireY,1);
  }
}

void CheckFire()
{
  if(fireState && millis() > (lastFire + 2) && FireY >0)
  {
    FireY--;
    lastFire = millis();
 
    TV.set_pixel(FireX,FireY+1,0);
    TV.set_pixel(FireX,FireY,1);
  }
}

1 comment:

  1. If you want your ex-girlfriend or ex-boyfriend to come crawling back to you on their knees (even if they're dating somebody else now) you need to watch this video
    right away...

    (VIDEO) Have your ex CRAWLING back to you...?

    ReplyDelete