danyboy666
Joined: 01 Mar 2011 Posts: 30
|
Matrix 4x4 Keypad w/ interrupt and EEPROM password |
Posted: Sat Mar 10, 2012 11:25 pm |
|
|
This is a little code i've did at the college. The function is simple; read a 4x4 keypad which is polled by an interrupt on RB2. The code can read a password from EEPROM and compare it to a user input.
Code: | /////////////////////////////////////////////////////////////////////////////////
// Applications des microcontrolleurs 243-444-RK //
// Laboratoire no. 3 //
// Programme no 3: Expérimentation avec clavier matriciel style matrice //
// carrée geré par interruptions(point boni). //
// //
// Ce programme vérifie et compare avec les données mis en mémoires morte. //
// Ces mot de passes sont stocker dans un tableau(array) et en appelant //
// la fonction read_from_EEPROM() ce mot de passe stocké en EEPROM et mis //
// dans une variable pour ensuite la comparer avec la combinaison entré par //
// l'utilisateur. //
// //
// Une porte ET à quatre entrés est relié entre les broches RD4 et RD7. Dès //
// qu'une touche est appuyé, un niveau bas se produit à la sortie de la //
// porte ET ce qui à pour effet de causer une interruption EXTERNE //
// sur l'entré RB2 qui est reliée à celle-ci. //
// //
/////////////////////////////////////////////////////////////////////////////////
// //
// Copyright@Dany Ferron 2012 //
// //
/////////////////////////////////////////////////////////////////////////////////
// //
// //
// _________________ //
// -|1 40|- //
// -| |- //
// -| PIC18F4550 |- //
// -| @20MHz |- //
// -| |- //
// -| |- //
// -| |-RB2 This is the port I use for the int_EXT2 //
// -| |- //
// -| |- //
// -| |- //
// -| |-RD7 //
// -| |-RD6 //
// -| |-RD5 //
// -| |-RD4 //
// -| |-RC7/RX <-This is the connection to the //
// -| |-RC6/TX ->MELabs serial LCD controller //
// -| |- //
// -| |- //
// RD0-| |-RD3 //
// RD1-|20 21|-RD2 //
// ----------------- //
// => RD0 to RD7 Connex to the Matrix keypad //
// => I'm using a 4-way AND gate to provide an interrupt on port RB2. //
// //
// //
// //
// //
// //
/////////////////////////////////////////////////////////////////////////////////
#include "Matrix Keyboard 3C.h"
#include "CLAVIER16T c-a interruption.c"
/////////////////////////////////////////////////////////////////////////////////
// Le début de l'addresse mémoire commence à 0xF00000: Il est à noté qu'il faut//
// spécifier au compilateur qu'elle est le type de variable, par défault il //
// stock en mémoire un integer d'une longueur de 16. Donc pas pratique si l'on //
// veux lire et stocker un octet à la fois. //
/////////////////////////////////////////////////////////////////////////////////
#rom int8 0xF00000={'9','8','7','6'}
// Definition et initialisation des variables servant au stockage de mot de passe
// en EEPROM
#define PASSWORD_LENGTH 4
char password[PASSWORD_LENGTH] = {};
// Variable de mémorisation des touche de clavier retournés par la fonction
// kbd_getc();
char k;
////////////////////////////////////////////////////////////////////////////////
// L'appui d'une touche provoque un interruption du programme principal. //
// En mettant au niveau bas les rangées et les colonnes, on identifie quelle //
// touche est pesée en effectuant un OU logique et la fonction appelée par //
// l'interruption retourne la valeur de la touche appuyée. //
////////////////////////////////////////////////////////////////////////////////
#int_EXT2 // utilisation de l'interruption EXT2 cablé sur le portB bit 2
void EXT2_isr(void)
{
k=kbd_getc();
}
// Déclaration de la fonction de lecture du mot de passe stocké en mémoire morte.
char read_from_EEPROM(int8 adr);
void main()
{
// Variables servant à la lecture du code entré par l'utilisateur.
int1 passwordValid=false;
int8 inputCount=0;
char userInput[PASSWORD_LENGTH] = {};
int8 j=0;
// Variables servant à définir la position du curseur de l'afficheur.
int8 adr;
// Initialisation des interruptions.
enable_interrupts(int_EXT2);
enable_interrupts(GLOBAL);
ext_int_edge(2,H_TO_L);// Front descendant sur RB2 Interrupt ext 2
//Initialisation de l'affichage.
printf("%c%c",0xfe,0x1);
printf("%c%c",0xfe,0x81);
printf("Entrez votre code");
adr=0xc7;// Adresse de retour pour le curseur.
do
{
// Initialisation du port pour la lecture du clavier
set_tris_d(0x0f);//Bit0 à bit3 en entrée et bit 4 à bit7 en sortie
output_low(pin_D4);
output_low(pin_D5);
output_low(pin_D6);
output_low(pin_D7);
// L'appel de cette fonction lit le code qui est en EEPROM à la premiere
// case d'adresse mémoire disponible dans le Micro controlleur.
read_from_EEPROM(0x00);
if(k!='\0') // Si une touche est appuyée, donc si interruption
{
printf("%c%c",0xfe,adr);
printf("%c",k);
delay_ms(300); // Delai servant de fonction anti-rebond(DEBOUNCE)
printf("%c%c",0xfe,adr);
printf("*");
delay_ms(200); // Cache le caractère entré par l'utilisateur.
// Incrémentation de l'addresse de la position du curseur pour la
// prochaine touche entrée par l'utilisateur.
adr++;
// Vérification du nombre d'appuis par l'utilisateur.
if(inputCount<PASSWORD_LENGTH)
{
userInput[inputCount]=k;
inputCount++;
}
// On s'assure de remettre une valeur NULL à la variable de lecture.
k='\0';
}
// La validation du nombre de touche appuyées se fait ici.
else if(inputCount==PASSWORD_LENGTH)
{
passwordValid=true;
for(j=0;j<PASSWORD_LENGTH;j++)
{
// On compare le code entré par l'utilisateur avec le mot de passe
// qui à été lut auparavant par la fonction read_from_EEPROM().
if(userInput[j]!=password[j])
{
passwordValid=false;
printf("%c%c",0xfe,0x1);
printf("%c%c",0xfe,0x97);
printf("Votre code est");
printf("%c%c",0xfe,0xd9);
printf("incorrect!");
delay_ms(500);
printf("%c%c",0xfe,0x1);
printf("%c%c",0xfe,0xd5);
printf("Veuillez reessayer");
printf("%c%c",0xfe,0x1);
printf("%c%c",0xfe,0x81);
printf("Entrez votre code");
adr=0xc7;
}
// On remet la chaine entrée par l'utilisateur a NULL pour
// un autre essai.
userInput[j]='0';
}
// On remet la variable de touche appuyée par l'utilisateur à 0 une
// fois que les 4 touches on été validées.
inputCount=0;
if(passwordValid==true)
{
printf("%c%c",0xfe,0x1);
printf("%c%c",0xfe,0x97);
printf("Votre code est");
printf("%c%c",0xfe,0xdb);
printf("correct!");
delay_ms(1000);
printf("%c%c",0xfe,0x1);
printf("%c%c",0xfe,0x81);
printf("Entrez votre code");
adr=0xc7;
}
}
}
while(true);
}
// Cette fonction lit et retourne le code qui est en EEPROM.
char read_from_EEPROM(int8 adr)
{
int8 i;
for(i=0;i<PASSWORD_LENGTH;i++)
{
password[i]=read_eeprom(i+adr);
}
return password[i];
}
|
This is its Header file:
Code: | #include <18F4550.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES WDT128 //Watch Dog Timer uses 1:128 Postscale
#FUSES HS //High speed Osc (> 4mhz)
#FUSES NOPROTECT //Code not protected from reading
#FUSES BROWNOUT //Reset when brownout detected
#FUSES BORV20 //Brownout reset at 2.0V
#FUSES NOPUT //No Power Up Timer
#FUSES NOCPD //No EE protection
#FUSES STVREN //Stack full/underflow will cause reset
#FUSES NODEBUG //No Debug mode for ICD
#FUSES LVP //Low Voltage Programming on B3(PIC16) or B5(PIC18)
#FUSES NOWRT //Program memory not write protected
#FUSES NOWRTD //Data EEPROM not write protected
#FUSES IESO //Internal External Switch Over mode enabled
#FUSES FCMEN //Fail-safe clock monitor enabled
#FUSES PBADEN //PORTB pins are configured as analog input channels on RESET
#FUSES NOWRTC //configuration not registers write protected
#FUSES NOWRTB //Boot block not write protected
#FUSES NOEBTR //Memory not protected from table reads
#FUSES NOEBTRB //Boot block not protected from table reads
#FUSES NOCPB //No Boot Block code protection
#FUSES MCLR //Master Clear pin enabled
#FUSES LPT1OSC //Timer1 configured for low-power operation
#FUSES NOXINST //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
#FUSES PLL12 //Divide By 12(48MHz oscillator input)
#FUSES CPUDIV4 //System Clock by 4
#FUSES USBDIV //USB clock source comes from PLL divide by 2
#FUSES VREGEN //USB voltage regulator enabled
#FUSES ICPRT //ICPRT enabled
#use delay(clock=20000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
|
The driver i used is a modified CCS driver:
Code: |
//////////////////////////////////////////////////////////////////////////////////
//// CLAVIER16T c-a interruption.c ////
//// Clavier matriciel 4x4 gérer par une interruption matérielle ////
//// Utilise le port D du 16F4550 ////
//// kbd_getc(); // appelle la fonction ////
//// char kbd_getc(); // retourne le caractère entrée ////
//// ////
//// Auteur : Paul Bernard ////
//// ////
//////////////////////////////////////////////////////////////////////////////////
#byte kbd = 0xF83 // adresse du porB= F81h, du porD = F83h
// #define constante équivalence elles sont remplacées par leur valeur lors de la compilation
#define set_tris_kbd(x) set_tris_d(x) // configuration du port 0=ouput, 1=input
#define COL0 (1 << 4) // COL0=décalage à gauche de 4 bit : 0001 0000
#define COL1 (1 << 5) // COL1=décalage à gauche de 5 bit : 0010 0000
#define COL2 (1 << 6) // COL2=décalage à gauche de 6 bit : 0100 0000
#define COL3 (1 << 7) // COL3=décalage à gauche de 7 bit : 1000 0000
#define ROW0 (1 << 0) // ROW0=décalage à gauche de 0 bit : 0000 0001
#define ROW1 (1 << 1) // ROW1=décalage à gauche de 1 bit : 0000 0010
#define ROW2 (1 << 2) // ROW2=décalage à gauche de 2 bit : 0000 0100
#define ROW3 (1 << 3) // ROW3=décalage à gauche de 3 bit : 0000 1000
#define ALL_ROWS (ROW0|ROW1|ROW2|ROW3) // All_ROWS=0000 1111 le résultat du OU entre Bits des vars ROWx
#define ALL_PINS (ALL_ROWS|COL0|COL1|COL2|COL3) //ALL_PINS=1111 1111 le résultat du OU entre Bits des vars ROWx et colx
// Keypad layout:
char const KEYS[4][4] ={{'1','4','7','a'}, // déclaration d'un tableau de
{'2','5','8','0'}, // caractères de votre clavier
{'3','6','9','b'}, // ( 4 lignes 4 rangées)
{'*','/','-','+'}};
char kbd_getc() // retourne le caractère entrée
{
static BYTE col;
BYTE kchar;
BYTE row;
kchar='\0'; // la variable=une chaine nulle
for (col=0;col<5;++col)
{
switch (col) // exécute l'instruction selon la valeur de col
{
case 0 : set_tris_kbd(ALL_PINS&~COL0); // &~ : ET logique avec le complément 1 de COL0
kbd=~COL0&ALL_PINS; // Le portB =~ le comp 1 de COL1 ET ALL_PIN
break; // On sort de sa structure switch
case 1 : set_tris_kbd(ALL_PINS&~COL1);
kbd=~COL1&ALL_PINS;
break;
case 2 : set_tris_kbd(ALL_PINS&~COL2);
kbd=~COL2&ALL_PINS;
break;
case 3 : set_tris_kbd(ALL_PINS&~COL3);
kbd=~COL3&ALL_PINS;
break;
}
if((kbd & (ALL_ROWS))!=(ALL_ROWS)) // si (le portb ET logique 0000 1111) n'égale pas 0000 1111
{
if((kbd & ROW0)==0) row=0; // choix de la rangée
else if((kbd & ROW1)==0) row=1;
else if((kbd & ROW2)==0) row=2;
else if((kbd & ROW3)==0) row=3;
kchar=KEYS[row][col-1];
}
}
set_tris_kbd(ALL_PINS); // configuration du portB en I/O selon la variable ALL_PINS
return(kchar);
} |
I'm sorry for the comments in french but i think the code itself isn't too complicated to read and understand. |
|