 |
These forums are now closed Please see the new forums
|
| View previous topic :: View next topic |
| Author |
Message |
devo
Joined: 11 Jan 2007 Posts: 31 Location: Omaha, NE
|
Posted: Mar Wed 07, 2007 8:09 am Post subject: Homemade ASCII Keyboard |
|
|
The bare (almost) PCB:
Programming the Replica I SE in BASIC:

Last edited by devo on Mar Wed 07, 2007 8:44 am; edited 3 times in total |
|
| Back to top |
|
 |
devo
Joined: 11 Jan 2007 Posts: 31 Location: Omaha, NE
|
Posted: Mar Wed 07, 2007 8:14 am Post subject: |
|
|
Description:
- 52 regular keys
- 4 special keys (ctl, reset, shift, caps lock)
- key autorepeat
- LED power and caps lock indicators
- ctl + reset sends a reset to the keyboard controller and the keyboard connector
When the snow melts and I can get to my table saw, maybe I'll see about making a proper case...
Last edited by devo on Mar Wed 07, 2007 8:58 am; edited 2 times in total |
|
| Back to top |
|
 |
devo
Joined: 11 Jan 2007 Posts: 31 Location: Omaha, NE
|
Posted: Mar Wed 07, 2007 8:18 am Post subject: |
|
|
Here's the microcontroller code. Sorry about the uneven spacing, phpBB seems to do strange things with tabs. The clock fuses on the 8515 are set for a high-frequency external crystal and long start-up time (CKSEL=1111,SUT=11).
| Code: |
; Summary: ASCII keyboard interface
; Target hardware: ATMEGA8515
; Author: John Calhoun, modified for homemade keyboard, caps lock and autorepeat by Devin Nickol
; Date: 2/22/07
; AVR ports used:
; PORT A: Input from keyboard the 8 columns (Col 0 - Col 7)
; PORT B: Output to the 8 keyboard rows (in this order: 0,2,4,6,1,3,5,7)
; PORT C: Input from the control (Col 8), shift (Col 9) keys and the caps lock (Pin C0)
; and output to the caps lock LED (Pin C1)
; PORT D: Output of the 7-bit ASCII keycode & 1-bit strobe
; Description: Each row is brought low in turn, and the columns are scanned for
; a keypress. If a key is down, the control and shift keys are
; also checked and the appropriate offset is added to the keycode.
; The row and column of the pressed key are used to extract its
; ASCII value from a table, and this value (plus a 40 ms strobe
; signal) is sent to the outputs.
; Limitations: Correct strobe timing requires running at 8 mHz.
;*** Included files ***
.include "8515def.inc" ; definitions file for ATMEGA8515
;*** Definition ***
.def temp = R16 ; scratch variable
.def temp2 = R17 ; scratch variable
.def row = R18 ; current row
.def keycode = R19 ; row/column value for a key
.def ASCII = R20 ; ASCII code for a key
.def lastkey = R21 ; previous key pressed
.def repeating = R22 ; autorepeating flag
.def repeattimer = R23 ; autorepeat loop counter
.def repeattimer2 = R24 ; second autorepeat loop counter
.def capslock = R25
.org 0x0000 ; place the program at the beginning of memory
;*** Program entry point ***
rjmp Reset ; jump to Reset
;*** Reset ***
; configure stack pointer, hardware ports and registers
Reset:
ldi temp, high(RAMEND)
out SPH, temp
ldi temp, low(RAMEND) ; set up stack pointer so we can return from rcalls
out SPL, temp
ldi temp,0x00 ; configure port A pins as inputs from keyboard columns
out DDRA,temp
ldi temp,0xFF
out PORTA,temp ; enable pull-up resistors on port A inputs
ldi temp,0xFF ; configure port B pins as outputs to keyboard rows
out DDRB,temp
ldi temp, 0x40 ; configure port C pins for inputs and outputs
out DDRC,temp
ldi temp, 0xBF
out PORTC,temp ; enable pull-up resistors on port C inputs
ldi temp,0xFF ; configure port D pins as outputs for ASCII code
out DDRD,temp ; and strobe
clr repeating ; make sure caps lock is off and autorepeat counters are zeroed
clr repeattimer
clr repeattimer2
clr capslock
; *** Loop ***
; main program loop
Loop:
rcall Scan_keyboard ; scan for keypress and store result in keycode
cpi keycode,0xFF ; is keycode = 0xFF? if so, no key was pressed
breq store_lastkey ; if no key pressed save 0xFF in lastkey and scan again
cp lastkey,keycode ; same key pressed as last time?
breq autorepeat ; if so, handle autorepeat
clr repeattimer ; if not, clear the repeattimer
clr repeattimer2 ; and repeattimer2
clr repeating ; and the repeat flag
cpi keycode,0xFE ; is it the caps lock?
breq capslock_down ; if so, handle it
repeat_key: ; loop re-entry point when autorepeating
rcall Get_ASCII ; we have a new key so get its ASCII code
cpi capslock,0x01 ; is the caps lock down?
brne output_key ; if not, output the key
sbis PINC,0x01 ; is the shift key down?
rjmp both_down ; if so, see if we need to uncapitalize
cpi ASCII,0x61 ; do we need to worry about the caps lock?
brlt output_key ; not if ASCII < 'a'
cpi ASCII,0x7B
brge output_key ; and not if ASCII > 'z'
ldi temp, 0x20
sub ASCII,temp ; otherwise capitalize the letter
rjmp output_key
both_down:
cpi ASCII,0x41 ; do we need to uncapitalize?
brlt output_key ; not if ASCII < 'A'
cpi ASCII,0x5B
brge output_key ; and not if ASCII > 'Z'
ldi temp,0x20
add ASCII,temp ; otherwise, make the letter lowercase
rjmp output_key
output_key:
ldi temp,0x80 ; 10000000 = strobe bit
add ASCII,temp ; add the strobe bit to the ASCII code
out PORTD,ASCII ; output the ASCII keycode and the strobe
ldi temp, 0x27 ; 40ms delay at 80 mHz
rcall Strobe_delay ; hold strobe 40 milliseconds
ldi temp, 0x80 ; reload the strobe bit into temp
sub ASCII, temp ; remove the strobe bit from the ASCII code
out PORTD,ASCII ; output the ASCII code without the strobe
store_lastkey:
mov lastkey,keycode ; save the keypad scan results
rjmp Loop ; scan again
autorepeat:
cpi keycode,0xFE ; is it the caps lock?
breq Loop ; if so, ignore it
cpi repeating,0x01 ; are we already autorepeating?
breq repeat_delay ; if so, jump down to the repeat delay
inc repeattimer ; if not, increment the counter
cpi repeattimer, 0xFF ; ready to increment repeattimer2?
brne Loop ; if not, jump back to the start of the loop
inc repeattimer2 ; if so, do it
cpi repeattimer2, 0x80 ; ready to trigger autorepeating?
brne Loop ; if not, jump back to the start of the loop
ldi repeating,0x01 ; if so, set the repeating flag
repeat_delay:
ldi temp, 0xFF ; autorepeat delay
rcall Strobe_delay ; re-use the strobe delay loop :)
ldi temp, 0xFF ; two times through seems about right
rcall Strobe_delay
rjmp repeat_key ; output the key with autorepeat
capslock_down:
mov lastkey,keycode ; store it
cpi capslock,0x01 ; was it already down?
breq clear_capslock ; if so, turn it off
ldi capslock,0x01 ; if not, turn it on
ldi temp, 0xFF ; and turn on the LED
out PORTC,temp
rjmp Loop ; go back to the top of the loop
clear_capslock:
clr capslock ; turn it off
ldi temp, 0xBF ; and turn off the LED
out PORTC,temp
rjmp Loop ; go back to the top of the loop
; *** Scan_keyboard ***
; scan each keyboard row and column for a keypress and store the result in keycode
Scan_keyboard:
ldi row,0x00 ; start with R0
ldi keycode,0xFF ; assume no keypress until proven otherwise
ldi temp2,0xFE ; get ready to output 11111110 on PORTB to check R0
scan_next_row:
out PORTB,temp2 ; bring the current row low on PORTB
ldi temp,0x14 ; give it time to get low
short_wait:
dec temp
brne short_wait
; one row has been brought low, so hunt for a low column input
sbis PINA,0x00 ; skip if column 0 is high
ldi keycode,0x00 ; if column 0 is low, store 0 in keycode
sbis PINA,0x01 ; skip if column 1 is high
ldi keycode,0x01 ; if column 1 is low, store 1 in keycode
sbis PINA,0x02 ; skip if column 2 is high
ldi keycode,0x02 ; if column 2 is low, store 2 in keycode
sbis PINA,0x03 ; skip if column 3 is high
ldi keycode,0x03 ; if column 3 is low, store 3 in keycode
sbis PINA, 0x04 ; skip if column 4 is high
ldi keycode,0x04 ; if column 4 is low, store 4 in keycode
sbis PINA, 0x05 ; skip if column 5 is high
ldi keycode,0x05 ; if column 5 is low, store 5 in keycode
sbis PINA, 0x06 ; skip if column 6 is high
ldi keycode,0x06 ; if column 6 is low, store 6 in keycode
sbis PINA, 0x07 ; skip if column 7 is high
ldi keycode,0x07 ; if column 7 is low, store 7 in keycode
sbis PINC, 0x07 ; skip if caps lock is not down
ldi keycode,0xFE ; if caps lock is down, store 0xFE in keycode
cpi keycode, 0xFE ; did we get a caps lock press?
breq scan_done ; if so, we're done scanning
cpi keycode,0xFF ; was one of the columns low?
brne got_key ; if so, handle it
; if no column was low, bring the next row low and scan the columns again
inc row ; get ready for the next row
cpi row,0x08 ; have we scanned all 8 rows yet?
breq scan_done ; if so, we're done
rol temp2 ; if not, rotate the low output bit to the next row
rjmp scan_next_row
got_key:
sbis PINC, 0x00 ; is the control key down?
rjmp control_down ; if so, handle it (and ignore shift)
sbis PINC,0x01 ; is the shift key down?
rjmp shift_down ; if so, handle it
rjmp modifiers_done ; done checking modifier keys
shift_down:
ldi temp,0x40 ; ASCII table offset for the shift key
add keycode,temp ; add the shift offset to the keycode
rjmp modifiers_done ; done checking modifier keys
control_down:
ldi temp, 0x80 ; ASCII table offset for the ctl key
add keycode, temp ; add the ctl offset to the keycode
modifiers_done:
cpi row,0x00 ; was the key in R0?
breq scan_done ; if so, we don't need to add anything more to the code
ldi temp,0x08 ; otherwise, we add 8 for each row
add_row_offset:
add keycode,temp ; add 8 for each row
dec row
cpi row,0x00
brne add_row_offset
rjmp scan_done
scan_done:
ret
; *** Strobe_delay ***
Strobe_delay:
ldi temp2, 0xFF ; perform a 40 ms loop at 8 mHz
delay_loop:
dec temp2
cpi temp2, 0x00
brne delay_loop
dec temp
cpi temp, 0x00
brne Strobe_delay
ret
;*** Get_ASCII ***
; translate the row/col code in keycode into an ASCII code and store in ASCII
Get_ASCII:
ldi ZH,high(2 * ASCII_table)
ldi ZL,low(2 * ASCII_table)
add ZL,keycode ; increase the table address based on keycode
brcc got_ascii ; if we didn't overflow the low byte, we're done
inc ZH ; if we did, increment the high byte
got_ascii:
lpm ; move the byte in the Z register into R0
mov ASCII,R0 ; copy R0 into ASCII
ret
; *** ASCII_table ***
; contains the ASCII codes for the keys on the keyboard
ASCII_table:
.db 0x1B, '`', '1', '2', '3', '4', '5', '6'
.db 0x09, 'q', 'w', 'e', 'r', 't', 'y', 0x00
.db 'a', 's', 'd', 'f', 'g', 'h', 0x00, 0x00
.db 'z', 'x', 'c', 'v', 'b', 'n', 0x00, 0x00
.db '7', '8', '9', '0', '-', '=', 0x08, 0x00
.db 'u', 'i', 'o', 'p', '[', ']', 0x5C, 0x00
.db 'j', 'k', 'l', ';', 0x27, 0x0D, 0x00, 0x00
.db 'm', ',', '.', '/', 0x20, 0x00, 0x00, 0x00
; beginning of shifted data:
.db 0x1B, '~', '!', '@', '#', '$', '%', '^'
.db 0x09, 'Q', 'W', 'E', 'R', 'T', 'Y', 0x00
.db 'A', 'S', 'D', 'F', 'G', 'H', 0x00, 0x00
.db 'Z', 'X', 'C', 'V', 'B', 'N', 0x00, 0x00
.db '&', '*', '(', ')', '_', '+', 0x08, 0x00
.db 'U', 'I', 'O', 'P', '{', '}', '|', 0x00
.db 'J', 'K', 'L', ':', 0x22, 0x0D, 0x00, 0x00
.db 'M', '<', '>', '?', 0x20, 0x00, 0x00, 0x00
; beginning of ctl key data:
.db 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E
.db 0x09, 0x11, 0x17, 0x05, 0x12, 0x14, 0x19, 0x00
.db 0x01, 0x13, 0x04, 0x06, 0x07, 0x08, 0x00, 0x00
.db 0x1A, 0x18, 0x03, 0x16, 0x02, 0x0E, 0x00, 0x00
.db 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x08, 0x00
.db 0x15, 0x09, 0x0F, 0x10, 0x1B, 0x1D, 0x1C, 0x00
.db 0x0A, 0x0B, 0x0C, 0x00, 0x00, 0x0D, 0x00, 0x00
.db 0x0D, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00
|
Last edited by devo on Mar Wed 07, 2007 9:41 am; edited 3 times in total |
|
| Back to top |
|
 |
devo
Joined: 11 Jan 2007 Posts: 31 Location: Omaha, NE
|
Posted: Mar Wed 07, 2007 8:26 am Post subject: |
|
|
Schematic:
The actual schematic file is here (requires ExpressPCB software).
PCB layout:
PCB layout file is here (requires ExpressPCB software).
Last edited by devo on Mar Wed 07, 2007 10:49 am; edited 1 time in total |
|
| Back to top |
|
 |
devo
Joined: 11 Jan 2007 Posts: 31 Location: Omaha, NE
|
Posted: Mar Wed 07, 2007 8:52 am Post subject: |
|
|
Parts list:
1 x ATMEGA8515 (Digikey: ATMEGA8515-16PU-ND)
1 x 40 pin DIP socket (Digikey: ED3740-ND)
1 x 16 pin DIP socket (Digikey: ED3116-ND)
1 x 8 MHz crystal (Digikey: 631-1099-ND)
2 x 15 pF caps (Digikey: 1427PH-ND)
59 x keyswitches (Digikey: CH160-ND)
59 x keycaps (Digikey: CH696-ND)
51 x clear key covers (Digikey: CH695-ND)
2 x 1k resistors (Jameco: 29664)
2 x LEDs (Jameco: 34761)
2 x 16 pin ribbon cable connectors (Jameco: 42673)
Ribbon cable (Jameco: 37671)
Scavenged backspace, tab, enter, caps lock, left shift, right shift and space bar key caps of appropriate size to be cemented onto the Digikey keycaps.
I did some trimming of the Digikey caps to make them fit nicely into the bottom of the reclaimed caps and used "LocTite Household Cement" to attach them. I tried some fancy epoxy, but the cement seemed to work better and was much more pleasant to use.
Last edited by devo on Mar Wed 07, 2007 9:23 am; edited 1 time in total |
|
| Back to top |
|
 |
devo
Joined: 11 Jan 2007 Posts: 31 Location: Omaha, NE
|
Posted: Mar Wed 07, 2007 9:11 am Post subject: |
|
|
| One interesting phenomenon I've noticed - if I forget to put caps lock on and type lowercase letters to the Replica I SE, the letters show up on the screen as uppercase, but they are ignored by the monitor. It's interesting that they get displayed as upper case but not parsed as upper case. |
|
| Back to top |
|
 |
fsafstrom

Joined: 26 Dec 2006 Posts: 155 Location: San Antonio, Texas
|
Posted: Mar Wed 07, 2007 11:45 am Post subject: |
|
|
How cool...
Great work... |
|
| Back to top |
|
 |
cheese1113
Joined: 13 Nov 2005 Posts: 91 Location: Reedley, CA
|
Posted: Mar Wed 07, 2007 1:50 pm Post subject: |
|
|
Good job, looks awesome! _________________ Max Wooden |
|
| Back to top |
|
 |
vbriel Site Admin
Joined: 19 Jul 2005 Posts: 723 Location: Ohio
|
Posted: Mar Wed 07, 2007 5:02 pm Post subject: |
|
|
| devo wrote: | | One interesting phenomenon I've noticed - if I forget to put caps lock on and type lowercase letters to the Replica I SE, the letters show up on the screen as uppercase, but they are ignored by the monitor. It's interesting that they get displayed as upper case but not parsed as upper case. |
Yeah, if you look at a character set from the 2513 character generator, there is no lower case character, upper case is repeated. I simulated the same thing with the replica 1 video. So, the replica 1 will actually see them as lower case but they are illegal characters to a certain degree.
For example:
I can go into BASIC and type
10 print "hello"
The lower case is showing that caps lock is off
The result is an error because BASIC doesn't understand lower case letters. But if you type it in like this:
10 PRINT "hello" (turn caps lock off while typing hello)
This will work! If the replica 1 firmware was programmed with lower case characters you would get lower case in the quotes. There may be a replica or two out there with lower case and they don't even know it because I accidently added lower case on production firmware versions.
Long story, sorry.
Great work on the keyboard! I like how you use IIe keys when you couldn't locate the key you wanted (tab, space bar, etc)
Cheers,
Vince |
|
| Back to top |
|
 |
devo
Joined: 11 Jan 2007 Posts: 31 Location: Omaha, NE
|
Posted: Mar Wed 07, 2007 7:27 pm Post subject: |
|
|
Aha...thanks for the explanation, Vince. I was hoping it was something like that, and not a keyboard malfunction!
On an unrelated note, I've really gotten to appreciate the capabilities of the ATMEGA8515...is there anything it can't do? Seems like you could make an 8-bit computer using one as a PIA, one as a CPU, one as a video interface and one to generate video signals...
EDIT: Ok, maybe that wouldn't work so well since you would have a hard time getting to the registers from the outside fast enough to work as a PIA. And the 64k of external memory is for data only, not program, so I guess it wouldn't make a very good CPU either. Too bad! |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|