//-----------------------------------------------------------------------------
// Title: KEYBOARD_To_PC_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 18f4550 por RedPic
//
//-----------------------------------------------------------------------------
//
// 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
// RB7 - Tren de impulsos (11 bit) Start+10101010+Paridad+Stop
//-----------------------------------------------------------------------------
//
// Commment : Permite conectar un teclado convencional de PC a un entorno
// gestionado por un PIC 18f4550.
// 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 <18f4550.h>
#fuses HS,MCLR,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT,NOPBADEN,NOLVP,NOCPD,NODEBUG,NOWRT,NOVREGEN // Fuses
#use delay(clock=20000000) // Clock a 20 Mhz
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) // Canal serie con el PC
#zero_ram
//-----------------------------------------------------------------------------
// Definiciones globales
//-----------------------------------------------------------------------------
unsigned char edge, bitcount;
char got_interrupt;
char interrupt_count;
char status_b3;
#bit INTF_BIT = 0xff2.1 // INTCON BIT 1 = INT0IF: INT0 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_B7);
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);
}
void flash_porte(void){
int i;
set_tris_e(0b00010000); // Prepraro PORTE para flashear, Digital y Salida
for(i=0;i<3;i++){
output_High(PIN_E0); // Enciendo los tres Led's de la RRBOARD2
output_High(PIN_E1);
output_High(PIN_E2);
delay_ms(333); // Espero para que se vea
output_Low(PIN_E0); // Apago los tres Led's de la RRBOARD2
output_Low(PIN_E1);
output_Low(PIN_E2);
delay_ms(333); // Espero para que no se vea
}
}
void on_reset(){
disable_interrupts(global); // Deshabilito todas las interrupciones
disable_interrupts(int_timer1); // Deshabilito ...
disable_interrupts(int_rda);
disable_interrupts(int_ext);
disable_interrupts(int_ext1);
disable_interrupts(int_ext2);
setup_adc_ports(NO_ANALOGS); // Configuro todo lo que voy
setup_adc(ADC_OFF); // a usar y lo que no ...
setup_spi(FALSE);
setup_psp(PSP_DISABLED);
setup_counters(RTCC_INTERNAL,RTCC_DIV_2);
setup_timer_0(RTCC_OFF);
setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
setup_timer_2(T2_DISABLED,0,1);
setup_timer_3(T3_DISABLED);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
set_tris_c(0b10000000);
delay_ms(333); // Espero 333 milisegundos a que todo se estabilice
printf("\r\n"); // Me presento como deben hacer todos los PIC's de buena familia
printf("PC AT Keyboard Interface by XP8100\r\n");
printf("Adpapted for 18F4550 by Redpic\r\n");
printf("Decoder and Monitor connected ...\n\r");
printf("\r\n");
flash_porte();
delay_ms(100);
init_kb();
//-------- Los pins indicados (B0 y B7) son configurados como entradas.
output_float(PIN_B0);
output_float(PIN_B7);
//-------- 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;
//-------- Habilito Interrupciones
enable_interrupts(INT_EXT);
enable_interrupts(GLOBAL);
}
//-----------------------------------------------------------------------------
// Main
//-----------------------------------------------------------------------------
void main(void)
{
//-------- Hago todo lo que tengo que hacer al resetear el micro
On_reset();
//-------- 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
bitcount = 11;
}
//-----------------------------------------------------------------------------
// 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);
//-------- 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
}
}