chingB
Joined: 29 Dec 2003 Posts: 81
|
Keypad using A2D Interrupt |
Posted: Sat Aug 26, 2006 1:16 am |
|
|
Hi,
I am sharing a simple code that will implement a keypad using the A2D interrupt of a PICmicro. BTW, I use the PIC18F452 chip for a circuit prototype.
The link below is the image file of the resistor network and tactile switches that will form a complete keypad circuit with an addition of an Op-Amp since the A2D input of a PICmicro has a maximum input impedance of 2.5Kohms.
Image Thumbnail:
Image HotLink:
http://img247.imageshack.us/my.php?image=keypadnetworkgx8.jpg
Below is the source code:
Code: |
/******************************************************************************
* Filename : A2D KEYPAD-B.C
* Purpose : Using the #INT_AD (A/D Interrupt) for Keypad Encoding
* Written by : Ritchie Babaylan
* Users :
******************************************************************************/
/******************************************************************************
*
* Interrupts Used:
*
* #int_ad --> an interrupt for Analog-to-Digital Conversion (10-Bit)
*
******************************************************************************/
#include <18F452> // Target PIC Microcontroller IC
#device *=16 ADC=10 // use a 16-bit pointer & 10bit A/D
#fuses HS,NOPROTECT,NOWDT // PIC MCU Configuration
#use delay(clock=20000000) // 20MHz Crystal clock speed
#use rs232(baud=115200,parity=N,xmit=PIN_B3,rcv=PIN_B2,bits=8)
/////////////////////////////////////
// Include Files //
/////////////////////////////////////
#include <LCD>
/////////////////////////////////////
/////////////////////////////////////
// PIC18F452 Config Register //
/////////////////////////////////////
unsigned char ADRESL;
#locate ADRESL=0x0FC3
unsigned char ADRESH;
#locate ADRESH=0x0FC4
unsigned char PIR1;
#locate PIR1=0x0F9E
struct {
unsigned char TMR1IF:1;
unsigned char TMR2IF:1;
unsigned char CCP1IF:1;
unsigned char SSPIF :1;
unsigned char TXIF :1;
unsigned char RCIF :1;
unsigned char ADIF :1;
unsigned char PSPIF :1;
} PIR1bits;
#locate PIR1bits=0x0F9E
unsigned char ADCON0;
#locate ADCON0=0x0FC2
struct {
unsigned char ADON :1;
unsigned char ADNONE:1;
unsigned char GODONE:1;
unsigned char CHS0 :1;
unsigned char CHS1 :1;
unsigned char CHS2 :1;
unsigned char ADCSO :1;
unsigned char ADCS1 :1;
} ADCON0bits;
#locate ADCON0bits=0x0FC2
unsigned char ADCON1;
#locate ADCON1=0x0FC1
struct {
unsigned char PCFG0 :1;
unsigned char PCFG1 :1;
unsigned char PCFG2 :1;
unsigned char PCFG3 :1;
unsigned char ANONE1:1;
unsigned char ANONE2:1;
unsigned char ADCS2 :1;
unsigned char ADFM :1;
} ADCON1bits;
#locate ADCON1bits=0x0FC1
unsigned char INTCON1;
#locate INTCON1=0x0FF2
struct {
unsigned char RBIF :1;
unsigned char INT0IF:1;
unsigned char TMR0IF:1;
unsigned char RBIE :1;
unsigned char INT0IE:1;
unsigned char TMR0IE:1;
unsigned char GIEL :1;
unsigned char GIEH :1;
} INTCON1bits;
#locate INTCON1bits=0x0FF2
/////////////////////////////////////
/////////////////////////////////////
// Defines and Macros //
/////////////////////////////////////
// Six (6) Most Significant bits of ADRESH are read as �0�
#define ADC_RIGHT_JUSTIFY 1
// Six (6) Least Significant bits of ADRESL are read as �0�
#define ADC_LEFT_JUSTIFY 0
/////////////////////////////////////
#define ADC_SIZE 8
byte adcbuffer[ADC_SIZE];
byte adc_in=0;
byte adc_out=0;
/////////////////////////////////////
// Global Flag Variables //
/////////////////////////////////////
int1 glADCdone = 0; // A/D done conversion flag bit
/////////////////////////////////////
/////////////////////////////////////
// Global Variables //
/////////////////////////////////////
unsigned int8 gi8Next=1;
unsigned int16 gi16ADCresult; // A/D result value after conversion
/////////////////////////////////////
/////////////////////////////////////
// Interrupt Service Routines //
/////////////////////////////////////
/*
The data sheet says there must be a delay of 2 x Tad
after a conversion. Since we're using a Tad of 3.2 usec,
this delay must be 2 x 3.2 = 6.4 usec. But we know that the
CCS interrupt handler takes at least that long to go in
and out of this interrupt routine (with our 20 MHz crystal),
so we don't need to put in a line of code to do the delay.
*/
#int_ad // ADC interrupt service routine
void adc_isr()
{
// read the 10-bit ADC result
// this requires reading the high and low bytes of the
// ADC register, and putting them into a 16-bit variable
gi16ADCresult = (ADRESH<<8);
gi16ADCresult |= ADRESL;
glADCdone = 1; // ADC conversion complete
while (PIR1bits.ADIF) // check if ADIF is set
PIR1bits.ADIF = 0; // set ADIF to zero
}
/////////////////////////////////////
// End Interrupt Service Routines //
/////////////////////////////////////
//void display_ADCresult()
//{
//
//}
void get_ADCresult(unsigned int16 data)
{
lcd_gotoxy(gi8Next,2);
if ((gi16ADCresult<268>786))
#asm nop #endasm
else if (data<=289){
gi8Next++; lcd_putc("1");}
else if (data<=332){
gi8Next++; lcd_putc("2");}
else if (data<=384){
gi8Next++; lcd_putc("3");}
else if (data<=432){
gi8Next++; lcd_putc("4");}
else if (data<=480){
gi8Next++; lcd_putc("5");}
else if (data<=527){
gi8Next++; lcd_putc("6");}
else if (data<=572){
gi8Next++; lcd_putc("7");}
else if (data<=617){
gi8Next++; lcd_putc("8");}
else if (data<=662){
gi8Next++; lcd_putc("9");}
else if (data<=707){
gi8Next++; lcd_putc("*");}
else if (data<=752){
gi8Next++; lcd_putc("0");}
else if (data<=786){
gi8Next++; lcd_putc("#");}
}
void nuladcbuffer() // put a NULL
{
unsigned int8 i;
for (i=0; i<ADC_SIZE; i++) // to entire buffer size
*(adcbuffer + i) = 0;
adc_in=0; // reset RF data in index
}
///////////////////////////////////
// MCU Initialization Routines //
///////////////////////////////////
//************************************************************************
void init_chip() { // Initialize the MCU Chip
lcd_init(); // LCD should be initialized first
delay_ms(100);
lcd_init(); // Init LCD again, coz sometimes can't initialize LCD
delay_ms(100);
lcd_init(); // Once more, to be sure LCD gets initialized
setup_adc_ports(RA0_ANALOG); // setup the ADC analog pins
set_adc_channel(0); // specify ADC channel to use (PortA0)
// with a 20MHz clock, we divide the oscillator by 32
// to get an ADC clock of 625KHz, so Tad=1.6usec
setup_adc(ADC_CLOCK_DIV_32); // configure the ADC clock to 1.6usec
ADCON0bits.ADON = 1; // ADC converter module is powered up
// Six (6) Most Significant bits of ADRESH are read as �0�
ADCON1bits.ADFM = ADC_RIGHT_JUSTIFY;
PIR1bits.ADIF = 0; // clear ADC interrupt before enabling
enable_interrupts(int_ad); // enable ADC interrupt
enable_interrupts(global); // enable global interrupt
}
///////////////////////////////////
//End MCU Initialization Routines//
///////////////////////////////////
//************************************************************************
// Main Program
//************************************************************************
main()
{
init_chip(); // Initialize the MCU Chip
lcd_putc("\fADC Demo");
nuladcbuffer();
gi16ADCresult = 0; // initialize the ADC result variable to zero
delay_us(20); // wait for ADC aquisition time
ADCON0bits.GODONE = 1; // start an ADC conversion
while (TRUE)
{
if (glADCdone) // ADC conversion completed
{
glADCdone = 0; // prevent multi-trigger of ADC conversion
get_ADCresult(gi16ADCresult);
printf("ADC Result = %lx ADC Steps = %lu\n\r",gi16ADCresult,gi16ADCresult); // print the result
// for demo purpose delay 1sec. for screen updating with
// the new ADC result
delay_ms(100);
ADCON0bits.GODONE = 1; // start another ADC conversion
}
}
}
//************************************************************************
// End Program
//************************************************************************
|
Thanks to ImageShack for Free Image Hosting
Hope this will help in the community.
Enjoy
... |
|