📄 interfacing the pc's keyboard.htm
字号:
<HR>
<P>Now it is time to look at the code. I cannot include a description of
all the code in this article. The list file is just on 19 pages. Most of
it (hopefully) is easy to follow. (Just like other good code, count the
number of spelling errors while you are at it!) </P>
<P>Remember the KBD Clock line? If you take it low, the keyboard will
buffer any keys pressed. The Keyboard will only attempt to send when
both the Data and Clock lines are idle (high). As it can take
considerable time to decode the keys pressed, we must stop the keyboard
from sending data. If not, some of the data may be lost or corrupted.
</P></FONT><PRE> Receive ldx #08 ;Number of Bits
clr PAR ;Clear Parity Register
bclr clk,DDRA ;Clear to Send
brset clk,PORTA,* ;wait on idle Clock
brset data,PORTA,Receive ;False Start Bit, Restart
</PRE><FONT face=ARIAL>
<P>The program, will keep the KBD Clock line low, unless it is ready to
accept data. We will use a loop to retrieve the data bits from the
keyboard, thus we will load index register X with the number of bits be
want to receive. PAR will be used to verify the parity bit at the end of
the transmission. We must clear this first. </P>
<P>We can then place the KBD Clock line in the idle state so that the
keyboard will start transmitting data if a key has been pressed. The
program then loops while the clock line is Idle. If the KBD clock goes
low, the loop is broken and the KBD Data pin is read. This should be the
start bit which should be low. If not we branch to the start of the
receive routine and try again. </P></FONT><PRE> Recdata ror byte
jsr highlow ;Wait for high to low Transition
brset data,PORTA,Recset
bclr 7,byte
jmp Recnext
Recset bset 7,byte
inc PAR
Recnext decx
bne Recdata ;Loop until 8 bits been received
</PRE><FONT face=ARIAL>
<P>Once the start bit has been detected, the 8 data bits must follow.
The data is only valid on the falling edge of the clock. The subroutine
highlow shown below will wait for the falling edge of the clock.
</P></FONT><PRE> highlow brclr clk,PORTA,* ;Loop until Clk High
brset clk,PORTA,* ;Loop until Clk Low
rts
</PRE><FONT face=ARIAL>
<P>After the falling edge we can read the level of the KBD Data line. If
it is high we can set the MSbit of the byte or if it is clear, we can
clear it. You will notice if the bit is set, we also increment PAR. This
keeps track of the number of 1's in the byte and thus can be used to
verify the Parity Bit. Index register X is decremented as we have read a
bit. It then repeats the above process, until the entire 8 bits have
been read. </P></FONT><PRE> lda PORTA ; MSb is Parity.
rola ; Shift MSbit to LSbit.
rola ; thru carry
eor PAR
and #$01
beq r_error
</PRE><FONT face=ARIAL>
<P>After the 8 data bits, comes the dreaded parity bit. We could ignore
it if we wanted to, but we may as well do something about it. We have
been keeping a tally of the number of 1's in PAR. The keyboard uses odd
parity, thus the parity bit should be the complement of the LSbit in
memory location, PAR. By exclusive OR-ing PAR with the Parity Bit, we
get a 1 if both the bits are different. I.e a '1' if the parity bit
checks out. </P>
<P>As we are only interested in the LSbit we can quite happy XOR the
accumulator with PAR. Then we single out the LSb using the AND function.
If the resultant is zero, then a parity error has occurred and the
program branches to r_error. </P></FONT><PRE> jsr highlow
brclr data,PORTA,r_error ;Stop Bit Detection
bset clk,DDRA ;Prevent Keyboard from sending data
;(Clear to Send)
rts
</PRE><FONT face=ARIAL>
<P>After the Parity Bits comes the Stop Bit. Once again we can ignore it
if we desire. However we have chosen to branch to an error routine if
this occurs. The stop bit should be set, thus an error occurs when it is
clear. </P></FONT><PRE> r_error lda #$FE ;Resend
sta byte
jsr Transmit
jmp Receive ;Try again
</PRE><FONT face=ARIAL>
<P>What you do as error handling is up to you. In most cases it will
never be executed. In fact I don't yet know if the above error handling
routine works. I need to program another HC705 to send a false parity
bit. I've tried it out in close proximity to the Washing Machine, but I
really need a controlled source! </P>
<P>When an error occurs in the Parity or Stop Bit we should assume that
the rest of the byte could have errors as well. We could ignore the
error and process the received byte, but it could have unexpected
results. Instead the keyboard has a resend command. If we issue a resend
(FE) to the keyboard, the keyboard should send the byte back again. This
is what occurs here. </P>
<P>You may notice that we branch to the error routine which transmits a
resend command straight away, without waiting for the corrupt
transmission to finish. This is not a problem, as the keyboard considers
any transmission to be successful, if the 10th bit is sent, i.e. the
parity bit. If we interrupt the transmission before the parity bit is
sent, the keyboard will place the current byte in it's buffer for later
transmission. </P>
<P>Reading a byte doesn't really require bi-directional data and clock
lines. If you can process the byte fast enough then no handshaking (RTS)
is required. This means you no longer need to fiddle with the Data
Direction Register. I have successfully done this with the HC705,
outputting only scan codes on a parallel bus. But as you can imagine,
you must be quick in order to catch the next transmission. </P><B><FONT
size=+2>Writing Bytes to the Keyboard.</FONT></B>
<HR>
<P>The following routine given here is a generic one which can be used
for your own purposes. During normal execution of this program the KBD
clock line should be low, to prevent data being sent when the MCU isn't
ready for it. However in this example, we take low the KBD clock line
and wait for the 64uS which is pointless as the line is already low and
has been like this for quite some time, since the end of the last
transmission or reception. </P></FONT><PRE> transmit ldx #$08 ;8 Data Bits
bset clk,DDRA ;Set Clock Low
lda #$13 ;Delay 64uS
jsr delay
clra ;Clear Parity Register
bset data,DDRA ;Set Data Low
bclr clk,DDRA ;Release Clock Line
jsr highlow
</PRE><FONT face=ARIAL>
<P>The program then initiates the Host to Keyboard transmission by
taking the KBD data line low and releasing the KBD clock line. We must
then wait for a high to low transition on the KBD clock, before we load
the first bit on the KBD data line. </P></FONT><PRE> loop ror byte
bcs mark
space bset data,DDRA ; Clear Bit
jmp next
mark bclr data,DDRA ; Clear Bit
inca ; Parity Calculation
next jsr highlow ; Wait for high to low transition
decx
bne loop
</PRE><FONT face=ARIAL>
<P>The loading of the individual bits on the KBD data line is done in
very similar fashion to the read cycle. The X register is used to keep
track of the number of bits sent. Also simular to the read cycle, we
increment the accumulator so we can calculate the parity bit later on.
</P></FONT><PRE> and #$01
bne clr_par
set_par bclr data,DDRA
jmp tr_ackn
clr_par bset data,DDRA
tr_ackn jsr highlow
</PRE><FONT face=ARIAL>
<P>After the data bits have been sent, it is now time to send the parity
bit. Unlike the read cycle, we can't ignore the parity bit. If we do the
keyboard will issue a resend (FE) command if the parity bit is
incorrect, a 50% probability! </P></FONT><PRE> bclr data,DDRA ;Release Data Line
jsr highlow
brset data,PORTA,error ;Check for Ack
brclr clk,PORTA,* ;Wait for idle line
bset clk,DDRA ;Prevent Keyboard from sending data
;(Clear to Send)
rts
</PRE><FONT face=ARIAL>
<P>Once the Parity bit has been set and the falling edge of the KBD
clock detected, we must release the KBD data line, and wait for another
falling edge of the KBD clock to see if the Keyboard has acknowledged
the byte. The keyboard does this by pulling the KBD data line low. If it
is not low, then the program branches to an error handler. If all has
been successful, the MCU pulls down the KBD clock, to prevent it from
transmitting. </P></FONT><PRE> error lda #$FF ;Reset
sta byte
jsr transmit
rts
</PRE><FONT face=ARIAL>
<P>We have taken a harsher approach to handing any transmit errors.
Ideally we should wait for the keyboard to send a resend command and
then retransmit the byte. However what we have done is to issue a reset
to the keyboard. So far I've never had an error, however if this starts
to become a problem, then a better error handler could be written.
</P><BR><B><FONT size=+2>Download Source Code</FONT></B>
<HR>
<UL><BR>
<LI><A
href="http://www.beyondlogic.org/keyboard/keybrd05.zip">Download
Keybrd05.zip </A>- Source code for 68HC705J1A (20,604 Bytes)<BR><BR>
<LI><A href="http://www.beyondlogic.org/keyboard/keylst.htm">View .Lst
(List) File</A> <BR></LI></UL><BR><FONT size=+2><B>Links to other
information.</B></FONT> <BR>
<HR>
<UL><BR>
<TABLE>
<TBODY>
<TR>
<TD vAlign=top><FONT face=ARIAL>
<LI><A href="http://www.ezl.com/~rsch/projects.htm">Two Line
Mini-Terminal</A> </FONT></LI></TD>
<TD><FONT face=ARIAL>Roger Schaefer has developed a Mini RS-232
Terminal using the 68HC11. As an input device the terminal uses
a <B>standard IBM compatible PC keyboard.</B> In a normal full
duplex mode the controller converts the keyboard scan codes to
ASCII and transmits them to the RS-232 output. Input from the
RS-232 is displayed on the LCD.
<BR><BR></FONT></TD></TR></TBODY></TABLE></UL></FONT></UL></TD></TR></TBODY></TABLE><FONT
size=2>Copyright 1999-2001<A href="mailto:Craig.Peacock@beyondlogic.org">Craig
Peacock</A> - 19th August 2001.</FONT> <BR><BR></CENTER></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -