C語言中回調(diào)函數(shù)的使用詳情
下文將學(xué)習(xí)到;
- 程序架構(gòu)的核心理念和需求
- 掌握回調(diào)函數(shù)的作用
- 掌握回調(diào)函數(shù)的程序編寫
- 掌握回調(diào)函數(shù)在產(chǎn)品中的應(yīng)用
1.程序架構(gòu)
一個好的程序架構(gòu)至少要達(dá)到以下要求:
硬件層和應(yīng)用層的程序代碼分開,相互之間的控制和通訊使用接口,而且不會共享的全局變量或者數(shù)組。
用專業(yè)術(shù)語描述就是可移植性、可擴(kuò)展性。
在51單片機(jī)寫程序時,基本上一個.c文件解決,包括寄存器配置,產(chǎn)品功能。到了stm32時,我們會把不同的外設(shè)功能,比如led,按鍵,串口等外設(shè)功能代碼分別寫在不同的.c文件里,然后統(tǒng)一用函數(shù)接口去調(diào)用它,比方說控制一個LED燈亮,直接在led.c文件里寫一個驅(qū)動led燈狀態(tài)的函數(shù)然后給外部調(diào)用就好了。硬件層和應(yīng)用層代碼分開,應(yīng)用層用硬件層提供的接口來控制,而且不會有硬件層和應(yīng)用層共享的全部變量或數(shù)組。
還有一種情況,應(yīng)用程序需要收集硬件層的數(shù)據(jù),比如串口接收數(shù)據(jù),按鍵采集,adc值采集,這種值應(yīng)該怎么樣從硬件層獲取呢?
簡單的方法就是用全局變量或者數(shù)組,比方說硬件層串口接收到數(shù)據(jù)了,那么我們把數(shù)據(jù)丟到數(shù)組里面,然后把接收完成的全局變量標(biāo)志置為1,比方說全局變量名為RcvFlag,然后應(yīng)用層程序會輪詢判斷RcvFlag==1?是的話就把數(shù)組里面的數(shù)據(jù)取出來解析。
但是這種方法存在實時性差和移植性差的問題,比如說需要把串口的硬件層封裝起來給客戶使用,不能讓客戶看到實現(xiàn)的源碼,只能提供函數(shù)接口給客戶使用,不可能通過告訴客戶先判斷哪個變量為1,然后在取哪個數(shù)組中的數(shù)據(jù)這種做法。
在這里就需要回調(diào)函數(shù)了。
2.回調(diào)函數(shù)的作用
在stm32中,像外部中斷、定時器中斷、串口中斷都有點類似回調(diào)函數(shù),這種函數(shù)的目的是把采集到的數(shù)據(jù)傳遞給cpu使用。
回調(diào)函數(shù)的核心作用:
- 把數(shù)據(jù)從一個.c文件傳遞到另一個.c文件。
3.掌握回調(diào)函數(shù)的程序編寫
傳統(tǒng)寫法的缺點:
- 1、移植性差
- 2、實時性差
- 3、功能代碼封裝難
回調(diào)函數(shù)寫法:
main.c代碼:
#include <stdio.h> #include "key.h"? void KeyScanHandle(KEY_ID_TYPEDEF KeyID,KEY_STATE_TYPEDEF KeyState) { //?? ?if(KeyID == KEY2) //?? ?{ //?? ??? ?if(KeyState = KEY_PRESS) //?? ??? ?{ ?? ??? ??? ? ?? ??? ??? ?printf("KeyID=%d, KeyState=%d\r\n",KeyID,KeyState); //?? ??? ?} //?? ?} } int main(int argc, char *argv[]) { ?? ?KeyInit(); ?? ?KeyScanCBSRegister(KeyScanHandle); ?? ?KeyPoll(); ? ?? ?return 0; }
key.c代碼:
#include "key.h" KEY_ID_TYPEDEF keyVal;?? ?//按鍵ID KEY_STATE_TYPEDEF keyState;?? ? pKeyScanCallBack pKeyScanCBS; void KeyInit() { ?? ?keyVal = 0; ?? ?keyState = KEY_IDLE; ?? ?pKeyScanCBS = 0; }? void KeyScanCBSRegister(pKeyScanCallBack pCBS) { ?? ?if(pKeyScanCBS == 0) ?? ?{ ?? ??? ?pKeyScanCBS = pCBS; ?? ?} } void KeyPoll() { ?? ?printf("Please Enter key value:"); ?? ?if(scanf("%d",&keyVal)==1) ?? ?{ ?? ??? ?printf("\r\n"); ?? ??? ?printf("Please enter key state:"); ?? ??? ?if(scanf("%d",&keyState)==1) ?? ??? ?{ ?? ??? ??? ?if(pKeyScanCBS != 0) ?? ??? ??? ?{ ?? ??? ??? ??? ?pKeyScanCBS(keyVal,keyState); ?? ??? ??? ?} ?? ??? ?}?? ??? ? ?? ?} }
key.h代碼:
#ifndef _KEY_H_ #define _KEY_H_ typedef enum? { ?? ?KEY1, ?? ?KEY2,?? ? }KEY_ID_TYPEDEF; typedef enum { ?? ?KEY_IDLE,?? ?//空閑? ?? ?KEY_PRESS,?? ?//按鍵短按 ?? ?KEY_LONG_PRESS,?? ?//按鍵長按 ?? ?KEY_RELEASE,//按鍵釋放 ? }KEY_STATE_TYPEDEF;? typedef void (*pKeyScanCallBack)(KEY_ID_TYPEDEF KeyID,KEY_STATE_TYPEDEF KeyState); ? void KeyInit(); void KeyPoll(); void KeyScanCBSRegister(pKeyScanCallBack pCBS); #endif
4.回調(diào)函數(shù)在產(chǎn)品中的應(yīng)用
根據(jù)收到的不同幀內(nèi)容,做出不同的功能
到此這篇關(guān)于C語言中回調(diào)函數(shù)的使用詳情的文章就介紹到這了,更多相關(guān)C語言回調(diào)函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++11/14 線程調(diào)用類對象和線程傳參的方法
這篇文章主要介紹了C++11/14 線程調(diào)用類對象和線程傳參的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-01-01C語言之棧和堆(Stack && Heap)的優(yōu)缺點及其使用區(qū)別
本篇文章主要介紹了什么是棧(Stack) 、什么是堆( Heap),以及棧和堆的優(yōu)缺點,同時介紹了應(yīng)該什么時候使用堆和棧,有需要的朋友可以參考下2015-07-07C++ 隨機(jī)數(shù)與隨機(jī)種子數(shù)的實例
這篇文章主要介紹了C++ 隨機(jī)數(shù)與隨機(jī)種子數(shù)的實例的相關(guān)資料,需要的朋友可以參考下2017-07-07C++編程中__if_exists與__if_not_exists語句的用法
這篇文章主要介紹了C++編程中__if_exists與__if_not_exists語句的用法,是C++中用于判斷指定的標(biāo)識符是否存在的基礎(chǔ)的條件判斷語句,需要的朋友可以參考下2016-01-01c++之解決char轉(zhuǎn)string時出現(xiàn)的亂碼問題
這篇文章主要介紹了c++之解決char轉(zhuǎn)string時出現(xiàn)的亂碼問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-08-08VC實現(xiàn)ODBC數(shù)據(jù)庫操作實例解析
這篇文章主要介紹了VC實現(xiàn)ODBC數(shù)據(jù)庫操作的方法,非常有實用價值,需要的朋友可以參考下2014-07-07