打印
[菜农助学交流]

【第四批】入门笔记第一帖_trigkey(by zxcscm)

[复制链接]
2822|4
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
zxcscm|  楼主 | 2012-1-4 16:00 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
gp, IO, GPIO, pi, ST
先不多说,直接上代码,功能说明啥的都在程序注释里
说明:
/*********************************************************************
* 文件名称:        tirgkey.c
* 功能说明:        触发器键盘识别驱动程序,可区分短按与长按
* 版本日期: 2011年12月28日
* 修改记录:
* 声    明:1、该部分程序参照二姨网友XIANSir的程序,具体请见:https://bbs.21ic.com/icview-229561-2-1.html
                  2、在保持原功能不变的情况下,区分短按与长按,不再买一赠一
***********************************************************************/
KeyScan()
/
/**************************************************************************
* 函数名称:        KeyScan()
* 功能说明: 扫描按键,并给出按键值,存储在KeyCode中
* 输    入: 无
* 输    出: 无
* 注意事项: 1、按键处理与按键的硬件连接息息相关,本函数当前能够正确处理的按键硬件连接为:
*                        KEY_1<->GPB.15        KEY_2<->GPB.14
*                        
****************************************************************************/

void KeyScan(void)
{
      uint32_t stat  = 0x00; //按键的状态值
    static uint32_t trig  = 0;    //按键触发,按键的下降沿将trig置1,以表示有按键被按下;在下一个检测周期(下一次本函数被调用)tirg会被本函数自动清零
    static uint32_t press = 0;    //保存stat的状态,表示按键持续按下
    static uint32_t count = 0;    //记录press值持续时间,以检测长按键
    static uint32_t save  = 0;    //记录按键按下时的按键值,只有短按键抬起时才用到,长按后抬起也被清除

    stat = (DrvGPIO_GetPortBits(E_GPB) & 0xC000) ^ 0xC000; //按键的状态值,实际是GPB15和GPB14引脚电平逻辑的按位取反值
        
    if((trig != 0x00) && (stat == press)) //trig置位表示发生了一次按键动作,
    {                                  //stat == press这个判断可以起到“消抖”作用
        save=stat;                        //有按键按下, 暂时保存按键值
    }        
        
      trig  = stat&(stat^press);//实际的核心代码,stat^press保证只有在按键变化时(有键被按下或释放),trig才有机会为1;而stat&部分则保证只有按键被按下才会置位tirg,而按键被释放则不会置位tirg
      press = stat;             //保存stat的状态,stat与press协同工作构建了一个“软件触发器”

    if((press==0)&&(save!=0))    //按键按下且抬起了,判断为短按
    {
             switch(save)             //判断是哪一个按键被按下了
        {
                     case 0x4000:
                              KeyCode = KEY_1;
                              break;
                      case 0x8000:
                              KeyCode = KEY_2;
                              break;
                      default:            //多个按键同时被按下的情况当前代码不支持,但如果有需要加入复合键的支持非常容易
                    KeyCode = NOKEY;
                              break;
             }
            save=0;                //判断完按键值,清除按键值
    }
      if(press != 0x00)
     {
            count++;
            if(count == 100)     //按键被持续按住长达10ms*100=1s,表示有按键被长按
        {
                  save=0;          //清空短按值,防止长按后抬起执行短按功能
            count = 50;      //将计数器置为50,目的是长按后每隔(100-50)*10ms,连续执行长按实现类似连加的功能。若想仅执行一次长按可将count置大于100的数,如KEY2
                  switch(stat)     //判断是哪一个按键被长按了
            {
                         case 0x4000:
                                   KeyCode = KEY_1L;
                                   break;
                         case 0x8000:
                                  KeyCode = KEY_2L;
                                  count=101;   //将count置大于100的值,屏蔽长按KEY2时连续的执行KEY2功能,
                      break;
                       default:
                                KeyCode = NOKEY;        //多个按键同时被按下的情况当前代码不支持,但如果有需要加入复合键的支持非常容易
                break;
                  }
          }
          if(count>200)
                count=101;
    }
    else
    {
          count=0;
    }               
}
main()

/***********************************************************************
* 函数名称: main()
* 功能说明: 根据按键值点亮相应LED。
            短按K1:LED1亮/灭;长按K1:LED2亮/灭,若持续按下K1则LED2闪烁;
            短按K2:LED3亮/灭;长按K2:LED4亮/灭,若持续按下K2则LED4不再变化,直到抬起后再次长按。
* 输    入: 无
* 输    出: 无
************************************************************************/


int main(void)
{
    UNLOCKREG();
    SYSCLK->PWRCON.XTL12M_EN = 1;// SYSCLK =>12Mhz
    LOCKREG();
   
    DrvGPIO_Open( E_GPA, 2, E_IO_OUTPUT );//设置GPA.2~GPA.5为输出模式
   DrvGPIO_Open( E_GPA, 3, E_IO_OUTPUT );
    DrvGPIO_Open( E_GPA, 4, E_IO_OUTPUT );
    DrvGPIO_Open( E_GPA, 5, E_IO_OUTPUT );
   
    DrvGPIO_ClrBit( E_GPA,2);            //做测试LED用
   DrvGPIO_SetBit( E_GPA,4);
   
    KeyInit();  //初始化按键相关的端口和定时器。
                //PS:开始调试时忘加该函数,导致反复的调试按键都没反应。几天后才通过断点调试发现定时器T0都没有运行。切记切记~~~

    while(1)
    {
        if(KeyCode!= NOKEY)
        {
            switch (KeyCode)
            {
            case KEY_1:                     //短按KEY1,LED1状态取反
                if(DrvGPIO_GetBit(E_GPA,2))
                       {
                            DrvGPIO_ClrBit(E_GPA,2);
                       }
                       else
                           DrvGPIO_SetBit(E_GPA,2);
                       KeyCode=0;
                       break;
            case KEY_1L:                   //长按KEY1,LED2状态取反,若一直按着不放,LED2会闪烁
               if(DrvGPIO_GetBit(E_GPA,3))
                      {
                              DrvGPIO_ClrBit(E_GPA,3);
                       }
                       else
                             DrvGPIO_SetBit(E_GPA,3);
                       KeyCode=0;
                       break;
            case KEY_2:                    //短按KEY2,LED3状态取反
                if(DrvGPIO_GetBit(E_GPA,4))
                       {
                               DrvGPIO_ClrBit(E_GPA,4);
                        }
                        else
                               DrvGPIO_SetBit(E_GPA,4);
                        KeyCode=0;
                        break;
            case KEY_2L:                   //长按KEY2,LED4状态取反,若一直按着不放,就不会再执行了,具体原因见KeyScan()
            {
                       if(DrvGPIO_GetBit(E_GPA,5))
                      {
                             DrvGPIO_ClrBit(E_GPA,5);
                       }
                       else
                             DrvGPIO_SetBit(E_GPA,5);
                       KeyCode=0;
                       break;
             }
            default:break;
            }
        }
    }
}
工程文件包: 01_trigkey_zxcscm.rar (867.93 KB)

作为第四批的园地M0幸运者,由于各种原因现在才开始真正意义上的第一帖笔记,真的很惭愧,对不起自己当初的热情,更对不起菜农大叔的辛苦。俺从园地的第一届助学活动就开始关注,目睹了菜农大叔的各种辛苦,大叔的真诚、热心以及助学活动的信心大家有目共睹,心知肚明的,但是总是有各种怀疑和议论声,我就不明白为什么不能多些理解和支持呢。大叔如此热情的进行这个义务的助学活动,不管是精神上、物质上还是时间上都付出那么多,为的是什么?“挽救失足青年”仅此而已,我们作为学子能做的就是把握机会,好好学习,认真记笔记,我想就是对菜农最大的支持了。

无论如何,从现在开始俺将真正的学习M0,学习嵌入式,争取从51菜鸟转成M0菜农,能在园地里耕作,收获属于自己的果实。

声明一点,俺的基础薄,所以笔记不会有多少含金量的,但俺会一直向各位网友学习,一步一个脚印的学扎实了,同时欢迎各位来拍砖!

相关帖子

沙发
zxcscm|  楼主 | 2012-1-4 16:01 | 只看该作者

灌水,吐糟

本帖最后由 zxcscm 于 2012-1-4 16:03 编辑

二楼纯属吐糟,说下俺中断学习原因之一,可直接绕过


俺是第四批最后一个拿到助学板的,刚开始时对着菜地里的例程很快学会了keil工程建立和断点调试以及ICP程序下载,当板上的LED开始亮起来时,甚是高兴。兴奋之余,想探索开发板其他的功能。
首先是ISP下载:在公司里对着例程将ISP固件下载到板子上,连上串口线,开始用新塘的ISP下载,尝试若干次没连上,换用大叔的HotISP,也不行,单独用usb给板子供电也不行,开始纳闷了,难道是ISP固件下载的不对?然后就重新用ICP下载最新固件(注意此时我没有拔掉板子上的USB电源,即NU_Link和板子都连接了USB),结果出现了更让人郁闷的结果:ICP连接不上NU_Link,提示要重新擦除FLASH,按照提示操作一通,还好,ICP连上了也下载了程序,ISP依然没有连接上。无奈,重新用keil调试下载程序。问题来了,keil连接不上U_Link了,所有的配置都没动,怎么就会出现这种问题呢,马上用ICP试试,又出现提示:quedin
确定后,ICP也连接不上了!!!
第一反应,完了板子坏了:因为我将板子一直放在主机箱上面,我就怀疑会不会是机箱漏电或静电什么的把开发板给电坏了。
不甘心,真希望是我某个设置的问题,尝试了下脱机下载,一切正常,ICP能连接NU_Link并下载程序,可是无论如何就是下载不到开发板上,当天晚上回家在自己的电脑上出现同样的问题,ICP要擦除FLASH 最终但也连接不上。然后就找菜农大叔,寻求帮助,菜农大叔很热心,让我一步一步的重新配置,用一晚上的时间,尝试了各种方法都没成功,结论是:NU_Link连接正常,没问题,问题就出现在开发板上。这更让我确信:开发板坏了!

郁闷至极:新拿的开发板还没开始用呢就这样坏了,多心疼。心想着只好再想办法买一个了,之后工作上的事让我也无暇再顾及M0助学板,这一放就1个多月过去了,每每看到园地MM们陆续上传的笔记和桌子上躺着的M0 助学板,心里就说不出的滋味,想学可又没有板子用,那么好的一个开发板怎么就坏了呢……

直到偶然间看到这个帖子https://bbs.21ic.com/icview-229808-1-1.html,他在9楼的问题和我的完全一样,向他请教解决方法,确认后,赶紧按照他的方法,将NU_LINK上的102电阻换成100欧,连接ICP,哈哈,顺利的连接上了!!!不再有提示擦除FLASH ,换用keil一切正常,改用HotISP的usbisp也很顺利,心里甭提多高兴了!!!在这里真的要谢谢Swallow_0322 若没有他这个帖子我不知会郁闷到什么时候呢。

所以这次的教训就是:不能用两根USB线同时给NU—Link和开发板供电,否则有损坏NU—Link的可能,一定要切记!
还有另外一个方法就是更改NU—Link上电源处的0Ω电阻,换成二极管,防止电流倒灌。

使用特权

评论回复
板凳
lovebaby8848| | 2012-1-4 21:11 | 只看该作者
准备把线藏起来一根 不要让两根线见面

使用特权

评论回复
地板
zxcscm|  楼主 | 2012-1-5 10:34 | 只看该作者
3# lovebaby8848

对的,当时就是因为看到有两根线就直接都给用上了

使用特权

评论回复
5
仙人球W| | 2014-11-18 11:59 | 只看该作者
路过

使用特权

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

本版积分规则

5

主题

628

帖子

1

粉丝