我使用的是官方的协议栈,下载地址在这里:链接:https://pan.baidu.com/s/1kpzgGxyuqLQLheLdu90PTQ?pwd=0000
提取码:0000
下载好协议栈后我们打开协议栈的文件夹,找到BLE-CC254x-1.5.2.0\Projects\ble\SimpleBLEPeripheral\CC2540DB
然后打开2540的工程,看到协议栈的结构如下:
- SimpleBLEPeripheral:是主要的应用程序文件夹,包含了实现 BLE 外围设备功能的源代码和头文件。appBLEPeripheral.c 是应用程序的入口点,负责初始化和配置 BLE 协议栈和硬件。osal_SimpleBLEPeripheral.c 是操作系统抽象层 (OSAL) 的文件,负责管理任务和事件。SimpleBLEPeripheral.h 是头文件,定义了一些常量和变量。
- HAL:是硬件抽象层 (HAL) 的文件夹,包含了 hal.h 头文件,用于包含所有 HAL 模块的头文件。HAL 模块提供了一些通用的硬件接口和功能,例如 ADC, GPIO, LCD, LED, UART 等。
- LIB:是库文件夹,包含了 lib.h 头文件,用于包含一些通用的库函数的头文件,库函数提供了一些基本的数据类型,内存管理,调试,错误处理等功能。
- INCLUDE:是包含文件夹,包含了 include.h 头文件,用于包含一些 BLE 协议栈相关的头文件。这些头文件定义了一些 BLE 协议栈的数据结构,常量,枚举,函数等。
- OSAL:是操作系统抽象层 (OSAL) 的文件夹,包含了一些 OSAL 相关的源代码和头文件。OSAL 提供了一些操作系统相关的功能,例如任务管理,事件处理,定时器,信号量,互斥锁,非易失性存储等。
- PROFILES:是 BLE 服务和特征的文件夹,包含了一些实现 BLE 服务和特征的源代码和头文件。这些文件定义了一些 BLE 服务和特征的 UUID, 属性, 值, 回调函数等。
- TOOLS:这个文件夹是工具文件夹,包含了一些辅助的工具文件
大概了解了项目结构,加下来来看看代码是如何运行的~
SimpleBLEPeripheral_Main是是 BLE 协议栈的入口点,即从该函数开始执行
意思即,当我们编译运行协议栈时,以下函数将从上到下依次运行进行各项初始化
蓝牙参数修改
BLE参数配置位于simpleBLEPeripheral.c中
、
// How often to perform periodic event
#define SBP_PERIODIC_EVT_PERIOD 5000 //这是一个周期性事件的间隔,单位是毫秒,表示每隔 5000 毫秒执行一次周期性事件,例如检查电池电量,更新连接参数等。
// What is the advertising interval when device is discoverable (units of 625us, 160=100ms)
#define DEFAULT_ADVERTISING_INTERVAL 160 //广播间隔,单位是 625 微秒,表示设备在可发现模式下的广播周期,160 表示 100 毫秒。
// Limited discoverable mode advertises for 30.72s, and then stops
// General discoverable mode advertises indefinitely
//发现模式,有两种选择,一种是有限可发现模式,表示设备只广播 30.72 秒,然后停止;
//另一种是一般可发现模式,表示设备无限期地广播。这个宏的值取决于是否定义了 CC2540_MINIDK 宏,如果定义了,就是有限可发现模式,否则就是一般可发现模式。
#if defined ( CC2540_MINIDK )
#define DEFAULT_DISCOVERABLE_MODE GAP_ADTYPE_FLAGS_LIMITED
#else
#define DEFAULT_DISCOVERABLE_MODE GAP_ADTYPE_FLAGS_GENERAL
#endif // defined ( CC2540_MINIDK )
// Minimum connection interval (units of 1.25ms, 80=100ms) if automatic parameter update request is enabled
#define DEFAULT_DESIRED_MIN_CONN_INTERVAL 80 //最小连接间隔,单位是 1.25 毫秒,表示如果启用了自动连接参数更新请求,设备希望的最小连接间隔,80 表示 100 毫秒。
// Maximum connection interval (units of 1.25ms, 800=1000ms) if automatic parameter update request is enabled
#define DEFAULT_DESIRED_MAX_CONN_INTERVAL 800 //最大连接间隔,单位是 1.25 毫秒,表示如果启用了自动连接参数更新请求,设备希望的最大连接间隔,800 表示 1000 毫秒。
// Slave latency to use if automatic parameter update request is enabled
#define DEFAULT_DESIRED_SLAVE_LATENCY 0 //从机延迟,表示如果启用了自动连接参数更新请求,设备允许的最大连续丢失连接事件的次数,0 表示不允许丢失任何连接事件。
// Supervision timeout value (units of 10ms, 1000=10s) if automatic parameter update request is enabled
#define DEFAULT_DESIRED_CONN_TIMEOUT 1000 //连接超时,单位是 10 毫秒,表示如果启用了自动连接参数更新请求,设备允许的最大连接事件间隔,1000 表示 10 秒。
// Whether to enable automatic parameter update request when a connection is formed
#define DEFAULT_ENABLE_UPDATE_REQUEST TRUE //表示是否启用自动连接参数更新请求,当设备与中心设备建立连接后,是否向中心设备发送连接参数更新请求,TRUE 表示启用,FALSE 表示禁用。
// Connection Pause Peripheral time value (in seconds)
#define DEFAULT_CONN_PAUSE_PERIPHERAL 6 //连接暂停外围设备的时间值,单位是秒,表示当设备与中心设备建立连接后,多长时间内不允许中心设备发起连接参数更新请求,6 表示 6 秒。
// Company Identifier: Texas Instruments Inc. (13)
#define TI_COMPANY_ID 0x000D //公司标识符,表示设备的制造商,0x000D 表示 Texas Instruments Inc.
#define INVALID_CONNHANDLE 0xFFFF //一个无效的连接句柄,表示设备没有与任何中心设备建立连接,0xFFFF 表示无效值
// Length of bd addr as a string
#define B_ADDR_STR_LEN 15 //蓝牙地址字符串的长度,表示设备的蓝牙地址转换为字符串后的字符数,15 表示 15 个字符,例如 “00:12:34:56:78:9A”。
/*********************************************************************
* TYPEDEFS
*/
/*********************************************************************
* GLOBAL VARIABLES
*/
/*********************************************************************
* EXTERNAL VARIABLES
*/
/*********************************************************************
* EXTERNAL FUNCTIONS
*/
/*********************************************************************
* LOCAL VARIABLES
*/
static uint8 simpleBLEPeripheral_TaskID; // Task ID for internal task/event processing
static gaprole_States_t gapProfileState = GAPROLE_INIT;
// GAP - SCAN RSP data (max size = 31 bytes)
/*
* 这里是修改广播标识的,可以修改为自己喜欢的广播名称
*/
static uint8 scanRspData[] =
{
// complete name
0x14, // length of this data
GAP_ADTYPE_LOCAL_NAME_COMPLETE,
0x53, // 'S'
0x69, // 'i'
0x6d, // 'm'
0x70, // 'p'
0x6c, // 'l'
0x65, // 'e'
0x42, // 'B'
0x4c, // 'L'
0x45, // 'E'
0x50, // 'P'
0x65, // 'e'
0x72, // 'r'
0x69, // 'i'
0x70, // 'p'
0x68, // 'h'
0x65, // 'e'
0x72, // 'r'
0x61, // 'a'
0x6c, // 'l'
// connection interval range
0x05, // length of this data
GAP_ADTYPE_SLAVE_CONN_INTERVAL_RANGE,
LO_UINT16( DEFAULT_DESIRED_MIN_CONN_INTERVAL ), // 100ms
HI_UINT16( DEFAULT_DESIRED_MIN_CONN_INTERVAL ),
LO_UINT16( DEFAULT_DESIRED_MAX_CONN_INTERVAL ), // 1s
HI_UINT16( DEFAULT_DESIRED_MAX_CONN_INTERVAL ),
// Tx power level
0x02, // length of this data
GAP_ADTYPE_POWER_LEVEL,
0 // 0dBm
};
最后简单分析一下OSAL:
/*********************************************************************
* GLOBAL VARIABLES
*/
// The order in this table must be identical to the task initialization calls below in osalInitTask.
/*
* 定义了一个任务处理函数的数组,包含了各个协议栈层和应用层的事件处理函数;
*/
const pTaskEventHandlerFn tasksArr[] =
{
LL_ProcessEvent, // task 0
Hal_ProcessEvent, // task 1
HCI_ProcessEvent, // task 2
#if defined ( OSAL_CBTIMER_NUM_TASKS )
OSAL_CBTIMER_PROCESS_EVENT( osal_CbTimerProcessEvent ), // task 3
#endif
L2CAP_ProcessEvent, // task 4
GAP_ProcessEvent, // task 5
SM_ProcessEvent, // task 6
GATT_ProcessEvent, // task 7
GAPRole_ProcessEvent, // task 8
GAPBondMgr_ProcessEvent, // task 9
GATTServApp_ProcessEvent, // task 10
SimpleBLEPeripheral_ProcessEvent // task 11
};
/*
* 定义了一个任务数量的常量,等于任务处理函数数组的长度;
*/
const uint8 tasksCnt = sizeof( tasksArr ) / sizeof( tasksArr[0] );
/*
* 定义了一个任务事件的指针,用于存储每个任务的事件标志;
*/
uint16 *tasksEvents;
/*********************************************************************
* FUNCTIONS
*********************************************************************/
/*********************************************************************
* @fn osalInitTasks
*
* @brief This function invokes the initialization function for each task.
*
* @param void
*
* @return none
*/
/*
* 在osalInitTasks函数中,为每个任务分配一个任务ID,并调用相应的初始化函数;
*/
void osalInitTasks( void )
{
uint8 taskID = 0;
tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);
/* The tasksEvents allocated pointer must be valid */
/*
* 为每个任务分配一块内存空间,用于存储任务事件标志,并将其清零;
*/
if (tasksEvents != NULL)
{
osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));
}
else
{
HAL_ASSERT_FORCED();
}
/*
* 调用LL、Hal、HCI、L2CAP、GAP、SM、GATT、GAPRole、GAPBondMgr、GATTServApp和SimpleBLEPeripheral等模块的初始化函数,完成各个模块的配置;
*/
/* LL Task */
LL_Init( taskID++ );
/* Hal Task */
Hal_Init( taskID++ );
/* HCI Task */
HCI_Init( taskID++ );
#if defined ( OSAL_CBTIMER_NUM_TASKS )
/* Callback Timer Tasks */
osal_CbTimerInit( taskID );
taskID += OSAL_CBTIMER_NUM_TASKS;
#endif
/* L2CAP Task */
L2CAP_Init( taskID++ );
/* GAP Task */
GAP_Init( taskID++ );
/* SM Task */
SM_Init( taskID++ );
/* GATT Task */
GATT_Init( taskID++ );
/* Profiles */
GAPRole_Init( taskID++ );
GAPBondMgr_Init( taskID++ );
GATTServApp_Init( taskID++ );
/* Application */
SimpleBLEPeripheral_Init( taskID );
}
简单的来说,就是协议栈编译运行后,初始化OSAL,在协议栈中是采用任务调度的方式来运行的,官方的协议栈其实在编译运行后就会启动我们的广播,然后我们的其他设备就可以找到CC2540发出的广播,然后我们就可以连接到CC2540