<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>

新聞中心

EEPW首頁(yè) > 牛人業(yè)話(huà) > 開(kāi)關(guān)檢測二三事:端口不足,濾波時(shí)間不同

開(kāi)關(guān)檢測二三事:端口不足,濾波時(shí)間不同

作者:驢三 時(shí)間:2020-03-18 來(lái)源:電子產(chǎn)品世界 收藏

熟悉灑家寫(xiě)作風(fēng)格的朋友們都知道,灑家行文一向生動(dòng)活潑,甚而有時(shí)浮夸得沒(méi)個(gè)章法。但是,在這個(gè)全民戰疫的關(guān)鍵時(shí)刻,似乎任何的輕佻都是對前線(xiàn)戰士的不恭敬。故而,今天嚴肅緊張一把,跟大家開(kāi)門(mén)見(jiàn)山,講一講開(kāi)關(guān)檢測的問(wèn)題。

本文引用地址:http://dyxdggzs.com/article/202003/411046.htm

有的朋友可能會(huì )覺(jué)得,開(kāi)關(guān)檢測對于每一個(gè)嵌入式工程師來(lái)講都是入門(mén)級別的問(wèn)題,有什么好講的呢?好吧,對于你這種想法,我只能像春晚上曉明哥哥對祖兒妹妹講的那樣:

我不要你覺(jué)得,我要我覺(jué)得!

問(wèn)你三個(gè)問(wèn)題吧。第一,如果因為這樣或那樣的原因,您選用的MCU的IO口不夠,無(wú)法一一對應地處理那么多路開(kāi)關(guān)信號,你該咋個(gè)辦?

第二,如何區分開(kāi)關(guān)的“動(dòng)作”和“狀態(tài)”?按下和彈起的動(dòng)作一閃即逝,狀態(tài)卻長(cháng)期保持,怎么區分并處理?

第三,是關(guān)于大家耳熟能詳的濾波問(wèn)題,您可不要說(shuō)只需要進(jìn)行硬件濾波就夠了這種跌份的話(huà)哈。假設您的開(kāi)關(guān)信號性質(zhì)有所不同,它們需要的濾波時(shí)間也不一樣,你怎么以一種統一的方式去處理他們呢?

今天灑家和大家分享的就是關(guān)于這三個(gè)問(wèn)題的想法和解決方案。

要想逃避現實(shí),最好的方式就是深深介入現實(shí)之中。

嵌入式工程師的日常工作不是在錦繡河山里做文章,而是在螺絲殼里做道場(chǎng)。在日復一日的工作中,工程師逐漸積累了豐富的實(shí)戰經(jīng)驗。比如硬件不夠可以用軟件來(lái)湊,內存不足可以犧牲實(shí)時(shí)性,以時(shí)間換空間。

那么,IO口不夠呢?

魯迅先生曾說(shuō):“希望是本無(wú)所謂有,無(wú)所謂無(wú)的。這正如地上的路,其實(shí)地上本沒(méi)有路,走的人多了,也便成了路?!?/p>

勇敢的嵌入式工程師是遇山開(kāi)路、遇水搭橋的開(kāi)拓者,面對無(wú)路之境,自會(huì )以大無(wú)畏的霹靂手段趟出一條路來(lái)。IO口不夠,MCU又不能換(想一想老板那冷颼颼的目光),自然也會(huì )另辟蹊徑,柳暗花明,不至于山窮水復,找不到出路的。

聰明的小伙伴們應該已經(jīng)躍躍欲試,準備搶答了。不過(guò),授人以魚(yú)不如授人以漁,在直接給出答案之前,大家可以先想一個(gè)問(wèn)題:為什么現在大家用的計算機,基本上沒(méi)有并口了呢?

在計算機剛剛出現的那個(gè)年代里,打印和繪圖是非常重要的應用。由于計算機速度的限制,串行傳輸速度相當有限,無(wú)法應對打印繪圖這種需要高速數據傳輸的應用,于是,并口大行其道數十載。說(shuō)句不怕暴露年齡的話(huà),筆者剛上班時(shí),單位的臺式機和筆記本都是有并口的。

當然,魚(yú)與熊掌不可兼得,并行傳輸也有其缺點(diǎn),那就是需要的端口和線(xiàn)路遠高于串行傳輸,會(huì )消耗較高的電路板資源和軟件解析能力,所以,隨著(zhù)計算機和串行傳輸速度的提升,并口也開(kāi)始慢慢地退出了歷史的舞臺。

觸類(lèi)旁通,見(jiàn)微知著(zhù),大家是不是品出來(lái)什么了?

對,在嵌入式設計中,一個(gè)MCU端口處理一路開(kāi)關(guān)信號是“并行處理方式”,類(lèi)比于計算機并口,需要消耗較多的端口。端口不夠的解決方案自然是“并行轉串行”,以串行的方式進(jìn)行開(kāi)關(guān)信號的檢測。

在具體的實(shí)現上,需要選擇“多路開(kāi)關(guān)檢測接口芯片”,這種芯片可以檢測多路開(kāi)關(guān)量輸入信號,并將檢測到的開(kāi)關(guān)狀態(tài)通過(guò)SPI發(fā)送給MCU。這種方式可以極大地節省MCU的IO口資源,比如說(shuō)檢測16路開(kāi)關(guān),并行方式需要16個(gè)MCU IO端口,串行方式只需要一個(gè)SPI端口就可以了。

話(huà)不多說(shuō),再來(lái)看第二個(gè)問(wèn)題:怎么區分開(kāi)關(guān)的“動(dòng)作”和“狀態(tài)”?

至于為什么要區分“動(dòng)作”和“狀態(tài)”。是因為在嵌入式產(chǎn)品中,有一種很常見(jiàn)的應用邏輯:開(kāi)關(guān)A、B、C處于閉合狀態(tài)且開(kāi)關(guān)D、E、F處于斷開(kāi)狀態(tài)時(shí),按下或松開(kāi)開(kāi)關(guān)G,執行某個(gè)操作。

在這種邏輯里,“按下”和“松開(kāi)”是兩種動(dòng)作,“閉合”和“斷開(kāi)”是兩種狀態(tài)。用電路的知識來(lái)類(lèi)比的話(huà),動(dòng)作是沿跳變,狀態(tài)是電平。

“動(dòng)作”是一閃即逝的花火,狀態(tài)是千年不變的承諾。我們做區分為的是,讓動(dòng)作“閱后即焚”,不至于成為反復觸發(fā)操作的脈搏。

為了說(shuō)明這一點(diǎn),灑家跟大家分享一下自己設計的結構體和代碼實(shí)現,這部分也可以用在對第三個(gè)問(wèn)題的解答上。

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;

在這個(gè)結構體的成員變量里面,switch_id標識開(kāi)關(guān)節點(diǎn),大家可以用“解釋性”很強的枚舉來(lái)表示它。這里的switch_state表示的是開(kāi)關(guān)信號的狀態(tài),swon_event和swoff_event分別表示開(kāi)關(guān)從斷開(kāi)到閉合和從閉合到斷開(kāi)的變化,即上述的“動(dòng)作”。 cursw和detect_cnt用于開(kāi)關(guān)信號采集的軟件消抖功能。

為了同時(shí)檢測開(kāi)關(guān)狀態(tài)和動(dòng)作,可以設置一個(gè)10ms的周期定時(shí)器,周期性地對每個(gè)SWITCH_ID對應的開(kāi)關(guān)信號進(jìn)行檢測,具體實(shí)現為:

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;

        }

    }

}

當開(kāi)關(guān)動(dòng)作發(fā)生時(shí),swon_event和swoff_event置一,在執行完相關(guān)操作之后,將swon_event和swoff_event清零,就完成了讓動(dòng)作“閱后即焚”。

所以,上面那種根據某些開(kāi)關(guān)的狀態(tài)和動(dòng)作執行相關(guān)操作的邏輯的具體實(shí)現為:

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

{

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

    操作1;

}

Switch[SWITCH_ID_1].swon_event = 0;

}

下面接著(zhù)講第三個(gè)問(wèn)題:怎么應對不同的濾波時(shí)間?

正如上面講過(guò)的那樣,對于一般的開(kāi)關(guān)節點(diǎn),設計一10ms的定時(shí)器周期性地讀取開(kāi)關(guān)當前狀態(tài)cursw,然后根據其維持當前狀態(tài)的周期次數(根據不同應用場(chǎng)景,可以設置為5次或者10次,分別對應50ms或100ms的濾波時(shí)間)以判斷switch_state、swon_event、swoff_event。

那么,對于那些特殊的開(kāi)關(guān)信號,也許需要采用較典型值長(cháng)或者短的消抖時(shí)間,我們只需要針對該開(kāi)關(guān)信號對應的那個(gè)SWITCH_ID表征的結構體變量,設置它的濾波次數filter_time(見(jiàn)上面那段程序)即可。

講到這里,有些不愛(ài)看代碼的同學(xué)可能模糊了,這里,幫人幫到底,灑家不惜筆墨,詳細開(kāi)展一番。

首先,設定一個(gè)10ms的定時(shí)器,在它的中斷服務(wù)程序里,執行開(kāi)關(guān)信號檢測。

對應在我們這里,可以認為它的中斷服務(wù)程序(ISR)執行的就是下面這個(gè)IoInputDetect函數。(需要說(shuō)明的是,一般情況下我們不會(huì )在中斷服務(wù)程序里執行這種耗時(shí)較長(cháng)的程序,這里只是為了方便大家理解)

void IoInputDetect(void)

{

    e_SwId sw_idx;

    ReadIoSwitch();

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

        SwDetect(sw_idx);   

    } 

}

這個(gè)函數里面,在ReadIoSwitch函數里面讀取每個(gè)開(kāi)關(guān)(以SWITCH_ID標識)的當前狀態(tài),賦給其cursw,需要注意的是,這里的cursw表示的是當下這一刻的開(kāi)關(guān)狀態(tài),不是經(jīng)過(guò)濾波處理后的穩定開(kāi)關(guān)狀態(tài)。

第二步:根據每個(gè)開(kāi)關(guān)的當前狀態(tài)cursw,判斷其穩定的開(kāi)關(guān)狀態(tài)switch_state、開(kāi)關(guān)動(dòng)作swon_event和swoff_event。即上面在for循環(huán)中執行的SwDetect函數。

SwDetect函數語(yǔ)句在第二節中,它的核心思想就是判斷開(kāi)關(guān)當前狀態(tài)cursw是否持續穩定在SWITCH_ON或者SWITCH_OFF狀態(tài)。當前的switch_state為ON的狀態(tài)下,如果持續filter_time個(gè)10ms,cursw一直為OFF狀態(tài),則將switch_state賦為OFF狀態(tài),同時(shí),將swoff_event賦為1。反之亦然。

當濾波時(shí)間不同時(shí),顯然只需要將該switch_id對應的開(kāi)關(guān)結構體的filter_time置為不同于典型值的特殊值即可。

后記

灑家在這篇文章里面分享的開(kāi)關(guān)檢測方法,不止適用于數字IO形式的開(kāi)關(guān)信號,還適用于其它信號。

比如通過(guò)RF方式接收的遙控信號,雖然是一種射頻性質(zhì)的信號,但是這種信號對應的是遙控器上的物理按鍵,它在邏輯上自然也等價(jià)于本文講的開(kāi)關(guān)信號,所以,可以用上述那個(gè)結構體和那些代碼判斷遙控信號,解析出某個(gè)遙控按鍵按下、松開(kāi)的動(dòng)作和狀態(tài),同時(shí)對它進(jìn)行濾波處理。

再舉一反三,無(wú)論是RF信號、模擬信號、數字信號、網(wǎng)絡(luò )信號,只要該輸入信號在邏輯上可以等價(jià)于物理開(kāi)關(guān),它就可以使用本文所述的方法處理。

你覺(jué)得呢?



關(guān)鍵詞:

評論


相關(guān)推薦

技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>