SYD8801是一款低功耗高性能蓝牙低功耗SOC,集成了高性能2.4GHz射频收发机、32位ARM
Cortex-M0处理器、128kB Flash存储器、以及丰富的数字接口。SYD8801片上集成了Balun无需阻抗匹配网络、高效率DCDC降压转换器,适合用于可穿戴、物联网设备等。具体可咨询:http://www.syd-tek.com/
TI 一主三从主机端分析
工程目录如下:
向上按键处理:
其中simpleBLEScanning代表目前蓝牙有没有在扫描状态,置1代表处于扫描状态,如果目前不是扫描态则进入if分支开始扫描并且设置simpleBLEScanning为1,这里在扫描事件的时候清除这个标志,如下:
注意:这里有一个过滤机制:if ( DEFAULT_DEV_DISC_BY_SVC_UUID == FALSE )也就是说只有广播中的service uuid满足相关要求的设备才会保存下来,这里要求广播中的UUID必须等于SIMPLEPROFILE_SERV_UUID!
发现完成后按下中间键将进入连接流程:
这里调用performPeriodicTask_AutoConnect函数进行连接,其源代码如下:
// 执行动连接
static void performPeriodicTask_AutoConnect( void ) // 执行动连接
{
uint8 addrType;
uint8 *peerAddr;
BLE_DEV *p = &(gDev[simpleBLEScanIdx]);
//NPI_PrintString(" [KEY_CENTER]\r\n");
NPI_PrintValue("Idx=", simpleBLEScanIdx, 10);
//NPI_PrintValue("State=", p->simpleBLEState, 10);
//NPI_PrintValue("num=", connectedPeripheralNum, 10);
//NPI_PrintValue("res=", simpleBLEScanRes, 10);
// Connect or disconnect
//if ( p->simpleBLEState == BLE_STATE_IDLE
// || connectedPeripheralNum < MAX_PERIPHERAL_NUM)
if ( p->simpleBLEState == BLE_STATE_IDLE )
{
// if there is a scan result
if ( simpleBLEScanRes > 0
&& simpleBLEScanIdx < simpleBLEScanRes )
{
// connect to current device in scan result
peerAddr = simpleBLEDevList[simpleBLEScanIdx].addr;
addrType = simpleBLEDevList[simpleBLEScanIdx].addrType;
p->simpleBLEState = BLE_STATE_CONNECTING;
//osal_pwrmgr_device( PWRMGR_ALWAYS_ON );
GAPCentralRole_EstablishLink( DEFAULT_LINK_HIGH_DUTY_CYCLE,
DEFAULT_LINK_WHITE_LIST,
addrType, peerAddr );
LCD_WRITE_STRING( "Connecting", HAL_LCD_LINE_1 );
LCD_WRITE_STRING( bdAddr2Str( peerAddr ), HAL_LCD_LINE_2 );
}
}
else if ( p->simpleBLEState == BLE_STATE_CONNECTING ||
p->simpleBLEState == BLE_STATE_CONNECTED ||
p->simpleBLEState == BLE_STATE_DISCONNECTING)
{
// disconnect
p->simpleBLEState = BLE_STATE_DISCONNECTING;
gStatus = GAPCentralRole_TerminateLink( p->simpleBLEConnHandle );
LCD_WRITE_STRING( "Disconnecting", HAL_LCD_LINE_1 );
}
}
这里如果相应地址不是连接状态将进行连接,如果是连接状态将断开连接!
这里将调用GAPCentralRole_EstablishLink函数进行连接,当连接完成的时候将进行下面的回调:
这里开启一个定时器去发现服务:osal_start_timerEx( simpleBLETaskId, START_DISCOVERY_EVT, DEFAULT_SVC_DISCOVERY_DELAY );
之后将进入如下系统回调:
/*********************************************************************
* @fn simpleBLEGATTDiscoveryEvent
*
* @brief Process GATT discovery event
*
* @return none
*/
static void simpleBLEGATTDiscoveryEvent( gattMsgEvent_t *pMsg )
{
attReadByTypeReq_t req;
BLE_DEV *p = simpleBLECentralGetDev(pMsg->connHandle);
if ( p->simpleBLEDiscState == BLE_DISC_STATE_SVC )
{
// Service found, store handles
if ( pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
pMsg->msg.findByTypeValueRsp.numInfo > 0 )
{
p->simpleBLESvcStartHdl = pMsg->msg.findByTypeValueRsp.handlesInfo[0].handle;
p->simpleBLESvcEndHdl = pMsg->msg.findByTypeValueRsp.handlesInfo[0].grpEndHandle;
}
// If procedure complete
if ( ( pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
pMsg->hdr.status == bleProcedureComplete ) ||
( pMsg->method == ATT_ERROR_RSP ) )
{
if ( p->simpleBLESvcStartHdl != 0 )
{
// Discover characteristic
p->simpleBLEDiscState = BLE_DISC_STATE_CHAR1;
req.startHandle = p->simpleBLESvcStartHdl;
req.endHandle = p->simpleBLESvcEndHdl;
req.type.len = ATT_BT_UUID_SIZE;
req.type.uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR1_UUID);
req.type.uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR1_UUID);
GATT_ReadUsingCharUUID( p->simpleBLEConnHandle, &req, simpleBLETaskId );
}
}
}
else if ( p->simpleBLEDiscState == BLE_DISC_STATE_CHAR1 )
{
NPI_PrintValue("1 pMsg->method", pMsg->method, 10);
NPI_PrintValue("1 numPairs", pMsg->msg.readByTypeRsp.numPairs, 10);
// Characteristic found, store handle
if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&
pMsg->msg.readByTypeRsp.numPairs > 0 )
{
p->simpleBLECharHdl[0] = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],
pMsg->msg.readByTypeRsp.dataList[1] );
LCD_WRITE_STRING( "CHAR 1 Found", HAL_LCD_LINE_3 );
p->simpleBLEProcedureInProgress = TRUE;
}
else // pMsg->msg.readByTypeRsp.numPairs is 0.
{
p->simpleBLEDiscState = BLE_DISC_STATE_CHAR6;
req.startHandle = p->simpleBLESvcStartHdl;
req.endHandle = p->simpleBLESvcEndHdl;
req.type.len = ATT_BT_UUID_SIZE;
req.type.uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR6_UUID);
req.type.uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR6_UUID);
GATT_ReadUsingCharUUID( p->simpleBLEConnHandle, &req, simpleBLETaskId );
}
}
else if (p->simpleBLEDiscState == BLE_DISC_STATE_CHAR6)
{ // Characteristic found, store handle
if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&
pMsg->msg.readByTypeRsp.numPairs > 0 )
{
p->simpleBLECharHdl[5] = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],
pMsg->msg.readByTypeRsp.dataList[1] );
LCD_WRITE_STRING( "CHAR 6 Found", HAL_LCD_LINE_4 );
p->simpleBLEProcedureInProgress = FALSE;
}
p->simpleBLEDiscState = BLE_DISC_STATE_IDLE;
}
}
这个函数就是我们发现服务后的操作, 这里,我们现实去发现服务 CHAR1, 然后再去发现CHAR6, 总共是2个, 当然可以去找更多,看有没有必要了, 这里的代码你可以琢磨一下,不详细讲了
接下来按下S1按键将发送数据,如下:
这里开启SBP_PERIODIC_EVT定时器进行数据轮训发送,定时器回调如下:
if ( events & SBP_PERIODIC_EVT )
{
// Restart timer
if ( SBP_PERIODIC_EVT_PERIOD )
{
osal_start_timerEx( simpleBLETaskId, SBP_PERIODIC_EVT, SBP_PERIODIC_EVT_PERIOD );
}
// Perform periodic application task
performPeriodicTask(); // amomcu 用于发送数据
return (events ^ SBP_PERIODIC_EVT);
}
其调用performPeriodicTask函数进行发送,其源代码如下:
// amomcu 用于发送数据
static void performPeriodicTask( void )
{
static int index = 0;
char str[32] = {0};
//uint8 value[20];
#if 0// 用于调试
for(int i = 0; i < simpleBLEScanRes; i++)
{
sprintf(str, "[%d].[%d,%d],[%08x,%d,%d]\r\n",
i, gDev[i].simpleBLECharHdl[0],gDev[i].simpleBLECharHdl[5],
gDev[i].simpleBLEConnHandle,
gDev[i].simpleBLEState,
simpleBLEScanIdx);
NPI_PrintString((uint8*)str);
/*
[0].[37,53],[00000000]
[1].[37,53],[00000001]
*/
}
NPI_PrintString("\r\n");
#endif
#if 0
// 往从机写入char1的值, 注意char1 是一个字节长度的
value[0] = gDev[simpleBLEScanIdx].simpleBLECharVal;
OneConnetedDevice_WriteCharX(simpleBLEScanIdx, BLE_CHAR1, value, 1);
#else
if(index == 0)
{
// 往从机写入char1的值, 注意char1 是一个字节长度的
#if 0
OneConnetedDevice_WriteCharX(simpleBLEScanIdx, BLE_CHAR1, &(gDev[simpleBLEScanIdx].simpleBLECharVal), 1);
// 发送的数据同样显示在显示屏上
sprintf(str, "Char1: %d", gDev[simpleBLEScanIdx].simpleBLECharVal);
HalLcdWriteString(str, HAL_LCD_LINE_6 );
gDev[simpleBLEScanIdx].simpleBLECharVal++;
#else
OneConnetedDevice_WriteCharX(simpleBLEScanIdx, BLE_CHAR1, &simpleBLESendValue, 1);
// 发送的数据同样显示在显示屏上
sprintf(str, "Char1: %d", simpleBLESendValue);
HalLcdWriteString(str, HAL_LCD_LINE_6 );
simpleBLESendValue++;
#endif
HalLedBlink (HAL_LED_1, 1, 50, 100);//这个的意思是, 100ms内,以50%的占空比闪烁1次, 实际就是点亮50ms
}
else if(index == 1)
{
uint32 time = osal_GetSystemClock();
sprintf(str, "time=%06ld", time);
// 往从机写入char6的值, 注意char6 是一个最大字节数为19的buffer, 这里为简单没有做长度判断
OneConnetedDevice_WriteCharX(simpleBLEScanIdx, BLE_CHAR6, (uint8*)str, osal_strlen(str));
// 发送的数据同样显示在显示屏上
sprintf(str, "CHAR6: time=%06ld", time);
HalLcdWriteString(str, HAL_LCD_LINE_7 );
// 更换成下一个从机, 注意我们都是先发
simpleBLEScanIdx++;
simpleBLEScanIdx %= simpleBLEScanRes;
HalLedBlink (HAL_LED_2, 1, 50, 100);//这个的意思是, 100ms内,以50%的占空比闪烁1次, 实际就是点亮50ms
}
index++;
index %=2;
#endif
}
主机发送函数到此为止!
这里上传本博客使用到的源代码:
http://download.csdn.net/detail/chengdong1314/9881528
更多更详细的教程请看上面资源里的《1主3从教程(阿莫单片机2014-12-13更新).pdf》,资源中更有一些视频资料!
发现服务流程
1.在simpleBLECentralEventCB回调函数的建立连接GAP_LINK_ESTABLISHED_EVENT分支中开启一个定时器事件:osal_start_timerEx( simpleBLETaskId, START_DISCOVERY_EVT, DEFAULT_SVC_DISCOVERY_DELAY );
注意:该事件只会被调用一次,虽然叫做定时器,但是不会被重复的调用
2.在定时器事件到来的时候,SimpleBLECentral_ProcessEvent函数会被回调并且进入 if ( events & START_DISCOVERY_EVT )分支,该分支中调用simpleBLECentralStartDiscovery函数开始服务特性handle的发现
注意:只会进入一次
3.simpleBLECentralStartDiscovery函数将调用GATT_DiscPrimaryServiceByUUID发现透传的主要服务的handle
4.GATT_DiscPrimaryServiceByUUID函数被调用之后协议栈会产生回调进入simpleBLECentralProcessGATTMsg函数的 else if ( p->simpleBLEDiscState != BLE_DISC_STATE_IDLE )分支,这里将发现特性的handle