第二十三節(jié) 藍(lán)牙協(xié)議棧之主機(jī)通訊
隨著藍(lán)牙4.0模塊的大量使用,為了很多從未接觸過藍(lán)牙的工程師也能快速便捷地開發(fā)藍(lán)牙項(xiàng)目或者使用藍(lán)牙,主從一體、遠(yuǎn)控IO等等特性也成為藍(lán)牙模塊必 備的條件。其實(shí),聯(lián)合第二十一節(jié)和本節(jié)(第二十二節(jié)),我們就能將一個本無固件的裸片藍(lán)牙,使其開發(fā)為具備主從一體功能的藍(lán)牙模塊。這兩節(jié)的內(nèi)容,也是本 連載篇的重點(diǎn)部分之一。
上一節(jié)我們對從機(jī)的工作流程有了一個整體的把握。我們現(xiàn)在接著來看主機(jī)的工作流程。
主機(jī)的工作主要是掃描設(shè)備,對發(fā)現(xiàn)的設(shè)備發(fā)起連接,然后就是對特征值的讀寫操作了。
手動連接
從機(jī)的對外廣播是在初始化的時候完成的,那主機(jī)的掃描是在哪里開始的呢?閱讀源碼可以發(fā)現(xiàn)主機(jī)的操作都在按鍵處理中完成的。主機(jī)通過五向按鍵中的五個按鍵實(shí)現(xiàn)不同的功能。
static void simpleBLECentral_HandleKeys( uint8 shift, uint8 keys )
{
?。╲oid)shift; // Intentionally unreferenced parameter
if ( keys & HAL_KEY_UP ) // 向上
{
// Start or stop discovery
if ( simpleBLEState != BLE_STATE_CONNECTED ) // 如果沒有連接,開始掃描
{
if ( !simpleBLEScanning )
{
simpleBLEScanning = TRUE;
simpleBLEScanRes = 0;
LCD_WRITE_STRING( “Discovering.。?!保?HAL_LCD_LINE_1 );
LCD_WRITE_STRING( “”, HAL_LCD_LINE_2 );
GAPCentralRole_StartDiscovery( DEFAULT_DISCOVERY_MODE,
DEFAULT_DISCOVERY_ACTIVE_SCAN,
DEFAULT_DISCOVERY_WHITE_LIST );
}
else
{
GAPCentralRole_CancelDiscovery();
}
}
else if ( simpleBLEState == BLE_STATE_CONNECTED && // 如果連接并且發(fā)現(xiàn)Handle進(jìn)行讀寫操作
simpleBLECharHdl != 0 &&
simpleBLEProcedureInProgress == FALSE )
{
uint8 status;
// Do a read or write as long as no other read or write is in progress
if ( simpleBLEDoWrite )
{
// Do a write
attWriteReq_t req;
req.handle = simpleBLECharHdl;
req.len = 1;
req.value[0] = simpleBLECharVal;
req.sig = 0;
req.cmd = 0;
status = GATT_WriteCharValue( simpleBLEConnHandle, &req, simpleBLETaskId );
}
else
{
// Do a read
attReadReq_t req;
req.handle = simpleBLECharHdl;
status = GATT_ReadCharValue( simpleBLEConnHandle, &req, simpleBLETaskId );
}
if ( status == SUCCESS )
{
simpleBLEProcedureInProgress = TRUE;
simpleBLEDoWrite = !simpleBLEDoWrite;
}
}
}
if ( keys & HAL_KEY_LEFT ) // 左
{
// Display discovery results
if ( !simpleBLEScanning && simpleBLEScanRes > 0 ) // 顯示掃描到的設(shè)備
{
// Increment index of current result (with wraparound)
simpleBLEScanIdx++;
if ( simpleBLEScanIdx >= simpleBLEScanRes )
{
simpleBLEScanIdx = 0;
}
LCD_WRITE_STRING_VALUE( “Device”, simpleBLEScanIdx + 1,
10, HAL_LCD_LINE_1 );
LCD_WRITE_STRING( bdAddr2Str( simpleBLEDevList[simpleBLEScanIdx].addr ),
HAL_LCD_LINE_2 );
}
}
if ( keys & HAL_KEY_RIGHT ) // 右
{
// Connection update
if ( simpleBLEState == BLE_STATE_CONNECTED ) // 如果連接,則更新連接
{
GAPCentralRole_UpdateLink( simpleBLEConnHandle,
DEFAULT_UPDATE_MIN_CONN_INTERVAL,
DEFAULT_UPDATE_MAX_CONN_INTERVAL,
DEFAULT_UPDATE_SLAVE_LATENCY,
DEFAULT_UPDATE_CONN_TIMEOUT );
}
}
if ( keys & HAL_KEY_CENTER ) // 中間鍵
{
uint8 addrType;
uint8 *peerAddr;
// Connect or disconnect
if ( simpleBLEState == BLE_STATE_IDLE ) // 空閑則連接
{
// if there is a scan result
if ( simpleBLEScanRes > 0 )
{
// connect to current device in scan result
peerAddr = simpleBLEDevList[simpleBLEScanIdx].addr;
addrType = simpleBLEDevList[simpleBLEScanIdx].addrType;
simpleBLEState = BLE_STATE_CONNECTING;
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 ( simpleBLEState == BLE_STATE_CONNECTING || // 連接則斷開連接
simpleBLEState == BLE_STATE_CONNECTED )
{
// disconnect
simpleBLEState = BLE_STATE_DISCONNECTING;
gStatus = GAPCentralRole_TerminateLink( simpleBLEConnHandle );
LCD_WRITE_STRING( “Disconnecting”, HAL_LCD_LINE_1 );
}
}
if ( keys & HAL_KEY_DOWN ) // 下
{
// Start or cancel RSSI polling
if ( simpleBLEState == BLE_STATE_CONNECTED ) // 連接則讀取RSSi的值
{
if ( !simpleBLERssi )
{
simpleBLERssi = TRUE;
GAPCentralRole_StartRssi( simpleBLEConnHandle, DEFAULT_RSSI_PERIOD );
}
else
{
simpleBLERssi = FALSE;
GAPCentralRole_CancelRssi( simpleBLEConnHandle );
LCD_WRITE_STRING( “RSSI Cancelled”, HAL_LCD_LINE_1 );
}
}
}
}
因?yàn)閺臋C(jī)一直處于廣播狀態(tài),所以秩序?qū)⑸弦还?jié)中的從機(jī)程序燒錄進(jìn)開發(fā)板即可,然后將主機(jī)程序燒錄到另外一快開發(fā)板,通過五向按鍵來實(shí)現(xiàn)和從機(jī)的連接和讀寫功能。
?。?) 上電提示
從機(jī)上電提示:
主機(jī)上電提示:
(2)根據(jù)主機(jī)的按鍵功能,我們按“UP”鍵,開始搜索周邊設(shè)備。搜索完成后,可以看到,掃描到了一個設(shè)備。
(3)接著我們查看掃描到的設(shè)備地址,按左鍵。可以看到掃描到的設(shè)備地址為0x7C669D9F638A。這個地址正是我們的從機(jī)地址。
?。?)按中間鍵連接從機(jī),可以看到主機(jī)提示連接成功,從機(jī)也提示連接成功。
?。?)接著我們開始讀取從機(jī)的RSSI值,按下鍵。
?。?)再次按下鍵,取消RSSI值的讀取。
?。?)對從機(jī)的CHAR1進(jìn)行讀寫,再次按上鍵讀取到CHAR1的值為1。
?。?)接著按上鍵,對CHAR1寫入0,同時看到從機(jī)提示CHAR1的值被修改為0。
主機(jī)寫入成功:
從機(jī)提示CHAR1被改變:
上電自動連接
上一節(jié)中我們通過五向按鍵實(shí)現(xiàn)了主機(jī)連接從機(jī)的功能,這一節(jié)中們來實(shí)現(xiàn)主機(jī)上電后自動搜索連接從機(jī)。
要實(shí)現(xiàn)連接,從機(jī)必須處于廣播狀態(tài),剩下的工作全部由主機(jī)完成,掃描、發(fā)起連接。
主機(jī)的狀態(tài)也有回調(diào)函數(shù),主機(jī)啟動后,第一個狀態(tài)是初始化,所以我們在初始化完成時開始掃描,
這樣開機(jī)后主機(jī)就會開始掃描周邊設(shè)備,接下來我們在掃描完成后對掃描到的設(shè)備發(fā)起連接。
將工程編譯下載后通過串口助手觀察主機(jī)和從機(jī)的輸出可以發(fā)現(xiàn)主機(jī)上電后自動的完成了一系列的操作。
評論