肥宅钓鱼网
当前位置: 首页 钓鱼百科

请求和响应的回调函数c语言(c语言回调函数的使用及实际作用详解)

时间:2023-06-16 作者: 小编 阅读量: 3 栏目名: 钓鱼百科

所以这节课呢我们会以程序架构的需求为出发点,讲解回调函数是怎么满足它这个需求的。所以通过这两个种类型的分析啊,我们就可以知道,回调函数基本是用在输入型的处理中。那么它们输入的时间节点都是未知的,这些就能够用回调函数来处理。就是通过函数指针注册函数。这样调用后,我们key.c文件的pKeyScanCBS这个指针其实就是指向的KeyScanHandle函数。最终执行的是main.c文件的KeyScanHandle函数。

大家好,我是无际。

今天给大家讲一下芯片/模块厂家写SDK必须会使用的一种技术:回调函数。

回调函数这个知识点其实并不是很难,难是难在网上很多讲解回调函数的都说得太学术化了化了,一点也不亲民。

很多人即使知道怎么写回调函数也根本就搞不懂它们在实际产品中也有什么用,什么时候用。

所以这节课呢我们会以程序架构的需求为出发点,讲解回调函数是怎么满足它这个需求的。

为了方便大家理解,这篇内容也对应有一篇文章,大家可以找无际单片机编程获取。

一、通过这节课程你能掌握以下知识:

  1. 掌握程序架构的核心理念或需求。
  2. 掌握回调函数的作用
  3. 掌握回调函数的程序编写
  4. 掌握回调函数在产品中的应用

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

很多人可能会说一个好的程序架构啊,就是代码很紧凑、执行效率也很高。

其实这个说得很片面,不完全对,这只能说明你程序算法写得好,但架构不一定做得好。

既然是架构,那自然是以从”大局”为重,思维不能局限于当下的产品功能,还要考虑到以后功能的增加和裁剪,那么对于单片机开发来说,我认为一个好的程序架构至少要达到以下要求:

硬件层和应用层的程序代码分开,相互之间的控制和通讯使用接口,而且不会共享的全局变量或数组。

这里呢,我就这个要求,别小看这一个要求,因为这个要求里面蕴藏着很多学问的,比如用专业称为可移植性、可扩展性。

那么我们来想象一下我们通常写单片机代码的方式啊,在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-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函数。

所以,我们来看下输出结果。

如果还是有点模糊,下面我再给大家捋一捋编写和使用回调函数的流程:

  1. 自定义函数指针,形参作为硬件层要传到应用层的数据。
  2. 硬件层定义一个函数指针和函数指针注册函数。
  3. 应用层定义一个函数,返回值和形参都要和函数指针一致。
  4. 应用层调用函数指针注册函数,把定义好的函数名称作为形参传入。

Ok,这就是回调函数的使用。

如果还看不懂建议多看两遍。

下面请大家思考一下,这个程序虽然简单,但是不是架构还不错?应用层和硬件层完全独立?

    推荐阅读
  • 高德地图智能导航最新版(高德地图12.0大版本更新)

    高德地图智能导航最新版今天,高德地图推送了12.0大版本更新,包含了多项功能改动。在新版本中,高德地图推出了基于3D图像的城市内沉浸式导航,相比传统2D导航,能够更为直观清晰的向用户展示路线的行进方向。除了上述功能外,此次更新还加入了诸如AR导航智能定向、步行/骑行防晒导航、智能红绿灯提醒、数字领航员等一系列新功能。

  • 鱼粉是什么东西做的(鱼粉的简介)

    鱼粉是什么东西做的?鱼粉是什么东西做的鱼粉是用鱼制成的,人们会把一种鱼或者是多种与混合在一起再经过去油、脱水、粉碎等工序制成的,鱼粉是一种非常重要的饲料原料,不过现在也有可食用鱼粉被研发出来,它可以在烤面包中代替蛋类。全世界的鱼粉生产国主要有秘鲁、智利、日本、丹麦、美国、前苏联、挪威等,其中秘鲁与智利的出口量约占总贸易量的70%。

  • 肌酸在运动前还是后(肌酸在运动前还是运动后吃)

    一旦服用肌酸,要在原有正常饮水量的基础上每天至少多喝1200ml的水,才能充分发挥肌酸的水合作用。如果以提高肌肉力量和爆发力为目的,建议不要忽视训练前肌酸的补充。初次使用肌酸,要注意冲击期和维持期相结合。1周的冲击期内,每天4次服用肌酸,每次5克。冲击期的目的在于让体内的肌酸在短时间内迅速达到饱和状态。如果不冲击,需要30天左右的时间才能让肌酸在体内达到饱和。

  • 祝福99岁老寿星(问候和祝福送给百岁寿星)

    9月22日起,承担慰问任务的孝德文化志愿者们热情地把问候和祝福送到百岁寿星家中。除了活动组织单位提供的慰问品,志愿者们还自筹资金购买牛奶、西洋参等补品孝敬老人,有的为老人理发、体检,有的送水果、送口罩、赠送红包。据悉,截至到2022年,两家牵头单位组织的全市百岁寿星慰问活动已连续进行4年。作为活动赞助单位,诸暨联合村镇银行和浙江绿球食品有限公司也连续4年出资捐物支持慰问活动。

  • 全国十大品牌铝合金门窗(铝合金高档门窗十大品牌排名)

    铝合金高档门窗十大品牌排名:1.阿尔卑斯门窗、2.欧哲门窗、3.贝克洛门窗、4.旭格门窗、5.罗兰西尼门窗、6.巴尔蒂克门窗、7.希洛门窗、8.森鹰门窗、9.良木道门窗、10.皇派门窗。所以,阿尔卑斯不仅产品质量过硬,而且货期也非常快。以上是关于铝合金高档门窗十大品牌排名的相关介绍。

  • 脸部皮肤粗糙怎么改善(都有什么改善的方法)

    以下内容大家不妨参考一二希望能帮到您!皮肤毛孔粗大如果是发生在面部,一般大多是并发有痤疮,或者是皮肤的皮脂腺分泌旺盛而导致的。所以对于这种情况出现的皮肤粗糙和毛孔扩大,可以适当的使用阿达帕林凝胶外涂,这样能够有效的改善皮肤局部的角化状态,也可以使用红蓝光照射,因为红蓝光照射以后,能够改善皮肤的胶原蛋白的形成,这样可以促进皮肤从外观上来看,有些细腻的表现。

  • 梦见银手镯是什么意思(梦见银手镯的寓意)

    接下来我们就一起去了解一下吧!梦见银手镯是什么意思怀有身孕的女人梦见银镯子,生女孩,冬占生男孩。感情中的人梦见银镯子,亲人有建议,不可灰心,终有希望结婚。本命年的人梦见银镯子,交好友小心,好友之事少管,谦虚得人和顺利。病人梦到银手镯:健康状况很好,很快就能摆脱病魔的束缚,以后多加锻炼身体。未婚者梦到银手镯:爱情运不错,感情的路上将会有些障碍,但是没有很大的关系。

  • 西红柿和鱼能一起吃吗(西红柿和鱼可以一起吃吗)

    不仅会降低蛋白质的营养价值,而且易产生可刺激胃粘膜形成不易消化的鞣酸物质,使人出现腹痛、恶心、呕吐等症状。西红柿和鱼都是常见的营养丰富的食物,鱼肉不仅蛋白质含量高,还含有多种维生素、微量元素,而脂肪和热量都偏低,适合大部分人食用。需注意的是,部分鱼类对于易敏体质和手术后的人,则不建议其食用,以免加重病情。

  • 一月新番最弱的少年(35部重量级七月新番)

    然而不幸地,他的一切幻想终被玷污。2012年动画化决定时,SNKPlaymore游戏公司提起侵权诉讼,导致漫画从2014年起连载中止,并回收了部分已出版的前五卷单行本。2016年和游戏公司达成和解,漫画于2016年起连载再开,并发行单行本第六卷和经过加笔修正的前五卷。

  • 关于坚持的简短小故事(有什么是关于坚持的小故事)

    关于坚持的简短小故事头悬梁锥刺骨战国时苏秦,与魏人张仪同师鬼谷先生。汉代孙敬好学,读书时,用绳子把头发系在屋梁上,以防止打瞌睡,来督促自己努力攻读。于是雪夜,特别是月光映照下的雪夜,就成了孙康苦读的好时光。正当他撰写的《史记》进展顺利的时候,“李陵事件”的牵联,使他遭受宫刑。