This week Bob takes the TVOut Library for Arduino that we demonstrated a few weeks back and ramps it up.  First, the switch to the Arduino Mega for more memory, adding a speaker and a keypad.

Downloads

HD Apple HD Apple SD Audio MP3

This episode used the following Arduino files (code listed below):

  • DemoNTSC.ino
  • TVOutDemo.ino
  • TVOut_Scoreboard2.ino
  • TVoutOscilloscope.ino
  • TVOut_timers.ino

Changes were made to the TVoutbeta1 library as well. A summary is listed below as well. This library can be found here: https://code.google.com/p/arduino-tvout/

The code, a Fritzing schematic, and the modified library, will also be put on Github at: https://github.com/texanfromiowa

The TVOut_timers.ino has an additional function, simple_matrix_effect, that was added after the show. Enjoy!!

The TVoutOscilloscope project can be found at: http://forum.arduino.cc/index.php?topic=64327.0

A few minor modifications were made for the show. Note that the original file, TVoutOscilloscope.pde, was written with a pre-1.0 Arduino IDE. This suggests that is it a Processing file, not an Arduino file. However, we were able to compile the code without issue using IDE 1.5.6-r2, and save it as an .ino file.

This Spectrum Analyzer project was shown during the show as well: http://blurtime.blogspot.com/2010/11/arduino-realtime-audio-spectrum.html

The YouTube video of the Spectrum Analyzer is here: https://www.youtube.com/watch?v=6Lt3kTIzNFY

Another cool project that was not in the show can be found here: http://www.instructables.com/id/2-player-Pong-using-Arduino/

As always, if you have questions, please email us!!!

DemoNTSC.ino

#include <TVout.h>
#include <fontALL.h>
#include "schematic.h"
#include "TVOlogo.h"

TVout TV;

int zOff = 150;
int xOff = 0;
int yOff = 0;
int cSize = 50;
int view_plane = 64;
float angle = PI/60;

float cube3d[8][3] = {
  {xOff - cSize,yOff + cSize,zOff - cSize},
  {xOff + cSize,yOff + cSize,zOff - cSize},
  {xOff - cSize,yOff - cSize,zOff - cSize},
  {xOff + cSize,yOff - cSize,zOff - cSize},
  {xOff - cSize,yOff + cSize,zOff + cSize},
  {xOff + cSize,yOff + cSize,zOff + cSize},
  {xOff - cSize,yOff - cSize,zOff + cSize},
  {xOff + cSize,yOff - cSize,zOff + cSize}
};
unsigned char cube2d[8][2];


void setup() {
  TV.begin(NTSC,120,96);
  TV.select_font(font6x8);
  intro();
  TV.println("I am the TVout\nlibrary running on a Arduino Mega\n");
  TV.delay(2500);
  TV.println("I generate a PAL\nor NTSC composite video using\ninterrupts\n");
  TV.delay(2500);
  TV.println("My schematic:");
  TV.delay(1500);
  TV.bitmap(0,0,schematic);
  TV.delay(10000);
  TV.clear_screen();
  TV.println("Lets see what\nwhat I can do");
  TV.delay(2000);
  
  //fonts
  TV.clear_screen();
  TV.println(0,0,"Multiple fonts:");
  TV.select_font(font4x6);
  TV.println("4x6 font FONT");
  TV.select_font(font6x8);
  TV.println("6x8 font FONT");
  TV.select_font(font8x8);
  TV.println("8x8 font FONT");
  TV.select_font(font6x8);
  TV.delay(2000);
  
  TV.clear_screen();
  TV.print(9,44,"Draw Basic Shapes");
  TV.delay(2000);
  
  //circles
  TV.clear_screen();
  TV.draw_circle(TV.hres()/2,TV.vres()/2,TV.vres()/3,WHITE);
  TV.delay(500);
  TV.draw_circle(TV.hres()/2,TV.vres()/2,TV.vres()/2,WHITE,INVERT);
  TV.delay(2000);
  
  //rectangles and lines
  TV.clear_screen();
  TV.draw_rect(20,20,80,56,WHITE);
  TV.delay(500);
  TV.draw_rect(10,10,100,76,WHITE,INVERT);
  TV.delay(500);
  TV.draw_line(60,20,60,76,INVERT);
  TV.draw_line(20,48,100,48,INVERT);
  TV.delay(500);
  TV.draw_line(10,10,110,86,INVERT);
  TV.draw_line(10,86,110,10,INVERT);
  TV.delay(2000);
  
  //random cube forever.
  TV.clear_screen();
  TV.print(16,40,"Random Cube");
  TV.print(28,48,"Rotation");
  TV.delay(2000);
  
  randomSeed(analogRead(0));
}

void loop() {
  int rsteps = random(10,60);
  switch(random(6)) {
    case 0:
      for (int i = 0; i < rsteps; i++) {
        zrotate(angle);
        printcube();
      }
      break;
    case 1:
      for (int i = 0; i < rsteps; i++) {
        zrotate(2*PI - angle);
        printcube();
      }
      break;
    case 2:
      for (int i = 0; i < rsteps; i++) {
        xrotate(angle);
        printcube();
      }
      break;
    case 3:
      for (int i = 0; i < rsteps; i++) {
        xrotate(2*PI - angle);
        printcube();
      }
      break;
    case 4:
      for (int i = 0; i < rsteps; i++) {
        yrotate(angle);
        printcube();
      }
      break;
    case 5:
      for (int i = 0; i < rsteps; i++) {
        yrotate(2*PI - angle);
        printcube();
      }
      break;
  }
}

void intro() {
unsigned char w,l,wb;
  int index;
  w = pgm_read_byte(TVOlogo);
  l = pgm_read_byte(TVOlogo+1);
  if (w&7)
    wb = w/8 + 1;
  else
    wb = w/8;
  index = wb*(l-1) + 2;
  for ( unsigned char i = 1; i < l; i++ ) {
    TV.bitmap((TV.hres() - w)/2,0,TVOlogo,index,w,i);
    index-= wb;
    TV.delay(50);
  }
  for (unsigned char i = 0; i < (TV.vres() - l)/2; i++) {
    TV.bitmap((TV.hres() - w)/2,i,TVOlogo);
    TV.delay(50);
  }
  TV.delay(3000);
  TV.clear_screen();
}

void printcube() {
  //calculate 2d points
  for(byte i = 0; i < 8; i++) {
    cube2d[i][0] = (unsigned char)((cube3d[i][0] * view_plane / cube3d[i][2]) + (TV.hres()/2));
    cube2d[i][1] = (unsigned char)((cube3d[i][1] * view_plane / cube3d[i][2]) + (TV.vres()/2));
  }
  TV.delay_frame(1);
  TV.clear_screen();
  draw_cube();
}

void zrotate(float q) {
  float tx,ty,temp;
  for(byte i = 0; i < 8; i++) {
    tx = cube3d[i][0] - xOff;
    ty = cube3d[i][1] - yOff;
    temp = tx * cos(q) - ty * sin(q);
    ty = tx * sin(q) + ty * cos(q);
    tx = temp;
    cube3d[i][0] = tx + xOff;
    cube3d[i][1] = ty + yOff;
  }
}

void yrotate(float q) {
  float tx,tz,temp;
  for(byte i = 0; i < 8; i++) {
    tx = cube3d[i][0] - xOff;
    tz = cube3d[i][2] - zOff;
    temp = tz * cos(q) - tx * sin(q);
    tx = tz * sin(q) + tx * cos(q);
    tz = temp;
    cube3d[i][0] = tx + xOff;
    cube3d[i][2] = tz + zOff;
  }
}

void xrotate(float q) {
  float ty,tz,temp;
  for(byte i = 0; i < 8; i++) {
    ty = cube3d[i][1] - yOff;
    tz = cube3d[i][2] - zOff;
    temp = ty * cos(q) - tz * sin(q);
    tz = ty * sin(q) + tz * cos(q);
    ty = temp;
    cube3d[i][1] = ty + yOff;
    cube3d[i][2] = tz + zOff;
  }
}

void draw_cube() {
  TV.draw_line(cube2d[0][0],cube2d[0][1],cube2d[1][0],cube2d[1][1],WHITE);
  TV.draw_line(cube2d[0][0],cube2d[0][1],cube2d[2][0],cube2d[2][1],WHITE);
  TV.draw_line(cube2d[0][0],cube2d[0][1],cube2d[4][0],cube2d[4][1],WHITE);
  TV.draw_line(cube2d[1][0],cube2d[1][1],cube2d[5][0],cube2d[5][1],WHITE);
  TV.draw_line(cube2d[1][0],cube2d[1][1],cube2d[3][0],cube2d[3][1],WHITE);
  TV.draw_line(cube2d[2][0],cube2d[2][1],cube2d[6][0],cube2d[6][1],WHITE);
  TV.draw_line(cube2d[2][0],cube2d[2][1],cube2d[3][0],cube2d[3][1],WHITE);
  TV.draw_line(cube2d[4][0],cube2d[4][1],cube2d[6][0],cube2d[6][1],WHITE);
  TV.draw_line(cube2d[4][0],cube2d[4][1],cube2d[5][0],cube2d[5][1],WHITE);
  TV.draw_line(cube2d[7][0],cube2d[7][1],cube2d[6][0],cube2d[6][1],WHITE);
  TV.draw_line(cube2d[7][0],cube2d[7][1],cube2d[3][0],cube2d[3][1],WHITE);
  TV.draw_line(cube2d[7][0],cube2d[7][1],cube2d[5][0],cube2d[5][1],WHITE);
}

TVOutDemo.ino

/**************************************************************
  Name      TVOutDemo                                
  Author    Bob Powell 
            texanfromiowa@gmail.com
            Copyright (C) 2012-2014, Parallelus Automation, Inc.
          
  Date      Jun 21, 2014    
  Modified  Jul 7, 2014                                
  Version   1.0.0      
  Arduino   1.5.6-r2
  
  Notes     
            
            
Legal Stuff:
============
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
at your option, any later version.
	 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
	 
You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
          
   
     
Personal note:

If you do something interesting with this code, expand it, or just
have a question, please email it to me at the address above.  

I hope you find this example helpful.  Enjoy.

Bob


****************************************************************/
// Set some variables - Global variables, except for the Arduino
// pins, are CAPITALIZED.

// This code uses the TVOutBeta1 version of the library
#include <TVout.h>
#include <fontALL.h>
#include "schematic.h"
#include "TVOlogo.h"

TVout TV;

// Global variables
char TEMPBUFFER[63];
bool DEBUG = false;
// For an UNO 120x96 is as large as possible (at least that is what it seems)
int WIDTH = 136;  // must be divisable by 8
int HEIGHT = 96;

// Needed for the cube demo originally from the TVOut example
int zOff = 150;
int xOff = 0;
int yOff = 0;
int cSize = 50;
int view_plane = 64;
float angle = PI/60;

float cube3d[8][3] = {
  {xOff - cSize,yOff + cSize,zOff - cSize},
  {xOff + cSize,yOff + cSize,zOff - cSize},
  {xOff - cSize,yOff - cSize,zOff - cSize},
  {xOff + cSize,yOff - cSize,zOff - cSize},
  {xOff - cSize,yOff + cSize,zOff + cSize},
  {xOff + cSize,yOff + cSize,zOff + cSize},
  {xOff - cSize,yOff - cSize,zOff + cSize},
  {xOff + cSize,yOff - cSize,zOff + cSize}
};
unsigned char cube2d[8][2];


/**************************************************************
Function: setup
Purpose:  set up Arduino
Args:     none
Returns:  nothing
Notes:    This function is required by the Arduino
***************************************************************/
void setup() {
  
  if(DEBUG){
    Serial.begin(9600);
    Serial.println("Starting.");
  }
  
  TV.begin(NTSC,WIDTH,HEIGHT);
  //TV.select_font(font6x8);
  TV.clear_screen();
  TV.set_font(6);

  letsmakeit_intro();  
    
  play_charge();
  TV.set_font(6);
  
  randomSeed(analogRead(0));
} // end of setup()

/**************************************************************
Function: loop
Purpose:  loop funtion for Arduino
Args:     none
Returns:  nothing
Notes:    This function is required by the Arduino, and the 
          Arduino will loop through this function indefinately.
***************************************************************/
void loop() {
  
  run_cube(5000);
  TV.clear_screen();
  delay(5000);
  
  
} // end of loop()  


/**************************************************************
Function: letsmakeit_intro
Purpose:  Lets Make It intro 
Args:     none
Returns:  nothing
Notes:    For Lets Make It, www.letsmakeit.tv, demo..
***************************************************************/
void letsmakeit_intro()
{
  int x, y;

  // Put something on screen for small delay
  TV.print("\nLets Make It\nwww.letsmakeit.tv\nTVOut Demo\n\nStarting.");
  TV.draw_line(0,48,120,48,WHITE);
  for(int i = 0; i < 6; i++){
    TV.delay(500);
    TV.print(".");
  }
  TV.print(".done");
  TV.delay(2000);
  TV.clear_screen();

  // Show the visable area
  TV.draw_rect(0,0,WIDTH-1,HEIGHT-1,WHITE);
  sprintf(TEMPBUFFER, "Visable Area");
  TV.print(get_centered_x(TEMPBUFFER), get_centered_y(TEMPBUFFER)-12, TEMPBUFFER);
  
  sprintf(TEMPBUFFER, "Width = %d", WIDTH);
  TV.print(get_centered_x(TEMPBUFFER), get_centered_y(TEMPBUFFER)+4, TEMPBUFFER);
  
  sprintf(TEMPBUFFER, "Height = %d", HEIGHT);
  TV.print(get_centered_x(TEMPBUFFER), get_centered_y(TEMPBUFFER)+12, TEMPBUFFER);
  delay(10000);  
 
}


/**************************************************************
Function: play_charge
Purpose:  plays Charge tune 
Args:     none
Returns:  nothing
Notes:    Used this for the tune: http://en.wikipedia.org/wiki/Charge_(fanfare)
          Frequency numbers from: http://en.wikipedia.org/wiki/Piano_key_frequencies
***************************************************************/
void play_charge()
{  
  
  TV.clear_screen();
  TV.set_font(8);
  sprintf(TEMPBUFFER, "Charge!!");  
  TV.print(get_centered_x(TEMPBUFFER), get_centered_y(TEMPBUFFER), TEMPBUFFER);
  int note = 250;
  int noteoff = 50;

  // G4
  TV.tone(392);
  delay(note*2);
  TV.noTone();
  TV.delay(noteoff);

  // C5
  TV.tone(523);
  delay(note*2);
  TV.noTone();
  TV.delay(noteoff);

  // E5
  TV.tone(659);
  delay(note*2);
  TV.noTone();
  TV.delay(noteoff);

  // G5
  TV.tone(784);
  delay(note*3);
  TV.noTone();
  TV.delay(noteoff);

  // E5
  TV.tone(659);
  delay(note);
  TV.noTone();
  TV.delay(noteoff);
  
  // G5
  TV.tone(784);
  delay(note*8);
  TV.noTone();

  TV.noTone();
  TV.clear_screen();
  sprintf(TEMPBUFFER, "All done");  
  TV.print(get_centered_x(TEMPBUFFER), get_centered_y(TEMPBUFFER), TEMPBUFFER);
  TV.delay(3000);
  
}


/**************************************************************
Function: get_centered_x
Purpose:  calculate x for centered text 
Args:     char *temp - pointer to string being printed
Returns:  x value
Notes:    
***************************************************************/
int get_centered_x(char *temp)
{
  int x = (WIDTH - strlen(temp)*TV.get_font_x())/2;
  return x;
}

/**************************************************************
Function: get_centered_y
Purpose:  calculate y for centered text 
Args:     char *temp - pointer to string being printed
Returns:  y value
Notes:    
***************************************************************/
int get_centered_y(char *temp)
{
  int x = (HEIGHT + (TV.get_font_y()/2))/2;
  return x;
}


/**************************************************************
Function: run_cube
Purpose:  runs the random cube demo from the TVOut example code
Args:     int duration - in milliseconds          
Returns:  nothing
Notes:    This is the TVOut code in its own function.
***************************************************************/
void run_cube(int duration){
  
  int currentTime = millis();
  int finishTime = currentTime + duration;
  // The cycleNum variable is only needed if DEBUG is true, 
  // however, to prevent compilier warnings it is left here.
  int cycleNum = 0;
  
  TV.clear_screen();
  TV.print(16,40,"Random Cube");
  TV.print(28,48,"Rotation");
  TV.delay(2000);
  
  // NOTE: if DEBUG is true, then the display will flicker!!!
  if(DEBUG){
    sprintf(TEMPBUFFER, "finishTime = %d", finishTime);
    Serial.println(TEMPBUFFER);
  }
    
  do {
    
    if(DEBUG){
      sprintf(TEMPBUFFER, "Starting cycleNum = %d", cycleNum);
      Serial.println(TEMPBUFFER);
      cycleNum++;
    }
    
    // Sets a random number of steps for any rotation direction
    int rsteps = random(10,60);
    
    //Runs a random direction (one of 6) for the number of rsteps set above.
    switch(random(6)) {
      case 0:
        for (int i = 0; i < rsteps; i++) {
          zrotate(angle);
          printcube();
        }
        break;
      case 1:
        for (int i = 0; i < rsteps; i++) {
            zrotate(2*PI - angle);
            printcube();
          }
          break;
      case 2:
        for (int i = 0; i < rsteps; i++) {
            xrotate(angle);
            printcube();
          }
          break;
      case 3:
        for (int i = 0; i < rsteps; i++) {
          xrotate(2*PI - angle);
          printcube();
        }
        break;
      case 4:
        for (int i = 0; i < rsteps; i++) {
          yrotate(angle);
          printcube();
        }
        break;
      case 5:
        for (int i = 0; i < rsteps; i++) {
          yrotate(2*PI - angle);
          printcube();
        }
        break;
    }
    
    currentTime = millis();
    if(DEBUG){
      sprintf(TEMPBUFFER, "currentTime = %d, finishTime = %d", currentTime, finishTime);
      Serial.println(TEMPBUFFER);
    }
  } while(currentTime < finishTime);
  
}

void intro() {
  unsigned char w,l,wb;
  int index;
  w = pgm_read_byte(TVOlogo);
  l = pgm_read_byte(TVOlogo+1);
  if (w&7)
    wb = w/8 + 1;
  else
    wb = w/8;
  index = wb*(l-1) + 2;

  for ( unsigned char i = 1; i < l; i++ ) {
    TV.bitmap((TV.hres() - w)/2,0,TVOlogo,index,w,i);
    index-= wb;
    TV.delay(50);
  }
  for (unsigned char i = 0; i < (TV.vres() - l)/2; i++) {
    TV.bitmap((TV.hres() - w)/2,i,TVOlogo);
    TV.delay(50);
  }
  TV.delay(3000);
  TV.clear_screen();
}

void printcube() {
  //calculate 2d points
  for(byte i = 0; i < 8; i++) {
    cube2d[i][0] = (unsigned char)((cube3d[i][0] * view_plane / cube3d[i][2]) + (TV.hres()/2));
    cube2d[i][1] = (unsigned char)((cube3d[i][1] * view_plane / cube3d[i][2]) + (TV.vres()/2));
  }
  TV.delay_frame(1);
  TV.clear_screen();
  draw_cube();
}

void zrotate(float q) {
  float tx,ty,temp;
  for(byte i = 0; i < 8; i++) {
    tx = cube3d[i][0] - xOff;
    ty = cube3d[i][1] - yOff;
    temp = tx * cos(q) - ty * sin(q);
    ty = tx * sin(q) + ty * cos(q);
    tx = temp;
    cube3d[i][0] = tx + xOff;
    cube3d[i][1] = ty + yOff;
  }
}

void yrotate(float q) {
  float tx,tz,temp;
  for(byte i = 0; i < 8; i++) {
    tx = cube3d[i][0] - xOff;
    tz = cube3d[i][2] - zOff;
    temp = tz * cos(q) - tx * sin(q);
    tx = tz * sin(q) + tx * cos(q);
    tz = temp;
    cube3d[i][0] = tx + xOff;
    cube3d[i][2] = tz + zOff;
  }
}

void xrotate(float q) {
  float ty,tz,temp;
  for(byte i = 0; i < 8; i++) {
    ty = cube3d[i][1] - yOff;
    tz = cube3d[i][2] - zOff;
    temp = ty * cos(q) - tz * sin(q);
    tz = ty * sin(q) + tz * cos(q);
    ty = temp;
    cube3d[i][1] = ty + yOff;
    cube3d[i][2] = tz + zOff;
  }
}

void draw_cube() {
  TV.draw_line(cube2d[0][0],cube2d[0][1],cube2d[1][0],cube2d[1][1],WHITE);
  TV.draw_line(cube2d[0][0],cube2d[0][1],cube2d[2][0],cube2d[2][1],WHITE);
  TV.draw_line(cube2d[0][0],cube2d[0][1],cube2d[4][0],cube2d[4][1],WHITE);
  TV.draw_line(cube2d[1][0],cube2d[1][1],cube2d[5][0],cube2d[5][1],WHITE);
  TV.draw_line(cube2d[1][0],cube2d[1][1],cube2d[3][0],cube2d[3][1],WHITE);
  TV.draw_line(cube2d[2][0],cube2d[2][1],cube2d[6][0],cube2d[6][1],WHITE);
  TV.draw_line(cube2d[2][0],cube2d[2][1],cube2d[3][0],cube2d[3][1],WHITE);
  TV.draw_line(cube2d[4][0],cube2d[4][1],cube2d[6][0],cube2d[6][1],WHITE);
  TV.draw_line(cube2d[4][0],cube2d[4][1],cube2d[5][0],cube2d[5][1],WHITE);
  TV.draw_line(cube2d[7][0],cube2d[7][1],cube2d[6][0],cube2d[6][1],WHITE);
  TV.draw_line(cube2d[7][0],cube2d[7][1],cube2d[3][0],cube2d[3][1],WHITE);
  TV.draw_line(cube2d[7][0],cube2d[7][1],cube2d[5][0],cube2d[5][1],WHITE);
}

TVOut_Scoreboard2.ino

/*
Project: ScoreBoard with TVOut Library and 12 Key KeyPad
 Start Date: 2014-04-13
 Date Updated: 2014-04-21
 Prototyped By: Jim F, Calgary AB, Canada
 */
/**************************************************************
  Name          TVOut_Scoreboard2                              
  Modified By   Bob Powell 
                texanfromiowa@gmail.com
          
  Date      Jul 1, 2014    
  Modified  Jul 7, 2014                                
  Version   ?     
  Arduino   1.5.6-r2
  
  Notes     This is Jim's code, with updates from Bob.
            Most of the updates have to do with using a 
            different keypad since he had a 12 key, and
            I have a 25 key.
            
            The only functional change is to stop the 
            timer when the maxPeriad is reach (ie end of game).
           
            Much of Jim's code that was not needed is 
            commented out. 

Legal Stuff:
============
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
at your option, any later version.
	 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
	 
You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
          
               
            
Personal note:

If you do something interesting with this code, expand it, or just
have a question, please email it to me at the address above.  

I hope you find this example helpful.  Enjoy.

Bob

*/

//=== TVOut Library and Golbal Variables ===
#include <TVout.h>
#include <fontALL.h>
#include <Keypad.h>

TVout TV; // Assign TVOut class to TV
int frame=0; // Counts number of times through the loop() function
// and when it reaches 0 then Refresh the Display

char TEMPBUFFER[63];
byte KEYVAL = 0;
byte LASTKEYVAL = 0;

const byte ROWS = 5; //five rows
const byte COLS = 5; //five columns
//define the symbols on the buttons of the keypads
char hexaKeys[ROWS][COLS] = {
  {132,'0','1','2','3'},    // Back arrow
  {133,'4','5','6','7'},    // DEL (BS)
  {134,'8','9','A','B'},    // Arrow 
  {135,'C','D','E','F'},    // Enter
  {' ',128,129,130,131}     // F0 to F3
};
//////////////////////////////////////////////////////////////
// Use an Arduino Mega 2560 because it has more I/O pins
//
byte rowPins[ROWS] = {43, 41, 39, 37, 35}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {53, 51, 49, 47, 45}; //connect to the column pinouts of the keypad
//
// or use a Cross Roads ATmega1284P board which has 10 I/O pins in a row
//
//byte rowPins[ROWS] = {26, 25, 24, 23, 22}; //connect to the row pinouts of the keypad
//byte colPins[COLS] = {31, 30, 29, 28, 27}; //connect to the column pinouts of the keypad
//
// comment out the unused board
//////////////////////////////////////////////////////////////
//initialize an instance of class NewKeypad
Keypad customKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS); 


unsigned long keypadPressed=0; // Integer value of the keypad buttons pressed
unsigned long lastButtons=0; // last keypad buttons pressed used for debounce
unsigned long extKey=0; // extended key value
unsigned long shiftKey=0; // shift key value toggle '#' key pressed
unsigned long fnKey=0; // function key value toggle '*' key pressed

//=== Global Variables used for Score Board ===
char tmp[20]="000000000000000"; // Temporary buffer used for formatted output
int teamA=0; // Team A Score
int teamB=0; // Team B Score
int period=1; // Game Period
int maxPeriod=4; // Maximum Number of Periods in the game
int maxTimer=10*60; // Maximum Number of seconds to countdown for timer
int timer1=maxTimer; // Countdown timer for periods
int timerOn=0; // Toggle for start/stop timer

//=== Standard Program Setup Function ======================================
void setup()  {
  
  TV.begin(NTSC,128,96);
  TV.select_font(font8x8);// Select the 8x8 font (This font is Large,Clear,Easy to Read)
  TV.delay(2000); // small delay to let TVOut get setup in memory
}

//=== Standard Program Infinite Loop Function ================================
void loop() {
  getInputs();// Get all kinds of inputs from the I/O pins
  processInputs();// Process the inputs
  TV.delay_frame(1);// Helpful for overall timing when using TVOut functions
}

//==========================================================================
// getInputs calls Keypad input routine for now, other inputs can be added
// for example: IRRemote, momentary buttons, sensors, real-time clock, etc.
void getInputs() {
  KEYVAL = customKeypad.getKey();
}



//========================================================
//== Here is where the heavy-duty processing logic happens
void processInputs() {
  //keypadPressed=keyMap[keyVal];// ASCII value assigned when keypad button pressed
  //keypadPressed=(int)hexaKeys[KEYVAL];// ASCII value assigned when keypad button pressed
  keypadPressed=KEYVAL;// ASCII value assigned when keypad button pressed
  displayKeysPressed();// Display the ASCII values (Note: used for debugging purposes)

  switch (KEYVAL) {
    
    case(48):    // 0
      teamA-=1;  //  Decrement Team A
      break;
    case(49):    // 1
      teamA+=1;  //  Decrement Team A
      break;
    case(50):    // 2
      teamB-=1;  //  Decrement Team B
      break;
    case(51):    // 3
      teamB+=1;  //  Increment Team B
      break;
    case(52):    // 4
      period-=1; //  Decrement Period
      break;
    case(53):    // 5
      period+=1; //  Increment Period
      break;
    case(54):   // 6

      break;
    case(55):   // 7

      break;
    case(56):   // 8

      break;
    case(57):   // 9

      break;
    case(65):   // A

      break;
    case(66):   // B

      break;
    case(67):   // C

      break;
    case(68):   // D

      break;
    case(69):   // E

      break;
    case(70):   // F

      break;
      
    case(32):   // Space

      break;
    case (128): // F0 function key
      timerOn=1-timerOn;  // Turn Timer on/off
      break;
    case (129): // F1 function key

      break;
    case (130): // F2 function key

      break;
    case (131): // F3 function key
      teamA=0; // Reset Team A Score
      teamB=0; // Reset Team B Score
      TV.clear_screen(); // Clear the TVOut screen
      displayScores();// Display the Team A & Team B Scores
      timer1=maxTimer;// Reset the countdown timer
      timerOn=0;
      break;
    case (132):   // <==== arrow

      break;
    case (133):       // DEL

      break;
    case (134):   // ====> arrow

      break;
    case (135):              // Enter

      break;
    default:  // This should never happen
      break;
  }    
  
  
  period=constrain(period,0,4);// Make sure Period value is in the range of 0 to 4
  teamA=constrain(teamA,0,199);// Make sure Team A Score is in the range of 0 to 199
  teamB=constrain(teamB,0,199);// Make sure Team B Score is in the range of 0 to 199
   
/*  
  // When keypadPressed is not equal to lastButtons then process the input values
  if(!(keypadPressed==lastButtons)) {
    if(extKey==176) {// Extended keypressed = "*1" (asterisk then 1)
      timer1=10;// reset countdown timer to 10 seconds
      resetButtonsPressed();
    }
    if(extKey>175) {// Reset extended keypressed and function key pressed
      fnKey=0;
      extKey=0;
      resetButtonsPressed();
    }
    if(extKey=='A') { // Extended keypressed = "#1" (pound then 1)
      timer1=maxTimer; // reset countdown timer
      timerOn=0;// pause the countdown timer
      resetButtonsPressed();
    }
    if(extKey=='B') {// Extended keypressed = "#2"
      timerOn=1-timerOn;
      resetButtonsPressed();
    }
    if(extKey=='C') {// Extended keypressed = "#3"
      teamA=0; // Reset Team A Score
      teamB=0; // Reset Team B Score
      TV.clear_screen(); // Clear the TVOut screen
      displayScores();// Display the Team A & Team B Scores
      timer1=maxTimer;// Reset the countdown timer
      resetButtonsPressed();
    }
    if(extKey=='F') {// Extended keypressed ="#6"
      teamA=0;// Reset Team A Score
      resetButtonsPressed();
    }
    if(extKey=='I') {// Extended keypressed = "#9"
      teamB=0;// Reset Team B Score
      resetButtonsPressed();
    }
    shiftKey+=(lastButtons==35);// If the '#' (pound key) pressed, then shiftKey activated
    fnKey+=(lastButtons==42);// If the '*' (asterisk key) pressed, then the functionKey activated
    extKey=(fnKey>0)*127+(shiftKey>0)*16+keypadPressed;// Assign the extended key value based on fnKey,shiftKey & keypadPressed values
    if( (shiftKey==0) & (fnKey==0) ) {// If the shiftKey and the fnKey are not assigned, then process normal keypad keys pressed
      period+=(keypadPressed=='1')*-1; // Keyapad 1 pressed, decrease period value by 1
      period+=(keypadPressed=='3');// Keypad 3 pressed, increase period value by 1
      teamA+=(keypadPressed=='4')*-1;// Keypad 4 pressed, decrease Team A Score by 1
      teamA+=(keypadPressed=='6');// Keypad 6 pressed, increase Team A Score by 1
      teamB+=(keypadPressed=='7')*-1;// Keypad 7 pressed, decrease Team B Score by 1
      teamB+=(keypadPressed=='9');// Keypad 9 pressed, increase Team B Score by 1
      period=constrain(period,0,4);// Make sure Period value is in the range of 0 to 4
      teamA=constrain(teamA,0,199);// Make sure Team A Score is in the range of 0 to 199
      teamB=constrain(teamB,0,199);// Make sure Team B Score is in the range of 0 to 199
      displayTimer();// Display the Countdown Timer
      displayScores();// Display the Team A & Team B Scores
    }
  }
  lastButtons=keypadPressed;// Used for keypad debounce and shiftKey/functionKey pressed
  resetFnShiftKeys();// if shiftKey or fnKey pressed then Reset them
*/
  if(frame==0) {// If frame counter equals 0 then Refresh and Display the Items
    displayTimer();// Display Countdown Timer
    displayScores();// Display Team A & Team B Scores
    displayLine(4,'-');// Display a row of '-' characters on line 4
    displayLine(7,'-');// Display a row of '-' characters on line 7
  }
  if(timer1==0) {// When the Countdown Timer reaches 0
    if(period != maxPeriod){
      timer1=maxTimer;// Reset the Countdown Timer
      period++;// and Increase the Period Counter by 1
    }
    // stops the timer when maxPeriod is reached
    else
      timerOn=0;
  }
  // When everything is processed,
  // Increase the frame counter by 1 
  // and reset to 0 when frame counter reaches 60
  if(++frame == 60) frame = 0;
}

//=====================================================
//== Resets the keypadPressed and lastButtons pressed
void resetButtonsPressed() {
  lastButtons=0; // reset lastButtons
  keypadPressed=0; // reset keypadPressed
}

//== Resets the fnKey,shiftKey,extKey ===
void resetFnShiftKeys() {
  if(extKey>16) {// Toggle Shift Key off
    shiftKey=0;
  }
  if(extKey>127) {// Toggle Function Key off
    fnKey=0;
  }
}

//==============================================================================
// Displays the integer values of the keypressed and extended keypressed values
void displayKeysPressed() {
  if(KEYVAL != 0)
    LASTKEYVAL = KEYVAL;
    
  //sprintf(tmp,"%04d",keypadPressed);
  sprintf(tmp,"%03d %c",LASTKEYVAL, LASTKEYVAL);
  TV.print(0*10,8*10,tmp);
  //sprintf(tmp,"%04d",extKey);
  //TV.print(7*10,8*10,tmp);
  //delay(1000);
  
  switch (LASTKEYVAL) {
    
    case(48):    // 0
    case(49):    // 1
    case(50):    // 2
    case(51):    // 3
    case(52):    // 4
    case(53):    // 5
    case(54):   // 6
    case(55):   // 7
    case(56):   // 8
    case(57):   // 9
    case(65):   // A
    case(66):   // B
    case(67):   // C
    case(68):   // D
    case(69):   // E
    case(70):   // F
      sprintf(tmp,"     ");
      break;
      
    case (32): // F0 function key
      sprintf(tmp,"Space");
      break;
    case (128): // F0 function key
      sprintf(tmp,"F0   ");
      break;
    case (129): // F1 function key
      sprintf(tmp,"F1   ");
      break;
    case (130): // F2 function key
      sprintf(tmp,"F2   ");
      break;
    case (131): // F3 function key
      sprintf(tmp,"F3   ");
      break;
    case (132):   // <==== arrow
      sprintf(tmp,"<==  ");
      break;
    case (133):       // DEL
      sprintf(tmp,"DEL  ");
      break;
    case (134):   // ====> arrow
      sprintf(tmp,"==>  ");
      break;
    case (135):              // Enter
      sprintf(tmp,"Enter");
      break;
    default:  // This should never happen
      break;
  } 
  
  TV.print(8*10,8*10,tmp);

}

//================================
//== Displays the Countdown Timer
void displayTimer() {
  if(frame==0) {
    if(timerOn==1) {
      timer1--;
      timer1=constrain(timer1,0,999);
    }
  }
  int mins=int(timer1 / 60);
  int secs=int(timer1 % 60);
  sprintf(tmp,"TIMER  -> %02d:%02d",mins,secs);
  TV.print(0*10,0*10,tmp);
  period=constrain(period,0,4);
  sprintf(tmp,"PERIOD -> %02d",period);
  TV.print(0*10,1*10,tmp);
}

//================================
//== Displays a row of characters
void displayLine(int lineNum, char chr) {
  for(int i=0; i<16; i++) {
    TV.print_char(i*8,lineNum*10,chr);
  }  
}

//=========================================
//== Displays Team A Score & Team B Score
void displayScores() {
  sprintf(tmp,"TEAM A -> %03d",teamA);
  TV.print(0*10,2*10,tmp);
  sprintf(tmp,"TEAM B -> %03d",teamB);
  TV.print(0*10,3*10,tmp);
}

TVoutOscilloscope.ino

/*

TVout-Oscilloscope, v1.0

Lets you display the voltage on analog pin A0 on your TV using the TVout Library.

It displays the average, the minimal and the maximal voltage, and the sampling
frequency. 100 sample points are displayed.

The maximal sampling frequency is about 8kHz (on an Arduino Uno). 

Add a button to digital pin 2 to scale the voltage range, and to digital pin 3
to scale the sample range.

(c) Juerg Wullschleger 2011.

http://creativecommons.org/licenses/by/3.0/
*/

/**************************************************************
  Name      TVoutOscilloscope                              
  Modified By   Bob Powell 
                texanfromiowa@gmail.com
          
  Date      Jul 5, 2014    
  Modified  Jul 5, 2014                                
  Version   ?     
  Arduino   1.5.6-r2
  
  Notes     This code was downloaded from http://forum.arduino.cc/index.php?topic=64327.0
            and modified only slightly (added a tone for an onboard signal and keypress
            simulation code) for the Lets Make It Show demonstration.
            www.letsmakeit.tv
            
            The file was save with an .ino extension rather than the .pde extension 
            used on pre-1.0 Arduino IDE files.
            
            
Personal note:

If you do something interesting with this code, expand it, or just
have a question, please email it to me at the address above.  

I hope you find this example helpful.  Enjoy.

Bob

*/


#include <TVout.h>
#include <font4x6.h>

//input pins
const int inputPin = 0;
const int scalePin = 2;
const int samplePin = 3;

// define the graph area
const int graphOffsetX = 18;
const int graphOffsetY = 94;
const int graphWidth = 100;
const int graphHeight = 86;

const int upperGraphLimit = graphOffsetY + 1;
const int lowerGraphLimit = graphOffsetY - graphHeight;

int scaleFactor = 1024/graphHeight+1;
int offset = 0;
int sampleSize = 1;

int minValue, maxValue, avgValue;
long sampleTime = 0;

//used if sampleSize <=3 to draw faster
int data[graphWidth];
uint8_t dispY[graphWidth];

TVout TV;

// Used to simulate keypress later
int TEST = 0;

void setup(){                                         
  pinMode(scalePin, INPUT);     
  pinMode(samplePin, INPUT);     

  //init TV
  TV.begin(_NTSC,120,96);
  TV.select_font(font4x6);
  
  clearGraph();
  drawScale();
  
  // Connected Audio out pin (digital 11 on Uno, 10 on Mega)
  // to analog 0 (input pin) with a 100 ohm resistor for testing.
  TV.tone(200);
  
}

void drawPixel(int x, int y, char c){
  if((y > lowerGraphLimit) && (y < upperGraphLimit)){
    TV.set_pixel(x,y,c);
  }
}

int val2y(int val){
  return graphOffsetY - val/scaleFactor - offset;
}

void drawScale(){
  //delete old scale
  TV.draw_rect(0,lowerGraphLimit, graphOffsetX-2,graphHeight+1,0,0);
  
  for(int i = 0; i<=20;i++){
    int y = val2y(1024 * i / 20);
    drawPixel(graphOffsetX-2,y,1);
    if((i % 2 != 0) && (scaleFactor < 8) && (y > lowerGraphLimit + 3) && (y < upperGraphLimit - 3)){
      TV.print(graphOffsetX - 18,y-3,i/4.0,2);
    }
    if(i % 2 == 0){
      drawPixel(graphOffsetX-3,y,1);  
      if((i % 4 != 0) && (scaleFactor <=8) && (y > lowerGraphLimit + 3) && (y < upperGraphLimit - 3)){
        TV.print(graphOffsetX - 15,y-3,i/4.0,1);
      }
    }
    if(i % 4 == 0){
      drawPixel(graphOffsetX-4,y,1);
      drawPixel(graphOffsetX-5,y,1);
      if((y > lowerGraphLimit + 3) && (y < upperGraphLimit - 3)){
        TV.print(graphOffsetX - 9,y-3,i/4);
      }
    }
  }
}

void clearGraph(){
  TV.draw_rect(graphOffsetX - 1,graphOffsetY - graphHeight, graphWidth+1,graphHeight+1,1,0);
}

void drawData(int i, int val){
  // we use dispY[i] to store the displayed pixel. so we only need to
  // erase that pixel, and not the whole column.
  int y = val2y(val);
  int x = i + graphOffsetX;
  drawPixel(x,dispY[i],0);
  drawPixel(x,y,1);
  dispY[i] = y;
}

void drawData(int i, int v1, int v2){
  int u = val2y(v1);
  int v = val2y(v2);
  int x = i + graphOffsetX;
  TV.draw_column(x, graphOffsetY, graphOffsetY - graphHeight + 1, 0);
  u = min(max(u,lowerGraphLimit),upperGraphLimit);
  v = min(max(v,lowerGraphLimit),upperGraphLimit);
  TV.draw_column(x, u, v, 1);
}

void changeScaleFactor(){
  int i = 1;
  while(i < scaleFactor)
    i = i*2;
  scaleFactor = i / 2;
  if(scaleFactor == 0){
    scaleFactor = 1024/graphHeight+1;
  }
  offset = graphHeight/2 - avgValue/scaleFactor;
  
  // we need: 0/scaleFactor + offset >= 0 and 1024/scaleFactor + offset <= graphHeight
  offset = max(graphHeight - 1024/scaleFactor,offset);
  offset = min(0,offset);

  drawScale();
  clearGraph();
}

void changeSampleSize(){
  if(sampleSize<5)
    sampleSize = sampleSize + 1;
  else
    sampleSize = sampleSize * 8 / 5;
  if(sampleSize > 300){
    sampleSize = 1;
  }
  clearGraph();
}

boolean scaleButtonPressed = false, sampleButtonPressed = false;
boolean checkButtons(){
  if(digitalRead(scalePin) == HIGH){
    scaleButtonPressed = true;
  }else{
    if(scaleButtonPressed){
      changeScaleFactor();
      scaleButtonPressed = false;
      return true;
    }
  }
  if(digitalRead(samplePin) == HIGH){
    sampleButtonPressed = true;
  }else{
    if(sampleButtonPressed){
      changeSampleSize();
      sampleButtonPressed = false;
      return true;
    }
  }
  return false;
}

float val2volts(int val){
  return val * 5 / 1024.0;
}

void printVolts(){
  TV.print(2,2,val2volts(avgValue),2);
  TV.print("V ("); 
  TV.print(val2volts(minValue),2);
  TV.print("V-"); 
  TV.print(val2volts(maxValue),2);
  TV.print("V)"); 
}

void printSampleRate(){
  long gw = graphWidth;
  TV.print(90,2, gw*1000000/sampleTime);
  TV.print("Hz ");
}

void loop() {
  
  // Simpulate a keypress, if needed
  if(TEST <= 2){
    changeSampleSize();
    TEST++;
  }  
    
  
  checkButtons();
  
  // wait for the next raising edge, but only for max. 400 steps.
  boolean wasLow = false;
  for(int w=0 ; w avgValue) && wasLow){
      break;
    }
  }
  
  minValue = 1024; maxValue = 0;
  long sum = 0;
  int i = 0;  
  long t = micros();

  while(i < graphWidth){
    if(sampleSize <= 3){
      //for small sampleSize, sample first and then draw
      if(sampleSize == 1){
        //read as fast as possible
        i=0;
        while(i < graphWidth){
           data[i] = analogRead(inputPin);
           i++;
        }
      }else{
        i=0;
        while(i < graphWidth){
          int s=0;
          for(int j=0; j<sampleSize;j++)
            s = s + analogRead(inputPin);
          data[i] = s/sampleSize;
          i++;
        }
      }
      sampleTime = micros() - t;
      i=0;
      while(i < graphWidth){
        int val = data[i];
        minValue = min(minValue, val);
        maxValue = max(maxValue, val);
        sum = sum + sampleSize*val;
        drawData(i,val);
        i++;
      }
    }else{
      //for large samleSize, do sample and draw at the same time.
      int minV = 1024, maxV = 0;
      for(int j = 0; j< sampleSize; j++){
        int val = analogRead(inputPin);
        minV = min(minV,val);
        maxV = max(maxV,val);
        sum = sum + val;
      }
      drawData(i,minV,maxV);
      minValue = min(minValue,minV);
      maxValue = max(maxValue,maxV);
      i++;

      if(checkButtons()){
        //button has been pressed. reset values.
        i = 0;
        t  = micros();
        minValue = 1024; maxValue = 0;
        sum = 0;
      }
      if(i==graphWidth)
        sampleTime = micros() - t;
    }
  }
  avgValue =  sum / (graphWidth*sampleSize);

  printVolts();
  printSampleRate(); 
}

TVOut_timers.ino

/**************************************************************
  Name      TVOut_Timers                              
  Author    Bob Powell 
            texanfromiowa@gmail.com
            Copyright (C) 2012-2014, Parallelus Automation, Inc.
          
  Date      Jun 24, 2014    
  Modified  Jul 7, 2014                                
  Version   1.0.0      
  Arduino   1.5.6-r2
  
  Notes     
            
            
Legal Stuff:
============
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
at your option, any later version.
	 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
	 
You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
          
   
     
Personal note:

If you do something interesting with this code, expand it, or just
have a question, please email it to me at the address above.  

I hope you find this example helpful.  Enjoy.

Bob


****************************************************************/
// Set some variables - Global variables, except for the Arduino
// pins, are CAPITALIZED.

// This code uses the TVOutBeta1 version of the library
#include <TVout.h>
#include <fontALL.h>

char TEMPBUFFER[63];
TVout TV;
// For an UNO 120x96 is as large as possible (at least that is what it seems)
int WIDTH = 136;  // must be divisable by 8
int HEIGHT = 96;

/**************************************************************
Function: setup
Purpose:  set up Arduino
Args:     none
Returns:  nothing
Notes:    This function is required by the Arduino
***************************************************************/
void setup() {

  ////Serial.begin(115200);
  ////Serial.println("\n\nStarting...\n");
  
  TV.begin(NTSC,WIDTH,HEIGHT);
  //TV.select_font(font6x8);
  TV.clear_screen();
  TV.set_font(6);

  letsmakeit_intro();  

  TV.set_font(6);

  randomSeed(analogRead(0));
  
}

/**************************************************************
Function: loop
Purpose:  loop funtion for Arduino
Args:     none
Returns:  nothing
Notes:    This function is required by the Arduino, and the 
          Arduino will loop through this function indefinately.
          
          Runs several examples of putting text on the
          TV screen.
***************************************************************/
void loop() {

  int minutes, seconds, x, y, x_char, y_char, charNum;

  // 
  simple_matrix_effect(6,150,250);

  // Size 6 font, 10millisecond delay, 2000 cycles
  random_chars(6,10,2000);
  
  
  // Count from 0 to 200, and back to 0
  TV.clear_screen();
  TV.set_font(6);
  TV.print("\nCounting");
  for(int i = 0; i <= 200; i++){
    sprintf(TEMPBUFFER,"%d", i);
    x = 30 - strlen(TEMPBUFFER)*TV.get_font_x();
    TV.print(x,25,TEMPBUFFER);
    TV.delay(15);
  }  
  TV.delay(1000);
  for(int i = 199; i >= 0; i--){
    sprintf(TEMPBUFFER,"%d", i);
    x = 30 - strlen(TEMPBUFFER)*TV.get_font_x();
    TV.print(0,25,"          ");
    TV.print(x,25,TEMPBUFFER);
    TV.delay(15);
  }
  TV.delay(2000);
  TV.clear_screen();
  TV.delay(2000);
   
     
  // Scroll lines
  TV.clear_screen();
  TV.set_font(6);  
  sprintf(TEMPBUFFER, "Scroll line # 1");
  TV.print(TEMPBUFFER);
  TV.delay(500);
  for(int i = 2; i < 13; i++){
    sprintf(TEMPBUFFER, "\nScroll line # %d", i);
    TV.print(TEMPBUFFER);
    TV.delay(500);
  }
  TV.delay(500);
  TV.print("\nOops, lost top line");
  TV.delay(5000);
  TV.clear_screen();
  
  // Scroll lines fast
  sprintf(TEMPBUFFER, "Fast scrolling # 1");
  TV.print(TEMPBUFFER);
  TV.delay(500);
  for(int i = 2; i <= 25; i++){
    sprintf(TEMPBUFFER, "\nFast scrolling # %d", i);
    TV.print(TEMPBUFFER);
    TV.delay(250);
  }
  TV.delay(5000);
  TV.clear_screen();
  
    
  // Count down from 70sec to 0
  TV.print("\nTime coundown:\n");
  TV.set_font(4);
  TV.print("\n (70sec to 0)");
  TV.set_font(6);
  for(int i = 70; i >= 0; i--){
    minutes = i / 60; 
    seconds = i % 60;
    sprintf(TEMPBUFFER, "%02d:%02d", minutes, seconds);
    TV.print(10,35,TEMPBUFFER);
    TV.delay(1000);
  }  
  TV.delay(2000);
  TV.clear_screen();
  TV.delay(2000);


  // Count up from 0 to 70sec
  TV.print("\nTime count up:\n");
  TV.set_font(4);
  TV.print("\n (0 to 70sec)");
  TV.set_font(6);
  for(int i = 0; i < 70; i++){
    minutes = i / 60; 
    seconds = i % 60;
    sprintf(TEMPBUFFER, "%02d:%02d", minutes, seconds);
    TV.print(10,35,TEMPBUFFER);
    TV.delay(1000);
  }  
  TV.delay(2000);
  TV.clear_screen();
  TV.delay(2000);
 
}


/**************************************************************
Function: random_chars
Purpose:  place random chars on the screen
Args:     int font_size - 4, 6, or 8 from the font library
          int duration - how long to delay between cycles
          int steps - number of cycles
Returns:  nothing
Notes:    This function is required by the Arduino, and the 
          Arduino will loop through this function indefinately.
***************************************************************/
void random_chars(int font_size, int duration, int steps)
{
  TV.clear_screen();
  TV.set_font(font_size);
  
  int x, y, x_char, y_char, charNum, numCharsX, numCharsY;
 
  numCharsX = (WIDTH - 1) / TV.get_font_x();    
  numCharsY = HEIGHT / TV.get_font_y();  
    
  // Random chars on screen
  sprintf(TEMPBUFFER, "Randon characters");
  TV.print(get_centered_x(TEMPBUFFER), get_centered_y(TEMPBUFFER)-(TV.get_font_y() * 1.5), TEMPBUFFER);
  sprintf(TEMPBUFFER, "placed on screen");
  TV.print(get_centered_x(TEMPBUFFER), get_centered_y(TEMPBUFFER)-(TV.get_font_y() * 0.5), TEMPBUFFER);
  sprintf(TEMPBUFFER, "in a grid pattern");
  TV.print(get_centered_x(TEMPBUFFER), get_centered_y(TEMPBUFFER)+(TV.get_font_y() * 0.5), TEMPBUFFER);
  TV.delay(3000);
  
  for(int i = 0; i < steps; i++){
    x_char = random(numCharsX);  
    y_char = random(numCharsY); 
    charNum = random(32,129); 
    x = x_char * font_size;
    y = y_char * 8;
    sprintf(TEMPBUFFER, "%c", charNum);
    TV.print(x,y,TEMPBUFFER);   
    TV.delay(duration); 
  }  
  
  TV.delay(3000);
  TV.clear_screen();
  //TV.set_font(8);
  sprintf(TEMPBUFFER, "That was fun!");
  x = (WIDTH/2) - (strlen(TEMPBUFFER)*TV.get_font_x())/2;
  y = (HEIGHT/2);
  TV.print(x, y, TEMPBUFFER);
  //TV.set_font(6);
  TV.delay(5000);
  TV.clear_screen();
  TV.delay(1000);

}

/**************************************************************
Function: simple_matrix_effect
Purpose:  place random chars on the screen
Args:     int font_size - 4 or 6 from the font library
                          (font 8 is not setup yet)
          int duration - how long to delay between cycles
          int steps - number of cycles
Returns:  nothing
Notes:    A simple version of the Matrix movie effect to 
          demo how it could be done.  
***************************************************************/
void simple_matrix_effect(int font_size, int duration, int cycles)
{
  
  TV.clear_screen();
  TV.set_font(font_size);
  
  int x, y, x_char, y_char, charNum, numCharsX, numCharsY;
 
  // Set the number of chars in X and Y  
  numCharsX = (WIDTH - 1) / TV.get_font_x();    
  numCharsY = HEIGHT / TV.get_font_y();  
    
  // create variables for each column 
  int cursor_y[numCharsX];     // number of rows
  int cursor_speed[numCharsX]; // speed for each columns
  int cursor_delay[numCharsX]; // speed counter for each column

  // show intro
  sprintf(TEMPBUFFER, "Simple");
  TV.print(get_centered_x(TEMPBUFFER), get_centered_y(TEMPBUFFER)-(TV.get_font_y() * 0.5), TEMPBUFFER);
  sprintf(TEMPBUFFER, "Matrix Effect");
  TV.print(get_centered_x(TEMPBUFFER), get_centered_y(TEMPBUFFER)+(TV.get_font_y() * 0.5), TEMPBUFFER);
  TV.delay(3000);
  TV.clear_screen();

  
  // Set an initial, random speed multiplier for each column
  for(int i = 0; i < numCharsX; i++){
    cursor_speed[i] = random(10); 
    cursor_delay[i] = cursor_speed[i];
    cursor_y[i] = 0;
  }


  int i, j;
  
  for(i = 0; i < cycles; i++){
    for(j = 0; j < numCharsX; j++){
        
      // time to print
      if(cursor_delay[j] == 0){
        
        // reset cursor delay
        cursor_delay[j] =  cursor_speed[j];    
        
        // calculate position  
        x = j * TV.get_font_x();
        y = cursor_y[j] * TV.get_font_y();
        sprintf(TEMPBUFFER, "%c", 128);
        TV.print(x, y, TEMPBUFFER);
        
        if(cursor_y[j] == 0){
          charNum = 128;
        }
        else{
          charNum = random(33,127); 
        }  
        

       if(cursor_y[j] > 0){  
         y = (cursor_y[j]-1) * TV.get_font_y();
         sprintf(TEMPBUFFER, "%c", charNum);
         TV.print(x, y, TEMPBUFFER);
       }
       
       cursor_y[j] = cursor_y[j] + 1;        
        
       // Reached the last row in a column -  reset cursor 
       // position, speed for next column drop, and make
       // the last char a random char 
       if(cursor_y[j] == numCharsY){
         charNum = random(33,127);
         y = (numCharsY-1) * TV.get_font_y();
         sprintf(TEMPBUFFER, "%c", charNum);
         TV.print(x, y, TEMPBUFFER);
         cursor_y[j] = 0;
         cursor_speed[j] = random(10); 
         cursor_delay[j] = cursor_speed[j];
       }  
        
     }
      
      // cursor_delay[j] != 0)
      else{
        // decrement the delay counter
        cursor_delay[j] = cursor_delay[j] - 1;
      }   


    }

    TV.delay(duration);
  }

  TV.delay(3000);
  TV.clear_screen();
  sprintf(TEMPBUFFER, "That was fun!");
  x = (WIDTH/2) - (strlen(TEMPBUFFER)*TV.get_font_x())/2;
  y = (HEIGHT/2);
  TV.print(x, y, TEMPBUFFER);
  //TV.set_font(6);
  TV.delay(5000);
  TV.clear_screen();
  TV.delay(1000);

}
/**************************************************************
Function: letsmakeit_intro
Purpose:  Lets Make It intro 
Args:     none
Returns:  nothing
Notes:    For Lets Make It, www.letsmakeit.tv, demo..
***************************************************************/
void letsmakeit_intro()
{
  int x, y;

  // Put something on screen for small delay
  TV.print("\nLets Make It\nwww.letsmakeit.tv\nTVOut Demo\n\nStarting.");
  TV.draw_line(0,48,120,48,WHITE);
  for(int i = 0; i < 6; i++){
    TV.delay(500);
    TV.print(".");
  }
  TV.print(".done");
  TV.delay(2000);
  TV.clear_screen();

  // Show the visable area
  TV.draw_rect(0,0,WIDTH-1,HEIGHT-1,WHITE);
  sprintf(TEMPBUFFER, "Visable Area");
  TV.print(get_centered_x(TEMPBUFFER), get_centered_y(TEMPBUFFER)-12, TEMPBUFFER);
  
  sprintf(TEMPBUFFER, "Width = %d", WIDTH);
  TV.print(get_centered_x(TEMPBUFFER), get_centered_y(TEMPBUFFER)+4, TEMPBUFFER);
  
  sprintf(TEMPBUFFER, "Height = %d", HEIGHT);
  TV.print(get_centered_x(TEMPBUFFER), get_centered_y(TEMPBUFFER)+12, TEMPBUFFER);
  delay(10000);  
 
}


/**************************************************************
Function: get_centered_x
Purpose:  calculate x for centered text 
Args:     char *temp - pointer to string being printed
Returns:  x value
Notes:    
***************************************************************/
int get_centered_x(char *temp)
{
  int x = (WIDTH - strlen(temp)*TV.get_font_x())/2;
  return x;
}

/**************************************************************
Function: get_centered_y
Purpose:  calculate y for centered text 
Args:     char *temp - pointer to string being printed
Returns:  y value
Notes:    
***************************************************************/
int get_centered_y(char *temp)
{
  int x = (HEIGHT + (TV.get_font_y()/2))/2;
  return x;
}

Summary of modifications to the TVoutbeta1 library files:

Added to font4x6.cpp file:

    //127 DEL  - Copied char 127 and 128 from 6x8 font
    //set and modified so code works for all fonts.
	0b00000000,
	0b00000000,
	0b00000000,
	0b00000000,
	0b00000000,
	0b00000000,
	// 128 Extended ascii char 219
    // needed for matrix effect
	0b11100000,
	0b11100000,
	0b11100000,
	0b11100000,
	0b11100000,
	0b00000000

Added to font6x8.cpp file:

	// 128 Extended ascii char 219
    	// needed for matrix effect
	0b11111000,
	0b11111000,
	0b11111000,
	0b11111000,
	0b11111000,
	0b11111000,
	0b11111000,
	0b00000000

Added to keywords.txt file:

set_font	KEYWORD2
get_font_x	KEYWORD2
get_font_y  	KEYWORD2

Added to TVout.h file: In the printing functions section:

    uint8_t get_cursor_x(void);
    uint8_t get_cursor_y(void);
    void set_font(int);
    int get_font_x(void);
    int get_font_y(void);

In the private section:

	uint8_t cursor_x,cursor_y,font_int_x,font_int_y; 

Added to TVoutPrint.cpp file:

// Using set_font will set both the "font" variable that is set in select_font,
// and font_int variable that is later used in print centered functions.
void TVout::set_font(int f)
{
    font_int_x = f;
    
    switch (f) {
        case 4:
            font = font4x6;
            font_int_y = 6;
            break;
        case 6:
            font = font6x8;
            font_int_y = 8;
            break;
        case 8:
            font = font8x8;
            font_int_y = 8;
            break;
            
        default:
            break;
    }
}
int TVout::get_font_x()
{
    return font_int_x;
}
int TVout::get_font_y()
{
    return font_int_y;
}


uint8_t TVout::get_cursor_x(void)
{
    return cursor_x;
}

uint8_t TVout::get_cursor_y(void)
{
    return cursor_y;
}