按键一端连接在普通IO口上,好啊其实结局是又发现了新的题材

背景

只要使用单片机,按键检查和测试基本上是自但是然要完毕的效益。按键检查和测试要好用,最关键的是实时和去抖。初学者往往会在主循环调用按键检查和测试程序(实时)并应用延时去抖(准确)。那种在主循环内延时的做法对全体程序很是不和谐,也十一分不便捷。因而,本篇就本人要好实现的3个检测按键并可看清按键是还是不是长短按的程序做个介绍和记录。

鼠标改造安顿

正文

在硬件连接上,按键一端连接在平时IO口上,另一端接地,IO配置为在那之中弱上拉。

在软件上,先安排一个5ms定时器并开拓中断,每进入该定时刹车则置位一回申明位“key_handle”。接着在主循环调用四个“scan_key()”函数,判断“key_handle”标志位是或不是在定时器内被置位,若被置位则将该位复位并读取连接按键的IO口值。

此时,“scan_key()”函数内分为按键按下和松手五个支行:

  • 按键按下,则计数值“longkey”每隔5ms自加一次,因为这些分支每隔5ms才会进入执行二回;

  • 按键松开,则先判断“longkey”的值,若“longkey”的值换算出来表示按键按下时间在10ms-1s内,(10ms是去抖值,1s是与短按与长按的分界点。)则判断按键为短按;若“longkey”的值大于1s,则判断按键为长按。并将按键状态赋值给按键状态变量“keybuf”。同时,由于此时按键已经加大,由此“longkey”的值要置位“0”等待用户下次按下按键并执行从“0”先河的自加操作。

若程序又1次进入按键检查和测试代码段,表达拥有作用块代码已经获知key状态,有对key感兴趣的代码段也肯定已经进展过相应处理,因而此时要立时将“keybuf”置为无按键按下情形这么些来二头实际按键状态。

实质上代码如下:

void scan_key(void)
{
    unsigned char key_status;

    if((longkey == 0) && (keybuf != _KEYNULL)){
        // 在keybuf被标记为长按或短按后,若是按键已经松开,
        // 则在主循环跑完一次后,及时将按键状态标记为无按键按下。
        keybuf = _KEYNULL;
    }
    if(key_handle == _ON) { //5ms进入一次
        key_handle = _OFF;    // 复位5ms标志位 
        key_status = GPIO_ReadInputDataBit(KEYRESET_GPIO_PORT, KEYRESET_GPIO_PIN);
        if(key_status == 0) {   //按下按键
            longkey++;
        }
        else {  // 松开按键
            if((longkey >= 3) && (longkey <= 100) ){    // 15ms - 1s
                keybuf = _SHORTKEY;
            } else if(longkey >= 200) { // 2s
                keybuf = _LONGKEY;
            } else {
                keybuf = _KEYNULL;// 若为扰动,按键状态也该为无按键按下
            }
            longkey = 0;
        }
    }
}

               ——基于STC15F104E的异彩呼吸灯

格Russ哥金融学院 音讯科技高校 集成162 Listen C

补充:

Tony~Liu座谈了下,发现实际上还有效能更高,占用CPU更少的按键检查和测试方法。

在硬件上,按键连接在富有外部中断的IO口上,按键连接在该IO口上的脚外部上拉,按键另一端接地。

在软件上,连接按键的IO口配置为两岸沿中断,同时安排三个1ms定时器中断。当按键按下时,触发外部中断,在外部中断内判断IO口电平,以此明确此为上涨沿如故下落沿。降低沿则象征按键按下,初叶计时,回升沿则代表按键松手,截至计时。上涨沿中断时,在暂停内置位“key_handle”,主循环在认清到“key_handle”被置位后,则起头判断计时器时间,即使时间在10ms-1s内,(10ms是去抖值,1s是与短按与长按的分界点。)则判断按键为短按;若时间超越1s,则判断按键为长按。具体实施也很简短,在此就不再贴代码,只是说说那种考虑。

到现在,记录实现

记录时间:2017-1-19
笔录地方:卡拉奇WZ

一.任务简介

新近作者的鼠标终于光荣下岗了,出于“主子”对“伙计”的“怜悯之情”,加上近日又恰恰发现STC15F104E如此个神奇的单片机,居然唯有八个脚,于是主决定恩赐它新的性命活力……好啊不撒谎了,只是一味的想搞个事情而已。可是,从现实的角度来看,好像真的无误,用尽量小的体积做尽量多的政工啊。也是出于上次可怜播放器被那芯片坑了三次不服气,打算换个体系“制服”它。好呢其实结局是又发现了新的难题,后文详述,那里就先留个伏笔,哈哈。

二.任务须求

(一)       改造指标

原指望改造的鼠标是下图那位“功臣”,因为其体积小外围透明,又得体下岗,故获此“殊誉”。

永利会娱乐 1

         可是,在晚期改造的经过中,遇上点小麻烦……具体怎样状态下文解释,那里为了文体整洁直接注明结果。结果便是,这些鼠标一时搁置了,换了学长2个临时不要的鼠标,下图:

永利会娱乐 2

         关于那多个鼠标技术上的差别,经试验发现,当按下鼠标按键时,前者小黑(第1个鼠标,下同)产生的是高电平,后者小白(第③个鼠标,下同)发生的是低电平,具体怎么考虑那些题材下文探究。

(二)       改造思路

先是,先让我们看下STC15F104E的法则图吧!

永利会娱乐 3

         由其原理图外加查询数据手册,简单发现,除去Vcc和Gnd,还剩伍个IO,当中除了P3.1,都足以做表面中断使用。关于定时器中断,对差异批次的芯片存在争议,需按实际景况做决定,因为这次改造安排没有采取定时器中断,所以不去探索。

         而关于外部中断,数据手册上说,P3.2(INT0)和P3.3(INT1)既可做上涨沿触发,也可降低沿触发,而剩余的P3.4(INT2)、P3.5(INT3)、P3.6(INT4)只能降落沿触发。

         而至于彩灯,我选取了三灯芯共阳灯泡,下图所示:

永利会娱乐 4

如此,依照三本色的规律,理论上我们能够组成出各个颜色。请允许小编盗个图。

永利会娱乐 5

         由此,大家的指标也就溢于言表了。

(1)      首先,我们必要三个IO去组合灯效

(2)      其次,我们供给多个按键来触发中断(鼠标左键、右键、中键)

(3)      然后,大家在暂停未触及的场馆下,让彩灯不断转换灯效

(4)      最后,发生中断时,灯效改变

理所当然,为了不那么工巧,通过发生中断,我们能够变更灯效变换的效率,相当于是做了二个调节机制。

这么,细心的情侣一定会发现,哎,全体的IO刚好用完,多个下跌沿也够用。那约等于为什么我要低电平的由来了。假如要高电平的话,唯有2个中断可触及,所以是有限定的。然而不急,实际上大家能够用非门电路改变电平,比如三极管,反相器。反相器用74HC00的话有4路,多联机,但是要三个输入控制一个出口,详情请自行检索下多少手册,也可用74HC04,六反相器,一输入相应一出口。当然笔者手头唯有印了74HC04的74HC00芯片(不要问我何以。。。贪便宜的自小编飘过),而且都以直插的,感觉尤其大,所以只能先一时中断下,有空再给小黑手术吧。反正,有小白呢。

顺便把原理图也沾满吧!

永利会娱乐 6

(三)       改造效果简述

至于具体的灯效,上文有提,那里详述一下。

先是是未触及中断的图景。

此间,小编使用了呼吸灯的规律,通过软件PWM,完成让灯效从A色缓缓变为B色,B色缓缓变为C色……G色缓缓变为A色,如此循环。关于颜色的整合,依照上海教室三本色原理,3种颜色任意组合:

单色:红,绿,蓝

双色:黄,青,紫

三色:百

总共7种颜色。

         当按下鼠标按键时,我让它对应突显单色,最近自家的相应原则如下,大家能够轻易交流:

         左键:红

         中键:绿

         右键:蓝

当按下右键时再按下左键,小编让它亮出自己颜色的其余颜料即蓝的争论黄,此时扩充彩灯周期,同理反之收缩彩灯周期。为了防止二货的自家调乱了,当按下中键时按下任意其余键,小编的操作是让周期复位。那样,贰个简便的灯效思路就有了。

三.改造与制作

(一)       鼠标

第③将鼠标“大卸八块”,探索内部结构,顺便测试是哪一类情况(小黑or小白)

永利会娱乐 7

(二)焊接电路

据悉原理图准备资料

 

彩灯 x1

STC15F104E x1

220Ω电阻 x3

单片机底座 x1

洞洞板 x0.5(整个太大了就掰开了)

永利会娱乐,导线若干

 永利会娱乐 8

         然后,根据原理图将它们焊好

永利会娱乐 9

永利会娱乐 10

         最终,将它与鼠标焊在联合。装好就OK啦。

永利会娱乐 11

四.程序设计

最后正是大家的主脑——程序了。老规矩,先让大家看看文件结构。

 永利会娱乐 12

头文件:

 

STC15F104E.h          芯片配置

USER_Config.h                 用户配置

interrupt.h                中断配置

delay.h                       延时配置

LED.h                         彩灯配置

 

先后文件

 

main.c                        主函数文件

it.c                              中断服务文件

delay.c                       延时函数文件

LED.c                          彩灯控制文件

 

         上边分别介绍下各部分的贯彻

 

USER_Config.h

 

/******************************************

            USER HEARD      2017/6/25

*******************************************/

#ifndef _USERCONFIG_H_
#define _USERCONFIG_H_
/*    定义数据类型    */
#define uchar unsigned char
#define uint unsigned int
#define NOP() _nop_()

/*    灯效    */
/*
    Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
    -    -    -    -    -   红   绿   蓝
低电平0为亮,高电平1为暗
*/
#define WHITE               0x00        //白 ----_-000
#define YELLOW      0x01        //黄 ----_-001
#define PURPLE      0x02        //紫 ----_-010
#define RED         0x03        //红 ----_-011
#define CYAN        0x04        //青 ----_-100
#define GREEN               0x05        //绿 ----_-101
#define BLUE          0x06      //蓝 ----_-110
#define CLOSE_ALL       0x07        //无 ----_-111

/*    PWM周期调节    */
#define INITCYCLE       1500        //初值
#define STEPCYCLE       100         //步进值

/*    包含头文件    */    
#include "STC15F104E.h"
#include <intrins.h>
#include "interrupt.h"
#include "delay.h"
#include "LED.h"

/*    彩灯    */
sbit LED_Blue  =  P3^3;
sbit LED_Green =  P3^2;
sbit LED_Red   =  P3^1;
/*    按键    */
sbit Key_Left  =  P3^4;
sbit Key_Mid   =  P3^5;
sbit Key_Right =  P3^0;

#endif

那边带有了用户全体须要的事物,包蕴定义数据类型、引用头文件、宏定义、定义引脚功效等。那里仅介绍首要部分

         先说说PWM调节周期吧。对于PWM调节,笔者只是做了周期调节处理。那里自个儿定义了一个效能初始值和贰个调节步进值,便于更改。具体那三个值的功能,在LED.c中详尽解释。

         对于各个灯效值的原故,大概能够如此清楚。首先作者将3中颜色点亮与否的值分别设有了1个unsigned char数据中的低几位,二进制中的0表示低电平,而以此LED是共阳的,所以是灌电流方式,那样就时有产生了三个电势差,故点亮LED。而置1时,两端都为高电平,电势差为0,故灭掉LED。这样,再依据三本色原理,对着颜色取值,就取出了7种标准颜色的值。

         那么难点来了,三灯芯的7色灯只可以显示7种颜色吗?作者觉着,其实不是的。别忘了,我们只是取了标准色,倘使说,混合颜色的“亮度”不一样,即颜色的吃水差异,就足以勾兑出别样颜料了。借使要如此完成的话,笔者个人觉得有三种方案。一是PWM分别调节三色,使得一样为灯的亮度差异。二我们能够利用DAC,直接给模拟量,调节尤其便于。那里大家只要等效循环变换,不必要规范取色,故不做深远处理了。

 

delay.c

一般说来的延时函数,不过多解释直接上代码

 

/*************************************

        延时函数库    By LZK

        频率:12MHz


*************************************/
#include "USER_Config.h"

/*    延时x*9us    */
void delay_8us(uint x)
{                           
    uint i,j;
    for(i=0;i<x;i++)
        for(j=0;j<1;j++);    
}

/*    延时xms    */
void delay_ms(uint x)
{                           
    uint i,j;
    for(i=0;i<x;i++)
        for(j=0;j<120;j++);
}

/*    延时    */
void delay(uint x)
{
    while(x--);
}

it.c

暂停服务。那里大家用的是多少个外表中断,下落沿触发。关于怎么利用这两当中断,那里就须要查询大家的数量手册了。数据手册笔者叁头扔进了压缩包里大家自取好了。

/*---------------------------------------------------

        中断服务文件

        By Listen C    2017/6/25

        参考自官方数据手册

----------------------------------------------------*/

#include "USER_Config.h"

extern uint CYCLE;

/*    中断初始化    */
void IT_Config()
{
    /*  开启外部中断  */
    Key_Left  = 1;
    Key_Mid   = 1;
    Key_Right = 1;
    INT_CLKO |= 0x70;// 0111_0000
    EA   =   1;
}
/*    外部中断2,3,4 对应 10,11,16  */
void Int2_Left() interrupt 10
{
    INT_CLKO   = 0x8F;          //1110_1111
    Open_LED(BLUE);
    while(!Key_Left)
    {
        if(!Key_Right)              //如果按下鼠标右键
        {
            delay_ms(10);               //去抖
            while(!Key_Right)
                Open_LED(YELLOW);   //默认蓝色的对立色为红+绿=黄
            Open_LED(BLUE);         //松开复位颜色
            if(CYCLE < 65400)
                CYCLE += STEPCYCLE;
        }
    }
    INT_CLKO  |= 0x70;
}

void Int3_Mid() interrupt 11
{
    INT_CLKO   = 0x8F;                                          //1101_1111
    Open_LED(GREEN);
    while(!Key_Mid)
    {
        if((!Key_Left)||(!Key_Right))                   //在按住鼠标中键时判断是否按下鼠标左键或鼠标右键
        {                                                                           //是的话,周期复位
            Open_LED(PURPLE);                                       //默认绿色的对立为蓝+红=紫
            CYCLE  = INITCYCLE;                                 
        }
        Open_LED(GREEN);                                            //松开颜色复位
    }
    INT_CLKO  |= 0x70;
}

void Int2_Right() interrupt 16
{
    INT_CLKO   = 0x8F;              //1011_1111
    Open_LED(RED);
    while(!Key_Right)
    {
        if(!Key_Left)                       //如果按下鼠标左键
        {
            delay_ms(10);                   //去抖
            while(!Key_Left)
                Open_LED(CYAN);         //默认红色的对立为蓝+绿=青
            Open_LED(RED);              //松开颜色复位
            if(CYCLE > 200)
                CYCLE -= STEPCYCLE;
        }
    }
    INT_CLKO  |= 0x70;
}

其间要专注的是,我们的思路是如此的。首先,先触发中断,触发中断后,先一时关闭中断,注意二个中断标志位不相同,注释中是实际位,儿为了制止混乱,我一切都置0了,然后亮相应等效提醒进入暂停了。然后继续判断,上文提到的非中键的话判断相反键是或不是按下,那里用了按键去抖,放手有效,随即对应扩展或回落PWM周期。中键的论断只须要按下其他任意键并拓展复位,故不须要去抖。

当成功这个干活儿时,大家的操作是卸下最初按下的按键,此时我们须要再行打开中断。

 

LED.c

         大家的为主部分到了,话不多说先上代码。

/*--------------------------------------------------------------------

        彩灯控制文件

        By Listen C    2017/6/26

        Open_LED函数说明:
            为方便调节灯色,本人将灯色选择存在了一个unsigned char变量中
            通过位运算
            低1位为蓝色开关
            低2位为绿色开关
            低3位为红色开关

            具体三色混合效果参见USER_Config.h

-------------------------------------------------------------------*/
#include "USER_Config.h"

uint PWM_LOW  =  0;
uint CYCLE    =  INITCYCLE;

/*    点灯函数    */
void Open_LED(uchar x)
{
    LED_Blue  =  x&0x01;
    LED_Green =  (x&0x02)>>1;
    LED_Red   =  (x&0x04)>>2;
}

/*    彩灯效果    */
void PWM_LED(uchar x,uchar y)
{
    for(PWM_LOW = 1;PWM_LOW < CYCLE;PWM_LOW++)
    {
        Open_LED(x);
        delay(PWM_LOW);
        Open_LED(y);
        delay(CYCLE-PWM_LOW);
    }
    delay(CYCLE);
}

         首先先让大家详细探索下点灯函数。稍有根基的心上人民代表大会致一看就清楚了,这里用的是位运算,取某位的值。即,先对对应位举行一个人与,其他0位与,以只保留对应位,然后通过右移操作移到最没有,给引脚赋值。

         说句题外话,用位运算存款和储蓄数据真的特别好用,曾经本人比赛时对4方位的红外障碍进行了位运算的积存,将多个方面的场合存在3个数量里,正是跟我们那么些职务恰好相反的历程,直接优势便是,在认清进程中变的可怜简单,只必要看清数据的值就能知道哪儿遇到阻力了,除去了糊涂的if判断,程序上反就是舒服多了,也为此那部分做的效能照旧不错的。

         关于PWM调节的标题,就是咱们灯效的决定了。假如知道PWM,那里或者就很掌握了,不知底的话可以自行查一下,互联网的介绍比自个儿那清楚多了。总而言之就是,在三个稳住的周期内,高电平占一定时间,低电平占剩下的年月,那样等效地调节了灯的亮度。然后,如若低电平稳步扩充,那么就等效认为亮度在大增。大家只考虑一种颜色的动静,那么它在缓慢变亮,反过来就缓慢变暗,如此就是呼吸灯的原理。注意全亮之后给一段时间固定,这样尤其栩栩欲活。而笔者辈的天职是,亮完这些颜色,在它灭掉的时候去亮下一种颜色,故将点灯部分改为了二种灯效。关于那多个灯效,在主函数中来计量,因为涉嫌到要让那一个函数越发通用嘛。假设不去更换灯效,也同等能够调用它,大不断y取CLOSE_ALL。

 

main.c

         既然宗旨部分都搞好了,剩下的调用就好了。

/*---------------------------------------------------------------

    基于STC15F104E的鼠标改造方案

    目的:通过外部中断控制三灯芯小灯
                通过PWM信号来变换灯效

                按下鼠标左键时按下鼠标右键,PWM周期增加
                按下鼠标右键时按下鼠标左键,PWM周期减少
                按下鼠标中键时按下任意键,PWM周期复位

                灯效参见it.c的注释


                为方便调节灯色,本人为灯色选择函数做了优化,详见LED.c

  By Listen C    2017/6/25

-----------------------------------------------------------------*/
#include "STC15F104E.h"
#include "USER_Config.h"

uchar i = 0;

void main()
{
    uchar x,y;

    Open_LED(CLOSE_ALL);

    IT_Config();

    while(1)
    {
        for(i=0;i<7;i++)
        {
            x=(i+1)%7;
            y=i;
            PWM_LED(x,y);
        }
    }
}

         注意先要中断初步化,然后7色循环闪烁既可。

 

五.反思与总括

说句良心话,这几个小说的Bug依旧非常大的。小编遇上最大的题材是,当按键频率过高时,中断会莫明其妙挂掉了。固然出了难点应有先考虑本人程序难题,可是自身认为本人的刹车没有进入那种情况的步调,况且作者在主函数中while里时刻打开外部中断都不算,于是就上网查了下,果然有网上好友蒙受了平等的标题。有人的解答是初期的该芯片存在Bug,不过早先时期的修复了。好吧作者就临时认为这锅芯片背啊!

实际上,表面上,职分以改造鼠标做依托进行的,但那么些灯效的小玩意儿能够做其余的点缀,比如USB彩灯。恰好又一个人好友过生日,于是亲手又焊了二个给她,礼轻情义重嘛~。可是说句良心话,做USB彩灯的功效,是有过之而无不及放进鼠标里的。下图为送她的彩灯。

永利会娱乐 13

永利会娱乐 14永利会娱乐 15

最后,附上共享链接:

链接:http://pan.baidu.com/s/1gf5n0vL
密码:yfpz

STC15F104E数额手册:

链接:http://pan.baidu.com/s/1qYuLNas
密码:a3au

 

相关文章