藍牙(bluetooth)技術是一種低功耗短距離的無線通信技術,被廣泛應用于10米以內的嵌入式設備通信當中。其最高傳輸速度根據藍牙協議的版本不同,有1Mbps(BR、LE)、2-3Mbps(EDR)、24Mbps(HS)之分。在工業現場,藍牙技術可以代替串行線纜,實現無線通信。在智能手機普及的今天,通過藍牙與手機建立連接,手機作為上位機發送指令給下位機,可以實現低成本的UI控制方案。
BlueZ是當前比較成熟的藍牙協議棧,作為Linux系統的官方協議棧,集成在Linux內核之中。英創公司在ESM928x的Linux系統中,又移植了BlueZ用戶空間協議棧和相關工具,使得ESM928x Linux平臺能夠支持藍牙技術,通過socket編程實現藍牙無線連接,代替串行線纜進行通信。
圖1 ESM928xW系列主板+底板
用戶使用藍牙串口功能主要分為兩個步驟:藍牙功能配置和socket應用程序編寫。
1、藍牙功能配置
1、加載ap2610藍牙模塊上電驅動
insmod /lib/modules/4.1.14/ap6210_bt_bcm20710.ko
2、加載藍牙固件,設定波特率、藍牙地址、使能hci等
brcm_patchram_plus --patchram /lib/firmware/ap6210/bcm20702a.hcd --baudrate 3000000 --enable_hci --bd_addr aa:00:55:44:33:22 --no2bytes --tosleep 5000 /dev/ttyS5 1> /dev/null&
3、啟動dbus后臺服務
dbus-daemon --system --nofork --nopidfile &
4、以兼容模式啟動bluetooth后臺服務
/libexec/bluetooth/bluetoothd -C &
5、啟動hci0,并設置name和可見屬性
hciconfig hci0 up
hciconfig hci0 name esm9287
hciconfig hci0 piscan
hciconfig hci0 reset
以上5個步驟已經寫成一個shell腳本set_bluetooth.sh,用戶也可以直接運行該腳本完成以上設置。至此,完成了對藍牙的設置,可以通過hciconfig hci0 -a來查看藍牙信息,如圖2。這時,其他藍牙設備就可以搜索到esm9287,圖3所示是android手機搜索到esm9287藍牙設備,點擊即可完成配對。
圖2 使用hciconfig查看藍牙信息
圖3 搜索esm9287并配對
2、Socket應用編程
藍牙協議棧中的RFCOMM協議實現了對串口RS232的仿真,最多能提供兩個藍牙設備之間60路的連接。應用程序中,可以使用socket進行服務端和客戶端的編程,其過程與TCP/IP的socket通信沒有太大區別。
a)環境配置
開發bluez協議棧的藍牙應用需要用到libbluetooth.so和相關頭文件,需要添加到eclipse對應的藍牙項目中。libbluetooth.so是編譯bluez協議棧生產的動態鏈接庫,提供了頭文件bluetooth.h、hci_lib.h、sdp_lib.h中的函數實體,實現藍牙地址與常用數據類型的轉換、hci設備和sdp服務的一系列操作函數。
1、在項目中新建文件夾include/bluetooth,其中放入藍牙協議相關頭文件;新建文件夾lib,其中放動態鏈接庫libbluetooth.so。
圖4 新建include和lib文件夾
2、進入項目Properties設置,添加項目下的include文件夾為GCC C++ Compiler和GCC C Complier編譯器的頭文件路徑(下圖是GCC C++ Compiler的設置,GCC C Compiler設置步驟相同)。
圖5 添加頭文件搜索路徑
3、為Sourcery G++ Lite C++ Linker鏈接器添加libbluetooth.so庫文件及搜索路徑,如下圖。
圖6 添加編譯庫及搜索路徑
b)服務端程序
1、申請藍牙RFCOMM socket
s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
2、綁定本地適配器,BDADDR_ANY默認為第一個可用藍牙適配器
loc_addr.rc_family = AF_BLUETOOTH;
loc_addr.rc_bdaddr = *BDADDR_ANY;
loc_addr.rc_channel = (uint8_t) 1;
bind(s, (struct sockaddr *)&loc_addr, sizeof(loc_addr));
3、設置socket監聽模式,這里只允許建立一個連接
listen(s, 1);
4、等待連接
client = accept(s, (struct sockaddr *)&rem_addr, &opt);
5、select模式讀取socket數據流
while(1)
{
FD_ZERO(&working_set);
max_sd = client;
FD_SET(client, &working_set);
timeout.tv_sec = 3 * 60;
timeout.tv_usec = 0;
// Call select() and wait 5 minutes for it to complete.
printf("Waiting on select() %ld sec...\n", timeout.tv_sec);
int rc_select = select(max_sd + 1, &working_set, NULL, NULL, &timeout);
// Check to see if the select call failed.
if (rc_select < 0)
{
perror(" select() failed");
break;
}
else if (rc_select > 0)
{
if(FD_ISSET(max_sd,&working_set))
{
// read data from the client
bytes_read = read(client, buf, sizeof(buf));
if( bytes_read > 0 ) {
printf("received: [%s]\n", buf);
}
else
{
break;
}
write(client,ack,sizeof(ack));
}
}
// Else if rc_select == 0 then the 5 minute time out expired.
else
{
printf(" select() timed out.\n");
break;
}
}
6、關閉套接字
close(client);
close(s);
c)客戶端
1、申請藍牙RFCOMM socket
s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
2、設置藍牙連接服務器的地址
struct sockaddr_rc addr = { 0 };
// set the connection parameters (who to connect to)
addr.rc_family = AF_BLUETOOTH;
addr.rc_channel = (uint8_t) 1;
str2ba( dest, &addr.rc_bdaddr );
3、連接藍牙服務器
// connect to server
status = connect(s, (struct sockaddr *)&addr, sizeof(addr));
4、讀寫socket數據流
for(i = 0; i < 3; i++)
{
// send a message
write(s, message[i], strlen(message[i])+1);
printf("write \"%s\" to %s\n", message[i],dest);
bytes_read = read(s, buf, sizeof(buf));
if( bytes_read > 0 ) {
printf("received: [%s]\n", buf);
}
}
其中,message[i]為發送內容的地址。
5、關閉socket
close(s);
在一張板子上運行藍牙rfcomm服務程序,在另一張板子上運行藍牙rfcomm客戶端程序,如圖6、圖7所示:
圖7 服務端程序
圖8 客戶端程序
通過socket編程,藍牙應用程序可以像tcp/ip的網絡編程一樣,建立連接,實現無線通信。如果有用戶對藍牙的串口socket編程感興趣,可以聯系我們。我們將提供驅動文件、藍牙庫文件及相應的示例程序。
成都英創信息技術有限公司 028-8618 0660