Using a Max7219 8×8 LED Matrix with an ATTINY85, like Trinket or DigiSpark

While waiting for part two of the handheld construction article, I thought I’d give you a little distraction about interfacing an ATTINY85 to an 8×8 LED Matrix using the Max7219 chip.

ATTINY85LEDMatrix1Been working on getting either a DigiSpark or Trinket to work with one of my 8×8 LED matrix displays. Connection is simple, but the maxmatrix library doesn’t seem to like the ATTINY85 processor. So, I went looking for something that did or, at least, getting enough knowledge to bit bang my way to displaying SOMETHING on the little display. Well, I found some code to do this, but it is not very pretty and doesn’t do enough. However, it does give a good demo of how to make these arrays do something and, even better, work with the confines of the ATTINY85 processor.
The code shows how turn on and off pixels (a specific LED in the matrix, to be more precise) and send a ‘bitmap’ to the display.
Cool stuff. Could be another game or, perhaps, a temperature display, mood indicator, etc.

You can grab the code I used (middle of the page) here…http://www.avrfreaks.net/…/max7219-8×8-dot-matrix-led-drive…

FYI-To connect it:
PB0 -> DIN
PB1 -> CS
PB2 -> CLK
+5 -> VCC
GND -> GND

Pretty easy. ATTINY85LEDMatrix21

The code I found puts a smiley face, inverts the screen, frowny face, etc. up on the display. I took out the inversion as it takes too much time.  This code, which is unattributed as the poster on the AVR forum did not credit the code, is a good start, but needs work.  I thought about modifying it to handle ASCII text, but that will be a ways off yet. I have several things to finish up before then. 

I’d love to see what you can do with this, so drop us a note in the comments or send me an email and I’d be happy to write it up and post it here.

Code:

/*
  One MAX7219 connected to an 8x8 LED matrix.
 */

#include <avr/io.h>
#include <util/delay.h>

#define CLK_HIGH()  PORTB |= (1<<PB2)
#define CLK_LOW()   PORTB &= ~(1<<PB2)
#define CS_HIGH()   PORTB |= (1<<PB1)
#define CS_LOW()    PORTB &= ~(1<<PB1)
#define DATA_HIGH() PORTB |= (1<<PB0)
#define DATA_LOW()  PORTB &= ~(1<<PB0)
#define INIT_PORT() DDRB |= (1<<PB0) | (1<<PB1) | (1<<PB2)

uint8_t smile[8] = {
        0b00000000,
        0b01100110,
        0b01100110,
        0b00011000,
        0b00011000,
        0b10000001,
        0b01000010,
        0b00111100};

uint8_t sad[8] = {
        0b00000000,
        0b01100110,
        0b01100110,
        0b00011000,
        0b00011000,
        0b00000000,
        0b00111100,
        0b01000010,
};


void spi_send(uint8_t data)
{
    uint8_t i;

    for (i = 0; i < 8; i++, data <<= 1)
    {
  CLK_LOW();
  if (data & 0x80)
      DATA_HIGH();
  else
      DATA_LOW();
  CLK_HIGH();
    }
    
}

void max7219_writec(uint8_t high_byte, uint8_t low_byte)
{
    CS_LOW();
    spi_send(high_byte);
    spi_send(low_byte);
    CS_HIGH();
}

void max7219_clear(void)
{
    uint8_t i;
    for (i = 0; i < 8; i++)
    {
  max7219_writec(i+1, 0);
    }
}

void max7219_init(void)
{
    INIT_PORT();
    // Decode mode: none
    max7219_writec(0x09, 0);
    // Intensity: 3 (0-15)
    max7219_writec(0x0A, 1);
    // Scan limit: All "digits" (rows) on
    max7219_writec(0x0B, 7);
    // Shutdown register: Display on
    max7219_writec(0x0C, 1);
    // Display test: off
    max7219_writec(0x0F, 0);
    max7219_clear();
}


uint8_t display[8];

void update_display(void)
{
    uint8_t i;

    for (i = 0; i < 8; i++)
    {
  max7219_writec(i+1, display[i]);
    }
}

void image(uint8_t im[8])
{
    uint8_t i;

    for (i = 0; i < 8; i++)
  display[i] = im[i];
}

void set_pixel(uint8_t r, uint8_t c, uint8_t value)
{
    switch (value)
    {
    case 0: // Clear bit
  display[r] &= (uint8_t) ~(0x80 >> c);
  break;
    case 1: // Set bit
  display[r] |= (0x80 >> c);
  break;
    default: // XOR bit
  display[r] ^= (0x80 >> c);
  break;
    }
}


int main(void)
{
    uint8_t i;
    
    max7219_init();
    
    while(1)
    {
  image(sad);
  update_display();
  _delay_ms(500);
  image(smile);
  update_display();
  _delay_ms(500);

  // Invert display
//  for (i = 0 ; i < 8*8; i++)
//  {
//      set_pixel(i / 8, i % 8, 2);
//      update_display();
//      _delay_ms(10);
//  }
  _delay_ms(500);
    }
}

 

 

Advertisements

A Spark of Life: More DigiSpark fun

WP_20151019_22_42_59_Pro__highresI recently wrote about the cool little DigiSpark ATTiny 85 controller board. This little USB wonder, like the AdaFruit Trinket, is based on the ATTiny85 Microcontroller and has limited I/O, memory and is cheap, very cheap.

One thing it is not short on, however, is uses. This little thing can be used for a variety of things, including games and control applications.  For any use, though, you will need some kind of input and some kind of output.  In a previous post, I postulated about porting my ‘Battlestar Galactica’ game to the DigiSpark from the Trinket.  So, here are the results of that endeavor and some other things as well.

For the backstory of the game and why I wrote it, check out this post. I’ll wait.

Read it?  Cool.WP_20151019_22_44_34_Pro__highres

Ok, so there are few differences between the Trinket and the DigiSpark, other than size.  The way you program it is very similar and the pins are nearly identical.  The way you talk to things, is, however, a little different.

The Trinket needed SoftwareSerial. We don’t here, we just use DigitalRead and DigitalWrite and Serial.write to read the button and write to the screen.

The display is a 16×2 Serial LCD from Parallax.  The button is actually a ‘controller’ I built a couple of years ago for my game console. I did not use it for that, opting for the Wii Nunchuck instead.  So, the controller has three buttons that would be used for left, right and ‘fire’ or action.  Here, they just return a 0 if pressed and a 1 when ‘open’.  The code periodically polls the controller for a press and then acts on the press to evaluate a hit or miss.

WP_20151019_22_44_06_Pro__highres

Now, one of the problems I had was the lack of GROUND pins. So, I made a ground bus, a four pin strip with a wire connecting all four pins. I then connected this to ground on the DS and the button and the LCD as well are connected to this bus. I have one free ground pin.  Well, what I did not realize was that you can use any pin for ground.  While I did not change my connections, I find this pretty cool.

TIP! To use a free pin as ground:

(From the wiki)

You can use an I/O pin as a ground/+5V if you have some left and the current that flow in it is low (a few milliamps if you want the pin to stay around 0V/+5V. If you don’t care about the exact voltage you can go up to 40mA per pin according to the datasheet but it’s good to keep a safety margin).

Configure the pin as an output and set its value to either LOW or HIGH (for ground or +5V

#define button 0
#define gnd 2
 
void setup() {                
  pinMode (button, INPUT);
  digitalWrite (button, HIGH); // enable pullup
  pinMode(gnd, OUTPUT);
  digitalWrite (gnd, LOW); // use this pin as a ground
}

For much more information and tips, go to the wiki, located here.

The game code is below.

Come back for more on this cool little device.  Since it is capable of serial i/o, I’m thinking of using the Bluetooth Serial module and connecting the DS to one of my HalfByte Consoles running the graphical serial software for video display from the DS.

WP_20151019_22_45_35_Pro__highresWP_20151019_22_43_27_Pro__highres

Game Code:

#include <TinyPinChange.h>

 // globals
 int  cylonpos;
 int  oldcylonpos;
 int  cyDirection;
 int  button;
 int  posStart;
 int  lin2Start;
 int  bsgpos;
 
 // special characters
 int  bsg;
 int  cylon;
 
 // total number of torpedos the ship has left
 int  tShots=10;
 
 // the setup routine runs once when you press reset:
 void waitforbutton();
 void moveCylon();
 
 void setup() {  // initialize the digital pin as an output.  
   Serial.begin(9600); 
   Serial.write(12);
   Serial.write(17);
   
   //define the ship character
   Serial.write(249);
   Serial.write(0x4);
   Serial.write(0xE);
   Serial.write(0xE);
   Serial.write(0x15);
   Serial.write(0x1F);
   Serial.write(0x15);
   Serial.write(0xE);
   Serial.write(0xE);
   
   // baddies
   Serial.write(251);

   Serial.write(uint8_t(0x0));//to handle a goofy issue with '0'
   Serial.write(uint8_t(0x0));
   Serial.write(0xE);
   Serial.write(0x15);
   Serial.write(0x1F);
   Serial.write(uint8_t(0x0));
   Serial.write(uint8_t(0x0));
   Serial.write(uint8_t(0x0));
 
 // the button is on pin 0  
   pinMode(0,INPUT);
   
 // the initial direction is right
   cyDirection=1;
   
 } // the loop routine runs over and over again forever:
 void loop() {
  int score;
  score=0;
  
  Serial.write(12); // clear the screen and show the instructions
  Serial.println("Shoot the Cylon\n");
  Serial.println("press btn strt");
  
  // wait for the button
  waitforbutton();
  
  // define somethings before we start the game loop
  tShots=10;
  cylon=3;
  bsg=1;
  lin2Start=148; // the baddies appear on line 1
  posStart=128;  // the good guys on line 2
  randomSeed(analogRead(0)); // gen a random seed
  
  bsgpos = 8;  // our ship starts in the middle of the sector
  cylonpos=random(0,15); // baddies warp in at a random spot
  oldcylonpos=cylonpos;
  
  Serial.write(12);  // clear screen
  Serial.write(17);  // turn on backlight so we can see
  Serial.write(posStart + cylonpos);  // uh oh...the Cylon appeared!
 
  Serial.write(cylon);
  Serial.write(lin2Start+bsgpos);
  Serial.write(bsg); // and here we are
  
  // begin the game 
  while(1){
    /* Game loop */
    int button;
    Serial.write(22); // kill the cursor
    moveCylon();
    delay(200);
    button=digitalRead(0);  // check the button
    
    if(button==0){ // torpedo fired?
      if(cylonpos==bsgpos){ // Hit?
        Serial.write(132); // center 'Hit' on screen
        Serial.print("** HIT **");
        score ++;  // update score
        Serial.write(213); // noise (C at half note, 3rd scale)
        Serial.write(215); // play the note
        Serial.write(224);
        Serial.write(225);
        if(score==10){  // did we win?
           Serial.write(12); // clear screen
           Serial.write(128);// start at beginning
           Serial.print("You have saved\nthe Galactica.");
           delay(2000);
           loop();  // start game again
        }
        delay(3000); // did not win yet
        Serial.write(12); // clear screen
        Serial.write(lin2Start); // move cursor to beginning of line
        Serial.write("Score:");  // put up score
        Serial.print(score);
        Serial.write(lin2Start+bsgpos); // Since we shot the Cylon, we have to leave the sector, so...
        Serial.write(0x20); // go into hyperdrive and erase the BSG
        bsgpos=random(9,15);  // calculate new position
        Serial.write(lin2Start+bsgpos); //...and, we are here
        Serial.write(bsg);
        Serial.write(posStart+cylonpos);
        Serial.write(0x20);
        cylonpos=random(0,15); // Damn, they found us!
        oldcylonpos=cylonpos;
        moveCylon();
      } 
      
      tShots --; // decrement our torpedo inventory
      if(tShots<1){ // out of ammo?
        Serial.write(12);  // clear screen
        Serial.write(posStart); // start at beginning of line
        Serial.print("The Cylons win.\n");
        int count=1;
        // show animation of our ship exploding
        while (count<10){
          Serial.write(lin2Start+bsgpos);
          Serial.write(bsg);
          delay(500);
          Serial.write(lin2Start+bsgpos);
          Serial.write('*');
          delay(500);
          count++;
        }        
        loop(); // Play again
      }
    }  
  }
}
void moveCylon(){
  // sneaky Cylons...they show up anywhere!
  Serial.write(posStart+oldcylonpos);
  Serial.write(0x20);
  if (random(0,6)>3){
      //Cylon warped
      cylonpos=random(0,15);
      oldcylonpos=cylonpos;
  }
  
  cylonpos += cyDirection; // figure out which way to move
  if (cylonpos>15){
   cylonpos=15;
   cyDirection=-1;
  }
  
  if (cylonpos<0){
    cylonpos=0;
    cyDirection=1;
  }
  // erase from old spot
  Serial.write(posStart+oldcylonpos);
  Serial.write(0x20);
  Serial.write(posStart+cylonpos);
  Serial.write(cylon);
  oldcylonpos=cylonpos;
} 

void waitforbutton(){
   
  int button;
  button=digitalRead(0);
  while(button==1){     //wait for button press
    button=digitalRead(0);
    delay(1000);
  }  
  Serial.write(1);  
  delay(1000);
  Serial.write(12); 
}

Developing a handheld console with Arduino

IMG_3163Since my first exposure to computers and video games, I have wanted to design and build my own. Lacking, however, the resources and knowledge, I thought it would just be a pipedream. Well, fortunately for me, that is not the case.  The technology is to the point where just about anyone can do so and for just a little money and the internet.

Microcontrollers are the key and companies like SparkFun and AdaFruit can supply the bits. If you are really tight on funds or just cheap (like me) you can save a bit by shopping eBay. 

So, what can these microcontrollers do for you? Well, anything you want. And, yes, they can play games.

My original plan was to use something like AdaFruit’s Trinket for the brains and the Nokia 5110 LCD for the screen. Well, the Trinket is just too limited (and, frankly, difficult to program.)  During a lengthy eBay search, I found a bunch of Arduino UNO clones that fit in about the same space as the Trinket, only with more I/O and more memory. I ordered a few of them and then waited almost a month to get them. In the mean time, I used my UNO to start writing code.

IMG_3182Along the way, I discovered the Arduino’s were capable of video, so I spent a few weeks playing with that and have built a game console that I will revisit once my plate is clear. Adafruit and other vendors sell interfaces for the Wii Classic Controller and the Nunchuk…both of which are very easy to code.

Back to the handheld. The Trinket filled in, physically, for my board layout. When the Mini Pro finally arrived, I socketed it and began to wire it up. A strip for the 5110, connector for the speaker and daughter board for the audio amplifier. I wrote up a short demo that married the audio to the graphics library and produced a static Mario splash screen and beginning of the game.  It plays the Super Mario Brothers 2 theme upon startup.1398742_562906223779137_852686949_o

My next tasks include a controller (a matrix of four buttons: Left, Right, Shoot, Start/Stop) and a case. The actual game code will be last. I want the hardware nailed down before I do all of the code.

The system will run off of three 1.5 volt AA batteries. I wanted to use a rechargeable battery, but the added complexity is more than I want to deal with for now.

1425448_569760583093701_1031881671_oThe case is my biggest headache. I was going to use Lego’s, but the cost is more than I want to pay. I have an old Mattel JuiceBox that I will attempt to use. It looks big enough and already contains a battery compartment, holes for the controls and a speaker bay. It’s just really ugly.

I am also building version two of the handheld concurrently. This one will be for myself (the other is for my step son) so it doesn’t need to be as friendly and compact.  At some future point, I may take lessons learned from both and make a third version.  My version will also output video and has a PS/2 keyboard connector.  I have a version of Tiny Basic that will work with this hardware and this will be my portable computer and game console.1267690_572617716141321_1112089022_o

I have, so far, been pretty successful with my creations, even though I have a very rudimentary knowledge of electronics. I know what resistors and capacitors do and an understanding of transistors. More importantly, however, I can read a schematic and everything I’ve done has come from schematics found on the internet. In some cases, I’ve only borrowed parts of the schematic, in other cases, I used a basic schematic from a datasheet (talk about boring) and have put this stuff together on my own.  AdaFruit and SparkFun have terrific user forums and they have been a big help as well.  But, there is one site in particular: Arduino-Info. This site has code, schematics and really easy to understand explanation about each project. It covers basic things like LCD’s, keypad’s, servo motors and basic Arduino. It explains many electronics concepts and has lots of examples. It has been invaluable.

The Nokia 5110 LCD is a low cost and easy to code panel. It is low res, 84 pixels wide by 48 down. It is challenging (I have an even better appreciation for developers in the ‘70s and early ‘80s) to come up with graphics that look good in such low res. My Mario character looks more like Mega Man. It is a great choice, however, because it has a low memory footprint: 504 bytes for the frame buffer. This still gives about 1.4K to work with, a gold mine.  You can get them from AdaFruit or Sparkfun for under ten dollars or on eBay from $1.88 to about $3.00.

That brings me to parts buying. If you buy them on eBay, it will likely be from an overseas vendor.  I ordered parts from several Chinese vendors and, in all but one case, I got the items within two weeks and free shipping. I would highly recommend getting them from North American vendors. If you look, you can get pricing that is close to the Chinese vendors and still get free shipping. I got my Mega and one of my UNO’s from vendors located in North America. I had those items in just a few days, so it was worth the extra dollar or two.  I also buy from AdaFruit, SparkFun and Jameco. Some things, like the UNO and Mega, cost two to three times the eBay price. I paid ten bucks for the UNO clone and AdaFruit wants $23 and JameCo had one for nearly fifty. Radio Shack sells the UNO for $34.00. As for the Chinese vendors, I bought a bunch of small parts: joysticks, Mini Pro’s, keypads, LCD panels, sensors, etc.  The smallest order was $1.88 and the biggest was $16.  In all but one case, I got the parts in about two weeks, one took a month and one never arrived, but they did issue a rebate and an apology. I would buy from them again, That was the $1.88 order.

I will post more about my project at a later date

Follow Half-Byte on Facebook for more frequent updates on my projects and other tech news.

Coding for small platforms is nearly a lost art OR why I love tiny computers

There was a time when a computer with 4K of memory was something to behold. Indeed, 4K was enough for a BASIC interpreter AND have room left over for user programs. Most I/O was serial, so ALL of that space was for code. The ‘operating system’ was something called a ‘monitor’ or the BASIC itself. Either way, the I/O code was ‘built’ into either the BASIC or the monitor. And, if you had a video terminal, well, you were THE stuff.

Just a few years later, that 4K grew to 16K then 64K and, suddenly, we are talking MEGAbytes. Wow. Well, funny thing happened, code went from small, tight and mostly efficient to BIG, heavy and bloated.  Code in that 4K system that put a character on the screen took, maybe six bytes suddenly took a DLL, which was probably ten times that or more.  Programmers got complacent, including this one.

I recall one job I had, I was maybe 17, that required me to write an accounting screen for a paging system (remember the pocket pager?) I had 2k for the data entry screen AND the billing code. Plus, the datastream to/from the paging system was like 32 bytes.  In that 32 bytes, I had to squeeze in the client number (10 digits), number of pages, and about two dozen status bits and more. I did it. The software went into a dozen or ‘head end’ systems (hey, it was a SMALL market) but it was my first ‘professional’ gig.

My career took me down the Microsoft/Lotus path. I had all kinds of wonders to code with, Visual Studio, Visual Basic, Lotus Notes, web.  My code, while functional and often clever, was sloppy. I forgot what it was to REALLY code.

Well, I had a shot a programming for the Palm Pilot, which reminded me of my old days, but it didn’t last long and I was back to programming for machines with memory measured in the gigabytes.

Imagine my delight when I discovered the world of Microcontrollers.  These things have big capability, but tiny (and I mean tiny) memory spaces. My current microcontroller project, the Adafruit Trinket, based on the ATMel ATtiny85, has 5,2k of available programming memory and 512 BYTES of RAM (as well as 512 bytes of EEPROM.)

Having found some cool 2×16 LCD panels for five bucks each at Radio Shack, these Trinkets and a bunch of parts, I set out to make a game for my step son.  I’m still working on a game concept that will keep his interest, but I did a proof of concept game based on Space Invaders (my all time favorite game.) So, how can one make a Space Invaders on a TWO line by SIXTEEN character display? Well…you need to be creative. AND…you have to fit it, along with a necessary library, into under 5.1K.

So…what did I do? Well, found an old notebook I kept from my TRS-80 days. Looked at some old Tiny Basic game code and…coded.

BSG001First, I needed an idea. The display I am using, from Parallax, allows for eight special characters.  So, I played around with a few designs and one of them looked like the Battlestar Galactica. After some thought, I had the idea: The Galactica’s Viper squadrons are out on patrol. The Galactica was in a fierce battle that has rendered it nearly immovable, it can only hyperjump. It’s turrets are all damaged, save the forward bank, she can only shoot from her forward cannons.  A Cylon has discovered the Galactica and is taking runs at it.  Problem is, the Cylon is jumping randomly, making a direct hit nearly impossible.  If, however, the Galactica does manage to destroy the Cylon, the Galactica then hyperjumps too.  Then, it all happens again.

Cool, huh?IMG_2758

So, I set out to code it. I put code together to read a switch, move a character back and forth and come up with an interrupt mechanism for the button.

Turns out, it was simpler than I thought.  I had some hiccups with the Arduino IDE (which involved upgrading the toolchain, upgrading part of it again, some choice words…) but got them ironed out and, now, the Colonials are fighting the nasty Cylons again.

First, the source code:

#include <SoftwareSerial.h>

SoftwareSerial s(0,2);
 
// globals
int  cylonpos;
int  oldcylonpos;
int  cyDirection;
int  button;
int  posStart;
int  lin2Start;
int  bsgpos;
// special characters
int  bsg;
int  cylon;
 
// the setup routine runs once when you press reset:
void waitforbutton();
void moveCylon();
 
void setup() {  // initialize the digital pin as an output. 
   s.begin(9600);
   s.write(12);
   s.write(17);
   //define the character
   s.write(249);
   s.write(0x4);
   s.write(0xE);
   s.write(0xE);
   s.write(0x15);
   s.write(0x1F);
   s.write(0x15);
   s.write(0xE);
   s.write(0xE);
  
   // baddies
   s.write(251);

   s.write(uint8_t(0x0));//to handle a goofy issue with ‘0’
   s.write(uint8_t(0x0));
   s.write(0xE);
   s.write(0x15);
   s.write(0x1F);
   s.write(uint8_t(0x0));
   s.write(uint8_t(0x0));
   s.write(uint8_t(0x0));
  
   pinMode(0,INPUT);
   cyDirection=1;
  
} // the loop routine runs over and over again forever:
void loop() {
  int score;
  score=0;
 
  s.write(12);
  s.println("Shoot the Cylon\n");
  s.println("press btn 2 strt");
 
  waitforbutton();
 
  cylon=3;
  bsg=1;
  lin2Start=148;
  posStart=128;
  randomSeed(analogRead(0)); // gen a random seed
 
  bsgpos = 8;
  cylonpos=random(0,15);
  oldcylonpos=cylonpos;
 
  s.write(12);
  s.write(17);
  s.write(posStart + cylonpos);
 
  s.write(cylon);
  s.write(lin2Start+bsgpos);
  s.write(bsg);
 
  while(1){
    /* Game loop */
    int button;
    s.write(22); // kill the cursor
    moveCylon();
    delay(200);
    button=digitalRead(0);
    if(button==HIGH){
      if(cylonpos==bsgpos){
        s.write(132); // center ‘Hit’ on screen
        s.print("** HIT **");
        score ++;  // update score
        delay(3000);
        s.write(12); // clear screen
        s.write(lin2Start); // move cursor to beginning of line
        s.write("Score:");  // put up score
        s.print(score);
        s.write(lin2Start+bsgpos); // Since we shot the Cylon, we have to leave the sector, so…
        s.write(0x20); // go into hyperdrive and erase the BSG
        bsgpos=random(9,15);  // calculate new position
        s.write(lin2Start+bsgpos); //…and, we are here
        s.write(bsg);
        s.write(posStart+cylonpos);
        s.write(0x20);
        cylonpos=random(0,15); // Damn, they found us!
        oldcylonpos=cylonpos;
        moveCylon();
      }
    } 
  }
}
void moveCylon(){
  // sneaky Cylons…they show up anywhere!
  s.write(posStart+oldcylonpos);
  s.write(0x20);
  if (random(0,6)>3){
      //Cylon warped
      cylonpos=random(0,15);
      oldcylonpos=cylonpos;
  }
 
  cylonpos += cyDirection; // figure out which way to move
  if (cylonpos>15){
   cylonpos=15;
   cyDirection=-1;
  }
 
  if (cylonpos<0){
    cylonpos=0;
    cyDirection=1;
  }
  // erase from old spot
  s.write(posStart+oldcylonpos);
  s.write(0x20);
  s.write(posStart+cylonpos);
  s.write(cylon);
  oldcylonpos=cylonpos;
}

void waitforbutton(){
  SoftwareSerial s(0,1);
 
  int button;
  button=digitalRead(0);
  while(button==LOW){
    button=digitalRead(0);
    delay(1);
  } 
  s.write(1); 
  delay(1000);
  s.write(12);
}

SInce the Trinket is limited, I/O wise, I have only five pins, two of which are shared with the USB programmer and one is shared with the red programming LED, it really limits what you can add. At least, for those of us who are electronically challenged. I have my LCD on pin 2 and the switch on pin 0.  The LCD is controlled with a single line, it also has a five volt line (which goes to the USB power) and ground. The switch is connected to power and a 10k ohm resistor. It connects to pin 0. In the LOOP code, there is a While loop that handles the game logic. Inside the loop, it checks the pin for HIGH, which means the button was pressed. It then checks the position of the BSG and the Cylon. If there is a hit, it tells the user that they hit the Cylon and then increments the score, recalculates the positions and does it all again.  Simple, but kind of hard since the Cylon jumps so much.

While the game is not sophisticated, it does show what you can do in 5K of memory, a limited input mechanism and very limited display.  Now, about the game for my step son…