/* v1.0
Programa ejemplo que hace uso del teclado matricial
4x4 mediante interrupciones y liberando 4 pines del portb,
haciendo posible cambiarlas por cualquier pin del uC PIC.
Los 4 pines liberados corresponden a las columnas que maneja el teclado
Caracteristicas:
- Cambio de estado en los pines RB[7-4]
- Retardo antirrebotes por Timer0
con la interrupción por cambio en PORTB, se gestiona el teclado sin tener
que encerrar todo el programa principal en un bucle.
la interrupción del timer0 sirve para crear un retardo antirrebotes SIN
hacer demorar la ejecución del programa principal.
el próposito de ambas interrupciones es detectar la pulsación de una
tecla y garantizar que no sea un falso contacto todo ello sin "detener"
el bucle principal.
solo se gestionará el proceso correspondiente cuando se pulsa la tecla
(está validado para no responder a soltar la tecla o mantenerla
indefinidamente).
si quiere ejecutar el proceso asociado a la tecla nuevamente, basta pulsar
otra vez dicha tecla.
Autor: Pocher
Modificación: PalitroqueZ 14-May-2008 11:10am
Este código puede usarse libremente siempre que se mantenga/n y/o respete/n
el/los credito/s de/los autor/es
*/
#include <18F4550.h>
#fuses XTPLL,NOMCLR,NOWDT,NOPROTECT,
#fuses NOLVP,NODEBUG,NOPBADEN,USBDIV,PLL1
#fuses CPUDIV1,NOVREGEN,NOIESO // IESO bit ignorado
#use delay(clock=48M)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7) // opcional
#use fast_io(A) // opcional
#use fast_io(B) // "
#use fast_io(C) // "
#use fast_io(D) // "
#use fast_io(E) // "
#byte PORTB=0xF81
// declarar la dirección del portb
//*********************************
// variables globales
//*********************************
int8 const iVeces_iContador_1ms=30;
int8 iFlanco_RB=0; // bandera que detecta el primer flanco del pulsador
int8 iContador_1ms=0; // con Fcpu=48MHz, el timer0 cuenta máximo ~ 5ms
int8 iTecla_capturada=0;
int1 fImprimir=0; // Bandera ejemplo para imprimir tecla presionada
#define iColumna0 PIN_D7
#define iColumna1 PIN_C2
#define iColumna2 PIN_A0
#define iColumna3 PIN_D0
//*********************************
// archivos a incluir
//*********************************
#include "Teclado_flex_change_portb.C"
//----------------------------------------------------
#int_timer0
void tmr0_isr(){
int8 temp;
if(iContador_1ms==iVeces_iContador_1ms){
// retardo antirebotes = 1ms * iVeces_iContador_1ms
// ya pasaron 30 ms después de la interrupción
// por cambio de PORTB (el retardo puede variarse)
temp = input_b() & iLos_Cuatro_MSB_PORTB;
if(iFlanco_RB == temp){
// pregunta si realmente la tecla se pulsó
// o por el contrario es un falso contacto
// aqui es donde se procesa la tecla para lo que queramos hacer
iTecla_capturada=kbd_getc();
fImprimir=1;
}
Limpiar_Columnas();
iContador_1ms=0;
disable_interrupts(INT_TIMER0);
#asm movf PORTB,0 #endasm
clear_interrupt(int_rb); // RBIF = 0 limpia la bandera
enable_interrupts(int_rb);
}else{
iContador_1ms++;
// continua el miniretardo que es multiplo de retardo deseado
}
}
//----------------------------------------------------
#int_rb // Interrupcion cambio de estado RB[4-7]
void control_rb() {
iFlanco_RB = input_b() & iLos_Cuatro_MSB_PORTB;
// almacena el valor de RB[7-4] inicial
if(iFlanco_RB != iLos_Cuatro_MSB_PORTB){
// este condicional sirve para validar cuando se pulsa
// la tecla (mas NO cuando se suelta).
// consume 4 lineas de asm.
disable_interrupts(INT_RB);
// deselecciona la interrupción por cambio en PORTB
// para comenzar el retardo antirebote
iContador_1ms=0;
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_64|RTCC_8_BIT);
// configura el Timer0 base de tiempo interno, pre-escaler=1:256
set_timer0(68); // retardo de ~ 1ms
enable_interrupts(INT_TIMER0);
}
#asm movf PORTB,0 #endasm
Limpiar_Columnas();
}
//--------------------------------------------------
void main() {
output_a(0);
output_b(0);
output_c(0);
output_d(0);
output_e(0);
set_tris_a(0x0);
set_tris_b(0b11110000); // RB[7-4] son entradas
set_tris_c(0x0);
set_tris_d(0x0);
set_tris_e(0x0);
port_b_pullups(true);
// no es obligatorio. Si es false, se colocan pull-up externas en RB[7-4]
disable_interrupts(global);
disable_interrupts(INT_TIMER0);
printf("Preparando al teclado por interrupcion (int_RB)\n\r");
Limpiar_Columnas();
enable_interrupts(int_rb);
#asm movf PORTB,0 #endasm // con estas 2 lineas, se borra
clear_interrupt(INT_RB); // RBIF al inicio del programa
enable_interrupts(global);
while(1){
if(fImprimir){
printf("interrupcion: %x\n\r",iTecla_capturada
); iTecla_capturada=0;
fImprimir=0;
}
}
}