蓝牙4.0协议栈按键流程分析
- 格式:docx
- 大小:21.08 KB
- 文档页数:11
BLE4.0教程⼀蓝⽛协议连接过程与⼴播分析1.蓝⽛简介什么是蓝⽛4.0蓝⽛⽆线技术是使⽤范围最⼴泛的全球短距离⽆线标准之⼀,蓝⽛4.0版本涵盖了三种蓝⽛技术,即传统蓝⽛、⾼速蓝⽛和低功耗蓝⽛技术,将三种规范合⽽为⼀。
它继承了蓝⽛技术在⽆线连接上的固有优势,同时增加了⾼速蓝⽛和低功耗蓝⽛的特点。
这三个规格可以组合或者单独使⽤。
蓝⽛4.0规范的核⼼是低功耗蓝⽛(Low Energy),即蓝⽛4.0BLE。
该技术最⼤特点是拥有超低的运⾏功耗和待机功耗,蓝⽛低功耗设备使⽤⼀粒纽扣电池可以连续⼯作数年之久。
蓝⽛4.0技术同时还拥有低成本、向下兼容、跨⼚商互操作性强等特点。
蓝⽛4.0 BLE的特点蓝⽛4.0 BLE技术具有如下特点:1.⾼可靠性对于⽆线通信⽽⾔,由于电磁波在传输过程中容易受很多因素的⼲扰,例如,障碍物的阻挡、天⽓状况等。
因此,⽆线通信系统在数据传输过程中,具有内在的不可靠性。
蓝⽛技术联盟(SIG)在制定蓝⽛4.0规范时已经考虑到了这种数据传输过程中的内在的不确定性,所以在射频、基带协议、链路管理协议(LMP)中采⽤可靠性措施,包括:差错检测和校正、进⾏数据编解码、差错控制、数据加噪等,极⼤地提⾼了蓝⽛⽆线数据传输的可靠性。
另外,使⽤⾃适应跳频技术,最⼤程度地减少和其他2.4GHz ISM频段⽆线电波的串扰。
2.低成本、低功耗低功耗蓝⽛⽀持两种部署⽅式:双模⽅式和单模⽅式。
(1)双模⽅式,低功耗蓝⽛功能集成在现有的经典蓝⽛控制器中,或在现有经典蓝⽛技术(2.1+EDR/3.0+HS)芯⽚上增加低功耗堆栈,整体架构基本不变,因此成本增加有限。
(2)单模⽅式,⾯向⾼度集成、紧凑的设备,使⽤⼀个轻量级连接层(Link Layer)提供超低功耗的待机模式操作。
蓝⽛4.0BLE技术可以应⽤于8bit MCU,⽬前TI公司推出的兼容蓝⽛4.0BLE协议的SoC芯⽚CC2540/CC2541,外接PCB天线和⼏个阻容器件构成的滤波电路即可实现蓝⽛⽹络节点的构建。
蓝牙协议栈开发流程1. 硬件平台选择在进行蓝牙协议栈开发之前,首先需要选择一个合适的硬件平台。
一般而言,蓝牙协议栈开发需要依托于一个蓝牙芯片或模块,这个芯片或模块需要支持蓝牙标准,并且提供相应的开发工具和文档。
在选择硬件平台时,需要考虑到项目的需求以及硬件的成本和可用性等因素。
2. 硬件平台驱动开发一般而言,蓝牙协议栈开发需要依赖于底层的硬件平台驱动,这需要涉及到对硬件的了解和驱动程序的开发。
这包括对芯片或模块的寄存器映射、时序要求、接口协议等方面的了解,并且需要编写相应的驱动程序来与硬件进行交互。
在驱动开发过程中,需要考虑到硬件的特性和限制,同时也需要保证驱动程序的效率和稳定性。
3. 协议栈架构设计蓝牙协议栈是蓝牙通信的核心部分,它负责处理蓝牙连接、数据传输、设备发现、配对等功能。
协议栈一般包括多个层次,包括物理层、链路层、L2CAP层、RFCOMM层、SDP 层等。
在进行协议栈的开发时,需要对整个协议栈的架构进行设计,包括各个层次的功能和接口等。
同时也需要考虑到协议栈的效率、可扩展性、可移植性等方面的要求。
4. 协议栈的实现在协议栈的实现过程中,需要根据协议规范和硬件平台的要求,编写相应的代码来实现蓝牙协议栈的各个功能。
这需要对蓝牙规范有较深的了解,并且需要在编写代码的过程中充分考虑到硬件平台的特性和限制。
在进行协议栈的实现时,需要进行模块化设计,确保各个功能模块之间的接口清晰,同时也需要进行充分的测试和调试,确保实现的功能正确和稳定。
5. 协议栈的优化在进行协议栈的开发过程中,需要进行各个方面的优化,包括代码的优化、内存的优化、功耗的优化等。
这需要根据具体的硬件平台和应用场景来进行优化的选择,以确保协议栈在实际应用中能够满足相应的要求。
6. 测试和验证在协议栈的开发完成后,需要进行相应的测试和验证工作。
这包括功能测试、性能测试、兼容性测试、安全性测试等。
这需要根据蓝牙标准和相关的测试要求,编写测试用例,并且对协议栈进行全面的测试。
本系列教程将结合TI 推出的CC254x SoC 系列,讲解从环境的搭建到蓝牙 4.0 协议栈的开发来深入学习蓝牙 4.0 的开发过程。
教程共分为六部分,本文为第五部分:第五部分知识点:第二十一节DHT11 温湿度传感器第二十二节蓝牙协议栈之从机通讯第二十三节蓝牙协议栈主从一体之主机通讯第二十四节OAD 空中升级第二十五节SBL 串口升级有关TI 的CC254x 芯片介绍,可点击下面链接查看:主流蓝牙BLE控制芯片详解(1):TI CC2540同系列资料推荐:由浅入深,蓝牙4.0/BLE 协议栈开发攻略大全(1)由浅入深,蓝牙4.0/BLE 协议栈开发攻略大全(2)由浅入深,蓝牙4.0/BLE 协议栈开发攻略大全(3)由浅入深,蓝牙 4.0/BLE 协议栈开发攻略大全(4)有关本文的工具下载,大家可以到以下这个地址:朱兆祺ForARM第二十一节DHT11 温湿度传感器DHT11简介DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器,它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性和卓越的长期稳定性。
传感器包括一个电阻式感湿元件和一个NTC测温元件,并与一个高性能8 位单片机相连接。
因此该产品具有品质卓越、超快响应、抗干扰能力强、性价比极高等优点。
每个DHT11 传感器都在极为精确的湿度校验室中进行校准。
校准系数以程序的形式存在OTP内存中,传感器内部在检测型号的处理过程中要调用这些校准系数。
单线制串行接口,使系统集成变得简易快捷。
超小的体积、极低的功耗,使其成为给类应用甚至最为苛刻的应用场合的最佳选择。
产品为 4 针单排引脚封装,连接方便。
技术参数供电电压: 3.3~5.5V DC输出:单总线数字信号测量范围:湿度20-90%RH,温度0~50 ℃测量精度:湿度+-5%RH,温度+-2℃分辨率:湿度1%RH,温度1℃互换性:可完全互换,长期稳定性:< ± 1%RH年/DHT11 数字湿温度传感器采用单总线数据格式。
本系列教程将结合TI推出的CC254x SoC 系列,讲解从环境的搭建到蓝牙4.0协议栈的开发来深入学习蓝牙4.0的开发过程。
教程共分为六部分,本文为第二部分:第二部分知识点:第六节独立按键之查询方式第七节独立按键之中断方式第八节 CC254x内部温度传感器温度采集第九节五向按键第十节蜂鸣器有关TI 的CC254x芯片介绍,可点击下面链接查看:主流蓝牙BLE控制芯片详解(1):TI CC2540同系列资料推荐:由浅入深,蓝牙4.0/BLE协议栈开发攻略大全(1)有关本文的工具下载,大家可以到以下这个地址:朱兆祺ForARM第六节独立按键之查询方式在MT254xboard上有一个独立按键KEY1,如图,独立按键和复位键在整个班子的左上角。
按键通过P0.0口和CPU连接,在没有按键时为高电平,按下后为低电平。
下面我们通过LCD来显示独立按键的状态。
其对应的原理图如下:我们先用查询的方式读取按键的状态。
因为按键接入在P0.0口,所以我们读取P0.0口的电平即可知道按键的状态。
uint8 KeyValue(void) // 读取按键状态{if((P0&0X01) == 0X00 ) // 按下为低电平{return KEY_DOWN;}else{return KEY_UP;}}这里我们在while循环中不断的读取按键状态,并且判断是否改变,如果改变则改变LCD的显示。
int main(void){uint8 OldKeyValue = 0;uint8 NewKeyValue = 0;SysStartXOSC();LCD12864_Init();LCD12864_DisStr(1,“ Key Test”);// 按键初始化P0SEL &= ~0X01; // 设置为 IO功能P0DIR &= ~0X01; // 设置为输入功能while(1){NewKeyValue = KeyValue(); // 读取按键状态if(OldKeyValue != NewKeyValue) // 按键状态改变{OldKeyValue = NewKeyValue; // 保存当前按键状态if(OldKeyValue == KEY_DOWN){LCD12864_DisStr(3,“ Key Down ”); }else{LCD12864_DisStr(3,“ Key Up ”); }}}return 0;}运行程序,效果如图所示:第七节独立按键之中断方式复制Key工程,重命名为KeyInterrupt。
在线学习好工作/蓝牙4.0BLE学习之协议栈蓝牙4.0BLE协议栈介绍问题:什么是BLE协议栈?BLE协议栈与BLE协议的关系?顾名思义,人类之间需要一种语言才能沟通,机器之间,电子之间也有一个标准,也就是作为通讯标准,也就是通讯协议。
协议:定义了一系列通讯标准,通讯双方都按照这一标准,进行数据通讯。
协议栈:协议的具体实现形式,实现的函数库,固件库。
把个个协议集合到了一起,以函数库的形式实现,并用这些给用户提供一些应用层的API接口,用户可以进行一些调度。
问题:如何使用BLE协议栈进行开发?三个步骤:1.不需要具体了解BLE协议栈的具体复杂的过程,只需要知道它的数据从哪里来,需要到哪里去就行了。
2.根据BLE协议栈调用它里面的函数,实现自己的一些功能。
3.可以自己编写一些函数,实现自己需要特定的功能。
协议结构图第一层:physicallayer(物理层)信道带宽提供2M,提供三个广播信道1M。
第二层:link layer(链路层)执行一些基带协议,底层的数据包管理协议。
第三层:host controller interface (主机控制接口层)提供主机与控制层的通讯方式,以及命令格式,重用蓝牙标准,比如一些串口,USB等等。
第四层:L2CAP(逻辑链路于适配器协议层)为它上层提供数据业务,提供端到端的逻辑数据通信。
第五层:security manager(SM)安全管理层层与层之间会有通信,它是建立数据交换安全方面的数据知识。
第六层:attribute protocol(ATT)通用接入层定义了一些通用接口,供应用层和底层之间的调用,比如你要调底层的硬件模块的东西,就需要这个层的底层的驱动模块去实现它的一些功能,所以它会同时封装一些API的函数设置。
第七层:generic attribute profile(GATT)(属性协议层)允许设备以属性的形式向外设备暴露它的一些数据,就像广播者与观察者之间,它一直在广播自己的属性,数据出去。
蓝牙协议分析讲解(BT1.1-5.0)本文通过以下大纲,扩展讲解蓝牙协议规范。
蓝牙协议分析详解大纲(BT 1.1~5.0)一、蓝牙的概述(一)蓝牙版本信息(二)典型蓝牙与BLE蓝牙对比(三)蓝牙的技术特点(四)Bluetooth的系统构成二、蓝牙协议规范(一)传输协议、中介协议、应用协议(二)蓝牙协议栈三、硬件接口四、蓝牙协议规范(射频、基带链路控制、链路管理)五、蓝牙协议规范(HCI、L2CAP、SDP、RFOCMM)一、蓝牙的概述(一)蓝牙版本信息蓝牙版本主要有1.1/1.2/2.0/2.1/3.0/4.0/5.01. 1.1版本传输率约在748~810kb/s,因是早期设计,容易受到同频率之产品所干扰下影响通讯质量。
2. 1.2版本同样是只有748~810kb/s 的传输率,但在加上了(改善Software)抗干扰跳频功能。
3. 2.0+EDR版本是1.2的改良提升版,传输率约在1.8M/s~2.1M/s,开始支持双工模式——即一面作语音通讯,同时亦可以传输档案/高质素图片,2.0 版本当然也支持Stereo 运作。
应用最为广泛的是Bluetooth2.0+EDR标准,该标准在2004年已经推出,支持Bluetooth 2.0+EDR标准的产品也于2006年大量出现。
虽然Bluetooth 2.0+EDR标准在技术上作了大量的改进,但从1.X标准延续下来的配置流程复杂和设备功耗较大的问题依然存在。
4. 2.1版本更佳的省电效果:蓝牙2.1版加入了SniffSubrating的功能,透过设定在2个装置之间互相确认讯号的发送间隔来达到节省功耗的目的。
5. 3.0+HS版本2009年4月21日,蓝牙技术联盟(Bluetooth SIG)正式颁布了新一代标准规范”Bluetooth Core Specification Version 3.0 High Speed”(蓝牙核心规范3.0版),蓝牙3.0的核心是”GenericAlternate MAC/PHY”(AMP),这是一种全新的交替射频技术,允许蓝牙协议栈针对任一任务动态地选择正确射频。
ti蓝牙4.0协议栈,解析竭诚为您提供优质文档/双击可除ti蓝牙4.0协议栈,解析篇一:蓝牙4.0ble协议栈的研究ticc2540cc2541osal1.蓝牙:a是一种支持短距离通讯的无线技术,主要工作在2.4ghz频带。
至今分为五个版本1.1,1.2,2.0,3.0,4.0(4.1),现在市面上流行三种设备传统蓝牙(bluetooth简称bR),低功耗蓝牙(bluetoothsmart 即是bluetoothlowenergy简称ble,蓝牙4.0(bluetoothsmartReady即是bR+ble))b蓝牙4.0由传统蓝牙,高速蓝牙和蓝牙低功耗三种规范合成。
其中常用的有两种模式(单模->支持(ble)和双模->支持(ble+bR))。
我们用的cc2540是单模芯片。
c蓝牙4.0中的ble(蓝牙低功耗bluetoothlowenergy)定义了两个频段2.4ghz(16个信道896/915mhz(896m一个信道915m 十个信道),共27个信道。
速度:支持1mbps数据传输率下的超短数据包。
所有连接都使用蓝牙2.1加入的减速呼吸模式(sniffsubrating)来达到超低工作循环跳频:蓝牙规范自适应跳频技术主控制:更加智能,可以休眠更长时间,只在需要执行动作的时候才唤醒。
延迟:可在3ms内实现连接并设置数据传输。
范围:提高调制指数,最大范围可到100m健壮性:所有数据包都经过24bitcRc校验。
确保最大程度抵御干扰。
安全:使用aes128ccm加密算法进行数据包加密和认证。
拓扑:每个数据包的每次接收都是用32位寻址,理论上可连接十亿台设备。
针对一对一连接,并支持新型拓扑的一对多连接。
d蓝牙4.0总共40个信道,都分布在2.4ghz,其中0.12.39三个信道用来广播信息。
e蓝牙4.0的引起超低的功耗而备受瞩目。
是3.0的升级版,较3.0更加省电,成本更低,3ms低延迟,超长有效连接距离,aes-128加密;2.blea.蓝牙4.0规范中的一种,其中master最多有7个外设,低功耗,低延迟,低吞吐量。
实验一蓝牙4.0的LedButton实验实验设备:蓝牙4.0模块1个无线模块开发板1个蓝牙4.0 IO实验板1个支持蓝牙4.0的IOS终端1台USB转串口连接线实验介绍:本次实验的目的是使用蓝牙4.0模块完成与支持蓝牙4.0的IOS终端的连接与通信功能。
本实验使用蓝牙4.0 IO实验板通过蓝牙模块接收或发送相应数据,完成与IOS终端应用的交互功能。
IOS终端需安装基于蓝牙4.0的测试应用RFduino LedButton。
实验步骤:(1)安装IOS应用IOS终端进入APP Store搜索并下载安装RFduino LedButton。
(2)初始配置首先将蓝牙4.0模块和蓝牙4.0 IO实验板插入无线模块验证板上,并使用短路子将DIN、DOUT和DTR的J2和USB两端连接,将短路子切换到USB处,将SLEEP_RQ开关调到H。
在蓝牙4.0 IO实验板上使用短路子将“蓝牙模块”和“RGB”两端连接,后用USB线将无线模块验证板与PC连接起来,上电。
(3)烧写程序将RFduino导入Arduino程序中,将RFduino文件夹全部复制粘贴到Arduino目录“..\hardware\arduino\”中。
重启Arduino程序,选择Tools→Board→RFduino,点击Serial Port 选择相应的端口,同时写入本实验所用的示例代码。
将示例程序烧写到无线模块验证板的Rfduino中。
唤醒:管脚唤醒广播:代码:#include <RFduinoBLE.h>int led = 3;//PIN 3 IO实验板的绿色灯(可以被APP控制亮灭的灯)int button = 5;//PIN 5 IO实验板的按钮A(可以控制APP图片颜色的按钮)int debounce_time = 10;//防抖动时间int debounce_timeout = 100;//防抖动延迟void setup() {pinMode(led, OUTPUT);pinMode(button, INPUT);RFduinoBLE.advertisementData = "ledbtn";//设置广播的数据,要保证设备名与广播数据之和不超过18字节RFduinoBLE.begin();//开启蓝牙并进行广播}int debounce(int state)//防抖动{int start = millis();int debounce_start = start;while (millis() - start < debounce_timeout)if (digitalRead(button) == state){if (millis() - debounce_start >= debounce_time)return 1;}elsedebounce_start = millis();return 0;}int delay_until_button(int state)//等待按钮{if (state)RFduino_pinWake(button, HIGH);elseRFduino_pinWake(button, LOW);doRFduino_ULPDelay(INFINITE);//切换到低功率模式直到按钮有响应时唤醒while (! debounce(state));//如果有多个按钮,确定怎样被唤醒if (RFduino_pinWoke(button)){//更多代码RFduino_resetPinWake(button);}}void loop() {//如果按钮A点击则发送1,否则发送0delay_until_button(HIGH);RFduinoBLE.send(1);delay_until_button(LOW);RFduinoBLE.send(0);}void RFduinoBLE_onDisconnect()//断开连接的接口{digitalWrite(led, LOW);}void RFduinoBLE_onReceive(char *data, int len)//当收到数据时运行的接口{//如果收到第一个数据是0x01即亮灯if (data[0])digitalWrite(led, HIGH);elsedigitalWrite(led, LOW);}(4)实验过程先打开IOS终端的蓝牙功能,后打开RFduino LedButton应用。
在介绍蓝牙按键流程分析之前,我们需要了解一个概念,那就是就是OSAL。
什么是OSAL呢?可能大伙对于OS是比较了解的,学了计算机的搞过OS的也基本接触过,简单来说就是一个操作系统抽象层,可以理解为运行在CC2540 上的操作系统,说操作系统还不能算,TI的OSAL只实现了任务切换和消息机制。
并且把协议栈的代码、硬件处理的代码,用户程序的代码等分别放到了OSAL 层的不同任务处理函数中去了,各任务函数之间通过消息机制、同一个任务之间通过事件的的方式来通信。
什么是EVENT 事件?OSAL 为每个任务函数分配了一个16 位的事件变量,每一位代表一个事件,最高位为0x8000表示为系统事件SYS_EVENT_MSG。
其余的15 位留给用户自定义需要的事件。
通常事件由定时器启动,比如一秒后我要点亮LED2,这就需要发送一个点亮LED2 的事件,然后等待定时器1s后溢出,于是启动点亮LED2事件,事件会调用相应的hal 层API点亮LED2。
什么是MSG 消息MSG 是比EVENT 事件更具体并且可以携带数据的一种通信方式,MSG 的标记是按数值,而不是按位。
比如0x01 和0x02 是两个不同的消息,但对于事件0x03 则是0x01 事件和0x02 事件的组合。
MSG 收发使用osal_msg_send()和osal_msg_receive();当调用osal_msg_send()发送一个msg 的同时会在EVENT 列表中触发一个message ready event。
(请注意最后一句话,这句话点出了为什么按键时间的触发为何会导致系统事件也接受到了)现在以SimpleBLEPeripheral 为例说明按键流程在SimpleBLEPeripheral 任务初始化函数中有这样一条代码:// Register for all key events - This app will handle all key eventsRegisterForKeys( simpleBLEPeripheral_TaskID );这个函数来自OnBoard.c 源文件中/********************************************************************** Keyboard Register function** The keyboard handler is setup to send all keyboard changes to* one task (if a task is registered).** If a task registers, it will get all the keys. You can change this* to register for individual keys.*********************************************************************/uint8 RegisterForKeys( uint8 task_id ){// Allow only the first taskif ( registeredKeysTaskID == NO_TASK_ID ){registeredKeysTaskID = task_id;return ( true );}elsereturn ( false );}向一个全局变量registeredKeysTaskID中赋值自己的任务ID,调用了这个函数就能成功注册按键服务,那这个全局变量在何时使用呢?分析到这里,感觉有点迷糊了,我们可以从顶到下分析。
任何一个程序都是从main函数开始的,这点我们要坚信。
所以我们首先找到这个main函数打开SimpleBLEPeripheral_Main.c文件可以看到/********************************************************************************************** ***** @fn main** @brief Start of application.** @param none** @return none*********************************************************************************************** ****/int main(void){/* Initialize hardware */HAL_BOARD_INIT();// Initialize board I/OInitBoard( OB_COLD );/* Initialze the HAL driver */HalDriverInit();/* Initialize NV system */osal_snv_init();/* Initialize LL *//* Initialize the operating system */osal_init_system();/* Enable interrupts */HAL_ENABLE_INTERRUPTS();// Final board initializationInitBoard( OB_READY );#if defined ( POWER_SAVING )osal_pwrmgr_device( PWRMGR_BATTERY );#endif/* Start OSAL */osal_start_system(); // No Return from herereturn 0;}我们打开InitBoard( OB_READY );可以看到如下代码/********************************************************************** @fn InitBoard()* @brief Initialize the CC2540DB Board Peripherals* @param level: COLD,WARM,READY* @return None*/void InitBoard( uint8 level ){if ( level == OB_COLD ){// Interrupts offosal_int_disable( INTS_ALL );// Turn all LEDs offHalLedSet( HAL_LED_ALL, HAL_LED_MODE_OFF );// Check for Brown-Out reset// ChkReset();}else // !OB_COLD{/* Initialize Key stuff */OnboardKeyIntEnable = HAL_KEY_INTERRUPT_ENABLE;//OnboardKeyIntEnable = HAL_KEY_INTERRUPT_DISABLE;HalKeyConfig( OnboardKeyIntEnable, OnBoard_KeyCallback);}}看到我上面标注的函数了吧?那个是一个按键回调服务注册函数,注册了一个OnBoard_KeyCallback函数HalKeyConfig 函数的实现:将上述的回调函数的地址复制给了函数指针变量。
通过跟踪发现该函数的指针变量在按键的轮询函数中调用了,如下图:/********************************************************************************************** ***** @fn HalKeyPoll** @brief Called by hal_driver to poll the keys** @param None** @return None*********************************************************************************************** ***/void HalKeyPoll (void){uint8 keys = 0;uint8 notify = 0;#if defined (CC2540_MINIDK)if (!(HAL_KEY_SW_1_PORT & HAL_KEY_SW_1_BIT)) /* Key is active low */{keys |= HAL_KEY_SW_1;}if (!(HAL_KEY_SW_2_PORT & HAL_KEY_SW_2_BIT)) /* Key is active low */{keys |= HAL_KEY_SW_2;}#elseif (!(HAL_KEY_SW_6_PORT & HAL_KEY_SW_6_BIT)) /* Key is active low */{keys |= HAL_KEY_SW_6;}if ((HAL_KEY_JOY_MOVE_PORT & HAL_KEY_JOY_MOVE_BIT)) /* Key is active HIGH */{keys = halGetJoyKeyInput();}#endif/* If interrupts are not enabled, previous key status and current key status* are compared to find out if a key has changed status.*/if (!Hal_KeyIntEnable){if (keys == halKeySavedKeys){/* Exit - since no keys have changed */return;}else{notify = 1;}}else{/* Key interrupt handled here */if (keys){notify = 1;}}/* Store the current keys for comparation next time */halKeySavedKeys = keys;/* Invoke Callback if new keys were depressed */if (notify && (pHalKeyProcessFunction)){(pHalKeyProcessFunction) (keys, HAL_KEY_STATE_NORMAL);}}在这里底层的按键查询函数调用一个函数指针,而非具体的函数,这样就将处理按键的接口留给了上层,上层应用中,叧需解析的函数指针传入的参数1:keys 就知道是哪个按键被按下了。