nRF52840 BLE Serial 通訊

Central Node


BLEClientBas  clientBas;  // battery client
BLEClientDis  clientDis;  // device information client
BLEClientUart clientUart; // bleuart client

void BLE_init(void) {
  // Initialize Bluefruit with maximum connections as Peripheral = 0, Central = 1
  // SRAM usage required by SoftDevice will increase dramatically with number of connections
  Bluefruit.begin(0, 1);
  
  Bluefruit.setName("CentralNode");

  // Configure Battyer client
  clientBas.begin();  

  // Configure DIS client
  clientDis.begin();

  // Init BLE Central Uart Serivce
  clientUart.begin();
  clientUart.setRxCallback(onBLE_UART_RXHandler);

  // Increase Blink rate to different from PrPh advertising mode
  Bluefruit.setConnLedInterval(250);

  // Callbacks for Central
  Bluefruit.Central.setConnectCallback(onConnectHandler);
  Bluefruit.Central.setDisconnectCallback(onDisconnectHandler);

  /* Start Central Scanning
   * - Enable auto scan if disconnected
   * - Interval = 100 ms, window = 80 ms
   * - Don't use active scan
   * - Start(timeout) with timeout = 0 will scan forever (until connected)
   */
  Bluefruit.Scanner.setRxCallback(scan_callback);
  Bluefruit.Scanner.restartOnDisconnect(true);
  Bluefruit.Scanner.setInterval(160, 80); // in unit of 0.625 ms
  Bluefruit.Scanner.useActiveScan(false);
  Bluefruit.Scanner.start(0);                   // // 0 = Don't stop scanning after n seconds
}

/**
 * Callback invoked when scanner pick up an advertising data
 * @param report Structural advertising data
 */
void scan_callback(ble_gap_evt_adv_report_t* report) {
  // Check if advertising contain BleUart service
  if (Bluefruit.Scanner.checkReportForService(report, clientUart)) {
    Serial.print("BLE UART service detected. Connecting ... ");

    // Connect to device with bleuart service in advertising
    Bluefruit.Central.connect(report);
  }
  else {      
    // For Softdevice v6: after received a report, scanner will be paused
    // We need to call Scanner resume() to continue scanning
    Bluefruit.Scanner.resume();
  }
}

/**
 * Callback invoked when an connection is established
 * @param conn_handle
 */
void onConnectHandler(uint16_t conn_handle) {
  Serial.println("Connected");

  Serial.print("Dicovering Device Information ... ");
  if (clientDis.discover(conn_handle)) {
    Serial.println("Found it");
    char buffer[32+1];
    
    // read and print out Manufacturer
    memset(buffer, 0, sizeof(buffer));
    if (clientDis.getManufacturer(buffer, sizeof(buffer))) {
      Serial.print("Manufacturer: ");
      Serial.println(buffer);
    }

    // read and print out Model Number
    memset(buffer, 0, sizeof(buffer));
    if (clientDis.getModel(buffer, sizeof(buffer))) {
      Serial.print("Model: ");
      Serial.println(buffer);
    }

    Serial.println();
  }
  else {
    Serial.println("Found NONE");
  }

  Serial.print("Dicovering Battery ... ");
  if (clientBas.discover(conn_handle)) {
    Serial.println("Found it");
    Serial.print("Battery level: ");
    Serial.print(clientBas.read());
    Serial.println("%");
  }
  else {
    Serial.println("Found NONE");
  }

  Serial.print("Discovering BLE Uart Service ... ");
  if (clientUart.discover(conn_handle)) {
    Serial.println("Found it");

    Serial.println("Enable TXD's notify");
    clientUart.enableTXD();

    Serial.println("Ready to receive from peripheral");
  }
  else {
    Serial.println("Found NONE");
    
    // disconnect since we couldn't find bleuart service
    Bluefruit.disconnect(conn_handle);
  }  
}

/**
 * Callback invoked when a connection is dropped
 * @param conn_handle
 * @param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h
 */
void onDisconnectHandler(uint16_t conn_handle, uint8_t reason) {
  (void) conn_handle;
  (void) reason;
  
  Serial.print("Disconnected, reason = 0x"); Serial.println(reason, HEX);
}

/**
 * Callback invoked when uart received data
 * @param uart_svc Reference object to the service where the data 
 * arrived. In this example it is clientUart
 */
void onBLE_UART_RXHandler(BLEClientUart& uart_svc) {
  uart_svc.setTimeout(10);
  if (uart_svc.available()) {
    uint8_t buf[128];
    uint16_t size = uart_svc.readBytesUntil('\n', buf, 128);
    Serial.write(buf, size);
    Serial.write('\n');
  }
}

void setup() {
  Serial.begin(115200);
  while (!Serial) {}

  Serial.setTimeout(10);
  

  BLE_init();
}

void loop() {
  if (Bluefruit.Central.connected() && clientUart.discovered()) {
    // Discovered means in working state
    // Get Serial input and send to Peripheral
    if (Serial.available()) {
      uint8_t buf[128];
      uint16_t size = Serial.readBytesUntil('\n', buf, 128);
      clientUart.write(buf, size);
      //clientUart.write('\n');
    }
  }
}

Client

#include <bluefr#include <bluefruit.h>

// BLE Service
BLEDfu  bledfu;  // OTA DFU service
BLEDis  bledis;  // device information
BLEUart bleuart; // uart over ble
BLEBas  blebas;  // battery

// callback invoked when central connects
void onConnectHandler(uint16_t conn_handle) {
  // Get the reference to current connection
  BLEConnection* connection = Bluefruit.Connection(conn_handle);

  char central_name[32] = { 0 };
  connection->getPeerName(central_name, sizeof(central_name));

  Serial.print("Connected to ");
  Serial.println(central_name);
}

/**
 * Callback invoked when a connection is dropped
 * @param conn_handle connection where this event happens
 * @param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h
 */
void onDisconnectHandler(uint16_t conn_handle, uint8_t reason) {
  (void) conn_handle;
  (void) reason;

  Serial.println();
  Serial.print("Disconnected, reason = 0x"); Serial.println(reason, HEX);
}

void BLE_init(void) {
  // Setup the BLE LED to be enabled on CONNECT
  // Note: This is actually the default behavior, but provided
  // here in case you want to control this LED manually via PIN 19
  Bluefruit.autoConnLed(true);

  // Config the peripheral connection with maximum bandwidth 
  // more SRAM required by SoftDevice
  // Note: All config***() function must be called before begin()
  Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);

  Bluefruit.begin();
  Bluefruit.setTxPower(4);    // Check bluefruit.h for supported values
  Bluefruit.setName("ClientNode"); // useful testing with multiple central connections

  Bluefruit.Periph.setConnectCallback(onConnectHandler);
  Bluefruit.Periph.setDisconnectCallback(onDisconnectHandler);

  // To be consistent OTA DFU should be added first if it exists
  bledfu.begin();

  // Configure and Start Device Information Service
  bledis.setManufacturer("RATH");
  bledis.setModel("nRF52840");
  bledis.begin();

  // Configure and Start BLE Uart Service
  bleuart.begin();

  // Start BLE Battery Service
  blebas.begin();
  blebas.write(100);
  
}

void BLE_startAdvertising(void) {
  // Advertising packet
  Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
  Bluefruit.Advertising.addTxPower();

  // Include bleuart 128-bit uuid
  Bluefruit.Advertising.addService(bleuart);

  // Secondary Scan Response packet (optional)
  // Since there is no room for 'Name' in Advertising packet
  Bluefruit.ScanResponse.addName();
  
  /* Start Advertising
   * - Enable auto advertising if disconnected
   * - Interval:  fast mode = 20 ms, slow mode = 152.5 ms
   * - Timeout for fast mode is 30 seconds
   * - Start(timeout) with timeout = 0 will advertise forever (until connected)
   * 
   * For recommended advertising interval
   * https://developer.apple.com/library/content/qa/qa1931/_index.html   
   */
  Bluefruit.Advertising.restartOnDisconnect(true);
  Bluefruit.Advertising.setInterval(32, 244);    // in unit of 0.625 ms
  Bluefruit.Advertising.setFastTimeout(30);      // number of seconds in fast mode
  Bluefruit.Advertising.start(0);                // 0 = Don't stop advertising after n seconds  
}

void setup() {
  Serial.begin(115200);

  while (!Serial) {}
  
  Serial.setTimeout(10);
  bleuart.setTimeout(10);

  BLE_init();

  // Set up and start advertising
  BLE_startAdvertising();

  Serial.println("Please use Adafruit's Bluefruit LE app to connect in UART mode");
  Serial.println("Once connected, enter character(s) that you wish to send");
}


void loop() {
  if (Serial.available()) {
    uint8_t buf[128];
    uint16_t size = Serial.readBytesUntil('\n', buf, 128);
    bleuart.write(buf, size);
    //bleuart.write('\n');
  } 

  if (bleuart.available()) {
    uint8_t buf[128];
    uint16_t size = bleuart.readBytesUntil('\n', buf, 128);
    Serial.write(buf, size);
    Serial.write('\n');
  }
}

測試用的 Python 代碼:

import random

import serial

ser = serial.Serial("COM20", 115200, timeout=0.01)

prev_t = time.time()

count = 0
counter = 0
while True:

    t = time.time()
    buf = "%s\n" % t
    #buf = "hi\n"
    counter += 1
    ser.write(buf.encode())

    time.sleep(0.005)
    buf = b""
    c = ser.read()

    while c and c != b"\n":
        buf += c
        c = ser.read()

    buf += c

    count += len(buf)

    #print(buf)
    try:
        prev_t = float(buf.decode().replace("\n", ""))
        print(t, "\t", time.time() - prev_t)
    except:
        pass


    if count > 100:
        print(count / (time.time() - prev_t), " wd/s")
        count = 0    
        prev_t = time.time()

另一端用個 echo client


import serial

ser = serial.Serial("COM23", 115200, timeout=0.1)

count = 0
while True:

    buf = b""
    c = ser.read()

    while c and c != b"\n":
        buf += c
        c = ser.read()

    buf += c


    #print(buf)
    
    ser.write(buf)

    
    count += 1

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末鼠哥,一起剝皮案震驚了整個濱河市窜司,隨后出現(xiàn)的幾起案子悬赏,更是在濱河造成了極大的恐慌府蛇,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件彼哼,死亡現(xiàn)場離奇詭異涯肩,居然都是意外死亡溺职,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進店門赛不,熙熙樓的掌柜王于貴愁眉苦臉地迎上來惩嘉,“玉大人,你說我怎么就攤上這事踢故∥睦瑁” “怎么了?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵殿较,是天一觀的道長耸峭。 經(jīng)常有香客問我,道長淋纲,這世上最難降的妖魔是什么劳闹? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮洽瞬,結(jié)果婚禮上玷或,老公的妹妹穿的比我還像新娘。我一直安慰自己片任,他們只是感情好偏友,可當我...
    茶點故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著对供,像睡著了一般位他。 火紅的嫁衣襯著肌膚如雪氛濒。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天鹅髓,我揣著相機與錄音舞竿,去河邊找鬼。 笑死窿冯,一個胖子當著我的面吹牛骗奖,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播醒串,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼执桌,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了芜赌?” 一聲冷哼從身側(cè)響起仰挣,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎缠沈,沒想到半個月后膘壶,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡洲愤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年颓芭,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片柬赐。...
    茶點故事閱讀 40,664評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡亡问,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出躺率,到底是詐尸還是另有隱情玛界,我是刑警寧澤,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布悼吱,位于F島的核電站慎框,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏后添。R本人自食惡果不足惜笨枯,卻給世界環(huán)境...
    茶點故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望遇西。 院中可真熱鬧馅精,春花似錦、人聲如沸粱檀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽茄蚯。三九已至压彭,卻和暖如春睦优,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背壮不。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工汗盘, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人询一。 一個月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓隐孽,卻偏偏與公主長得像,于是被迫代替她去往敵國和親健蕊。 傳聞我的和親對象是個殘疾皇子菱阵,可洞房花燭夜當晚...
    茶點故事閱讀 45,675評論 2 359

推薦閱讀更多精彩內(nèi)容

  • 前言 本文會用實例的方式,將iOS各種IM的方案都簡單的實現(xiàn)一遍绊诲。并且提供一些選型送粱、實現(xiàn)細節(jié)以及優(yōu)化的建議褪贵。 注:...
    會敲代碼的小熊貓閱讀 3,288評論 0 4
  • 前言 本文會用實例的方式掂之,將iOS各種IM的方案都簡單的實現(xiàn)一遍。并且提供一些選型脆丁、實現(xiàn)細節(jié)以及優(yōu)化的建議世舰。 注:...
    maTianHong閱讀 2,378評論 4 12
  • 翻譯?http://www.html5rocks.com/en/tutorials/webrtc/infrastr...
    bktmkd閱讀 6,329評論 1 28
  • WebSocket測試工具:http://www.websocket-test.com/ Websocket是ht...
    private_object閱讀 1,612評論 0 0
  • Node.js 網(wǎng)絡(luò)通信 Node 是一個面向網(wǎng)絡(luò)而生的平臺,它具有事件驅(qū)動槽卫、無阻塞跟压、單線程等特性,具備良好的可伸...
    強某某閱讀 997評論 0 1