These forums are now closed Forum Index These forums are now closed
Please see the new forums
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Homemade ASCII Keyboard

 
Post new topic   Reply to topic    These forums are now closed Forum Index -> Creation Room
View previous topic :: View next topic  
Author Message
devo



Joined: 11 Jan 2007
Posts: 31
Location: Omaha, NE

PostPosted: Mar Wed 07, 2007 8:09 am    Post subject: Homemade ASCII Keyboard Reply with quote



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
View user's profile Send private message Visit poster's website
devo



Joined: 11 Jan 2007
Posts: 31
Location: Omaha, NE

PostPosted: Mar Wed 07, 2007 8:14 am    Post subject: Reply with quote

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
View user's profile Send private message Visit poster's website
devo



Joined: 11 Jan 2007
Posts: 31
Location: Omaha, NE

PostPosted: Mar Wed 07, 2007 8:18 am    Post subject: Reply with quote

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
View user's profile Send private message Visit poster's website
devo



Joined: 11 Jan 2007
Posts: 31
Location: Omaha, NE

PostPosted: Mar Wed 07, 2007 8:26 am    Post subject: Reply with quote

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
View user's profile Send private message Visit poster's website
devo



Joined: 11 Jan 2007
Posts: 31
Location: Omaha, NE

PostPosted: Mar Wed 07, 2007 8:52 am    Post subject: Reply with quote

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
View user's profile Send private message Visit poster's website
devo



Joined: 11 Jan 2007
Posts: 31
Location: Omaha, NE

PostPosted: Mar Wed 07, 2007 9:11 am    Post subject: Reply with quote

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
View user's profile Send private message Visit poster's website
fsafstrom



Joined: 26 Dec 2006
Posts: 155
Location: San Antonio, Texas

PostPosted: Mar Wed 07, 2007 11:45 am    Post subject: Reply with quote

How cool...

Great work...
Back to top
View user's profile Send private message
cheese1113



Joined: 13 Nov 2005
Posts: 91
Location: Reedley, CA

PostPosted: Mar Wed 07, 2007 1:50 pm    Post subject: Reply with quote

Good job, looks awesome!
_________________
Max Wooden
Back to top
View user's profile Send private message Send e-mail AIM Address Yahoo Messenger MSN Messenger
vbriel
Site Admin


Joined: 19 Jul 2005
Posts: 723
Location: Ohio

PostPosted: Mar Wed 07, 2007 5:02 pm    Post subject: Reply with quote

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
View user's profile Send private message Send e-mail
devo



Joined: 11 Jan 2007
Posts: 31
Location: Omaha, NE

PostPosted: Mar Wed 07, 2007 7:27 pm    Post subject: Reply with quote

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
View user's profile Send private message Visit poster's website
Display posts from previous:   
Post new topic   Reply to topic    These forums are now closed Forum Index -> Creation Room All times are GMT - 5 Hours
Page 1 of 1

 
Jump to:  
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