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
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;
}