PIC32MZ tutorial -- Change Notification
2015-12-20 21:01
190 查看
In my last post I implement "Key Debounce" with port polling, port polling is not very efficient. And this time, I will use change notification instead of port polling. It generates interrupt and starts debounce when the level of digital port changes, so it will eliminate the MCU load of port 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 are 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> (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 gives no figure or details. After so many times retry, I get to know it has to clear CNSTATx bit corresponding to CN pin in the CN interrupt service routine. Otherwise, the interrupt service routine may not work.
Anyway, I get this change notification application work, and the following is the implementation.
TIMER module:
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;
LED module:
MAIN module (main function, timer1 ISR, CNB ISR):
The application runs well on PIC32MZ EC Starter Kit, SW1(connects to RB12) pressed, LED1(RH0) is off, SW1 released, LED1 is on.
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 are 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> (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 gives no figure or details. After so many times retry, I get to know it has to clear CNSTATx bit corresponding to CN pin in the CN interrupt service routine. Otherwise, the interrupt service routine may not work.
Anyway, I get this change notification application work, and the following is the implementation.
TIMER module:
void Timer1_Init(void) { T1CON = 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;
volatile unsigned char DEBOUNCE_EventStart; //volatile unsigned char DEBOUNCE_TimeFlag; unsigned long DEBOUNCE_PreInput; unsigned int DEBOUNCE_Integrator; void Key_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; } void Key_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:
#define LED_IOCTL() TRISHCLR = (1<<0) #define LED_SETON() LATHSET = (1<<0) #define LED_SETOFF() LATHCLR = (1<<0) #define LED_ONOFF() LATHINV = (1<<0) #define LED_OPEN() ANSELH &= 0xFFFFFFFE typedef enum _LED_STATE_t { /* Describe structure member. */ OFF = 0, /* Describe structure member. */ ON = 1 } LED_STATE_t; LED_STATE_t PreLedState, LedState; void Led_Init(void) { LED_OPEN(); LED_IOCTL(); LED_SETON(); LedState = ON; PreLedState = LedState; } void Led_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; unsigned long tmp = 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 } void main(void) { Led_Init(); Key_Init(); Timer1_Init(); Mvec_Interrupt(); while (1) { Led_Scheduler(); } }
The application runs well on PIC32MZ EC Starter Kit, SW1(connects to RB12) pressed, LED1(RH0) is off, SW1 released, LED1 is on.
相关文章推荐
- [u-boot] Net: smc911x: Invalid chip endian 0xc691c691 解决方案
- JAVA WEB连接mysql数据库编程
- Mysql常用命令
- Effective C++ 笔记目录
- React-用ImmutableJS提高性能
- tomcat脚本启动正常,服务无法启动,特定错误代码1
- [Medical Image Process] 3.4 Morphology Application—Watershed Algorithm 分水岭算法
- 【C#学习】——集合和数组
- ucosIII 互斥信号量、内嵌信号量
- Android进阶——声波振幅显示
- Leetcode 第268题Missing Number
- android studio ndk开发遇到的问题
- this的用法
- HDU 1072 Nightmare
- OSSEC初探
- linux编码
- 信息安全系统设计基础第十周学习总结
- Linux下执行定时任务
- c++学习笔记
- Ubuntu15.10 编译 Android4.1.1 源码