什么是回调函数(回调函数的参数)

大家好,我是无量 。
今天继续说回调函数 。
之前写过一篇文章,得到了广大老铁工的认可 。
最近几个新生对回调函数有点迷茫 。
我不明白为什么我要做这个圈圈指点点的功能 。
先写文章预热一下,晚上再直播和你互动讲解答疑 。
其实不是我想把简单的事情复杂化,而是如果你想写出一个好的代码架构,回调函数是必不可少的 。
【什么是回调函数(回调函数的参数)】你看看大神写的程序,会发现他们都是这么做的,比如蓝牙协议栈,实时操作系统,STM32固件库等等 。
每个人的文笔可能不一样,但本质是一样的 。
我们先来了解一下回调函数的作用 。
我一般喜欢把函数分为输出型和输入型(个人理解) 。
输出类型:
就是我们主动调用的控制功能,比如控制LED灯的开与关,控制蜂鸣器响与不响,控制液晶显示,控制继电器的开与关 。
简单地说,我们知道什么时候调用这些函数 。比如在满足一定条件时,我们会主动调用这些函数 。
这种函数就是输出函数 。
输入类型:
类型I功能通常用于在不同的之间传输信号和数据 。c文件/层(硬件层和应用层),如关键检测和串行数据 。
我们不知道什么时候按键,什么时候串口会有数据,对吧?
当然,我们可以写一个有返回值的函数,然后定期检查,比如10ms扫描按键 。
unsigned char ScanKey(){//按键检测程序…}然后我们在主程序中使用:
while(1){ unsigned char key; if(10ms时间到) { Key = ScanKey(); } if(Key == 有效按键值) { //执行按键功能程序 }}通过这种方式,连续扫描按键以检测按键是否被按下 。
当然这种方法也是可以的,但是不够专业,不够好 。
正因为如此,我需要一直判断while循环中Key的值,然后根据Key的值判断这个键是否被按下 。一定程度上浪费了cpu资源 。
而且在一些应用场景下,这种方法并不容易实现,比如串行数据 。while循环中总不能判断有没有新的串行数据进来吧?
我们的理想状态是怎样的?
也就是说,如果按了某个键,或者有新的数据出现,请再次通知我 。
这种通知方式一般称为事件触发,即按下一个按钮的事件被触发,我来处理 。
所以这个时候回调函数就可以很好的解决这个需求 。
我们以按键为例 。
前面说了,每个人写回调函数的风格可能不一样 。STM32固件库中的那些中断处理函数基本都是回调函数,不过和我的写作风格还是有一些区别的 。
当我们编写回调函数时,我们需要以下步骤:
第一步:
用keyevent _ callback _ t的名字定制一个函数指针类型 。
TYPEDEF void(* KEY event _ CallBack _ t)(KEY _ VALUE _ TYPEDEF keys);
这通常是在头文件中定制的,因为其他的 。也将使用c文件 。
这是一个没有返回值的函数指针类型,参数是KEY_VALUE_TYPEDEF枚举类型 。
通常,这个参数键是我们最终将传递给其他人的信号/数据 。通过回调函数调用c文件 。如果是按键检测,就是键值,哪个按键被按了 。
我们来看看枚举KEY_VALUE_TYPEDEF的值 。
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;本项目共有6个按键,每个按键需要检测短按、短按释放、长按释放、连续长按五种功能,所以有30个不同的枚举值对应不同按键的不同功能 。
第二步:
在定义了函数指针类型之后,我们可以通过类型名keyevent _ callback _ t来定义我们的函数指针变量 。
KeyEvent _ CallBack _ t KeyScanCBS
那么KeyScanCBS就是一个函数指针,所以它的返回值是void类型,它的参数是KEY_VALUE_TYPEDEF枚举类型 。
最后是这个指针指向其他的功能 。c文件,从而实现不同 。c文件,同时保持良好的可移植性(独立和互不干扰) 。
怎么点?我的方法是专门为这个指针重新定义一个函数,方便其他 。要调用的c文件 。我称这个函数为注册函数 。
例如,以下功能:


推荐阅读