c語言回調函數使用及實際作用詳解

      網友投稿 1018 2025-04-01

      大家好,我是無際。


      今天給大家講一下芯片/模塊廠家寫SDK必須會使用的一種技術:回調函數。

      回調函數這個知識點其實并不是很難,難是難在網上很多講解回調函數的都說的太學術化了化了,一點也不親民。

      很多人即使知道怎么寫回調函數也根本就搞不懂它們在實際產品中也有什么用,什么時候用。

      所以這節課呢我們會以程序架構的需求為出發點,講解回調函數是怎么滿足它這個需求的。

      為了方便大家理解,這篇內容也對應有一篇文章,大家可以找無際單片機編程獲取。

      一、通過這節課程你能掌握以下知識:

      掌握程序架構的核心理念或需求。

      掌握回調函數的作用

      掌握回調函數的程序編寫

      掌握回調函數在產品中的應用

      二、程序架構的核心理念和需求

      很多人可能會說一個好的程序架構啊,就是代碼很緊湊、執行效率也很高。

      其實這個說的很片面,不完全對,這只能說明你程序算法寫的好,但架構不一定做的好。

      即然是架構,那自然是以從”大局”為重,思維不能局限于當下的產品功能,還要考慮到以后功能的增加和裁剪,那么對于單片機開發來說,我認為一個好的程序架構至少要達到以下要求:

      硬件層和應用層的程序代碼分開,相互之間的控制和通訊使用接口,而且不會共享的全局變量或數組。

      這里呢,我就這個要求,別小看這一個要求,因為這個要求里面蘊藏著很多學問的,比如用專業稱為可移植性、可擴展性。

      那么我們來想象一下我們通常寫單片機代碼的方式啊,在51的時候基本一個.c文件解決,包括寄存器配置啊,產品功能啊。

      這種就是沒有架構的程序,然后我們進化到STM32這個單片機以后,程序大了,慢慢也會在工程文件里加幾個文件夾目錄把硬件層和應用層代碼分開了。

      于是我們會把一些不同的外設功能,比如Led、按鍵、串口等外設功能代碼分別寫在不同的.c文件里,然后統一用函數接口去調用它。

      比方說控制一個LED燈亮,直接在led.c文件里寫一個驅動led燈狀態的函數然后給外部調用就好了。

      那我們我們看這種Led的控制函數確實也是滿足程序架構的需求的,硬件層和應用層代碼分開,應用層用硬件層提供的接口來控制,而且又不會有硬件層和應用層共享的全部變量或數組。像這種是不是很簡單?

      那么不知道你們有沒有碰到另外一種情況,就是應用程序需要采集硬件層的數據,比如串口接收數據,按鍵采集、ADC值采集。

      這種硬件層的數據怎么通知應用層來拿,或者怎么主動給它?

      我們以往最簡單粗暴的方式是不是就是用一個全局變量,比方說硬件層串口接收到數據來了,那么我們把數據丟到數組里,然后把接收完成全局變量標志位置1。

      比方說全局變量名為RcvFlag,然后應用層程序會輪詢判斷RcvFlag==1?是的話就開始把數組里的數據取出來解析。

      很多人就會說了,你看我用這種方法照樣能實現功能啊,為什么還要學習別的架構。

      這樣做當然可以實現功能,但是會存在移植性很差的問題。

      比如說你們老板讓你把這個串口的硬件層封裝起來給客戶用,但不能讓客戶看到你實現的源代碼,只提供接口(函數名)給對方用。

      那么這時候難道你要告訴客戶先判斷哪個變量為1,然后再取哪個數組的數據這么LOW的做法嗎?

      那么如果是懂行的客戶一定會懷疑你們公司的技術實力是不是小學生水平。

      那怎樣做才會既方便又專業呢? 這里我們就需要用到回調函數啦。

      三、回調函數的作用

      那么在講回調函數之前呢,對于函數調用呢我一般分為2種類型:

      1.輸出型

      不知道大家有沒有用過C語言自帶的一些庫函數,比如說sizeof()獲取數據長度的函數,memcpy()是內存拷貝函數,我們調用這個函數之后呢就能完成相應的功能。

      還有我們基于單片機的一些程序函數,比方說控制LED點亮熄滅、繼電器吸合斷開、LCD驅動等等。

      那么這些呢,我一般稱為輸出型的函數。

      輸出型函數我們是主導的角色,我們知道什么時候該調用它。

      2.輸入型

      輸入型呢,也稱為的是響應式的函數。

      什么叫響應式的函數呢?

      比方說接收串口的數據,我們不知道什么數據什么時候來。

      再比方說,我們按鍵檢測的函數,我們不知道什么時候會按下按鍵,那么這些就要定義成響應式函數來實現,而響應式函數就可以用回調函數來實現。

      所以通過這兩個種類型的分析啊,我們就可以知道,回調函數基本是用在輸入型的處理中。

      比方說串口數據接收,那么數據是輸入到單片機里面的,單片機是處于從機角色。

      按鍵檢測,按鍵狀態是輸入到單片機里的。

      再比方說ADC值采集,ADC值也是輸入到單片機里的。

      那么它們輸入的時間節點都是未知的,這些就能夠用回調函數來處理。

      具體怎么處理后面我們會用代碼來給大家舉例。

      回調函數還有一個作用就是為了封裝代碼。

      比如說做芯片或者模組的廠家,我們拿典型的STM32來舉例,像外部中斷、定時器、串口等中斷函數都是屬于回調函數,這種函數的目的是把采集到的數據傳遞給用戶,或者說應用層。

      所以回調函數的核心作用是:

      1.把數據從一個.c文件傳遞到另一個.c文件,而不用全局變量共享數據這么LOW的方法。

      2.對于這種數據傳遞方式,回調函數更利于代碼的封裝。

      四、掌握回調函數的程序編寫

      前面說了很多概念性的東西,可能大家也比較難理解,回調函數最終呢是靠函數指針來實現的。

      c語言回調函數的使用及實際作用詳解

      那么我這里通過一些模擬按鍵的例子來演示下怎么回通過調函數來處理它們。

      下面是我們的c-free工程,用這個來模擬方便點:

      從模塊化編程的思想來看,整個工程分為2個部分,應用層main.c文件,硬件層key.c和key.h文件。

      不管再怎么復雜的程序,我們都要先從main函數一步步往下挖,main函數代碼如下。

      int main(int argc, char *argv[])

      {

      KeyInit();

      KeyScanCBSRegister(KeyScanHandle);

      KeyPoll();

      return 0;

      }

      KeyInit();是key.c文件的按鍵初始化函數

      KeyScanCBSRegister(KeyScanHandle);是key.c的函數指針注冊函數。

      這個函數可能大家會有點蒙,請跟進我們的節奏,下面開始燒腦環節,也是寫回調函數的必須步驟,

      想理解這個回調函數注冊函數,我們要先從硬件層(key.h)頭文件的函數指針定義說起,具體看下圖。

      這里自定義了一個函數指針類型,帶兩個形參。

      然后,我們在key.c這個文件里定義了一個函數指針變量。

      重點來了,我們就是通過這個函數指針,指向應用層的函數地址(函數名)。

      具體怎么實現指向呢?就是通過函數指針注冊函數。

      這個函數是在main函數里調用,使用這種注冊函數的方式注冊靈活性也很高,你想要在哪個.c文件使用按鍵功能就在哪里調用。

      這里要注意,main.c這個文件要定義一個函數來接收硬件層(key.c)過來的數據。

      這里定義也不是亂定義的,一定要和那個自定義函數指針類型返回值、形參一致。

      然后把這個函數名字直接復制給KeyScanCBSRegister函數的形參就可以了。

      這樣調用后,我們key.c文件的pKeyScanCBS這個指針其實就是指向的KeyScanHandle函數。

      也就是說執行pKeyScanCBS的時候,就是執行KeyScanHandle函數。

      那具體檢測按鍵的功能就是KeyPoll函數,這個在main函數里調用。

      當檢測到鍵盤有輸入以后,最終會調用pKeyScanCBS。

      最終執行的是main.c文件的KeyScanHandle函數。

      所以,我們來看下輸出結果。

      如果還是有點模糊,下面我再給大家捋一捋編寫和使用回調函數的流程:

      自定義函數指針,形參作為硬件層要傳到應用層的數據。

      硬件層定義一個函數指針和函數指針注冊函數。

      應用層定義一個函數,返回值和形參都要和函數指針一致。

      應用層調用函數指針注冊函數,把定義好的函數名稱作為形參傳入。

      Ok,這就是回調函數的使用。

      如果還看不懂建議多看兩遍。

      下面請大家思考一下,這個程序雖然簡單,但是不是架構還不錯?應用層和硬件層完全獨立?

      C 語言 單片機

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:excel表格添加斜線的教程(怎樣在excel表格中添加斜線)
      下一篇:怎樣去處word表格里的回車鍵(怎樣去word表中回車鍵)
      相關文章
      久久亚洲国产精品五月天| 亚洲精品久久久久无码AV片软件| 亚洲国产成人久久精品软件| 亚洲三级在线播放| 亚洲国产精品线观看不卡| 91亚洲国产成人精品下载| 亚洲高清国产拍精品26U| 亚洲熟妇av一区二区三区| 久久久久亚洲AV成人网人人网站 | 亚洲AⅤ无码一区二区三区在线 | 亚洲Av永久无码精品三区在线| 亚洲中文字幕不卡无码| 亚洲中文字幕无码一久久区| 亚洲综合熟女久久久30p| 亚洲熟妇丰满多毛XXXX| 国产亚洲精品自在久久| 久久亚洲精品成人综合| 亚洲精品自产拍在线观看动漫| 亚洲国产天堂久久综合网站| 亚洲一区二区三区首页| 亚洲欧洲校园自拍都市| 亚洲一区二区三区免费观看| 亚洲免费福利在线视频| 亚洲欧美aⅴ在线资源| 亚洲AV电影天堂男人的天堂| 亚洲 无码 在线 专区| 亚洲日韩国产成网在线观看| 亚洲爽爽一区二区三区| 国产综合亚洲专区在线| 人人狠狠综合久久亚洲88| 亚洲狠狠久久综合一区77777| 亚洲视频在线观看免费| 亚洲性一级理论片在线观看| 亚洲人成影院在线高清| 中文文字幕文字幕亚洲色| 亚洲va中文字幕| 亚洲成a人片在线观看国产| 国产精品亚洲美女久久久| 久久亚洲国产欧洲精品一| 午夜亚洲国产理论秋霞| 亚洲AV人人澡人人爽人人夜夜|