![](/media/cache/profiles/eric_duckman_mpreg_by_mpregediter-db5d0t8.png.50x50_q85.png)
Template for the workshop 'Ontwerp je eigen Bluetooth LE device' for the NIOC Congress 2018
Ontwikkel je eigen Bluetooth LE device
Welkom bij de workshop, tijdens deze workshop ga je aan de gang met het ontwikkelen van een Bluetooth LE device met behulp van MBED. Tijdens de workshop heb je het volgende nodig:
- Het bluetooth LE ontwikkel bord, dat door ons beschikbaar is gesteld
- Een laptop met internet toegang. Voor het ontwikkelen van de software gebruik je de online mbed ontwikkel omgeving
- Een redelijke kennis van C++ programmeren, de software voor het device wordt ontwikkeld met C++.
De handleiding en presentatie zijn hier te vinden:
Presentatie
Handleiding
Opzetten van de ontwikkel omgeving
Stap 1: Registreer je op de MBED website.
Ga naar de MBED OS website en registreer je op de website om toegang te krijgen tot de online IDE:
os.mbed.com
Stap 2: Voeg het NRF52-DK ontwikkelbord toe aan je ontwikkelomgeving.
Het ontwikkelbord wat beschikbaar is gesteld is het NRF52-DK ontwikkelbord, informatie over dit bord is te vinden via de volgende pagina:
https://os.mbed.com/platforms/Nordic-nRF52-DK/
Bekijk deze pagina, op deze pagina is ook een knop aanwezig om het platform toe te voegen aan je online ontwikkelomgeving. Gebruik de knop om het platform toe te voegen aan de compiler.
Selecteer het NRF52-Dk platform in de IDE rechtsboven in het browser scherm.
Stap 3: Installeer de NRF-Connect app op je smartphone.
Installeer de NRF-Connect app van Nordic op je smartphone. Deze app gaan we gebruiken om via bluetooth verbinding te maken met het ontwikkelbord. Deze app is beschikbaar voor zowel Android als IOS.
De ontwikkelomgeving is nu juist geconfigureerd om te gaan beginnen.
Het ontwikkelen van je eigen Bluetooth LE device
In een aantal stappen gaan we nu een eigen Bluetooth LE device ontwikkelen die aangestuurd kan worden m.b.v. je smartphone met de Nordic NRFConnect LE app.
Stap 1: Opzetten van een basis applicatie.
We beginnen vanaf een basis applicatie die reeds voor geprogrammeerd is. Hiervoor moet je een bestaand project importeren / clonen in de online ontwikkel omgeving. Hiervoor gebruiken we je import van de MBED omgeving:
- Klik op de knop import
- Selecteer het tabblad ‘Programs’
- Gebruik de link om een programma te importeren vanaf een URL
Importeer het programma vanaf de volgende url: https://os.mbed.com/users/wkleunen/code/saxion_nioc/
Stap 2: Compileer het programma en laad het op het ontwikkelbord.
Nadat je de basis applicatie hebt geimporteerd kun je hem compileren m.b.v. de ‘Compile’ button. Druk op compile, het project wordt nu gecompileerd op de server van mbed. Als de compilatie klaar en succesvol is, wordt de gecompileerde firmware automatisch gedownload in de vorm van een ‘hex’ bestand.
Sluit het ontwikkelbord aan op je laptop via de USB kabel. Na installatie van de noodzakelijke drivers, verschijnt er een nieuwe drive ‘JLINK’. Sleep het ‘hex’ bestand naar de JLINK drive om de applicatie te schrijven naar het ontwikkelbord. De applicatie wordt op het bord geprogrammeerd en wordt nu gestart.
Start nu de NRF-Connect app op je smartphone. Zodra je op ‘Scan’ drukt wordt het bord gedetecteerd met de naam ‘Nioc_BLE’. Aangezien er meer mogelijk meerdere borden worden gedetecteerd met dezelfde naam weet je dus niet of dit specifiek jouw bord is. Ga daarvoor verder naar de volgende stap.
Stap 3: Aanpassen van de device naam.
Pak de code van het basis programma er bij en pas nu de naam van het device aan in de code, succes!
Na het aanpassen van de code kun je het programma opnieuw compileren en op het device programmeren door de hex file naar de USB drive te slepen. Je hoeft niet eerst de oude applicatie weg te halen, de nieuwe hex file wordt over de oude applicatie heen gezet en automatisch gestart.
Stap 4: Stuur de LEDS aan m.b.v. een Gatt Characteristic.
In de voorbeeld code is reeds een Gatt Characteristic gedefinieerd genaamd ‘Alert Level’. M.b.v. de NRF Connect app kan na het connecten met het BLE device een waarde (byte) naar dit characteristic worden geschreven.
Connect met je BLE device m.b.v. NRF Connect en stuur een waarde naar de ‘Alert Level’ characteristic:
- Druk op ‘Write value’ knop (pijltje omhoog) in NRF connect om een waarde te gaan schrijven. (N.B. Als je de knop niet ziet, dan ben je niet verbonden met het BLE bord, druk op connect om te verbinden).
- Kies een waarde / alert level die naar de characteristic moet worden gestuurd
- Druk op send om de waarde naar het device te schrijven
In de code wordt de callback functie ‘onDataWrittenCallback’ aangeroepen als een waarde geschreven wordt naar de characteristic. Pas deze functie aan, dat de waarde gebruikt wordt om de LEDS op het bord aan te sturen. Er zijn 4 leds op het bord die aangestuurd kunnen worden, m.b.v. de ‘EnableLed’ en ‘DisableLed’ functies kunnen deze aan en uit worden gezet.
Stap 5: Pas de LEDS aan m.b.v. de knoppen op het bord.
Op het bord zijn ook 4 knoppen aanwezig. In de code is er reeds voor gezorgd dat op het moment dat één van de knoppen wordt ingedrukt, de functie ‘ButtonPressed’ wordt aangeroepen.
Pas de code aan dat de LEDs worden aangepast zodra op één van de knoppen wordt gedrukt. Maak het ook zo dat de ‘alert_characteristic’ wordt aangepast zodra één van de knoppen wordt ingedrukt. De waarde van de characteristic kan als volgt worden aangepast:
Code voor aanpassen van waarde van characteristic in mbed
uint8_t alert_value = 3; BLE::Instance().gattServer().write(alert_characteristic.getValueHandle(), &alert_value, sizeof(uint8_t));
Aangezien je de waarde van de ‘alert_characteristic’ aanpast, is het mogelijk om de nieuwe waarde via Bluetooth draadloos op te vragen aan het device.
- Connect weer met je device en druk op de ‘lezen’ knop (1) van de ‘Alert Level’ characteristic. De huidige waarde van het characteristic wordt nu getoond (2).
- Het is ook mogelijk om notifications aan te zetten, doe dit met behulp van de notifications knop (3). Als notifications aan staan is het niet meer nodig om de waarde van de characteristic handmatig op te vragen. Zodra de waarde van de characteristic wordt aangepast (door op een knop te drukken), wordt de nieuwe waarde gepushed naar je smartphone en wordt de waarde getoond (2).
Nawoord
Bedankt voor het bijwonen van de workshop ‘Ontwikkel je eigen Bluetooth LE device’. Wij zijn erg enthousiast over het MBED platform en de beschikbare hardware. Je hebt nu ervaren hoe eenvoudig het is om aan de gang te gaan met embedded software ontwikkeling onderwijs door gebruik te maken van het MBED online platform. Daarnaast biedt Bluetooth LE veel interessante mogelijkheden om (Embedded) software onderwerpen te behandelen en wordt het in de praktijk steeds meer gebruikt.
Naast het online platform biedt MBED de mogelijkheid om offline de tools te gebruiken. Dit is eenvoudig te installeren m.b.v. een installer: https://os.mbed.com/docs/latest/tools/installing-with-the-windows-installer.html
Hoewel dit prettig is als het druk is op de MBED cloud server, is onze ervaring dat studenten toch eigenlijk altijd met de online omgeving blijven werken. Binnen ons onderwijs wordt het MBED platform gebruikt voor microcontroller programmeren en draadloze communicatie.
Naast het ontwikkelen van een Bluetooth LE device met MBED is het ook mogelijk om Bluetooth LE te gebruiken voor Android en IOS software ontwikkeling en web software door de Bluetooth LE stack op een Raspberry PI te combineren met web m.b.v. NodeJS door gebruik te maken van de Noble library: https://github.com/sandeepmistry/noble
Wij zijn zeer geinteresseerd in de mogelijkheden die jullie zien voor MBED en BLE in het onderwijs,
Wouter van Kleunen
Wilco Bonestroo
HBO-ICT Saxion
Diff: main.cpp
- Revision:
- 0:23c0b182cbe6
- Child:
- 1:33f443eaa422
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Mon Jan 08 12:32:21 2018 +0000 @@ -0,0 +1,136 @@ +#include "mbed.h" +#include "rtos.h" +#include "ble/BLE.h" + +// Define the interface to the leds, they are digital outputs when can be +// enabled or disabled +enum { total_leds = 4 }; +DigitalOut led[total_leds] = { D6, D7, D8, D9 }; + +// Function to enable led with index 0..3 +void EnableLed(uint8_t index) +{ + if(index < total_leds) + led[index] = 0; +} + +// Function to disable led with index 0..3 +void DisableLed(uint8_t index) +{ + if(index < total_leds) + led[index] = 1; +} + +// Define the interface to the buttons, they are configured to +// generate an interrupt and call the ButtonPress function +enum { total_buttons = 4 }; +InterruptIn buttons[total_buttons] = { D2, D3, D4, D5 }; + +// The name of this device +// TODO .. Change the name of this device +const static char DEVICE_NAME[] = "Nioc_BLE"; + +// The UUID (Unique Universal Identifier) of our Led service and Led characteristic +enum { LED_SERVICE_UUID = 0xA000 }; +enum { LED_VALUE_UUID = 0xA001 }; + +// Definition our led characteristic +ReadWriteGattCharacteristic<uint8_t> led_characteristic(LED_VALUE_UUID, NULL, + GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY); + +// This function is called when data is written to a characteristic +void onDataWrittenCallback(const GattWriteCallbackParams *params) +{ + // Check if it really was the led characteristic that was written by checking the handle + if(params->handle == led_characteristic.getValueHandle() && params->len == sizeof(uint8_t)) + { + // We got a new value for the led characteristic, do something useful with this + uint8_t led_value = *(uint8_t const *)(params->data); + // TODO: .. do something useful with this value + } +} + +// This function is called when the gatt connection is disconnected +// we have to manually re-enable the advertisements again when this occurs +void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *) +{ + BLE::Instance().gap().startAdvertising(); +} + +// This function is called when the BLE stack is initialized +// Setup the GATT Service and Advertisement here for the example +void bleInitComplete(BLE::InitializationCompleteCallbackContext *params) +{ + if(params->error != BLE_ERROR_NONE) + return; + + BLE &ble = BLE::Instance(); + + // Initialize the default of our led characteristic + uint8_t init_led_value = 0; + BLE::Instance().gattServer().write(led_characteristic.getValueHandle(), &init_led_value, sizeof(uint8_t)); + + // First create our GATT Service (basicly a list of characteristics ) + enum { TOTAL_SERVICE_CHARACTERTERISTICS = 1 }; + GattCharacteristic *characteristics_table[TOTAL_SERVICE_CHARACTERTERISTICS] = { &led_characteristic }; + GattService led_service(LED_SERVICE_UUID, characteristics_table, TOTAL_SERVICE_CHARACTERTERISTICS); + ble.gattServer().addService(led_service); + + // Setup the BLE callbacks + ble.gap().onDisconnection(disconnectionCallback); + ble.gattServer().onDataWritten(onDataWrittenCallback); + + // Configure the advertisement, we add the name of the device to the advertisement and some service data + ble.gap().setDeviceName((uint8_t const *)DEVICE_NAME); + ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); + ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME, (uint8_t const *)DEVICE_NAME, sizeof(DEVICE_NAME)); + + uint8_t service_data[] = { 0x11, 0x18, 0x00 }; + ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, service_data, sizeof(service_data)); + + // Start advertising our device information now + ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); + ble.gap().setAdvertisingInterval(250); + ble.gap().startAdvertising(); +} + +// This function is called when a button is pressed +void ButtonPressed(uint8_t index) +{ + // TODO: ... do something useful here when a button is pressed +} + +// Eventqueue to handle incoming events +EventQueue eventQueue(16 * EVENTS_EVENT_SIZE); + +// Function required to process events from the BLE Stack +void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext *context) +{ + eventQueue.call(Callback<void()>(&BLE::Instance(), &BLE::processEvents)); +} + +// Let's setup the BLE stack +int main(void) +{ + // Configure the led to the default state + EnableLed(0); + DisableLed(1); + DisableLed(2); + DisableLed(3); + + // Configure the button callbacks + buttons[0].mode(PullUp); + buttons[0].fall(eventQueue.event(ButtonPressed, 0)); + buttons[1].mode(PullUp); + buttons[1].fall(eventQueue.event(ButtonPressed, 1)); + buttons[2].mode(PullUp); + buttons[2].fall(eventQueue.event(ButtonPressed, 2)); + buttons[3].mode(PullUp); + buttons[3].fall(eventQueue.event(ButtonPressed, 3)); + + // Start the BLE Stack + BLE::Instance().onEventsToProcess(scheduleBleEventsProcessing); + BLE::Instance().init(bleInitComplete); + eventQueue.dispatch_forever(); + return 0; +} \ No newline at end of file