zoukankan      html  css  js  c++  java
  • [笔记].菜农M0助学板之GPIO按键之边沿检测小练(寄存器操作方式)

    已发贴至:http://bbs.21ic.com/viewthread.php?tid=233787

    现象解释:
      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;
    }
    

    Snap1

    下面给出Multisim之硬件仿真图示范

    边沿检测 

    双边沿检测

    双边沿检测

    上升沿检测

    上升沿检测

    下降沿检测

    下降沿检测

     安德鲁® / CC BY 2.5     FPGA Run!
  • 相关阅读:
    1. cocos creator 连接服务端
    cocos creator 中的粒子效果
    cocos creator
    5.4 笔记
    事后诸葛亮
    PHP之魔术方法
    结队编程--作业一
    团队作业9——事后分析(Beta版本)
    团队作业8——测试与发布(Beta阶段)
    Beta版本冲刺计划
  • 原文地址:https://www.cnblogs.com/yuphone/p/2037203.html
Copyright © 2011-2022 走看看