A Universal Advanced Keypad Library
-
Upload
katrin-polvorosa -
Category
Documents
-
view
127 -
download
6
Transcript of A Universal Advanced Keypad Library
A Universal Advanced Keypad Library
Printer-friendly version | Forums | FAQs |
Getting an input from a user may seem trivial, but in real word it will lead to resolve some problems like switch bounce, input correction, input validation, polling function in each major loop of the program, and so on...
Here is a very convenient way to solve them : this interrupt-based keypad library will do it for you.
Page index :
Why another PIC Keypad LIBRARY ? Library functions Configuration Circuit example MikroC source code example Project download
Why another PIC Keypad LIBRARY ?
There are already tons of keypad PIC libraries on the web, but I think this one will be the most universal and versatile, featuring :
keypad up to 8x8 or buttons up to 8 fully configurable I/O :
o user defined ports o in keypad mode row port and column port may be different o user defined bits in port o user defined rows and columns number
user defined character lookup table user defined erase and enter keys works on interrupt : no polling necesary, no key lost auto debounce, delay is user defined switchable typematic (auto-repeat) mode at run time, rate is user defined switchable linear/circular buffer mode at run time input is available at any time in a string buffer maximum input size is user defined other functions :
o last key entered
o keypad status...
Learn more below :
Library Functions
PROTOTYPE void kp_init()
PARAMETERS None
RETURNS Nothing
DESCRIPTIONprepare the PIC keypad and button library.this function must be called before enabling timer interrupt.
REQUIRESthe file keypad_cfg.h must be set accordingly to user's hardware (see below)
EXAMPLE kp_init() ;
PROTOTYPE unsigned char kp_full()
PARAMETERS None
RETURNS return > 0 if the buffer is full, 0 otherwise
DESCRIPTION check for buffer full
REQUIRES kp_init() must have been called and timer interrupt must be enabled
EXAMPLE if(kp_full()) return ; // return if buffer full
PROTOTYPE unsigned char kp_hit()
PARAMETERS None
RETURNS return > 0 if a key is being pressed, 0 otherwise (pseudo function)
DESCRIPTION check for a key hit
REQUIRES kp_init() must have been called and timer interrupt must be enabled
EXAMPLE while(kp_hit()) ; // wait for key to be released
PROTOTYPE unsigned char kp_enter()
PARAMETERS none
RETURNS return > 0 if enter key has been pressed, 0 otherwise (pseudo function)
DESCRIPTION check for enter key
REQUIRES kp_init() must have been called and timer interrupt must be enabled
EXAMPLE if(kp_enter()) { ... } // do input treatment on enter key
PROTOTYPE unsigned char kp_erase()
PARAMETERS none
RETURNS return > 0 if last key was erase , 0 otherwise (pseudo function)
DESCRIPTION check for erase key
REQUIRES kp_init() must have been called and timer interrupt must be enabled
EXAMPLE if(kp_erase()) { ... } // do input treatment on erase key
PROTOTYPE unsigned char kp_last()
PARAMETERS none
RETURNS return last key pressed
DESCRIPTION get last key
REQUIRES kp_init() must have been called and timer interrupt must be enabled
EXAMPLE switch(kp_last()) { ... } // process keys
PROTOTYPE void kp_setCircular()
PARAMETERS none
RETURNS nothing
DESCRIPTION
switch on circular mode on input buffer :when buffer is full, new entry will cause the buffer to be left shifted (character at first position will be lost)new entry is then added to the end of the buffer.
REQUIRES kp_init() must have been called and timer interrupt must be enabled
EXAMPLE kp_setCircular() ;
PROTOTYPE void kp_setLinear()
PARAMETERS none
RETURNS nothing
DESCRIPTIONswitch on linear mode on input buffer :when buffer is full, new entry will be ignored.
REQUIRES kp_init() must have been called and timer interrupt must be enabled
EXAMPLE kp_setLinear() ;
PROTOTYPE unsigned char kp_circular()
PARAMETERS none
RETURNS return > 0 if input buffer is in circular mode, 0 otherwise.
DESCRIPTION check for buffer circular mode, default is linear mode.
REQUIRES kp_init() must have been called and timer interrupt must be enabled
EXAMPLE if(kp_circular()) kp_setLinear() ;
PROTOTYPE void kp_setTypematic()
PARAMETERS none
RETURNS nothing
DESCRIPTION switch on typematic (auto-repeat) mode
REQUIRES kp_init() must have been called and timer interrupt must be enabled
EXAMPLE kp_setTypematic() ;
PROTOTYPE void kp_unsetTypematic()
PARAMETERS none
RETURNS nothing
DESCRIPTION switch off typematic (auto-repeat) mode
REQUIRES kp_init() must have been called and timer interrupt must be enabled
EXAMPLE kp_unsetTypematic() ;
PROTOTYPE unsigned char kp_typematic()
PARAMETERS none
RETURNS return > 0 if typematic (auto-repeat) in enable, 0 otherwise.
DESCRIPTION return typematic state, default is not enabled.
REQUIRES kp_init() must have been called and timer interrupt must be enabled
EXAMPLE if(kp_typematic()) kp_unsetTypematic() ;
PROTOTYPE void kp_flush()
PARAMETERS none
RETURNS nothing
DESCRIPTION flush input, buffer is cleared
REQUIRES kp_init() must have been called and timer interrupt must be enabled
EXAMPLE kp_flush() ;
PROTOTYPE void kp_isr()
PARAMETERS none
RETURNS nothing
DESCRIPTION
this function must not be called directly by user, but must be placed in the timer interrupt() function.
the input is stored in buffer kp_buf, defined as a pointer to char.
REQUIRES kp_init() must have been called
EXAMPLE
void interrupt(void) { if(INTCON.T0IF) // timer 0 overflow ? { kp_isr() ; // call keypad service routine
INTCON.T0IF = 0 ; // done } }
Configuration
Keypad configuration is defined in file keypad_cfg.h, you can change it depending on your hardware and preferences :
SYMBOL USAGE EXAMPLE
KEYPAD_MODE
define this symbol if you are using a keypad (rows and colums)do not define this symbol if you are using buttons (colums only)
#define KEYPAD_MODE
KP_ROW_PORTPORT where rows are connected to(only if KEYPAD_MODE is defined)
#define KP_ROW_PORT PORTB
KP_ROW_TRISTRIS direction register corresponding to KP_ROW_PORT(only if KEYPAD_MODE is defined)
#define KP_ROW_TRIS TRISB
KP_ROW_BITNUMbit number of the first row in the PORT, other bits must be next and contiguous(only if KEYPAD_MODE is defined)
#define KP_ROW_BITNUM 0
KP_ROW_NUMBERnumber of rows(only if KEYPAD_MODE is defined)
#define KP_ROW_NUMBER 3
KP_COL_PORTPORT where columns are connected to.Each column input must be pulled down with a 10 K resistor.
#define KP_COL_PORT PORTB
KP_COL_TRISTRIS direction register corresponding to KP_COL_PORT
#define KP_COL_TRIS TRISB
KP_COL_BITNUMbit number of the first row in the PORT, other bits must be next and contiguous
#define KP_COL_BITNUM 3
KP_COL_NUMBER number of columns#define KP_COL_NUMBER 4
KP_SCAN_CODES scan codes lookup tablekeypad must be considered this way :
#define KP_SCAN_CODES
the top left key is the first one, the bottom right key is the last one.you have to read from top to bottom and from left to right : * 7 4 1 0 8 5 2 # 9 6 3
"*7410852#963"
KP_ERASE
erase key, must be one in KP_SCAN_CODES stringdon't define it if you don't need an erase key
#define KP_ERASE '*'
KP_ENTER
enter key, must be one in KP_SCAN_CODES stringdon't define it if you don't need an enter key
#define KP_ENTER '#'
KP_MAX_LENGTH maximum input length#define KP_MAX_LENGTH 16
KP_TMR_REPEAT
typematic rate, must be set depending on timer overflow period and user's preferences.you can use this formula :KP_TMR_REPEAT = (Fosc / 4 / TMR_PRESCALER / (2 ^ TMR_BITS)) * DELAY_REPEATwhere :Fosc is the frequency of the oscillator in Herz. For example if you are using a 8 Mhz crystal with HS clock mode, then Fosc = 8000000TMR_PRESCALER is the prescaler (or postscaler if any) value of your timer. For example if you are using a 1:1 prescaler then TMR_PRESCALER = 1TMR_BITS is the number of bits of your
#define KP_TMR_REPEAT 2343
timer, it is either 8 or 16DELAY_REPEAT is the delay in second before the next auto repeat.
when using a PIC16F877A @ 8 Mhz with 8 bit TMR0 and no prescaler, if you want an auto repeat rate of 300 ms, use :KP_TMR_REPEAT = (8000000 / 4 / 1 / (2 ^ 8)) * .3 = 2343
KP_TMR_DEBOUNCE
debounce time, must be set depending on timer overflow period and user's preferences.you can use this formula :KP_TMR_DEBOUNCE = (Fosc / 4 / TMR_PRESCALER / (2 ^ TMR_BITS)) * DEBOUNCE_DELAYwhere :Fosc is the frequency of the oscillator in Herz. For example if you are using a 8 Mhz crystal with HS clock mode, then Fosc = 8000000TMR_PRESCALER is the prescaler (or postscaler if any) value of your timer. For example if you are using a 1:1 prescaler then TMR_PRESCALER = 1TMR_BITS is the number of bits of your timer, it is either 8 or 16DEBOUNCE_DELAY is the delay in second before the keyboard to be read again.
when using a PIC16F877A @ 8 Mhz with 8 bit TMR0 and no prescaler, if you want a debounce time of 30 ms, use :KP_TMR_DEBOUNCE = (8000000 / 4 / 1 / (2 ^ 8)) * .03 = 234
#define KP_TMR_DEBOUNCE 234
KP_MAX_LENGTH maximum input length#define KP_MAX_LENGTH 16
CIRCUIT EXAMPLE
Click on the picture to enlargeColumns must be pulled down, use resistors from 4K7 to
22K.
Don't forget that columns are from bottom to top, and rows for left to right. This arrangement is due to code simplification, because library can work with buttons too.
If you use buttons only instead of keypad, they must also be pulled down.In this case, there is no row but only columns.
MIKROC SOURCE CODE EXAMPLE
Here is the mikroC source code of the program example. You have to use the zipped mikroC project to build it.
/* ******************************************************************************* * PIC ADVANCED UNIVERSAL KEYPAD LIBRARY ******************************************************************************* * * source code example for mikro C compiler * feel free to use this code at your own risks * * target : PIC16F877A, 8 Mhz crystal * HS clock, no watchdog. * * Author : Bruno Gavand, October 2007 * see more details on http://www.micro-examples.com/ * * This program shows how to use the library : * 4 bit LCD is connected to PORTD (EasyPIC4 board) * edit keypad_cfg.h header file to configure your own keypad * * LCD Line 1 : welcome message and keypad status symbols * LCD Line 2 : string as keyed in by user * * type 123 + enter to toggle circular/linear buffer mode * type 321 + enter to toggle typematic mode on/off * ******************************************************************************* */#include "keypad_lib.h" // keypad library header, includes also user's settings
/* * LCD custom characters */const char erase_char[] = {2,6,14,31,14,6,2,0} ; // erase key typedconst char enter_char[] = {1,1,5,13,31,12,4,0} ; // enter key typedconst char full_char[] = {0,10,21,10,21,10,0,0} ; // buffer is fullconst char hit_char[] = {0,4,4,4,31,14,4,0} ; // a key is pressedconst char circ_char[] = {16,24,28,25,19,7,3,1} ; // buffer is in circular modeconst char type_char[] = {31,21,21,4,4,4,4,14} ; // typematic enabled
/*
* print custom character pointed to by def at line pos_row column pos_char on LCD */void CustomChar(const char *def, unsigned char n, char pos_row, char pos_char) { char i ;
LCD_Cmd(64 + n * 8) ; for(i = 0 ; i <= 7 ; i++) { LCD_Chr_Cp(def[i]) ; } LCD_Cmd(LCD_RETURN_HOME) ; LCD_Chr(pos_row, pos_char, n) ; }
/* * interrupt routine, called on each timer0 overflow */void interrupt(void) { if(INTCON.T0IF) // timer 0 overflow ? { kp_isr() ; // call keypad service routine
INTCON.T0IF = 0 ; // done } }
/* * program entry */void main() { /* * init LCD */ LCD_Init(&PORTD) ; LCD_Cmd(LCD_CLEAR) ; LCD_Out(1, 1, "KeypadLib") ; LCD_Cmd(LCD_SECOND_ROW) ;
/* * init keypad and library */ kp_init() ;
/* * configure timer0 rollover interrupt * period is Fosc / 4 / 256 */ OPTION_REG = 0x80 ; // start timer 0, no prescaler
INTCON = 0xA0 ; // allow timer 0 interrupt
for(;;) // forever { if(kp_hit()) // if a key is pressed { LCD_Cmd(LCD_CURSOR_OFF) ; // no cursor CustomChar(hit_char, 1, 1, 12) ; // display hit symbol
if(kp_enter()) // if enter key is pressed { CustomChar(enter_char, 2, 1, 13) ;
if(strcmp(kp_buf, "123") == 0) // if entry is 123 { if(kp_circular()) // toggle buffer circular/linear mode { kp_setLinear() ; } else { kp_setCircular() ; } } else if(strcmp(kp_buf, "321") == 0) // if entry is 321 { if(kp_typematic()) // toggle typematic (auto-repeat) mode { kp_unsetTypematic() ; } else { kp_setTypematic() ; } } kp_flush() ; // clear entry buffer } else { LCD_Chr(1, 13, ' ') ; }
/* * buffer full symbol */ if(kp_full()) {
CustomChar(full_char, 0, 1, 11) ; } else { LCD_Chr(1, 11, ' ') ; }
/* * erase key symbol */ if(kp_erase()) { CustomChar(erase_char, 3, 1, 14) ; } else { LCD_Chr(1, 14, ' ') ; }
/* * circular mode symbol */ if(kp_circular()) { CustomChar(circ_char, 4, 1, 15) ; } else { LCD_Chr(1, 15, ' ') ; }
/* * typematic mode symbol */ if(kp_typematic()) { CustomChar(type_char, 5, 1, 10) ; } else { LCD_Chr(1, 10, ' ') ; }
LCD_Chr(1, 16, kp_last()) ; // display last char keyed in LCD_Chr(1, 12, ' ') ; // clear hit symbol
LCD_Out(2, 1, " ") ; // clear old buffer display LCD_Out(2, 1, kp_buf) ; // display current buffer
LCD_Cmd(LCD_BLINK_CURSOR_ON) ; // blink cursor
} } }
PROJECT DOWNLOAD
You can use this software as you wish, if you accept to do it at your own risks.
Download PIC Keypad Library C source code with demo example for mikroC : zipped file, 6
Ko
content of the archive :
keypad_lib.c, 10 Ko : library C source code keypad_lib.h, 3 Ko : library C definitions keypad_cfg.h, 2 Ko : user's configuration keypad.ppc, 1 Ko : mikroC project file keypad.c, 8 Ko : demo example for PIC16F877A
You can get mikroC from here : http://www.mikroe.com/en/compilers/mikroc/pic/
Please report any bug, comment or suggestion in my forums. Thanks !
FORUMSMicrocontrollers Project ExamplesNEW:: picoDetector : How to detect metal with a PICpicoBAT, an ultrasonic bat detector with 3 componentsLCDscope, not a GLCD but a text LCD
A PIC16F84A Alarm Clock
Printer-friendly version | Forums | FAQs |
oscilloscopeTouchClock : Design your own GLCD ClockComing Soon : Ethernal clock, a digital SNTP clock with embedded web serverPico OSD, a PIC video superimposerPicOClock, a PIC Oscilloscope ClockA Universal Advanced Keypad LibraryA PIC16F84A Alarm ClockBinary File to C, Basic and Pascal ConverterPIC16F877A Thermometer with MCP9700A sensorMysterious Opcodes in PIC16 Instruction Set !A Voice Controlled LED Light ShowPIC PAL Video Library
Photo : credits to Samir who built this clock
Here is a simple PIC16F84A alarm clock. This page summarizes this discussion (in french) in my forum, where Samir (aka numerique1) requested for help to build a weekly alarm clock for his school. Many thanks to him for his tests and patience.
This clock counts seconds, minutes, hours and day of the week.Time is displayed on 4 seven segment LED displays, and is adjustable with three buttons at start time (up, down, enter).You can program the day of the week, hour, minute and duration of the alarms.The number of alarms are limited by ROM space only.The alarm is on the RA4 open collector output of the PIC, and is repeated on a decimal point of the display.
For once, the program is in BASIC (mikroBasic) and I hope it will make a good start for beginners.
First, the BASIC source code.
Note that you can build it either for common cathod or common anode LED display.
'******************************************************************************' PIC16F84A ALARM CLOCK'******************************************************************************'' feel free to use this code at your own risks'
The Secret Functions of MikroC Ethernet Library for ENC28J60A Cheap Ultrasonic Range FinderA PIC16F819 DYMOCLOCKPIC16F84A MemoSound GameEasyPic3 Programming Status LEDEasyPic2 with on-board Ethernet AdapterC, Pascal & Basic to ASM translatorAutomatic LED display dimmerPIC PWM Calculator & Code GeneratorSimple & Cheap ThermometerMultiple non-blocking delays with 1 timerDCF-77 PIC LED clockSimple Frequency MeterSingle-Tube nixie clock
' target : PIC16F84A, 16 Mhz crystal' HS clock, no watchdog.'' Author : Bruno Gavand, September 2007' see more details on http://www.micro-examples.com/''******************************************************************************
program alarmClock
'' if you are using COMMON CATHODE LED display, uncomment this definition.' if you are using COMMON ANODE LED display, comment this definition.''#define CATHODE_COMMUNE
symbol LUNDI = 0 ' mondaysymbol MARDI = 1 ' thuesdaysymbol MERCREDI = 2 ' wednesdaysymbol JEUDI = 3 ' thursdaysymbol VENDREDI = 4 ' fridaysymbol SAMEDI = 5 ' saturdaysymbol DIMANCHE = 6 ' sundaysymbol LMMJV = 7 ' from monday to friday included
'' alarm definitions, to be changed on your needs'symbol NBALARM = 16 ' number of programmed alarms
const alarmTable as byte[NBALARM * 4] = (' JOUR HEURE MINUTE DUREE (secondes, 59 maxi)' DAY HOUR MINUTE DURATION (in seconds, max is 59) LUNDI, 8, 30, 10, LUNDI, 12, 30, 10, LUNDI, 14, 00, 10, LUNDI, 16, 30, 10, MARDI, 8, 30, 10, MARDI, 12, 30, 10, MARDI, 14, 00, 10, MARDI, 16, 30, 10, JEUDI, 8, 30, 10, JEUDI, 12, 30, 10, JEUDI, 14, 00, 10, JEUDI, 16, 30, 10, VENDREDI, 8, 30, 10, VENDREDI, 12, 30, 10, VENDREDI, 14, 00, 10, VENDREDI, 16, 30, 10 )
EasyPic2 programming status LEDPIC FAQsPIC .HEX Test Files Free DownloadLED Blinking ExampleVR Stamp development kit by mikroElektronikaSudoku SolverOnline ShopSite & Web SearchLinksAbout the AuthorDid you find this site useful ? Please
to help www.micro-
examples.com
If you need a coder or a freelance programmer, submit your project to me
Demandez à Google de traduire cette page en
dim maxcount as word ' number of TMR0 overflow per seconddim scaler as word ' RTC scalerdim jj as byte ' day of week, 0 is mondaydim hh as byte ' hourdim mn as byte ' mindim ss as byte ' secdim digiled as byte[4] ' 4 x 7 segment tabledim digit as byte ' number of current digit to be displayeddim dp as byte ' decimal pointdim key as byte ' key codedim alarm as byte ' alarm flag
'' the ISR works as real time clock'sub procedure interrupt dim i as byte
'' count time' scaler = scaler + 1 if scaler > maxcount then scaler = 0
inc(ss) if ss = 60 then ss = 0 inc(mn) if mn = 60 then mn = 0 inc(hh) if hh = 24 then hh = 0 inc(jj) if jj = 8 then jj = 1 end if end if end if end if end if
'' LED display'#ifdef CATHODE_COMMUNE
_s-xclick
-----BEGIN PKCS7
français PORTA = PORTA and $f0 TRISA = $0f key = PORTA TRISA = 0 PORTB = 0#else PORTA = PORTA or $0f TRISA = $0f key = PORTA key = not(key) TRISA = 0 PORTB = $ff#endif key = key and $07
digit = digit + 1
if digit > 3 then digit = 0 i = $01 else i = $01 << digit end if
#ifdef CATHODE_COMMUNE PORTB = digiled[digit] PORTA = PORTA or i#else PORTB = digiled[digit] PORTB = not(PORTB) PORTA = PORTA and not(i)#endif
INTCON.T0IF = 0end sub
'' converts digit to 7 segment'sub function intTo7seg(dim n as byte) as byte select case n case 0 result = $3F case 1 result = $06 case 2 result = $5B case 3 result = $4F case 4 result = $66 case 5 result = $6D case 6 result = $7D case 7 result = $07 case 8 result = $7F case 9 result = $6F end selectend sub
'' select a value with keys' value is pointed to by v, display char s as header, maximum value is max'sub procedure setValue(dim v as ^byte, dim s as byte, dim max as byte) digiled[0] = s digiled[1] = 0
while 1 if key.0 then inc(v^) if(v^ > max) then v^ = 0 end if end if
if key.1 then if(v^ = 0) then v^ = max else dec(v^) end if end if
if key.2 then Delay_ms(50) while key.2 wend Delay_ms(50) scaler = 0 ss = 0 return end if
digiled[2] = intTo7seg(v^ / 10) digiled[3] = intTo7seg(v^ mod 10)
delay_ms(300) wendend sub
'' program entry'main: dim i as byte
'
' init variables' dp = 0
hh = 0 mn = 0 ss = 0 jj = 0
maxcount = 15625
'' init I/O' PORTA = %00010000 TRISA = %00000000
PORTB = 0 TRISB = $00
'' init interrupts' INTCON = %10100000 OPTION_REG = %11011000
Delay_ms(50)
'' clock adjustment' setValue(@hh, 116, 23) setValue(@mn, 55, 59) setValue(@jj, 14, 6)
'' forever loop' while true if key then'' display day and seconds (what for ? don't remember !)' digiled[0] = intTo7seg(jj) digiled[1] = 0 digiled[2] = intTo7seg(ss / 10) digiled[3] = intTo7seg(ss mod 10) else'' display hours and minutes' if hh < 10 then digiled[0] = 0
digiled[1] = intTo7seg(hh) else digiled[0] = intTo7seg(hh / 10) digiled[1] = intTo7seg(hh mod 10) end if digiled[2] = intTo7seg(mn / 10) digiled[3] = intTo7seg(mn mod 10) end if
'' blinks semicolon (or decimal point)' if scaler > maxcount / 2 then dp.1 = 1 else dp.1 = 0 end if
'' set decimal points' digiled[0].7 = dp.0 digiled[1].7 = dp.1 digiled[2].7 = dp.2 digiled[3].7 = dp.3
'' check for alarm condition' alarm = 0 for i = 0 to (NBALARM - 1) * 4 if ((alarmTable[i] = jj) or ((alarmTable[i] = LMMJV) and (jj < SAMEDI))) and (alarmTable[i + 1] = hh) and (alarmTable[i + 2] = mn) and (alarmTable[i + 3] > ss) then inc(alarm) end if next i
if alarm then'' set alarm' dp.3 = 1 PORTA.4 = 0 else'
' clear alarm' dp.3 = 0 PORTA.4 = 1 end if wendend.
Here is the circuit schematic (click on the picture to get a full sized image) :
All trademarks and registered trademarks are the property of their respective owners
Automatic RoomLight Controller Automatic School Timer AVR Development Board Baby Incubator Car Parking Monitoring System Cellphone Operated Robot Controller Area Network CAN Electronic Voting Machine Floor Cleaner GreenHouse Robot Industrial control Using Cellphone Pick And Place Robot Public Garden Management Combat Robot Submarine Robot Temperature Controlled Fan Time Based Device Controlling Level Computing & Storage Device Person counter & Pwrd detector Temperature & Light monitoring Rolling display using Matrix LEDs Home Security System Greenhouse Monitor & Control