|
Conectando un Teclado PS/2 a la
RRBOARD1 (Previo al
Emulacion Teclado PS/2)
|
|
Descripción y
funcionamiento a "alto nivel":
|
-
Un
teclado PS/2 de 104 teclas para PC es un dispositivo razonablemente
inteligente. Esto quiere decir que él mismo se encarga de la
parte hardware del rastreo de teclas, de evitar los insufribles rebotes
y de transmitirnos, mediante una trama perfectamente establecida, de los
resultados de nuestras manipulaciones sobre sus teclas.
|
-
El teclado
PS/2 tiene un mapa de teclas a las que asigna un código,
de uno o dos bytes, para cada una de ellas y que son los códigos que nos
va a transmitir para indicarnos que se está pulsando una tecla
determinada. A estos códigos les vamos a llamar códigos de rastreo de
teclado. Más abajo os muestro una imagen de un teclado estándar
donde se muestran los códigos de rastreo de todas y cada una de las
teclas:
|
|
|
-
El teclado
PS/2 envía el código de rastreo asociado a una tecla al ser ésta
pulsada, tantas veces como sea necesario si se mantiene pulsada con una
cadencia tal como indique su tiempo de repetición, que es programable, y
el mismo código de rastreo con el prefijo del byte F0h al ser
soltada, también conocido como Break Code.
|
-
Por
ejemplo: Para conseguir la letra G Mayúscula debemos pulsar
la tecla Shift y mientras la mantenemos pulsada, pulsar la tecla G,
soltar la tecla G y soltar la tecla Shift. Esa secuencia de pulsaciones
nos va a hacer que el teclado transmita la siguiente secuencia de bytes:
Pulsar Shift -> 12h,
Pulsar "G" -> 34h,
Soltar "G" -> F0h 34h
y soltar Shift -> F0h 12h
o escribiendo solo los bytes que vamos a recibir:
1h, 34h, F0h, 34h, F0h, 12h
Ahí queda eso.
|
- Nuestro cometido va a ser recibir e
interpretar esta secuencia de bytes y actuar en consecuencia.
|
-
El teclado PS/2 también
admite comandos. Dispone de funciones build-in que podemos disparar
mediante el envío del comando correspondiente. Abajo muestro una tabla
con los comandos disponibles que podemos enviarle a nuestro teclado.
(Nosotros, en este proyecto no vamos a utilizarlos, pero ahí quedan por
si alguno de mis amables visitantes desea ampliar la funcionalidad del
mismo).
|
|
|
Conexionado
eléctrico: |
|
-
El teclado
PS/2 se conecta mediante cuatro hilos. Dos de ellos son para
alimentación Vcc a 5V y GND, y otros dos para las señales
Data y Clock. El pinout de los conectores Mini-DIN PS/2
tanto hembra, los del PC, como machos, los del Teclado, es tal como se
muestra en la imagen inferior:
|
|
-
En el
Teclado PS/2 las señales Data y Clock con de "colector abierto".
Esto quiere decir que para establecer un comunicación eléctricamente
correcta debemos nosotros suministrar voltaje para el nivel lógico alto,
y es él el encargado de dar los correspondiente niveles lógicos bajos,
tirando nuestra señal a GND cuando así sea necesario. Este tema
se soluciona conectando dos resistencias de 10K entre dichas líneas y
Vcc por lo que siempre tendrán nivel lógico alto, salvo cuando el
teclado disponga lo contrario y lo tire a GND para dar lo
correspondientes niveles lógicos bajos. Esto es lo que se llama conectar
unas resistencias Pull-Up.
|
- El esquema de mas abajo muestra como
conectar las resistencias Pull-Up entre el teclado y el PIC:
|
|
-
Nota:
Generalmente nuestros PIC's y en concreto el yo utilizo para este
proyecto, el PIC 16F628A, tiene todo el puerto B con la capacidad
de conectar, mediante la correspondiente configuración, una batería de
resistencias Pull-Up a todos sus pines. Esto hace innecesario la
conexión de las resistencias externas tal como se presenta en el esquema
anterior, pero lo indico porque podríamos tener que utilizar cualquier
otro puerto que no disponga de esta característica, y en ese caso sí que
deberíamos conectarlas para su correcto funcionamiento.
|
|
Protocolo de
comunicación PS/2: |
|
- El teclado PS/2 se comunica
mediante un Protocolo Serie Síncrono. Utiliza, por lo tanto, una
señal de Clock que índica cuando están disponibles los
correspondientes bits en la señal de Data.
|
|
- La trama completa se compone
de 11 bits. Siendo el primero un bit de Start, a
continuación los 8 bits del Dato a transmitir enviándose
primero el LSB (ó bit menos significativo), el décimo es el de
paridad (usa la Impar, u Odd en Inglés) y por último un bit de ACK
o Stop.
|
- Abajo puede verse un cronograma de
esta trama de comunicación PS/2 Teclado (Keyboard)
-> PC (host):
|
|
-
Este protocolo de
comunicación es bidireccional. El teclado PS/2 admite también
comandos enviados desde el PC con el mismo formato que estamos
estudiando, tal como adelantamos en el primer apartado de este proyecto.
Y tal como decíamos allí, nosotros no vamos a implementar el envío de
comandos al teclado, pero creo conveniente discutir también su
procedimiento de envío, a nivel de protocolo por si alguien desea
implementarlos en su propio trabajo.
|
- Para poder habilitar la comunicación
inversa, del PC (host) al Teclado PS/2 (Keyboard) debemos primero
indicárselo así al Teclado mediante la señal de Clock. Para ello
debemos poner a nivel bajo el Clock durante unos 160 uS, y la señal de
Data a bajo unos 35 uS después de haber lanzado la del Clock. A partir
de ahí debemos esperar la señal del Clock generada por el Teclado.
Esto nos indicará que el teclado está dispuesto para recibir nuestro
comando. Detectamos dicha señal como primer pulso de Clock, y a partir
del siguiente podemos comenzar a enviarle nuestro byte.
|
-
Le enviaremos
entonces los ocho bits de nuestro comando, cada uno de ellos cuando el
correspondiente pulso en bajo del Clock del teclado así nos lo
indique, empezando por el LSB, a continuación el bit de paridad impar
(El numero de unos en los datos mas el de paridad deber ser impar o
sea 1 si el numero de unos es par y cero si el total de unos es impar)
|
-
Y entonces debemos
esperar el ACK del teclado, que debe venir tras dos pulsos de reloj,
en nivel bajo, indicándonos de este modo que el teclado ha recibido
correctamente nuestro comando. en caso contrario debemos volver a
repetir nuestra secuencia de envío.
|
- Mas abajo se muestra un cronograma de
la transmisión PC (host) -> Teclado PS/2 (Keyboard)
|
|
|
Y con esto creo que ya
estamos en disposición de implementar la lectura de nuestro teclado con el
PIC. |
|
|
Implementación
en la RRBOARD1: |
|
|
|
-
La otra
característica que vamos a utilizar es la de la interrupción por
disparo externo, INT_EXT, que tenemos disponible en el
Pin RB0 del puerto B. Con esta interrupción vamos a detectar la señal
del Clock del teclado, que nos indica periódicamente cuando tenemos
disponible el siguiente bit a leer, hasta completar nuestra
comunicación.
|
-
Para ello he modificado
el conector de 10 pines de que dispone la RRBOARD1 publicando los pines
RB0 y RB3 que serán los encargados de las señales de Clock y Data
respectivamente. He cortado un cable alargador de Teclado PS/2, que
dispone de los correspondientes conectores macho y hembra PS/2 en sus
extremos, y he soldado los hilos correspondientes al conector hembra a
los hilos Vcc, GND, RB0 y RB3 del cable plano del conector de 10 hilos
de la RRBOARD1. Abajo puede verse una imagen de esta conexión:
|
|
Y con esto ya tenemos listo
todo el Hardware necesario para poder "leer" el teclado PS/2 desde la
RRBOARD1. A continuación vamos a ver el Software que vamos a construir. |
|
Software de
lectura: |
|
Antes que nada deciros que
este programa no lo he hecho yo. Como podéis ver en los créditos iniciales
está realizado por XP8100. Yo solo me he limitado a adaptarlo a mi
hardware específico, y a monitorizar tanto los códigos de rastreo de
teclado involucrados como el carácter decodificado correspondiente. |
|
|
|
|
|
//-----------------------------------------------------------------------------
// Title: keyboard_pc_to_rs232.c
// Description: Interfase entre un teclado convencional tipo AT y un puerto
RS232C
// Date: Abr-2005
// Ver.Rev.: V01
// Author: XP8100 (xp8100@gmail.com)
//
// #Based on the AN AVR313: Interfacing the PC AT Keyboard from ATMEL#
// #Adaptado para 16F628A por Redraven
//
//-----------------------------------------------------------------------------
//
// init_kb() Inicializa rutina y contadores
//
// decode (char) Decodifica la pulsación realizada, convirtiendola a un
caracter de la tabla
//
// int_ext_isr Rutina de gestión de interrupciones. Captura los diferentes
bit's
//
//-----------------------------------------------------------------------------
// RB0 - Señal de reloj
// RB3 - Tren de impulsos (11 bit) Start+10101010+Paridad+Stop
//-----------------------------------------------------------------------------
//
// Commment : Permite conectar un teclado convencional de PC a un entorno
// gestionado por un PIC 16F877.
// El actual sistema se define como un primer prototipo, en el que no se
realizan
// acciones concretas asociadas a teclas establecidas.
// Tampoco se actua sobre los indicadores luminosos del teclado, repetición
de teclas, ...
//
//
//
// THIS DOCUMENT IS PROVIDED TO THE USER 'AS IS'
//-----------------------------------------------------------------------------
#include "16F628a.h"
#fuses HS,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT,NOLVP
#use Delay(Clock=20000000)
#use rs232(baud=19200, xmit=PIN_B2, rcv=PIN_B1)
#zero_ram
//-----------------------------------------------------------------------------
// Definiciones globales
//-----------------------------------------------------------------------------
unsigned char edge, bitcount;
char got_interrupt;
char interrupt_count;
char status_b3;
#bit INTF_BIT = 0x0B.1 // INTCON BIT 1 = INTF RB0/INT External Interrupt
Flag Bit
//-------- Tabla de caracteres correspondientes a la pulsación de la tecla
//-------- en modalidad normal (sin pulsar SHIFT)
unsigned char const unshifted[68][2] = {
0x0d,9,
0x0e,'º', 0x15,'q', 0x16,'1', 0x1a,'z', 0x1b,'s', 0x1c,'a', 0x1d,'w',
0x1e,'2', 0x21,'c', 0x22,'x', 0x23,'d', 0x24,'e', 0x25,'4', 0x26,'3',
0x29,' ', 0x2a,'v', 0x2b,'f', 0x2c,'t', 0x2d,'r', 0x2e,'5', 0x31,'n',
0x32,'b', 0x33,'h', 0x34,'g', 0x35,'y', 0x36,'6', 0x39,',', 0x3a,'m',
0x3b,'j', 0x3c,'u', 0x3d,'7', 0x3e,'8', 0x41,',', 0x42,'k', 0x43,'i',
0x44,'o', 0x45,'0', 0x46,'9', 0x49,'.', 0x4a,'-', 0x4b,'l', 0x4c,'ñ',
0x4d,'p', 0x4e,''', 0x52,'´', 0x54,'`', 0x55,'¡', 0x5a,13, 0x5b,'+',
0x5d,'ç', 0x61,'<', 0x66,8, 0x69,'1', 0x6b,'4', 0x6c,'7', 0x70,'0',
0x71,'.', 0x72,'2', 0x73,'5', 0x74,'6', 0x75,'8', 0x79,'+', 0x7a,'3',
0x7b,'-', 0x7c,'*', 0x7d,'9',
0,0
};
//-------- Tabla de caracteres correspondientes a la pulsación de la tecla
//-------- en modalidad desplazamiento (pulsando SHIFT)
unsigned char const shifted[68][2] = {
0x0d,9,
0x0e,'ª', 0x15,'Q', 0x16,'!', 0x1a,'Z', 0x1b,'S', 0x1c,'A', 0x1d,'W',
0x1e,'"', 0x21,'C', 0x22,'X', 0x23,'D', 0x24,'E', 0x25,'$', 0x26,'·',
0x29,' ', 0x2a,'V', 0x2b,'F', 0x2c,'T', 0x2d,'R', 0x2e,'%', 0x31,'N',
0x32,'B', 0x33,'H', 0x34,'G', 0x35,'Y', 0x36,'&', 0x39,'L', 0x3a,'M',
0x3b,'J', 0x3c,'U', 0x3d,'/', 0x3e,'(', 0x41,';', 0x42,'K', 0x43,'I',
0x44,'O', 0x45,'=', 0x46,')', 0x49,':', 0x4a,'_', 0x4b,'L', 0x4c,'Ñ',
0x4d,'P', 0x4e,'?', 0x52,'¨', 0x54,'^', 0x55,'¿', 0x5a,13, 0x5b,'*',
0x5d,'Ç', 0x61,'>', 0x66,8, 0x69,'1', 0x6b,'4', 0x6c,'7', 0x70,'0',
0x71,'.', 0x72,'2', 0x73,'5', 0x74,'6', 0x75,'8', 0x79,'+', 0x7a,'3',
0x7b,'-', 0x7c,'*', 0x7d,'9',
0,0
};
//-----------------------------------------------------------------------------
// Definición de protipos
//-----------------------------------------------------------------------------
void init_kb(void);
void decode(unsigned char sc);
//-----------------------------------------------------------------------------
// Rutina de gestión de interrupciones
//-----------------------------------------------------------------------------
#int_ext
void int_ext_isr(void){
unsigned char data;
//-------- Los bit 3 a 10 se considerran datos. Paridad, start y stop
//-------- son ignorados
if(bitcount < 11 && bitcount > 2){
data = (data >> 1);
status_b3 = input(PIN_B3);
if((status_b3) == 1){
data = data | 0x80;
}
}
//-------- Todos los bits se han recibido
if(--bitcount == 0){
decode(data);
data = 0;
bitcount = 11;
got_interrupt = TRUE;
}
got_interrupt = TRUE;
interrupt_count++;
disable_interrupts(INT_EXT);
}
//-----------------------------------------------------------------------------
// Main
//-----------------------------------------------------------------------------
void main(void){
delay_ms(100);
init_kb();
//-------- Los pins indicados (B0 y B3) son configurados como entradas.
output_float(PIN_B0);
output_float(PIN_B3);
//-------- Activa pullups sobre todos los pins del puerto B.
port_b_pullups(TRUE);
//-------- Espera a que se activen.
delay_us(5);
//-------- Inicializa las variables usadas por la rutina de interrupción
//-------- antes de activar las interrupciones
interrupt_count = 0;
got_interrupt = FALSE;
status_b3 = 0;
//-------- Desde que se activó el modo PULLUPS del puerto B, el estado
//-------- normal del pin B0 es ALTO. La gestión de la interrupción
externa
//-------- se gestiona cuando se produce un cambio de nivel ALTO a BAJO.
ext_int_edge(H_TO_L);
//-------- Asegurarse de que el el bit de flag de la interrupción externa
//-------- es borrado antes de activar la gestión de dicha interrupción
//-------- externa.
INTF_BIT = 0;
enable_interrupts(INT_EXT);
enable_interrupts(GLOBAL);
//-------- Bucle principal.
//-------- Chequear si se produce alguna interrupción (got_interrupt). Si
es así, contar, borrar
//-------- el flag y esperar 50 ms, reactivando la gestión de las
interrupciones
while(1){
//-------- Chequear si se produce alguna interrupción (got_interrupt).
if(got_interrupt == TRUE){
//-------- Borrar el flag global que se inicio en la rutina
de servicio
//-------- de interrupciones externas.
got_interrupt = FALSE;
//-------- Esperar 50 ms para evitar rebotes en los contactos
de las teclas.
//delay_ms(50);
//-------- Borrar cualquier interrupción producida durante el
periodo de espera.
INTF_BIT = 0;
//-------- Reactivar interrupciones
enable_interrupts(INT_EXT);
} // --- End If ---
} // --- End While ---
} // --- End MAIN ---
//-----------------------------------------------------------------------------
// Funciones
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Inicialización de teclado.
//-----------------------------------------------------------------------------
void init_kb(void){
//-------- Longitud de la trama para cada pulsación y mensaje de
bienvenida
bitcount = 11;
printf("\n\rPC AT Keyboard Interface Ver 1.0 by XP8100" );
printf("\n\rAdpapted for 16F628A by Redpic" );
printf("\n\rDecoder and Monitoring for 16F628A connected ...\n\r\n\r" );
}
//-----------------------------------------------------------------------------
// Decodificación de pulsaciones
//-----------------------------------------------------------------------------
void decode(unsigned char sc){
static unsigned char is_up=0, shift = 0, mode = 0;
unsigned char i;
printf("[%X]",sc); // Monitor de código de rastreo
//-------- El último dato recibido fue el identificador de Up-Key
if (!is_up){
switch (sc){
//-------- Identificador de Up-Key
case 0xF0 :
is_up = 1;
break;
//-------- SHIFT Izquierdo
case 0x12 :
shift = 1;
break;
//-------- SHIFT Derecho
case 0x59 :
shift = 1;
break;
//-------- ENTER
case 0x5A :
shift = 0;
printf("\n\r" );
break;
//-------- Si no es ninguno de los
identificadores especiales, procesar
//-------- pulsación, localizando caracter en
tabla de caracteres.
default:
//-------- Pulsación normal
if(!shift){
for(i = 0; unshifted[ i
][ 0 ]!=sc && unshifted[ i ][ 0 ]; i++);
if (unshifted[ i ][ 0 ]
== sc){
printf("<%c>",
unshifted[ i ][ 1 ]);
}
}
else
//-------- Pulsación + SHIFT presionado
{
for(i = 0; shifted[ i ][ 0 ]!=sc
&& shifted[ i ][ 0 ]; i++);
if (shifted[ i ][ 0 ] == sc){
printf("<%c>",
shifted[ i ][ 1 ]);
}
}
break;
} // --- End Switch
}
else
{
//-------- No se permiten 2 0xF0 en una fila
is_up = 0;
switch (sc){
//-------- SHIFT Izquierdo
case 0x12 :
shift = 0;
break;
//-------- SHIFT Derecho
case 0x59 :
shift = 0;
break;
} // --- End Switch
}
}
|
|
|
Descargar
Fuentes |
|
- Y ahora como siempre una
imagen que vale mas que mil palabras. En este caso muestro el monitor
RS232 conectado al PIC y su contenido es lo que hemos pulsado en el
Teclado PS/2 conectado al PIC con la secuencia de [a][s][d][Intro][f][g]:
|
|
Ampliación: Con la RRBOARD2 |
Para el proyecto
KBDEMUL voy a necesitar "algo" que
reciba PS/2 y que no sea mi PC ya que puede ser una pequeña locura
intentar depurar un "emisor PS/2" utilizando la misma entrada donde tengo
conectado el teclado con el que estoy trabajando ...
Así que la solución lógica es utilizar otro PC, pero como no tengo otro no
tengo mas remedio que tirar de la
RRBOARD2 haciendo las mismas funciones que en este hacía la
RRBOARD1. Así mi "emisor" le hablará
a la RRBOAR2 y ésta transmitirá lo que reciba vía RS232 al PC con lo que
podré depurar sin problemas ...
Aquí os pego lo que realizado para conectarle el Teclado PS/2 a la
RRBOARD2 que calza un 18F4550:
Primero el Adaptador PS/2 a Cable Plano 10 pines ...
|
|
Después la conexión entre el Keyboard PS/2 y
la RRBOARD2 ...
|
|
Y por último un ejemplo de conexión con el
monitor serie del PC:
|
|
Esta página se modificó el
27/12/2008
|