打印
[菜农助学交流]

菜农M0助学板之GPIO按键之边沿检测小练(寄存器操作方式)

[复制链接]
4620|4
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
现象解释:
  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;
}




相关帖子

沙发
tear086|  楼主 | 2011-5-5 07:59 | 只看该作者
下面给出Multisim之硬件仿真图示范


双边沿检测


上升沿检测


下降沿检测

使用特权

评论回复
板凳
hotpower| | 2011-5-5 09:39 | 只看该作者
旧值新值感觉不如计数器简洁。
例如只测试压键事件:
计数器初始化为0,定时到,若压键,计数加一,否则直接减为零。
加到2认为有键压下。

加减注意要先判定越界处理。
如大于等于2不加。

若再判断长压键或键释放要稍复杂些。

使用特权

评论回复
地板
tear086|  楼主 | 2011-5-5 10:58 | 只看该作者
哈哈,俺看到边沿检测,就想起了D触发器。

使用特权

评论回复
5
ytfdhb| | 2011-8-24 12:56 | 只看该作者
学习了^_^

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:個人博客:yuphone.cnblogs.com 聯絡方式:張亞峰 15013013265@qq.com

0

主题

120

帖子

3

粉丝