Tuesday, November 03, 2015

Go for C64 - Part II - The Arduino Leonardo solution

After trying to turn my C64  into a USB keyboard the whole project ended in a cupboard for a year at 90% completion. In the end the whole PICAXE - Arduino Pro Micro combination felt a bit clumsy.
Then I recently stumbled on a blogpost where someone connects a ZX81 keyboard to the Arduino Leonardo, and I found a cheap (€12,-) Leonardo-clone so I decided this was the way to go.

The board came with front headers, which makes connecting the keyboard super easy.
This is the C64 Keyboard matrix: ( diagram from the 'WaitingForFriday' blog)



Corrected C64 Keyboard matrix and keyboard connector diagrams
It is connected to the Arduino as follows:

A - D0
B - D1
C - D2
D - D3
E - D4
F - D5
G - D6
H - D7
0 - D8
1 - D9
2 - D10
3 - D11
4 - A0
5 - A1
6 - A2
7 - A3

The code can be a mix of the code from 'Biosrythm' and TechTonic . :

#include <Keyboard.h>

// ZX81 USB Keyboard for Leonardo
// (c) Dave Curran
// 2013-04-27

// Modified with Function keys by Tony Smith
// 2014-02-15
// Adapted for use with Commodore 64 Keyboard by Cees Meijer
// 2015-11-04
// Enable the debug mode (serial output) by keeping F7 pressed when 
// starting the program
// Special Commodore graphic characters are not implemented

#define NUM_ROWS 8
#define NUM_COLS 8

#define SHIFT_ROW 3
#define SHIFT_COL 1

#define RSHIFT_ROW 4
#define RSHIFT_COL 6

#define F7_ROW 7
#define F7_COL 7

#define DEBOUNCE_VALUE 100
#define REPEAT_DELAY 500

// Keymap for normal use

byte keyMap[NUM_ROWS][NUM_COLS] =
{
  {'1', '3', '5', '7', '9', '+', '$', KEY_BACKSPACE},
  {KEY_LEFT_ARROW, 'w', 'r', 'y', 'i', 'p', '*', KEY_RETURN},
  {'~', 'a', 'd', 'g', 'j', 'l', ';', KEY_LEFT_ARROW},
  {'~', 0  , 'x', 'v', 'n', ',', '/', KEY_UP_ARROW},
  {' ', 'z', 'c', 'b', 'm', '.', 0  , KEY_F1},
  {'~', 's', 'f', 'h', 'k',':', '=' , KEY_F3},
  {'q', 'e', 't', 'u', 'o', '@', KEY_UP_ARROW, KEY_F5},
  {'2', '4', '6', '8', '0', '-', '~', KEY_F7}
};

// Keymap if Shift is pressed

byte keyMapShifted[NUM_ROWS][NUM_COLS] =
{
  {'!', '#', '%', '\'', ')', '+', '$', KEY_BACKSPACE},
  {KEY_LEFT_ARROW, 'W', 'R', 'Y', 'I', 'P', '*', KEY_RETURN},
  {'~', 'A', 'D', 'G', 'J', 'L', ']', KEY_RIGHT_ARROW},
  {'~', 0  , 'X', 'V', 'N', '<', '?', KEY_DOWN_ARROW},
  {' ', 'Z', 'C', 'B', 'M', '>', 0  ,KEY_F2},
  {'~', 'S', 'F', 'H', 'K','[', '=', KEY_F4},
  {'Q', 'E', 'T', 'U', 'O', '@', KEY_UP_ARROW, KEY_F6},
  {'"', '$', '&', '(', '0', '-', '~', KEY_F8}
};
// Global Variables

int debounceCount[NUM_ROWS][NUM_COLS];
int altKeyFlag;
bool serial_output;

// Define the row and column pins

byte colPins[NUM_COLS] = {0,1,2 ,3 ,4 ,5 ,6 ,7}; // A,B,C,D,E,F,G,H
byte rowPins[NUM_ROWS] = {8,9,10,11,A0,A1,A2,A3};

// SETUP

void setup()
{
  // Set all pins as inputs and activate pull-ups
  serial_output = false;
  for (byte c = 0 ; c < NUM_COLS ; c++)
  {
    pinMode(colPins[c], INPUT);
    digitalWrite(colPins[c], HIGH);
    
    // Clear debounce counts
    
    for (byte r = 0 ; r < NUM_ROWS ; r++)
    {
      debounceCount[r][c] = 0;
    }
  }
  
  // Set all pins as inputs
  
  for (byte r = 0 ; r < NUM_ROWS ; r++)
  {
    pinMode(rowPins[r], INPUT);
  }
  
  // Function key is NOT pressed
  
  altKeyFlag = ALT_KEY_OFF;
  pinMode(rowPins[F7_ROW], OUTPUT);
  if (digitalRead(colPins[F7_COL]) == LOW) serial_output = true;
  // Initialise the keyboard
  if (serial_output )
   {
    Serial.begin(9600);
   }
   else
   {
    Keyboard.begin();  
   }
}

// LOOP

void loop()
{
  bool shifted = false;
  bool r_shifted = false;
  bool keyPressed = false;
  
  // Check for the Shift key being pressed
  
  pinMode(rowPins[SHIFT_ROW], OUTPUT);
  if (digitalRead(colPins[SHIFT_COL]) == LOW) shifted = true;
  
  pinMode(rowPins[RSHIFT_ROW], OUTPUT);
  if (digitalRead(colPins[RSHIFT_COL]) == LOW) shifted = true;
  
    pinMode(rowPins[SHIFT_ROW], INPUT);
    pinMode(rowPins[RSHIFT_ROW], INPUT);
    
    for (byte r = 0 ; r < NUM_ROWS ; r++)
    {
      // Run through the rows, turn them on
      
      pinMode(rowPins[r], OUTPUT);
      digitalWrite(rowPins[r], LOW);
      
      for (byte c = 0 ; c < NUM_COLS ; c++)
      { 
        if (digitalRead(colPins[c]) == LOW)
        {
          // Increase the debounce count
          
          debounceCount[r][c]++;
          
          // Has the switch been pressed continually for long enough?
          
          int count = debounceCount[r][c];
          if (count == DEBOUNCE_VALUE)
          {
            // First press
            
            keyPressed = true;
            pressKey(r, c, shifted);
          }
          else if (count > DEBOUNCE_VALUE)
          {
            // Check for repeats
            
            count -= DEBOUNCE_VALUE;
            if (count % REPEAT_DELAY == 0)
            {
              // Send repeat
              
              keyPressed = true;
              pressKey(r, c, shifted);
            }
          }
        }
        else
        {
          // Not pressed; reset debounce count
          
          debounceCount[r][c] = 0;
        }
      }
     
    // Turn the row back off
     
    pinMode(rowPins[r], INPUT);
    }
    digitalWrite(rowPins[RSHIFT_ROW], LOW);
    digitalWrite(rowPins[SHIFT_ROW], LOW);
  
}

void pressKey(byte r, byte c, bool shifted)
{  
  // Send the keypress
  if (serial_output) 
    { 
    Serial.print("|");Serial.print("\r\n");Serial.print("|"); 
    Serial.print(r);Serial.print(",");Serial.print(c);Serial.print(":");
    }
  byte key = shifted ? keyMapShifted[r][c] : keyMap[r][c];

  if (serial_output)
   {
   if (key > 0){ Serial.write(key);}
   }
   else
   {
   if (key > 0 ) Keyboard.write(key);
   }
  
}


Wednesday, May 06, 2015

The 'Makr-B-Bot' Part 1: Getting started

When the 3D-Printing hype started a few years ago with the RepRap and it's followers, I immediately considered building one. By that time however it was not really easy to collect the parts. People were building their own electronics, frames and extruders from scratch which included a lot of experimenting and tinkering to get it right. Round the same time I ran into a product called 'MakerBeam', an aluminium T-Slot profile for small constructions. This seemed like the right framework for a 3-D printer so I bought the starter kit. Bolted a few parts together and decided it would still be a lot of work to build a printer from this. So the kit ended up in a closet, and I have not used it since..
MakerBeam

In the following years the 3D printer market exploded, and at some point even got mainstream with little €1000,- plug and play printers you could buy at the supermarket. So I lost interest.  The idea of building one did stick at the back of my mind however. And over time I did collect some parts like a set of stepper motors, some extra Makerbeams and  some electronics.

Until recently I got inspired by pictures of the Printrbot Simple Maker kit . This amazingly simple design is probably the most minimalistic printer possible, yet it performs remarkably well for it's price, which is as low as US$350 for a complete kit. Now US$350,- is absolutely a good price for the full kit, but unfortunately that only works if you live in the USA. Once you get it to Europe the total price has become a whopping €550,- (= US$ 590,- !) which more or less defies the idea of a 'cheap DIY printer'. 

Since this is an 'open source' printer so it is possible to download the drawings and make the plywood parts yourself, but that would still be quite expensive for a single unit.
While looking for additional pictures of the PrintrBot design I also found the R360 Printer by Replicator warehouse :

This looks almost identical, but they chose a rotating bed to print on. That seemed a bit too experimental to me, although I understand it works pretty well. I do think it's a little bit too much plastic...

So I wondered if it would be possible to build this specific design using standard Makerbeam parts.

   
And I did not want to spend too much money on it so I spend quite some time to find the cheapest parts....

Parts.

  • Makerbeam starter kit.+ extra set of right angle brackets. ( €100 )
  • Acme rod (trapezoidal thread) with nut . ( €20 ). This one used to be hard to get, but nowadays most 3D printer shops sell the standard 30 cm version that is used in the RepRap Mendel  (MakeMendel,VanAllesEnMeer (Dutch) )
  • Flexible coupling 5 mm to 8 mm.n (€6,50) Any 3D printer shop has these in stock
  • 2 pcs Aluminium pully, T2.5 (€ 6,50)
  • 1 m. of T2.5 5mm Timing belt (€4,50)
  • 12 pcs.  LM8UU linear ball Bearings (€12,-) (€1,- / each is really good deal ! Kromhout Electronixs (Dutch))
  • 3 pcs. NEMA 17 stepper motors (€30,- (special package deal, might be hard to get them that cheap now..))
  • Funduino Mega 2560 R3 Module (Arduino Mega compatible board) (€15)
  • RAMPS 1.4 interface board (€18, including the Motor Drivers)
  • 4 pcs. 4988 Motor Driver (Polulu or compatible) 
  • Geeetech MK8 All Metal 3D Printer Extruder (DealExtreme) (€45)
  • AT Power supply (second hand, from an old PC)
  • Lots of Ty-Raps
  • 16 Hose clamps, 12-22 mm (€10)
  • 2 pcs. 1m. 8mm.  Steel Rod (€15)
  • Heated bed (€15)
  • 16x24 Photo frame (€1,50)
  • 12V/ 20 A Power Supply (€24,-)
Total: € 322,50
 (Actually a little less since not the whole MakerBeam kit is used)

Again, the US$350,- for the the PrintrBot Simple kit seems like a bargain. You probably have to buy all parts in really large quantities to get that low. Not to mention the US$179,- TIKO 3D , or the US$199 Genesis UNO  ..
And with the colourful DaVinci minimaker entering the local toy-shop, 3D printing definitely entered the realm of consumer goods.