国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

單片機(jī)怎么用回調(diào)函數(shù)在不同文件之間傳遞數(shù)據(jù)

KavenFan / 1264人閱讀

摘要:今天繼續(xù)來聊下回調(diào)函數(shù)。輸入型輸入型函數(shù)一般是用在不同文件不同層硬件層應(yīng)用層之間傳遞信號(hào)和數(shù)據(jù)的,比如說按鍵檢測(cè)串口數(shù)據(jù)。最終就是把這個(gè)指針指向別的文件的函數(shù),從而實(shí)現(xiàn)不同文件之間的數(shù)據(jù)傳遞,同時(shí)又能保持很好的可移植性相互獨(dú)立,互不干擾。

大家好,我是無際。

今天繼續(xù)來聊下回調(diào)函數(shù)。

之前寫過一篇受到了廣大老鐵們的認(rèn)可。

最近有幾個(gè)新學(xué)員被回調(diào)函數(shù)搞得有點(diǎn)懵逼。

不理解為什么要搞這種繞來繞去、指針指來指去的函數(shù)。

先寫篇文章預(yù)熱一下,晚上再直播跟大家互動(dòng)講解和答疑。

其實(shí)并不是我想把簡(jiǎn)單的東西復(fù)雜化,而是如果你想寫出好的代碼架構(gòu),回調(diào)函數(shù)是必不可少的。

如果你去看那些大神寫的程序,你會(huì)發(fā)現(xiàn)他們都是這樣做的,比如說藍(lán)牙協(xié)議棧、實(shí)時(shí)操作系統(tǒng)、STM32固件庫等等。

每個(gè)人寫得風(fēng)格可能不一樣,但是本質(zhì)是一樣的。

我們先來理解一下回調(diào)函數(shù)的作用。

函數(shù)我一般喜歡分為輸出型和輸入型(個(gè)人理解)。

輸出型:

就是我們主動(dòng)去調(diào)用的控制函數(shù),比如說控制LED燈去亮和滅,控制蜂鳴器響和不響,控制LCD顯示,控制繼電器吸合和斷開。

簡(jiǎn)單來說,就是我們知道什么時(shí)候該去調(diào)用這些函數(shù),比如說滿足某些條件的時(shí)候,我們就會(huì)主動(dòng)去調(diào)用這些函數(shù)。

這種函數(shù),就是輸出型函數(shù)。

輸入型:

輸入型函數(shù)一般是用在不同.c文件/不同層(硬件層、應(yīng)用層)之間傳遞信號(hào)和數(shù)據(jù)的,比如說按鍵檢測(cè)、串口數(shù)據(jù)。

我們不知道什么時(shí)候按鍵會(huì)被按下、什么時(shí)候串口會(huì)有數(shù)據(jù)過來對(duì)吧?

當(dāng)然,我們可以寫一個(gè)帶返回值的函數(shù),然后定時(shí)去檢測(cè),比如說定時(shí)10ms去掃描一下按鍵。

Unsigned char ScanKey()

{

//按鍵檢測(cè)程序…
}

然后我們?cè)谥鞒绦蛴茫?/p>

while(1)

{

Unsigned char key;

If(10ms時(shí)間到)

{

Key = ScanKey();
}

?????? if(Key == 有效按鍵值)

?????? {

????????????? //執(zhí)行按鍵功能程序

}

}

這樣不斷地去掃描按鍵,檢測(cè)按鍵是否被按下。

這種方式當(dāng)然也是可以的,只是不夠?qū)I(yè),不夠好。

因?yàn)檫@個(gè)我需要一直在while循環(huán)里判斷Key的值,然后根據(jù)Key的值來判斷有沒有按鍵按下,在一定程度上,造成了cpu資源的浪費(fèi)。

而且有些應(yīng)用場(chǎng)景,這種方式不好實(shí)現(xiàn),比如說串口數(shù)據(jù),你不能一直在while循環(huán)里判斷是否有新的串口數(shù)據(jù)過來吧?

那我們理想的一種狀態(tài)是什么?

就是如果有按鍵按下了,或者有新的數(shù)據(jù)來了,再通知我。

這種通知方式一般叫事件觸發(fā),就是觸發(fā)了按鍵這個(gè)事件,我才去處理。

所以,這個(gè)時(shí)候回調(diào)函數(shù)就能很好地解決這種需求。

我們還是拿按鍵來舉例。

前面我說每個(gè)人寫回調(diào)函數(shù)的風(fēng)格可能都不一樣,STM32固件庫的那些中斷處理函數(shù)基本都是回調(diào)函數(shù),但是跟我的編寫風(fēng)格還是有些差異。

我們?cè)趯懟卣{(diào)函數(shù)的時(shí)候,需要以下幾步:

第一步:

自定義一個(gè)函數(shù)指針類型,類型名稱是KeyEvent_CallBack_t。

typedef void (*KeyEvent_CallBack_t)(KEY_VALUE_TYPEDEF keys);

還有這個(gè)一般是要自定義在頭文件,因?yàn)閯e的.c文件也會(huì)用到。

這是一個(gè)無返回值的形參是KEY_VALUE_TYPEDEF枚舉類型函數(shù)指針類型

一般這個(gè)形參keys就是我們最終要通過回調(diào)函數(shù)傳遞到別的.c文件的信號(hào)/數(shù)據(jù),如果是按鍵檢測(cè)的話也就是按鍵值,是哪個(gè)按鍵按下的。

我們來看下KEY_VALUE_TYPEDEF這個(gè)枚舉都有哪些值?

typedef enum

{

?????? KEY_IDLE_VAL,

?????? KEY1_CLICK,

?????? KEY1_CLICK_RELEASE,

?????? KEY1_LONG_PRESS,

?????? KEY1_LONG_PRESS_CONTINUOUS,

?????? KEY1_LONG_PRESS_RELEASE,?????????? //5

?????? KEY2_CLICK,?????????????????????????????????????????????????? //6

?????? KEY2_CLICK_RELEASE,

?????? KEY2_LONG_PRESS,

?????? KEY2_LONG_PRESS_CONTINUOUS,

?????? KEY2_LONG_PRESS_RELEASE,

?????? KEY3_CLICK,??????????????????????????????????????????? //11

?????? KEY3_CLICK_RELEASE,

?????? KEY3_LONG_PRESS,

?????? KEY3_LONG_PRESS_CONTINUOUS,

?????? KEY3_LONG_PRESS_RELEASE,

?????? KEY4_CLICK,???????????????????????????????????? //16

?????? KEY4_CLICK_RELEASE,

?????? KEY4_LONG_PRESS,

?????? KEY4_LONG_PRESS_CONTINUOUS,

?????? KEY4_LONG_PRESS_RELEASE,

?????? KEY5_CLICK,???????????????????????????????????? //21

?????? KEY5_CLICK_RELEASE,

?????? KEY5_LONG_PRESS,

?????? KEY5_LONG_PRESS_CONTINUOUS,

?????? KEY5_LONG_PRESS_RELEASE,

?????? KEY6_CLICK,???????????????????????????????????? //26

?????? KEY6_CLICK_RELEASE,

?????? KEY6_LONG_PRESS,

?????? KEY6_LONG_PRESS_CONTINUOUS,

?????? KEY6_LONG_PRESS_RELEASE,

}KEY_VALUE_TYPEDEF;

我們這個(gè)項(xiàng)目總共有6個(gè)按鍵,每個(gè)按鍵需要檢測(cè)短按、短按釋放、長(zhǎng)按、長(zhǎng)按釋放、連續(xù)長(zhǎng)按5個(gè)功能,所以總共有30個(gè)不同的枚舉值分別來對(duì)應(yīng)不同按鍵的不同功能。

第二步:

自定義了函數(shù)指針類型以后,我們就可以通過KeyEvent_CallBack_t這個(gè)類型名稱,去定義我們的函數(shù)指針變量。

KeyEvent_CallBack_t KeyScanCBS;

那KeyScanCBS就是函數(shù)指針,所以它的返回值是void類型,形參是KEY_VALUE_TYPEDEF枚舉類型的。

最終就是把這個(gè)指針指向別的.c文件的函數(shù),從而實(shí)現(xiàn)不同.c文件之間的數(shù)據(jù)傳遞,同時(shí)又能保持很好的可移植性(相互獨(dú)立,互不干擾)。

那怎么指向呢?我的方法是重新定義一個(gè)函數(shù),專門來為這個(gè)指針指向,這樣方便別的.c文件調(diào)用,這個(gè)函數(shù)我稱為注冊(cè)函數(shù)

比如以下函數(shù):

void hal_KeyScanCBSRegister(KeyEvent_CallBack_t pCBS)

{

?????? if(KeyScanCBS == 0)

?????? {

???????????????????? KeyScanCBS = pCBS;

?????? }

}?????

這個(gè)函數(shù)的作用就是把我們前面定義的KeyScanCBS函數(shù)指針指向外部的函數(shù)地址(也就是要指向那個(gè)函數(shù)的函數(shù)名)。

當(dāng)然,這個(gè)函數(shù)不是必須的,只是我的思維和代碼風(fēng)格,你也可以不多帶帶寫這樣的函數(shù),只要用之前把KeyScanCBS指向外部函數(shù)就可以了,否則等著程序死機(jī)吧哈哈哈。

第三步:

準(zhǔn)備好這幾步以后,我們繼續(xù)來說下怎么去使用它。

我們哪里要用到按鍵的功能,就在那個(gè).c文件那里重寫一個(gè)同樣的函數(shù)

比如說app.c這個(gè)文件是產(chǎn)品功能代碼(應(yīng)用層),我需要在應(yīng)用層使用按鍵功能。

重寫函數(shù)的時(shí)候,返回值和形參要跟那個(gè)函數(shù)指針類型一樣。

如果你忘記了,那我們?cè)賮砘仡櫹隆?/strong>

typedef void (*KeyEvent_CallBack_t)(KEY_VALUE_TYPEDEF keys);

無返回值,形參為KEY_VALUE_TYPEDEF類型。

只有這樣,你才能把這個(gè)函數(shù)的地址賦值給KeyScanCBS這個(gè)指針,才能正常傳遞數(shù)據(jù)。

重寫的這個(gè)函數(shù)就是通過形參來接收硬件層按鍵值的,如果是串口數(shù)據(jù),也是同理,只是形參不一樣。

然后,我們?cè)诋a(chǎn)品功能初始化的函數(shù)里直接調(diào)用剛剛hal_key.c的注冊(cè)函數(shù)

把KeyEventHandle這個(gè)函數(shù)的地址賦值給hal_key.c的KeyScanCBS這個(gè)函數(shù)指針。

所以,最終KeyScanCBS可以理解成等同于KeyEventHandle函數(shù)

我們?cè)趆al_key.c文件里,看按鍵檢測(cè)解析程序,最終就是執(zhí)行KeyScanCBS把我們keys(按鍵值)傳遞到我們app.c文件的。

這樣,就能做到以事件去驅(qū)動(dòng),只有按鍵按下,并且真實(shí)有效,我才會(huì)調(diào)用KeyScanCBS,才會(huì)把按鍵值傳遞給應(yīng)用層。

而中間,兩個(gè)文件之間沒有任何全局變量的依賴,也完全可以獨(dú)立,大家可以細(xì)品消化一下。

這里有個(gè)細(xì)節(jié)就是為什么我函數(shù)的形參要用枚舉類型。

如果你對(duì)接過一些模塊(WiFi、藍(lán)牙等)二次開發(fā)就知道了,模塊核心代碼都是封裝成lib這種庫給你的,你并看不到源代碼。

只能用他們的函數(shù),如果不用枚舉,那你不知道形參可以傳入什么值對(duì)吧?

如果用枚舉,我把能用的值都列出來給你,并且起好名字,讓你一看就知道是啥意思,這是不是就很方便?

Ok,今天就寫到這里,大家下去可以做下實(shí)驗(yàn)。

原創(chuàng)不易,盡量用最通俗的語言表達(dá),如果對(duì)你有幫助,麻煩安排個(gè)三連吧^ ^。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/121232.html

相關(guān)文章

  • 【STM32】標(biāo)準(zhǔn)庫與HAL庫對(duì)照學(xué)習(xí)教程八--串口通信詳解

    摘要:異步通信與同步通信異步通信異步通信是指通信的發(fā)送與接收設(shè)備使用各自的時(shí)鐘控制數(shù)據(jù)的發(fā)送和接收過程。同步通信同步通信時(shí)要建立發(fā)送方時(shí)鐘對(duì)接收方時(shí)鐘的直接控制,使雙方達(dá)到完全同步。配置串口設(shè)置為異步通信基礎(chǔ)參數(shù)波特率為。 ...

    yck 評(píng)論0 收藏0
  • 趣聊51之串口通信(概念篇)

    摘要:那么問題來了,單片機(jī)和之間的串口通信屬于哪種通信制式呢答案是全雙工,從單片機(jī)上有和兩個(gè)口就可以知道最后要講的一個(gè)重要的概念叫波特率。 ????????對(duì)于剛剛接觸單片機(jī)的同學(xué)們來說,串口通信似乎是一個(gè)神秘感十足的東西,筆者在剛剛開始學(xué)習(xí)51單片機(jī)時(shí),讀的是郭天祥先生的那本著名的《新概念51單...

    blastz 評(píng)論0 收藏0
  • 什么是面向?qū)ο螅?/b>

    摘要:第一章面向?qū)ο笮“资且婚T完全面向?qū)ο蟮木幊陶Z言嗯什么是面向過程什么又是面向?qū)ο竽卮罄性谖覀冋竭M(jìn)入學(xué)習(xí)這部分前,了解一下面向過程和面向?qū)ο筮@兩個(gè)概念,對(duì)于我們接下來的學(xué)習(xí)有很大的好處。這一部分我們會(huì)在面向?qū)ο髮W(xué)習(xí)結(jié)束后進(jìn)行系統(tǒng)的整理和總結(jié)。 showImg(https://segmentfault.com/img/remote/1460000019303357); 第一章 面向?qū)ο?小...

    DirtyMind 評(píng)論0 收藏0
  • 技術(shù)人攻略訪談九:逆襲!從技術(shù)編輯到云計(jì)算架構(gòu)師

    摘要:在云計(jì)算剛進(jìn)入中國的時(shí)候,成功地把握住了職業(yè)轉(zhuǎn)型的機(jī)會(huì),在實(shí)踐中成長(zhǎng)為優(yōu)秀的架構(gòu)師。技術(shù)人攻略在工作中遇到最大的挑戰(zhàn)是什么做云計(jì)算的難點(diǎn)在什么地方挑戰(zhàn)最大的是在工作的時(shí)候,要從頭到尾搭一套以為基礎(chǔ)的云計(jì)算平臺(tái)。 showImg(https://segmentfault.com/img/remote/1460000006889503); 導(dǎo)語:本期采訪對(duì)象李雨來@Blackte...

    chadLi 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<