您的位置 首页 元件

开关检测二三事:端口缺乏,滤波时刻不同

熟悉洒家写作风格的朋友们都知道,洒家行文一向生动活泼,甚而有时浮夸得没个章法。但是,在这个全民战疫的关键时刻,似乎任何的轻佻都是对前线战士的不恭敬。故而,今天严肃紧张一把,跟大家开门见山,讲一讲开关检

了解洒家写作风格的朋友们都知道,洒家行文一贯生动活泼,甚而有时浮夸得没个规矩。可是,在这个全民战疫的关键时刻,好像任何的轻佻都是对前哨兵士的不恭顺。故而,今日严厉严重一把,跟咱们开宗明义,讲一讲开关检测的问题。

有的朋友或许会觉得,开关检测关于每一个嵌入式工程师来讲都是入门级其他问题,有什么好讲的呢?好吧,关于你这种主意,我只能像春晚上晓明哥哥对祖儿妹妹讲的那样:

我不要你觉得,我要我觉得!

问你三个问题吧。榜首,假如因为这样或那样的原因,您选用的MCU的IO口不行,无法一一对应地处理那么多路开关信号,你该咋个办?

第二,怎样区别开关的“动作”和“状况”?按下和弹起的动作一闪即逝,状况却长期保持,怎样区别并处理?

第三,是关于咱们耳熟能详的滤波问题,您可不要说只需求进行硬件滤波就够了这种跌份的话哈。假定您的开关信号性质有所不同,它们需求的滤波时刻也不一样,你怎样以一种一致的办法去向理他们呢?

今日洒家和咱们共享的便是关于这三个问题的主意和解决方案。

要想逃避实际,最好的办法便是深深介入实际之中。

嵌入式工程师的日常作业不是在大好河山里做文章,而是在螺丝壳里做道场。在日复一日的作业中,工程师逐步积累了丰厚的实战经验。比方硬件不行能够用软件来凑,内存不足能够献身实时性,以时刻换空间。

那么,IO口不行呢?

鲁迅先生曾说:“期望是本无所谓有,无所谓无的。这正如地上的路,其实地上本没有路,走的人多了,也便成了路。”

英勇的嵌入式工程师是遇山开路、遇水搭桥的开拓者,面临无路之境,自会以大无畏的响雷手法趟出一条路来。IO口不行,MCU又不能换(想一想老板那冷飕飕的目光),天然也会另辟蹊径,山穷水尽,不至于山穷水复,找不到出路的。

聪明的小伙伴们应该现已摩拳擦掌,预备抢答了。不过,授人以鱼不如授人以渔,在直接给出答案之前,咱们能够先想一个问题:为什么现在咱们用的计算机,基本上没有并口了呢?

在计算机刚刚呈现的那个时代里,打印和绘图是非常重要的运用。因为计算机速度的约束,串行传输速度适当有限,无法应对打印绘图这种需求高速数据传输的运用,所以,并口大行其道数十载。说句不怕露出年纪的话,笔者刚上班时,单位的台式机和笔记本都是有并口的。

当然,鱼与熊掌不可兼得,并行传输也有其缺陷,那便是需求的端口和线路远高于串行传输,会耗费较高的电路板资源和软件解析才能,所以,跟着计算机和串行传输速度的提高,并口也开端慢慢地退出了前史的舞台。

触类旁通,见微知著,咱们是不是品出来什么了?

对,在嵌入式规划中,一个MCU端口处理一路开关信号是“并行处理办法”,类比于计算机并口,需求耗费较多的端口。端口不行的解决方案天然是“并行转串行”,以串行的办法进行开关信号的检测。

在具体的完成上,需求挑选“多路开关检测接口芯片”,这种芯片能够检测多路开关量输入信号,并将检测到的开关状况经过SPI发送给MCU。这种办法能够极大地节约MCU的IO口资源,比方说检测16路开关,并行办法需求16个MCU IO端口,串行办法只需求一个SPI端口就能够了。

话不多说,再来看第二个问题:怎样区别开关的“动作”和“状况”?

至于为什么要区别“动作”和“状况”。是因为在嵌入式产品中,有一种很常见的运用逻辑:开关A、B、C处于闭合状况且开关D、E、F处于断开状况时,按下或松开开关G,履行某个操作。

在这种逻辑里,“按下”和“松开”是两种动作,“闭合”和“断开”是两种状况。用电路的常识来类比的话,动作是沿跳变,状况是电平。

“动作”是一闪即逝的花火,状况是千年不变的许诺。咱们做区别为的是,让动作“阅后即焚”,不至于成为重复触发操作的脉息。

为了阐明这一点,洒家跟咱们共享一下自己规划的结构体和代码完成,这部分也能够用在对第三个问题的回答上。

typedef struct{

     unsigned switch_state:1;

     unsigned swon_event:1;

     unsigned swoff_event:1;

     unsigned cursw:1;

     unsigned detect_cnt:4;

     e_SwId   switch_id;

}s_Switch;

在这个结构体的成员变量里边,switch_id标识开关节点,咱们能够用“解释性”很强的枚举来表明它。这儿的switch_state表明的是开关信号的状况,swon_event和swoff_event别离表明开关从断开到闭合和从闭合到断开的改变,即上述的“动作”。 cursw和detect_cnt用于开关信号收集的软件消抖功用。

为了一起检测开关状况和动作,能够设置一个10ms的周期定时器,周期性地对每个SWITCH_ID对应的开关信号进行检测,具体完成为:

void SwDetect(e_SwId sw_id)  

{

    uint8_t filter_time;

    filter_time = SW_DETECT_TIMES;

    if(SWITCH_OFF == Sw[sw_id].switch_state){

        if(IOVALID == Sw[sw_id].cursw){

            if(Sw[sw_id].detect_cnt < filter_time){

                Sw[sw_id].detect_cnt++;   

            }else{                                          

                Sw[sw_id].switch_state = SWITCH_ON;       

                Sw[sw_id].detect_cnt = 0;                      

                Sw[sw_id].swon_event = 1;          

            }

        }else{

            Sw[sw_id].detect_cnt = 0;

        }

    }else{

        if(IOINVALID == Sw[sw_id].cursw){

            if(Sw[sw_id].detect_cnt < filter_time){

                Sw[sw_id].detect_cnt++;

            }else{                                                        

                Sw[sw_id].switch_state = SWITCH_OFF;

                Sw[sw_id].swoff_event = 1;

                Sw[sw_id].detect_cnt = 0;

            }

        }else{

            Sw[sw_id].detect_cnt = 0;

        }

    }

}

当开关动作产生时,swon_event和swoff_event置一,在履行完相关操作之后,将swon_event和swoff_event清零,就完成了让动作“阅后即焚”。

所以,上面那种依据某些开关的状况和动作履行相关操作的逻辑的具体完成为:

If(Switch[SWITCH_ID_1].swon_event == 1)

{

If(Switch[SWITCH_ID_2].switch_state == “ON”){

    操作1

}

Switch[SWITCH_ID_1].swon_event = 0

}

下面接着讲第三个问题:怎样应对不同的滤波时刻?

正如上面讲过的那样,关于一般的开关节点,规划一10ms的定时器周期性地读取开关当时状况cursw,然后依据其保持当时状况的周期次数(依据不同运用场景,能够设置为5次或许10次,别离对应50ms或100ms的滤波时刻)以判别switch_state、swon_event、swoff_event。

那么,关于那些特别的开关信号,或许需求选用较典型值长或许短的消抖时刻,咱们只需求针对该开关信号对应的那个SWITCH_ID表征的结构体变量,设置它的滤波次数filter_time(见上面那段程序)即可。

讲到这儿,有些不爱看代码的同学或许含糊了,这儿,帮人帮到底,洒家不吝翰墨,具体展开一番。

首要,设定一个10ms的定时器,在它的中止服务程序里,履行开关信号检测。

对应在咱们这儿,能够以为它的中止服务程序(ISR)履行的便是下面这个IoInputDetect函数。(需求阐明的是,一般情况下咱们不会在中止服务程序里履行这种耗时较长的程序,这儿仅仅为了便利咱们了解)

void IoInputDetect(void)

{

    e_SwId sw_idx;

    ReadIoSwitch();

    for(sw_idx = MIN_SWITCH;sw_idx < MAX_SWITCH;sw_idx++){

        SwDetect(sw_idx);   

    } 

}

这个函数里边,在ReadIoSwitch函数里边读取每个开关(以SWITCH_ID标识)的当时状况,赋给其cursw,需求留意的是,这儿的cursw表明的是当下这一刻的开关状况,不是经过滤波处理后的安稳开关状况。

第二步:依据每个开关的当时状况cursw,判别其安稳的开关状况switch_state、开关动作swon_event和swoff_event。即上面在for循环中履行的SwDetect函数。

SwDetect函数句子在第二节中,它的中心思维便是判别开关当时状况cursw是否继续安稳在SWITCH_ON或许SWITCH_OFF状况。当时的switch_state为ON的状况下,假如继续filter_time个10ms,cursw一向为OFF状况,则将switch_state赋为OFF状况,一起,将swoff_event赋为1。反之亦然。

当滤波时刻不一起,明显只需求将该switch_id对应的开关结构体的filter_time置为不同于典型值的特别值即可。

跋文

洒家在这篇文章里边共享的开关检测办法,不止适用于数字IO办法的开关信号,还适用于其它信号。

比方经过RF办法接纳的遥控信号,虽然是一种射频性质的信号,可是这种信号对应的是遥控器上的物理按键,它在逻辑上天然也等价于本文讲的开关信号,所以,能够用上述那个结构体和那些代码判别遥控信号,解分出某个遥控按键按下、松开的动作和状况,一起对它进行滤波处理。

再触类旁通,无论是RF信号、模拟信号、数字信号、网络信号,只需该输入信号在逻辑上能够等价于物理开关,它就能够运用本文所述的办法处理。

你觉得呢?

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/xinpin/yuanjian/114442.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部