现象解释:
KED1双边沿控制LED1:按下亮松开灭
KEY2下降沿控制LED2 第一次按下即亮,第二次按下灭
KEY2上升沿控制LED3:第一次松开即亮,第二次松开即灭
这个比较简单,直接贴出代码,大家可以验证一下。
main.c
#include "nuc1xx.h"
#include "DrvSYS.h"
/**********************************************************
* 宏定义
**********************************************************/
typedef enum{NO=0, YES=!NO}BOOL_T;
/* GPIO宏定义参考 */
// GPIO功能寄存器宏定义
//typedef struct
//{
// __IO uint32_t PMD0:2;
// __IO uint32_t PMD1:2;
// __IO uint32_t PMD2:2;
// __IO uint32_t PMD3:2;
// __IO uint32_t PMD4:2;
// __IO uint32_t PMD5:2;
// __IO uint32_t PMD6:2;
// __IO uint32_t PMD7:2;
// __IO uint32_t PMD8:2;
// __IO uint32_t PMD9:2;
// __IO uint32_t PMD10:2;
// __IO uint32_t PMD11:2;
// __IO uint32_t PMD12:2;
// __IO uint32_t PMD13:2;
// __IO uint32_t PMD14:2;
// __IO uint32_t PMD15:2;
//} GPIO_PMD_T;
// PMD[1:0] = 0; // 输入
// 1; // 输出
// 2; // 开漏
// 3; // 准双向
// GPIO输出寄存器宏定义
//typedef __IO uint32_t GPIO_DOUT_T;
// GPIO输入寄存器宏定义
//typedef __IO uint32_t GPIO_PIN_T;
/* 设置所用GPIO */
// GPIO方向
#define BEEP_OE GPIOB->PMD.PMD10 = 1 // BEEP输出
#define KEY_IE (*(uint32_t *)&GPIOB->PMD) &= 0x0FFFFFFF
//#define KEY_IE GPIOB->PMD.PMD15 = 0; \
// GPIOB->PMD.PMD14 = 0
#define LED_OE (*(uint32_t *)&GPIOA->PMD) |= 0x00000150
//#define LED_OE GPIOA->PMD.PMD2 = 1; \
// GPIOA->PMD.PMD3 = 1; \
// GPIOA->PMD.PMD4 = 1;
// GPIOIO电平
#define Close_BEEP GPIOB->DOUT&=~(1<<10)
#define Open_BEEP GPIOB->DOUT|=1<<10
#define Close_LED1 GPIOA->DOUT|=1<<2
#define Open_LED1 GPIOA->DOUT&=~(1<<2)
#define Close_LED2 GPIOA->DOUT|=1<<3
#define Open_LED2 GPIOA->DOUT&=~(1<<3)
#define Close_LED3 GPIOA->DOUT|=1<<4
#define Open_LED3 GPIOA->DOUT&=~(1<<4)
#define Read_KEY1 (GPIOB->PIN>>15)&0x1
#define Read_KEY2 (GPIOB->PIN>>14)&0x1
/**********************************************************
* 函数及变量申明
**********************************************************/
void MAIN_INIT(void);
void TMR0_IRQHandler(void) __irq;
BOOL_T Flag_tmr0_20ms = NO;
/**********************************************************
* 系统上电初始化
**********************************************************/
void MAIN_INIT(void)
{
UNLOCKREG();
{ /* 配置系统时钟 */
SYSCLK->PWRCON.XTL12M_EN = 1; // 设定12M外部晶振
DrvSYS_Delay(5000); // 等待时钟就绪
DrvSYS_SelectPLLSource(E_SYS_EXTERNAL_12M); // 选择12MHz为PLL输入
DrvSYS_Open(50000000); // 打开50MHz
}
{ /* 配置GPIO */
BEEP_OE; Close_BEEP;
LED_OE; Close_LED1; Close_LED2;
KEY_IE;
}
{ /* 配置TMR0 */
NVIC_DisableIRQ(TMR0_IRQn);
// 第一步 使能和选择定时器时钟源及使能定时器模块
SYSCLK->CLKSEL1.TMR0_S = 0; // 选择12Mhz作为定时器时钟源
SYSCLK->APBCLK.TMR0_EN =1; // 使能定时器0
TIMER0->TCSR.CEN = 1; // 使能定时器模块
// 第二步 选择操作模式
TIMER0->TCSR.MODE = 1; // 选择周期模式
TIMER0->TCSR.CRST = 1; // 清加1计数器
// 第三步 输出时钟周期 = 定时器时钟源周期*(8位预分频因子 + 1) * (24位比较因子TCMP)
TIMER0->TCSR.PRESCALE = 11; // 12分频
TIMER0->TCMPR = 5000; // 12M/12/20000, 20ms
// 第四步 使能中断
TIMER0->TISR.TIF = 1; // 清中断
TIMER0->TCSR.IE = 1; // 使能中断
NVIC_EnableIRQ(TMR0_IRQn); // 使能TMR0中断
// 第五步 使能定时器模块
TIMER0->TCSR.CRST = 1; // 复位向上计数器
TIMER0->TCSR.CEN = 1; // 使能TMR0
//TIMER0->TCSR.TDR_EN=1; // 无需读取加1计数器值
}
LOCKREG();
}
/**********************************************************
* TMR0 ISR
**********************************************************/
void TMR0_IRQHandler(void) __irq
{ // 注意:ISR内必须清中断
TIMER0->TISR.TIF = 1; // 清中断
Flag_tmr0_20ms = YES;
}
/**********************************************************
* 主函数
**********************************************************/
int main(void)
{
uint8_t KEY_OldVal[2] = {1,1}; // 按键之旧值,次态值
uint8_t KEY_NewVal[2] = {1,1}; // 按键之新值,现态值
uint8_t LED_Val[3] = {1,1,1}; // LED值
MAIN_INIT(); // 上电初始化系统
while(1) {
if(Flag_tmr0_20ms != NO) {
Flag_tmr0_20ms = NO;
KEY_NewVal[0] = Read_KEY2;
KEY_NewVal[1] = Read_KEY1;
/* KEY2双边沿控制LED1 */
if(KEY_NewVal[0] ^ KEY_OldVal[0]) {
// 先锁存旧值
KEY_OldVal[0] = KEY_NewVal[0];
// 双边沿采样
LED_Val[0] = KEY_OldVal[0];
}
/* KEY1单边沿控制LED2、LED3 */
if(KEY_NewVal[1] ^ KEY_OldVal[1]) {
// 下降沿控制LED2
if(KEY_OldVal[1]/* && (~KEY_NewVal[1])*/)
LED_Val[1] = LED_Val[1] ? 0 : 1;
// 上升沿采样LED3
if(/*(~KEY_OldVal[1]) && */KEY_NewVal[1])
LED_Val[2] = LED_Val[2] ? 0 : 1;
// 后锁存旧值
KEY_OldVal[1] = KEY_NewVal[1];
}
/* 响应双边沿控制 */
// 按下亮松开灭
if(!LED_Val[0]) Open_LED1;
else Close_LED1;
/* 响应下降沿控制 */
// 第一次按下即亮,第二次按下灭
if(!LED_Val[1]) Open_LED2;
else Close_LED2;
/* 响应上升沿控制 */
// 第一次松开即亮,第二次松开即灭
if(!LED_Val[2]) Open_LED3;
else Close_LED3;
}
if(0) break; // 跳出大循环
}
return 0;
}
|