In my last Post I implement "Key debounce" with Port polling, Port polling was not very efficient. And this time, I'll use the change notification instead of port polling. It generates interrupt and starts debounce when the level of digital ports changes, so it would eliminate the MCU load of PO RT polling.
On my pic32mz EC Starter Kit, every i/O port pin (RAX-RKX) can be used as a change notification pin (CNAX-CNKX). The CN pins is configured as follows:
1.Disable CPU interrupts.
2.Set the desired CN I/o pin as an input by setting the corresponding TRISx register bits = 1.
3.Enable the CN Module by setting the on bit (cnconx<15>) = 1.
4.Enable Individual CN input pins, Enable optional pull-ups or pull-downs.
5.Read The corresponding PORTX registers to clear the CN interrupt.
6.Configure the CN Interrupt priority bits, cnip<2:0> (ipc6<20:18>), and Sub-priority BITS,CNIS<1:0&G T (ipc6<17:16>).
7.Clear the CN Interrupt Flag bit, by setting the cnif bit (ifs1<0>) = 0.
8.Configure the CN pin interrupt for a specific edge detect using the Edgedetect bit in the Cnconx register, and set Up edge control using the Cnenx/cnnex bits.
9.Enable the CN Interrupt Enable bit, by setting the Cnie bit (iec1<0>) = 1.
10.Enable CPU interrupts.
The CNSTATX registers indicate whether a change occurred on the corresponding PIN since the last read of the PORTX bit. It is ridiculous, that data sheet, or reference manual mentions Cnstatx register but not gives no figure or details. After so many times retry. I get to know it have to clear cnstatx bit corresponding to CN pin in the CN interrupt Service routine. Otherwise, the interrupt service routine may isn't work.
Anyway, I get this change notification application work, and the following is the implementation.
TIMER module:
void timer1_init (void = 0x8010 ; PR1 = 0x30d3 ; Ipc1set = 0x5 ; TMR1 = 0 ; Iec0set = 0x10 ; IFS0CLR = 0x10 void Timer1_write (unsigned int value) {TMR1 = Value & 0xffff ;}
KEY Module (Enable change notification interrupt, debounce function):
#define DEBOUNCE_INPUT (PORTB & 0x1000)
#define Debounce_open () Anselb = 0xFFFFEFFF
#define DEBOUNCE_IOCTL () Cnpubset = 0x1000
#define Debounce_output Ledstate
#define DEBOUNCE_THREHOLDLOW 0
#define DEBOUNCE_THREHOLDHIGH 100
extern volatile unsigned char debounce_timeflag;
extern volatile unsigned char debounce_eventstart;
volatileUnsignedCharDebounce_eventstart; //volatile unsigned char debounce_timeflag;UnsignedLongDebounce_preinput; unsignedintDebounce_integrator; voidKey_init (void) {Debounce_eventstart=0; Debounce_integrator= Debounce_threholdhigh/2; //debounce_timeflag = 0;Debounce_open (); Debounce_ioctl (); Debounce_preinput=Debounce_input; Cnenbset=0x1000; Ipc29set=0x12000000; IFS3CLR=0x800000; Iec3set=0x800000; Cnconbset=0x8000; } voidKey_debounce (void) { if(Debounce_eventstart) {if(Debounce_input = =0) { if(debounce_integrator--= =Debounce_threholdlow) {Debounce_output=0; Debounce_preinput=Debounce_input; Debounce_eventstart=0; Debounce_integrator= Debounce_threholdhigh/2; } } Else //if (debounce_input = = 1) { if(debounce_integrator++ = =Debounce_threholdhigh) {Debounce_output=1; Debounce_preinput=Debounce_input; Debounce_eventstart=0; Debounce_integrator= Debounce_threholdhigh/2; } } } }
LED module:
#defineLed_ioctl () trishclr = (1<<0)#defineLed_seton () Lathset = (1<<0)#defineLed_setoff () lathclr = (1<<0)#defineLed_onoff () Lathinv = (1<<0)#defineLed_open () Anselh &= 0xFFFFFFFEtypedefenum_led_state_t {/*Describe structure member.*/OFF=0, /*Describe structure member.*/ on=1} led_state_t; led_state_t preledstate, ledstate;voidLed_init (void) {led_open (); Led_ioctl (); Led_seton (); Ledstate=On ; Preledstate=ledstate;}voidLed_scheduler (void){ if(Ledstate! =preledstate) {Led_onoff (); Preledstate=ledstate; }}
Main module (main function, Timer1 ISR, CNB ISR):
#include <xc.h>#include"Led.h"#include"Key.h"#include"Timer.h"#include"Interrupt.h"#include<sys/attribs.h>#include"ConfigurationBits.h"void__ISR (_change_notice_b_vector,ipl4auto) Cnb_handler (void){ if((CNSTATB &0x1000) ==0x1000) {Debounce_eventstart=1; CNSTATBCLR=0x1000; unsignedLongTMP =Debounce_input; } ifs3clr=0x800000;}void__ISR (_timer_1_vector,ipl1auto) Timer1_handler (void){ //debounce_timeflag = 1;key_debounce (); Timer1_write (0); IFS0CLR=0x10;//Clear Flag }voidMainvoid) {led_init (); Key_init (); Timer1_init (); Mvec_interrupt (); while(1) {Led_scheduler (); }}
PIC32MZ Tutorial--Change Notification