

Last week I built an Apple I Replica from a Briel Computers kit. While I loved the completed machine, I suffered a bit from the fact that backspace doesn’t work (you have to type the assembly *exactly* correct), and of course it loses the RAM contents when shut down.
I wanted to make an interface to the PC so I could use a modern editor and simply copy-paste to the Apple I. As a quick and dirty solution to the problem, I used an Arduino, wired it to the ASCII keyboard port of the Apple I and wrote a small sketch that listens on the serial port and sets the data pins accordingly.
Photos on Flickr.
Here’s the Arduino sketch, real simple:
/*
ASCII keyboard
Lionel Lemarie
2010-02
Listens on the serial port for characters from a PC.
Outputs the codes like an ASCII keyboard.
Compatible with Apple I Replica.
*/
// The order of the pins is chosen for minimal wire crossing
// when connected to an ASCII keyboard socket.
int ASCII0 = 7;
int ASCII1 = 8;
int ASCII2 = 3;
int ASCII3 = 5;
int ASCII4 = 4;
int ASCII5 = 6;
int ASCII6 = 2;
int STROBE = 10;
int NRESET = 9; //reset active low
// LED will blink when a character is emitted
int LED = 13;
unsigned long previousMillis = 0;
unsigned long interval = 200;
void setup()
{
analogReference(EXTERNAL); // Is this needed?
// Initialize the digital pins as output
pinMode(ASCII0, OUTPUT);
pinMode(ASCII1, OUTPUT);
pinMode(ASCII2, OUTPUT);
pinMode(ASCII3, OUTPUT);
pinMode(ASCII4, OUTPUT);
pinMode(ASCII5, OUTPUT);
pinMode(ASCII6, OUTPUT);
pinMode(STROBE, OUTPUT);
pinMode(NRESET, OUTPUT);
pinMode(LED, OUTPUT);
digitalWrite(STROBE, LOW); // set the STROBE pin to inactive
digitalWrite(NRESET, HIGH); // set the RESET pin to inactive
Serial.begin(9600);
}
void loop()
{
unsigned long currentMillis = millis();
if (Serial.available() > 0)
{
int iInput = Serial.read();
iInput &= 127;
if (iInput)
{
if (iInput>='a' && iInput<='z')
iInput = iInput - 'a' + 'A';
int D6 = LOW;
int D5 = LOW;
int D4 = LOW;
int D3 = LOW;
int D2 = LOW;
int D1 = LOW;
int D0 = LOW;
if ( iInput & 64 ) D6 = HIGH;
if ( iInput & 32 ) D5 = HIGH;
if ( iInput & 16 ) D4 = HIGH;
if ( iInput & 8 ) D3 = HIGH;
if ( iInput & 4 ) D2 = HIGH;
if ( iInput & 2 ) D1 = HIGH;
if ( iInput & 1 ) D0 = HIGH;
digitalWrite(LED, HIGH);
previousMillis = currentMillis;
// Output an A (100 0001)
digitalWrite(ASCII6, D6);
digitalWrite(ASCII5, D5);
digitalWrite(ASCII4, D4);
digitalWrite(ASCII3, D3);
digitalWrite(ASCII2, D2);
digitalWrite(ASCII1, D1);
digitalWrite(ASCII0, D0);
digitalWrite(STROBE, HIGH);
delay(40); // strobe for 40ms
digitalWrite(STROBE, LOW);
}
}
if ( (previousMillis>0) && (currentMillis-previousMillis>interval) )
{
digitalWrite(LED, LOW);
previousMillis = 0;
}
}