Implementacja obsługi klawiatur pojemnościowych w LPC17xx firmy NXP
W następnym etapie programu wykonywana jest kalibracja (funkcja calibrateAllChannels()). Polega ona na oszacowaniu przybliżonej wartości napięcia w każdym z aktywnych kanałów przetwornika A/C w stanie nienaciśnięcia przycisku. Odczyt każdego kanału wykonywany jest 200 razy, po czym obliczana jest wartość średnia pomiaru (listing 3, listing 4).
Listing 3. Wykonywana w pętli kalibracja aktywnych kanałów przetwornika A/C
/* calibration loop function */ void calibrateAllChannels(void) { KeypadIdType i; for(i=KBD1; i< NUM_KPAD; i++) if (UNUSED_CHANNEL != Kpad2ChMap[i]) _calibrateChannel(Kpad2ChMap[i]); }
Listing 4. Proces kalibracji pojedynczego kanału przetwornika A/C
/* calibration channel function */ #define CALIBRATION_LOOP (200) static void _calibrateChannel(ChannelIdType chNum) { int calibCntr; for (calibCntr=0; calibCntr < CALIBRATION_LOOP; calibCntr++) { reading[chNum] = (*AdcReadTable[chNum])(chNum); updateAverage(chNum); } }
Po wykonaniu powyższej konfiguracji mikrokontroler rozpoczyna etap pracy właściwej. Polega on na przejściu układu w tryb uśpienia, z którego cyklicznie jest budzony (co 10 ms) pod wpływem przerwania od licznika systemowego Systick (listing 5).
Listing 5.
/* config systick to generate interrupts at 100HZ - 10ms rate */ SysTick_Config(SystemFrequency/100); while (1) { __wfi(); /* processor goes to sleep in between readings */ processKeystrokes(); /* activate keystroke callbacks if key press detected */ }
W momencie wybudzenia mikrokontrolera z trybu uśpienia wywoływana jest funkcja od przerwania - SysTick_Handler() (listing 6).
Listing 6.
void SysTick_Handler(void) { /* iterate through the active channel list to perform readings */ processChannels(); /* just simple heartbeat indication, toggle every second */ cntr++; if(cntr == 49) { toggleLed(); cntr=0; } }
Umieszczona tam funkcja processChannels() odczytuje wartość napięcia z wyprowadzeń podłączonych do obwodów RC przycisków pojemnościowych. Odczytane wartości zapisywane są do tabeli reading[] (listing 7).
Listing 7.
/* this function iterates through the channels and reads the adc values */ /* result is stored within the reading array */ void processChannels(void) { ChannelIdType currentChannel; if(USE_KBD1) { currentChannel = Kpad2ChMap[KBD1]; reading[currentChannel] = (*AdcReadTable[currentChannel])(currentChannel); }; if(USE_KBD2) { currentChannel = Kpad2ChMap[KBD2]; reading[currentChannel] = (*AdcReadTable[currentChannel])(currentChannel); }; if(USE_KBD3) { currentChannel = Kpad2ChMap[KBD3]; reading[currentChannel] = (*AdcReadTable[currentChannel])(currentChannel); }; if(USE_KBD4) { currentChannel = Kpad2ChMap[KBD4]; reading[currentChannel] = (*AdcReadTable[currentChannel])(currentChannel); }; if(USE_KBD5) { currentChannel = Kpad2ChMap[KBD5]; reading[currentChannel] = (*AdcReadTable[currentChannel])(currentChannel); }; if(USE_KBD6) { currentChannel = Kpad2ChMap[KBD6]; reading[currentChannel] = (*AdcReadTable[currentChannel])(currentChannel); }; if(USE_KBD7) { currentChannel = Kpad2ChMap[KBD7]; reading[currentChannel] = (*AdcReadTable[currentChannel])(currentChannel); }; if(USE_KBD8) { currentChannel = Kpad2ChMap[KBD8]; reading[currentChannel] = (*AdcReadTable[currentChannel])(currentChannel); }; }