Bài đăng này ban đầu từ www.jaredwolff.com
Tôi đã bị đánh bại.
Tôi đã mất cả đêm để cố gắng làm cho dự án Bluetooth Low Energy hoạt động. Thật là đau đớn. Thật là bực bội. Tôi đã sẵn sàng từ bỏ.
Đó là trong những ngày đầu tiên của Bluetooth Low Energy. Kể từ đó, nó trở nên dễ dàng hơn và dễ phát triển hơn. Thư viện Bluetooth của Particle Mesh cũng không phải là ngoại lệ.
Trong hướng dẫn này, tôi sẽ chỉ cho bạn cách sử dụng API Bluetooth của Particle. Chúng tôi sẽ định cấu hình một số đèn LED và xem chúng thay đổi trên tất cả các thiết bị trong mạng Mesh. Chúng tôi sẽ sử dụng bảng Argon và Xenon.
Sẳn sàng? Hãy bắt đầu!
P.S. bài này dài. Nếu bạn muốn tải xuống thứ gì đó, hãy nhấp vào đây để có một tệp PDF được định dạng đẹp mắt.
Giai đoạn 1:Thiết lập Bluetooth
-
Tải xuống / Cài đặt Particle Workbench
-
Tạo một Dự án mới. Tôi đã chọn một vị trí thích hợp và sau đó đặt tên cho nó là
ble_mesh
-
Đi tới
/src/
của bạn hướng dẫn và mở<your project name>.ino
của bạn tệp -
Sau đó, hãy đảm bảo rằng bạn thay đổi phiên bản hệ điều hành thiết bị của mình thành> 1.3.0
Viết mã
Chúng tôi muốn thiết lập một dịch vụ có 3 đặc điểm. Các đặc điểm liên quan đến cường độ của đèn LED RGB tương ứng. Đây là cách thiết lập Bluetooth của bạn:
-
Trong
Setup()
của bạn chức năng cho phép điều khiển ứng dụng của đèn LED của bạnRGB.control(true);
-
Thiết lập UUID của bạn ở đầu
.ino
tệpconst char* serviceUuid = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"; const char* red = "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"; const char* green = "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"; const char* blue = "6E400004-B5A3-F393-E0A9-E50E24DCCA9E";
UUID là số nhận dạng hoặc địa chỉ duy nhất. Chúng được sử dụng để phân biệt các dịch vụ và đặc điểm khác nhau trên một thiết bị.
Các UUID ở trên được sử dụng trong các ví dụ về Hạt trước đây. Nếu bạn muốn tạo của riêng mình, bạn có thể sử dụng
uuidgen
trên dòng lệnh OSX. Bạn cũng có thể truy cập một trang web như Trình tạo GUID Trực tuyến.Sử dụng các cài đặt trên để nhận UUID của riêng bạn. Sau đó, bạn có thể tạo dịch vụ của mình và các UUIDS đặc trưng từ dịch vụ được tạo này:
const char* serviceUuid = "b425040**0**-fb4b-4746-b2b0-93f0e61122c6"; //service const char* red = "b4250401-fb4b-4746-b2b0-93f0e61122c6"; //red char const char* green = "b4250402-fb4b-4746-b2b0-93f0e61122c6"; //green char const char* blue = "b4250403-fb4b-4746-b2b0-93f0e61122c6"; //blue char
Không có cách nào đúng hay sai để làm điều này. Nhưng bạn phải cẩn thận khi không sử dụng UUID được Bluetooth SIG dành riêng. Điều này rất khó xảy ra. Nếu bạn muốn kiểm tra kỹ, bạn có thể vào đây và tại đây.
Hiện tại, chúng tôi sẽ gắn bó với tập hợp UUID đầu tiên.
-
Trong
Setup()
, khởi tạo dịch vụ của bạn.// Set the RGB BLE service BleUuid rgbService(serviceUuid);
Đây là bước đầu tiên của quá trình "đăng ký" dịch vụ của bạn. Tìm hiểu thêm về điều này bên dưới.
-
Khởi tạo từng đặc tính trong
Setup()
BleCharacteristic redCharacteristic("red", BleCharacteristicProperty::WRITE_WO_RSP, red, serviceUuid, onDataReceived, (void*)red); BleCharacteristic greenCharacteristic("green", BleCharacteristicProperty::WRITE_WO_RSP, green, serviceUuid, onDataReceived, (void*)green); BleCharacteristic blueCharacteristic("blue", BleCharacteristicProperty::WRITE_WO_RSP, blue, serviceUuid, onDataReceived, (void*)blue);
Đối với thiết lập này, chúng tôi sẽ sử dụng
WRITE_WO_RSP
tài sản. Điều này cho phép chúng tôi ghi dữ liệu và không mong đợi phản hồi.
Tôi đã tham chiếu UUID làm hai tham số tiếp theo. Đầu tiên là UUID đặc trưng. Thứ hai là UUID dịch vụ.Tham số tiếp theo là hàm gọi lại. Khi dữ liệu được ghi vào lệnh gọi lại này, hàm này sẽ kích hoạt.
Cuối cùng tham số cuối cùng là ngữ cảnh. Điều này có nghĩa là chính xác? Chúng tôi đang sử dụng cùng một lệnh gọi lại cho cả ba đặc điểm. Cách duy nhất chúng ta có thể biết đặc tính nào được ghi vào (ít nhất là trong deviceOS) là đặt một ngữ cảnh. Trong trường hợp này, chúng tôi sẽ sử dụng các UUID đã có sẵn.
-
Ngay sau khi xác định các đặc điểm, hãy thêm chúng để chúng hiển thị:
// Add the characteristics BLE.addCharacteristic(redCharacteristic); BLE.addCharacteristic(greenCharacteristic); BLE.addCharacteristic(blueCharacteristic);
-
Thiết lập chức năng gọi lại.
// Static function for handling Bluetooth Low Energy callbacks static void onDataReceived(const uint8_t* data, size_t len, const BlePeerDevice& peer, void* context) { }
Bạn có thể thực hiện việc này ở đầu tệp (ở trên
Setup()
) Chúng tôi sẽ xác định điều này nhiều hơn sau. -
Cuối cùng, để thiết bị của bạn có thể kết nối được, chúng tôi phải thiết lập quảng cáo. Đặt mã này ở cuối
Setup()
của bạn chức năng// Advertising data BleAdvertisingData advData; // Add the RGB LED service advData.appendServiceUUID(rgbService); // Start advertising! BLE.advertise(&advData);
Đầu tiên, chúng tôi tạo một
BleAdvertisingData
sự vật. Chúng tôi thêmrgbService
từ Bước 3. Cuối cùng, chúng tôi có thể bắt đầu quảng cáo để dịch vụ và đặc điểm của chúng tôi có thể khám phá được!
Đã đến lúc kiểm tra
Tại thời điểm này, chúng tôi có một chương trình khả thi tối thiểu. Hãy biên dịch nó và lập trình nó vào phần cứng Particle của chúng ta. Điều này sẽ hoạt động với bất kỳ thiết bị hỗ trợ Mesh nào. (Xenon, Argon, Boron)
-
Trước khi chúng tôi bắt đầu thử nghiệm, hãy tạm thời thêm
SYSTEM_MODE(MANUAL);
lên đầu tệp của bạn. Điều này sẽ ngăn thiết bị kết nối với mạng lưới. Nếu thiết bị nhấp nháy màu xanh lam khi khởi động, bạn sẽ phải thiết lập thiết bị bằng Ứng dụng Particle trước khi tiếp tục. -
Tải xuống hình ảnh 1.3.0-rc.1 tại đây. Đối với Xenon, bạn sẽ cần [email protected]. Đối với những người khác, hãy tìm [email protected] và [email protected]. Tệp ở cuối trang trong Nội dung
-
Đặt thiết bị của bạn vào chế độ DFU. Giữ Nút Chế độ và nhấp vào nút Đặt lại trong giây lát Nút. Tiếp tục giữ Nút chế độ cho đến khi đèn LED nhấp nháy màu vàng.
-
Trong cửa sổ dòng lệnh, hãy thay đổi các thư mục thành nơi bạn đã lưu trữ tệp bạn đã tải xuống. Trong trường hợp của tôi, lệnh là
cd ~/Downloads/
-
Sau đó chạy:
particle flash --usb [email protected]
Thao tác này sẽ cài đặt hệ điều hành mới nhất cho Xenon của bạn. Sau khi hoàn tất, nó sẽ tiếp tục nhanh chóng nhấp nháy màu vàng. Một lần nữa, nếu bạn có một thiết bị Particle Mesh khác, hãy thay đổi tên tệp cho phù hợp.
-
Trong Mã trực quan, sử dụng Command + Shift + P tổ hợp phím để bật lên menu lệnh. Chọn Hạt:Biên dịch ứng dụng (cục bộ)
-
Sửa mọi lỗi có thể bật lên.
-
Sau đó, mở cùng một trình đơn và chọn Ứng dụng Flash (cục bộ)
-
Khi quá trình lập trình hoàn tất, hãy rút điện thoại của bạn ra. Sau đó, mở ứng dụng Bluetooth Low Energy yêu thích của bạn. Những cái tốt nhất là NRF Connect và Light Blue Explorer. Tôi sẽ sử dụng Light Blue Explorer cho ví dụ này.
-
Kiểm tra xem thiết bị có tên "Xenon-
" là quảng cáo. Chèn -
Tìm thiết bị của bạn và nhấp vào tên.
-
Nhìn vào danh sách các dịch vụ và đặc điểm. Nó có bao gồm dịch vụ và UUID đặc trưng mà chúng tôi đã thiết lập cho đến nay không? Ví dụ:UUID dịch vụ có hiển thị là 6E400001-B5A3-F393-E0A9-E50E24DCCA9E ?
Nếu mọi thứ hiển thị như bạn mong đợi, bạn đang ở một nơi tốt. Nếu không thực hiện theo các hướng dẫn trước đó để đảm bảo mọi thứ đều khớp.
Giai đoạn 2:Xử lý dữ liệu
Giai đoạn tiếp theo của dự án của chúng tôi là xử lý các sự kiện viết. Chúng tôi sẽ cập nhật onDataReceived
của mình chức năng.
Viết mã
-
Đầu tiên, hãy tạo một cấu trúc sẽ giữ trạng thái của đèn LED. Điều này có thể được thực hiện ở đầu tệp.
// Variables for keeping state typedef struct { uint8_t red; uint8_t green; uint8_t blue; } led_level_t;
-
Nửa sau của quá trình đó là tạo một biến tĩnh sử dụng kiểu dữ liệu này
// Static level tracking static led_level_t m_led_level;
Hai bước đầu tiên cho phép chúng tôi sử dụng một biến duy nhất để đại diện cho ba giá trị của đèn LED RGB.
-
Tiếp theo, hãy kiểm tra các lỗi cơ bản bên trong
onDataReceive
function Ví dụ, chúng tôi muốn đảm bảo rằng chúng tôi chỉ nhận được một byte.// We're only looking for one byte if( len != 1 ) { return; }
-
Tiếp theo, chúng tôi muốn xem sự kiện này đến từ đặc điểm nào. Chúng ta có thể sử dụng
context
để xác định điều này.// Sets the global level if( context == red ) { m_led_level.red = data[0]; } else if ( context == green ) { m_led_level.green = data[0]; } else if ( context == blue ) { m_led_level.blue = data[0]; }
Hãy nhớ rằng, trong trường hợp này, ngữ cảnh sẽ bằng con trỏ của chuỗi UUID màu đỏ, xanh lá cây hoặc xanh lam. Bạn cũng có thể nhận thấy rằng chúng tôi đang đặt
m_led_level
. Bằng cách đó, chúng tôi có thể cập nhật đèn LED RGB ngay cả khi chỉ có một giá trị thay đổi. -
Cuối cùng, sau khi thiết lập, bạn có thể ghi vào
RGB
đối tượng// Set RGB color RGB.color(m_led_level.red, m_led_level.green, m_led_level.blue);
Kiểm tra mã
Hãy thực hiện quy trình tương tự như trước để flash thiết bị.
-
Đặt thiết bị của bạn vào chế độ DFU. Giữ Nút Chế độ và nhấp vào nút Đặt lại Nút. Tiếp tục giữ Nút chế độ cho đến khi đèn LED nhấp nháy màu vàng.
-
Sau đó, mở cùng một trình đơn và chọn Ứng dụng Flash (cục bộ)
-
Sau khi lập trình xong, hãy kết nối với thiết bị bằng Light Blue Explorer .
-
Nhấn vào đặc điểm áp dụng cho đèn LED màu đỏ.
-
Viết FF . Đèn LED màu đỏ sẽ bật.
-
Viết 00 . Đèn LED màu đỏ sẽ tắt.
-
Làm tương tự cho hai đặc điểm còn lại. Giờ đây, chúng tôi có toàn quyền kiểm soát đèn LED RGB qua Bluetooth năng lượng thấp!
Giai đoạn 3:Chia sẻ qua Mesh
Cuối cùng, bây giờ chúng tôi đã nhận được thông báo BLE thành công, đã đến lúc chuyển tiếp chúng đến mạng lưới của chúng tôi.
Viết mã
-
Đầu tiên, hãy loại bỏ chế độ MANUAL. Nhận xét
SYSTEM_MODE(MANUAL);
-
Ở đầu tệp, hãy thêm một biến mà chúng tôi sẽ sử dụng để theo dõi nếu chúng tôi cần xuất bản
// Tracks when to publish to Mesh static bool m_publish;
-
Sau đó khởi tạo nó trong
Setup()
// Set to false at first m_publish = false;
-
Sau đó, sau khi thiết lập đèn LED RGB trong
onDataReceived
callback, hãy đặt nó thành true:// Set RGB color RGB.color(m_led_level.red, m_led_level.green, m_led_level.blue); // Set to publish m_publish = true;
-
Hãy thêm một điều kiện trong
loop()
hàm số. Điều này sẽ khiến chúng tôi xuất bản trạng thái LED lên mạng Mesh:if( m_publish ) { // Reset flag m_publish = false; // Publish to Mesh Mesh.publish("red", String::format("%d", m_led_level.red)); Mesh.publish("green", String::format("%d", m_led_level.green)); Mesh.publish("blue", String::format("%d", m_led_level.blue)); }
Mesh.publish
yêu cầu một chuỗi cho cả hai đầu vào. Do đó, chúng tôi đang sử dụngString::format
để tạo một chuỗi với các giá trị đỏ, lục và lam của chúng tôi. -
Sau đó, hãy đăng ký các biến tương tự trong
Setup()
. Bằng cách đó, một thiết bị khác cũng có thể làm cho đèn LED trên thiết bị này cập nhật.Mesh.subscribe("red", meshHandler); Mesh.subscribe("green", meshHandler); Mesh.subscribe("blue", meshHandler);
-
Ở đầu tệp mà chúng tôi muốn tạo
meshHandler
// Mesh event handler static void meshHandler(const char *event, const char *data) { }
-
Trong ứng dụng này, chúng tôi cần
event
tham số vàdata
tham số. Để sử dụng chúng, chúng tôi phải thay đổi chúng thànhString
loại hình. Bằng cách đó, chúng ta có thể sử dụng các hàm chuyển đổi và so sánh được tích hợp sẵn. Vì vậy, bên trongmeshHandler
thêm chức năng:// Convert to String for useful conversion and comparison functions String eventString = String(event); String dataString = String(data);
-
Cuối cùng chúng tôi thực hiện một số so sánh. Trước tiên, chúng tôi kiểm tra xem tên sự kiện có khớp không. Sau đó, chúng tôi đặt giá trị của
dataString
đến mức dẫn đầu tương ứng.// Determine which event we recieved if( eventString.equals("red") ) { m_led_level.red = dataString.toInt(); } else if ( eventString.equals("green") ) { m_led_level.green = dataString.toInt(); } else if ( eventString.equals("blue") ) { m_led_level.blue = dataString.toInt(); } else { return; } // Set RGB color RGB.color(m_led_level.red, m_led_level.green, m_led_level.blue);
Sau đó, ở phần cuối, chúng tôi đặt màu RGB mới. Lưu ý cách tôi xử lý trạng thái không xác định bằng cách thêm
return
trongelse
tiết diện. Việc lọc ra các điều kiện lỗi luôn luôn tốt trước khi chúng tàn phá!
Kiểm tra mã
-
Mở ứng dụng Particle trên điện thoại của bạn
-
Hãy thiết lập Argon trước. Nếu nút này không nhấp nháy màu xanh lam, hãy giữ nút chế độ cho đến khi nút này nhấp nháy màu xanh lam.
Lưu ý:nếu bạn đã lập trình ứng dụng, đèn LED sẽ tắt theo mặc định. Giữ nút chế độ trong 5 giây rồi tiếp tục.
-
Thực hiện quá trình ghép nối. Ứng dụng sẽ hướng dẫn bạn qua tất cả các bước. Đảm bảo rằng bạn nhớ mật khẩu Quản trị viên cho mạng lưới của mình.
-
Lập trình Argon với chương trình cơ sở mới nhất (1.3.0) (xem Giai đoạn 1 - Thời gian kiểm tra - Bước 2 để được nhắc nhở về cách thực hiện việc này)
-
Sau khi nhấp nháy nhanh màu vàng, hãy lập trình Argon bằng ứng dụng Tinker. Bạn có thể tải xuống tại trang phát hành.
-
Sau khi chúng tôi có một đèn LED màu lục lam rắn đẹp (được kết nối với Đám mây hạt), chúng tôi sẽ lập trình ứng dụng. Sử dụng Cloud Flash trong trình đơn thả xuống.
Theo như tôi có thể nói, Particle buộc bất kỳ thiết bị nào được flash cục bộ ở chế độ an toàn khi kết nối với đám mây. Nó có thể là thiết lập của tôi. Số dặm của bạn có thể thay đổi ở đây. Tốt nhất nên sử dụng Cloud Flash .
Đảm bảo bạn chọn đúng phiên bản deviceOS ( 1.3.0-rc1 ), loại thiết bị ( Argon ) và tên thiết bị ( Bạn đã đặt tên thiết bị trong quá trình thiết lập )
-
Kết nối với Xenon bằng ứng dụng điện thoại
-
Kết nối Xenon với mạng Mesh của bạn bằng ứng dụng điện thoại
-
Flash Xenon của bạn bằng Cloud Flash . Sử dụng tên mà bạn đã đặt trong quá trình thiết lập ứng dụng điện thoại. Miễn là thiết bị được kết nối với Đám mây hạt hoặc ở chế độ an toàn (Đèn LED màu tím), thiết bị sẽ lập trình.
-
Sau khi kết nối, chúng ta hãy đến phần thú vị. Mở Light Blue Explorer. Kết nối với Argon hoặc Xenon .
-
Chọn một trong các đặc điểm của đèn LED và thay đổi giá trị.
Đèn LED sẽ thay đổi trên tất cả các thiết bị!
Mã cuối cùng
Đây là mã cuối cùng với tất cả các phần được ghép lại với nhau. Bạn có thể sử dụng điều này để đảm bảo rằng bạn đặt chúng vào đúng vị trí !!
/*
* Project ble_mesh
* Description: Bluetooth Low Energy + Mesh Example
* Author: Jared Wolff
* Date: 7/13/2019
*/
//SYSTEM_MODE(MANUAL);
// UUIDs for service + characteristics
const char* serviceUuid = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E";
const char* red = "6E400002-B5A3-F393-E0A9-E50E24DCCA9E";
const char* green = "6E400003-B5A3-F393-E0A9-E50E24DCCA9E";
const char* blue = "6E400004-B5A3-F393-E0A9-E50E24DCCA9E";
// Set the RGB BLE service
BleUuid rgbService(serviceUuid);
// Variables for keeping state
typedef struct {
uint8_t red;
uint8_t green;
uint8_t blue;
} led_level_t;
// Static level tracking
static led_level_t m_led_level;
// Tracks when to publish to Mesh
static bool m_publish;
// Mesh event handler
static void meshHandler(const char *event, const char *data)
{
// Convert to String for useful conversion and comparison functions
String eventString = String(event);
String dataString = String(data);
// Determine which event we recieved
if( eventString.equals("red") ) {
m_led_level.red = dataString.toInt();
} else if ( eventString.equals("green") ) {
m_led_level.green = dataString.toInt();
} else if ( eventString.equals("blue") ) {
m_led_level.blue = dataString.toInt();
} else {
return;
}
// Set RGB color
RGB.color(m_led_level.red, m_led_level.green, m_led_level.blue);
}
// Static function for handling Bluetooth Low Energy callbacks
static void onDataReceived(const uint8_t* data, size_t len, const BlePeerDevice& peer, void* context) {
// We're only looking for one byte
if( len != 1 ) {
return;
}
// Sets the global level
if( context == red ) {
m_led_level.red = data[0];
} else if ( context == green ) {
m_led_level.green = data[0];
} else if ( context == blue ) {
m_led_level.blue = data[0];
}
// Set RGB color
RGB.color(m_led_level.red, m_led_level.green, m_led_level.blue);
// Set to publish
m_publish = true;
}
// setup() runs once, when the device is first turned on.
void setup() {
// Enable app control of LED
RGB.control(true);
// Init default level
m_led_level.red = 0;
m_led_level.green = 0;
m_led_level.blue = 0;
// Set to false at first
m_publish = false;
// Set the subscription for Mesh updates
Mesh.subscribe("red",meshHandler);
Mesh.subscribe("green",meshHandler);
Mesh.subscribe("blue",meshHandler);
// Set up characteristics
BleCharacteristic redCharacteristic("red", BleCharacteristicProperty::WRITE_WO_RSP, red, serviceUuid, onDataReceived, (void*)red);
BleCharacteristic greenCharacteristic("green", BleCharacteristicProperty::WRITE_WO_RSP, green, serviceUuid, onDataReceived, (void*)green);
BleCharacteristic blueCharacteristic("blue", BleCharacteristicProperty::WRITE_WO_RSP, blue, serviceUuid, onDataReceived, (void*)blue);
// Add the characteristics
BLE.addCharacteristic(redCharacteristic);
BLE.addCharacteristic(greenCharacteristic);
BLE.addCharacteristic(blueCharacteristic);
// Advertising data
BleAdvertisingData advData;
// Add the RGB LED service
advData.appendServiceUUID(rgbService);
// Start advertising!
BLE.advertise(&advData);
}
// loop() runs over and over again, as quickly as it can execute.
void loop() {
// Checks the publish flag,
// Publishes to a variable called "red" "green" and "blue"
if( m_publish ) {
// Reset flag
m_publish = false;
// Publish to Mesh
Mesh.publish("red", String::format("%d", m_led_level.red));
Mesh.publish("green", String::format("%d", m_led_level.green));
Mesh.publish("blue", String::format("%d", m_led_level.blue));
}
}
Kết luận
Trong hướng dẫn này, bạn đã học cách thêm Bluetooth vào dự án Particle Mesh. Như bạn có thể tưởng tượng, khả năng là vô tận. Ví dụ:bạn có thể thêm ứng dụng người dùng / quản trị viên vào trải nghiệm. Giờ thì thật tuyệt vời. ?
Bạn có thể mong đợi nhiều nội dung như thế này trong cuốn sách sắp tới của tôi: Hướng dẫn cơ bản về lưới hạt . Đăng ký danh sách của tôi để cập nhật và nội dung. Ngoài ra, tất cả những người đăng ký sớm sẽ được giảm giá khi nó được phát hành! Nhấp vào đây để đăng ký.