STM32物联网实战开发(2)——回调函数

news2024/12/22 23:36:56

        在第一篇博客中提到了全新的程序框架,我们会大量的使用回调函数,其中包括枚举类型结构体函数指针的应用。

回调函数:就是一个通过函数指针调用的函数。如果你把函数的地址传递给中间函数的形参,中间函数通过函数指针调用其所指向的函数时,我们就说这是回调函数。如:

Fun1()			//应用层
{
	Fun2(Fun3);		//Fun2中间层,Fun3回调函数
}

通俗点的解释:函数Fun1调用函数Fun2,同时将函数Fun3作为形参传递给Fun2,此时,Fun1为应用层函数,Fun2为中间层函数,Fun3为回调函数,回调函数是一种说法而已。当Fun2被调用时,Fun3也会被接着调用。

这样编程的意义在于

        利于代码结构,将代码分为应用层,中间层,硬件驱动层,彼此独立,方便程序的编辑,阅读,修改与移植;

        结构化编程时,结构体只需要定义中间函数,减小内存的开销。

伪代码1

Fun1()
{
    Fun2()
    {
    	Fun3_1();
    	Fun3_2();
        …………
    }
}

这种函数调用写法的缺陷:

        当Fun3有多个功能函数时,每次增加一个,都要修改Fun2,这样代码的耦合性就大。

        通过函数指针的好处是,Fun2与Fun3实现隔离,比如Fun3具有多个功能函数,增加或减少时,不需要修改Fun2的代码。

伪代码2

LED.h

定义带有三个函数指针的结构体类型

//定义结构体类型
typedef struct
{
    LED_Num_t LED_Num;
    void (*LED_ON)(uint8_t );
    void (*LED_OFF)(uint8_t );
    void (*LED_Flip)(uint8_t );
}LED_t;

extern LED_t LED;

LED.c

初始化结构体,每个函数指针都指向一个函数

LED_t LED = 
{
    LED1,
    LED_ON,
    LED_OFF,
    LED_Flip
};

main.c

通过结构体调用函数

int main()
{
	LED.LED_ON();
	LED.LED_OFF();
}

这种函数调用写法的缺陷:

1、如果功能函数增多,那结构体里面的函数指针也要增多,增加内存开销

2、main函数或其他调用函数要修改,main函数想要调用增多的功能函数,也要增加调用的操作

回调函数调用关系

 

回调函数代码使用示例

原本LED.h头文件里的结构体

//定义结构体类型
typedef struct
{
    void (*LED_ON)(uint8_t );
    void (*LED_OFF)(uint8_t );
    void (*LED_Flip)(uint8_t );
}LED_t;

修改后

        本来结构体里是三个分别指向 LED_ONLED_OFFLED_Flip的函数指针,现在改为只定义一个中间层的函数指针LED_Fun,该指针名字为LED_Fun,可指向一个函数,该函数无返回值,一个参数类型为uint8_t,另一个参数为一个函数指针(指向一个无返回值,参数类型为uint8_t的函数)

        本来 LED_ONLED_OFFLED_Flip函数是用 static 修饰为静态函数的,只能通过结构体变量进行调用,现在用回调函数后,通过函数指针调用,所以要在源文件中把这三个函数的 static 去掉,并在头文件中加 extern 声明为外部可调用。(当初我和UP主一起写代码的时候,没有注意到static的用法,程序一直报错,原来是这样啊,受教了!

//定义枚举类型
typedef enum
{
    LED1 = (uint8_t)0x01,
    LED2 = (uint8_t)0x02,
    LED3 = (uint8_t)0x03
}LED_Num_t;

//定义结构体类型
typedef struct
{
    void (*LED_Fun)(uint8_t,void (*CallBack)(uint8_t));		//中间层函数
}LED_t;

/* extern variables-----------------------------------------------------------*/
extern LED_t LED;
extern void LED_ON(uint8_t );		//函数声明为外部可调用
extern void LED_OFF(uint8_t );
extern void LED_Flip(uint8_t );
/* extern function prototypes-------------------------------------------------*/ 

LED.c

        源文件里实现中间函数LED_Fun(),直接调用CallBack指针指向的函数;在结构体里初始化LED_Fun函数。

/* Private variables----------------------------------------------------------*/
static void LED_Fun(uint8_t ,void (*CallBack)(uint8_t));
/* Public variables-----------------------------------------------------------*/
LED_t LED = 
{
    LED_Fun
};
/* Private function prototypes------------------------------------------------*/

/*
* @name   LED_Fun
* @brief  LED功能函数,中间虚拟函数(回调函数)
* @param  LED_NUM:LED灯编号,CallBack:回调函数指针
* @retval None   
*/
static void LED_Fun(uint8_t LED_NUM,void (*CallBack)(uint8_t))
{
    (*CallBack)(LED_NUM);
}

main函数或其他函数使用

        STA_Machine.c状态机源文件通过结构体变量LED,调用LED_Fun函数,并传入第一个参数LED灯编号,然后第二个参数就传入具体实现功能的函数,因为函数名就等于函数的首地址,所以把LED_OFF函数的首地址给到了函数指针CallBack,当LED_Fun函数被调用,则LED_OFF函数也会紧接着被调用,从而实现回调函数机制。

/*
* @name   Fun_STA1
* @brief  状态函数1
* @param  None
* @retval None   
*/
static void Fun_STA1()
{
    HAL_Delay(500);                     //延时500ms
    LED.LED_Fun(LED1,LED_OFF);         //熄灭LED1    LED.LED_Fun(LED2,LED_OFF);         //熄灭LED2
    LED.LED_Fun(LED3,LED_OFF);         //熄灭LED3
    STA_Machine.ucSTA_Machine_Status = STA2;      //切换到STA2状态
}


 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/473933.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【VM服务管家】VM4.0软件使用_1.3全局模块类

目录 1.3.1 通讯管理:通讯管理的心跳管理功能的使用方法1.3.2 全局触发:使用全局触发功能执行流程的方法1.3.3 全局变量:全局变量关联流程中具体模块结果的方法1.3.4 全局脚本:方案加载完成信号发给通信设备的方法1.3.5 全局脚本&…

我做了个GPT3键盘,用了两个月发现它有点傻

自 ChatGPT 出世,各类文本类AI产品层出不穷。甚至接连几日,Producthunt 上新品过半都是AI相关。 这其中部分原因是 OpenAI 公司开放的 GPT3 1API 接口十分易用。只要一个简单的文本请求,就能将现有产品加入AI功能。例如,Notion、…

Docker在Windows系统中的安装方法和使用方法

Docker在Windows系统中的安装方法和使用方法 Docker是一种容器化技术,可以让开发者将应用程序和其依赖项打包成一个可移植的容器,从而实现快速部署和运行。在Windows系统中,Docker可以通过以下步骤进行安装和使用。 优点: Dock…

【VM服务管家】VM4.x算子SDK开发_3.3 模块工具类

目录 3.3.1 位置修正:位置修正算子工具的使用方法3.3.2 模板保存:实现模板自动加载的方法3.3.3 模板匹配: 获取模板匹配框和轮廓点的方法3.3.4 模板训练:模板训练执行完成的判断方法3.3.5 图像相减:算子SDK开发图像相减…

浅谈软件质量与度量

本文从研发角度探讨下高质量软件应具备哪些特点,以及如何度量软件质量。 软件质量的分类 软件质量通常可以分为:内部质量和外部质量。 内部质量 内部质量是指软件的结构和代码质量,以及其是否适合维护、扩展和重构。它关注的是软件本身的…

数据结构 | 常见的数据结构是怎样的?

本文简单总结数据结构的概念及常见的数据结构种类 1’ 2。 更新:2023 / 04 / 05 数据结构 | 常见的数据结构是怎样的? 总览概念分类 常用的数据结构数组链表跳表栈队列树二叉树完全二叉树、满二叉树 平衡二叉树单旋转左旋右旋 红黑树红黑树 V.S 平衡二叉…

2 天:我用文字 AI-ChatGPT 写了绘画 AI-Stable Diffusion 跨平台绘画应用

文本 AI - ChatGPT 和绘画 AI - Stable Diffusion,平地惊雷,突然进入寻常百姓家。 如果时间可以快进,未来的人们对于我们这段时光的历史评价,大概会说: 当时的人们在短时间连续经历了这几种情感。从不信,…

java多线程BlockingDeque的三种线程安全正确退出方法

本文介绍两种BlockingDeque在多线程任务处理时正确结束的方法 一般最开始简单的多线程处理任务过程 把总任务放入BlockingDeque创建多个线程,每个线程内逻辑时,判断BlockingDeque任务是否处理完,处理完退出,还有任务就BlockingDe…

对顶堆模板!!【DS对顶堆】ABC281 E - Least Elements

我想的思路和正解是差不多的 就是滑动窗口,每过去一个用DS维护一下前k个元素和sum 本来想的是用优先队列维护前k个 然后想着multiset维护前k个,但是具体不知道怎么操作 这里用的是multiset维护对顶堆 关于对顶堆,我在寒假的时候总结过 …

【Java笔试强训】(1)

🎉🎉🎉点进来你就是我的人了博主主页:🙈🙈🙈戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔🦾🦾🦾 目录 一、选择题 二、编程题 🔥组队竞…

Github创建一个新仓库,关联本地数据并上传文件的图文步骤

工作中,我们经常会使用github来承享别人的代码果实,同时我们也会把自己的成果分享给别人,互相帮助。 今天的这篇图文教程非常重要,目标是使用Github来创建一个远程仓库,并和本地仓库对接,同时要做上传新内容…

初始Vue3【Vue3】

1.Vue3简介 2020年9月18日,Vue.js发布3.0版本,代号:One Piece(海贼王)耗时2年多、2600次提交、30个RFC、600次PR、99位贡献者github上的tags地址:https://github.com/vuejs/vue-next/releases/tag/v3.0.0 …

使用docker容器化部署mysql8.0.27,并更改其默认端口3306为3306全流程记录。

使用docker容器化部署mysql8.0.27,并更改其默认端口3306为3306全流程记录。 1.创建镜像 #查看镜像 docker images|grep mysql #搜索镜像 docker search mysql #拉取镜像 docker pull mysql:latest #运行镜像,--name 后的参数自己命名,我的数…

js逆向之rpc远程调用(你强任你强,我无视一切)

一、找到加密函数位置 二、在其下面注入ws服务 (1)注入准备 资源>>替换>>随便选一个空文件夹 (2)进行注入 进行(1)操作后可直接编辑js代码了,做以下修改 (function() {var ws new WebSocket(…

ChatGPT实现代码生成

代码生成 就代码生成而言,ChatGPT 是一款卓越的工具,它为开发者提供强大的功能。ChatGPT 可以运用其出色的自然语言处理技术,深入理解和解释开发者的需求,快速生成适合的代码片段。对于那些繁琐的任务或者重复的代码,…

肝一肝设计模式【三】-- 原型模式

系列文章目录 肝一肝设计模式【一】-- 单例模式 传送门 肝一肝设计模式【二】-- 工厂模式 传送门 文章目录 系列文章目录前言一、什么是原型模式二、浅克隆三、深克隆写在最后 前言 前文中我们知道设计模式可以分为三大类:创建型模式、结构型模式、行为型模式。创…

Baumer工业相机堡盟相机如何使用偏振功能(偏振相机优点和行业应用)(C#)

项目场景: Baumer工业相机堡盟相机是一种高性能、高质量的工业相机,可用于各种应用场景,如物体检测、计数和识别、运动分析和图像处理。 Baumer的万兆网相机拥有出色的图像处理性能,可以实时传输高分辨率图像。此外&#xff0…

tp6.1 bingher/ueditor(百度编辑器)(七牛、阿里OSS第三方云)详情图文教程(2023年第二版)

之前做过一版:tp6 bingher/ueditor(百度编辑器)(七牛、阿里OSS第三方云)详情图文教程_我是高手高手高高手的博客-CSDN博客 登录权限是Session,现在系统是Cookie加jwt的Token方式验证 一、修改验证登录权限 修改文件: vendor\bingher\uedito…

react native ios 添加启动页 xcode14 react-native-splash-screen

最近更新xcode,有些配置有些不同,网上查的方法都是过时的,导致配了一段时间卡在这里,最后访问官网才弄好了,所以以后解决问题的办法先看官网再查其他各路神仙的办法。 官网的步骤:https://github.com/crazy…

ChatGPT原理剖析

文章目录 ChatGPT常见误解1. 罐头回应2. 网络搜寻重组 ChatGPT真正做的事——文字接龙ChatGPT背后的关键技术——预训练(Pre-train)一般机器是怎样学习的? ChatGPT带来的研究问题1. 如何精准提出需求2. 如何更改错误3. 侦测AI生成的物件4. 不…