Bueno, lo prometido es deuda. Aquí teneis el programa que nos permite conectar
un Keyboard PS/2 a un PIC.
Solo hago uso de dos hilos, uno debe ser RB0 para podernos aprovechar de su
función de Interrupción Externa, el otro puede ser cualquier pin de Entrada. Yo
he hecho uso del RB3. Como hace falta poner unas resistencias Pull-Up externas
a las lineas de Clock y Data he aprovechado la caracteristica de los PIC que incluye
dichas resistencias de forma programable en los pines del Puerto B, para activarlas
y evitarme así el tener de forma externa.
El teclado envia los códigos de rastreo, los fin de pulsado de tecla (break) y los de
teclas especiales mediante "bytes" de 11 bits start+codigo_8_bits+paridad+Stop
asi que la recogida de estos bits se produce en la interrupción externa, a la que está
conectada la señal de clock. Cada vez que se produce un pulso (negativo) de clock
se lee un bit. Cuando hemos leído los 11 bits en total tenemos un nuevo byte para
procesar. Este byte resulta de haber descartado los que no nos hacen falta y solo
se toman en cuenta realmente los codigo_8_bits de toda la secuencia.
Fijaos que para detectar cada uno de los bits en la Interrupción externa debemos
configurar ésta para que salte en el flaco de bajada ext_int_edge(H_TO_L);
Le dejo al programa los créditos originales de nuestro benefactor anónimo, añadiéndole
solo la modificación realizada por mi. Además he editado la tabla de conversión
poniéndola en columnas para que aparezcan mas compactas y se lea mejor el
código fuente.
<span class="texto_mini">Codigo:</span>
[
BR]//-----------------------------------------------------------------------------
// 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("
PC AT Keyboard Interface Ver 1.0 by XP8100" );
printf("
Adpapted for 16F628A by Redpic" );
printf("
Decoder and Monitoring for 16F628A connected ...
" );
}
//-----------------------------------------------------------------------------
// 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("
" );
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
}
}
Y por último, y como siempre, os pongo un volcado de mi monitor RS232 con
los resultados de la detección de teclas y su posterior envío por el puerto serie
del PIC. En este ejemplo monitorizo la secuencia de teclas [ a ][ s ][ d ][ intro ][ f ][ g ]
Fijaos que he incluido en la transmisión tanto los códigos de rastreo como las teclas
decodificadas que dichos códigos significan:

Resultado plenamente satisfactorio <img src="
http://pics.miarroba.com/caretos/lol.gif" alt="Muchas risas" title="Muchas risas" /> <img src="
http://pics.miarroba.com/caretos/lol.gif" alt="Muchas risas" title="Muchas risas" /> <img src="
http://pics.miarroba.com/caretos/lol.gif" alt="Muchas risas" title="Muchas risas" /> <img src="
http://pics.miarroba.com/caretos/bounce.gif" alt="Rebotado" title="Rebotado" /> <img src="
http://pics.miarroba.com/caretos/bounce.gif" alt="Rebotado" title="Rebotado" /> <img src="
http://pics.miarroba.com/caretos/bounce.gif" alt="Rebotado" title="Rebotado" /> <img src="
http://pics.miarroba.com/caretos/bounce.gif" alt="Rebotado" title="Rebotado" /> <img src="
http://pics.miarroba.com/caretos/bounce.gif" alt="Rebotado" title="Rebotado" />