BTLE example for a CJMCU-8223 (NRF51822+Lis3dh). Also includes an OLED display. Further details on ioprog.com

Dependencies:   mbed BLE_API nRF51822

Files at this revision

API Documentation at this revision

Comitter:
f3d
Date:
Wed Jun 24 11:37:11 2020 +0000
Commit message:
Initial commit for CJMCU-8223 offering an LED service and an accelerometer service. Also includes an Oled display

Changed in this revision

BLE_API.lib Show annotated file Show diff for this revision Revisions of this file
LEDService.h Show annotated file Show diff for this revision Revisions of this file
accelService.h Show annotated file Show diff for this revision Revisions of this file
font5x7.h Show annotated file Show diff for this revision Revisions of this file
lis3dh.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
nRF51822.lib Show annotated file Show diff for this revision Revisions of this file
oled.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BLE_API.lib	Wed Jun 24 11:37:11 2020 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/teams/Bluetooth-Low-Energy/code/BLE_API/#65474dc93927
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LEDService.h	Wed Jun 24 11:37:11 2020 +0000
@@ -0,0 +1,42 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __BLE_LED_SERVICE_H__
+#define __BLE_LED_SERVICE_H__
+
+class LEDService {
+public:
+    const static uint16_t LED_SERVICE_UUID              = 0xA000;
+    const static uint16_t LED_STATE_CHARACTERISTIC_UUID = 0xA001;
+
+    LEDService(BLEDevice &_ble, bool initialValueForLEDCharacteristic) :
+        ble(_ble), ledState(LED_STATE_CHARACTERISTIC_UUID, &initialValueForLEDCharacteristic)
+    {
+        GattCharacteristic *charTable[] = {&ledState};
+        GattService         ledService(LED_SERVICE_UUID, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
+        ble.addService(ledService);
+    }
+
+    GattAttribute::Handle_t getValueHandle() const {
+        return ledState.getValueHandle();
+    }
+
+private:
+    BLEDevice                         &ble;
+    ReadWriteGattCharacteristic<bool>  ledState;
+};
+
+#endif /* #ifndef __BLE_LED_SERVICE_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/accelService.h	Wed Jun 24 11:37:11 2020 +0000
@@ -0,0 +1,66 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __BLE_ACCEL_SERVICE_H__
+#define __BLE_ACCEL_SERVICE_H__
+#include <mbed.h>
+#include <lis3dh.h>
+lis3dh Lis3dh;
+class accelService {
+public:
+    const static uint16_t ACCEL_SERVICE_UUID = 0xA012;
+    const static uint16_t ACCEL_X_CHARACTERISTIC_UUID = 0xA013;
+    const static uint16_t ACCEL_Y_CHARACTERISTIC_UUID = 0xA014;
+    const static uint16_t ACCEL_Z_CHARACTERISTIC_UUID = 0xA015;
+
+    accelService(BLEDevice &_ble, int16_t initialValueForACCELCharacteristic) :
+        ble(_ble), AccelX(ACCEL_X_CHARACTERISTIC_UUID, &initialValueForACCELCharacteristic),AccelY(ACCEL_Y_CHARACTERISTIC_UUID, &initialValueForACCELCharacteristic),AccelZ(ACCEL_Z_CHARACTERISTIC_UUID, &initialValueForACCELCharacteristic)
+    {
+        GattCharacteristic *charTable[] = {&AccelX,&AccelY,&AccelZ};
+        GattService         AccelService(ACCEL_SERVICE_UUID, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
+        ble.addService(AccelService);
+        Lis3dh.begin();
+    }
+
+    GattAttribute::Handle_t getValueHandle() const {
+        return AccelX.getValueHandle();
+    }
+    void updateAccelX(uint16_t newValue) {
+        ble.gattServer().write(AccelX.getValueHandle(), (uint8_t *)&newValue, sizeof(uint16_t));
+    }
+    void updateAccelY(uint16_t newValue) {
+        ble.gattServer().write(AccelY.getValueHandle(), (uint8_t *)&newValue, sizeof(uint16_t));
+    }
+    void updateAccelZ(uint16_t newValue) {
+        ble.gattServer().write(AccelZ.getValueHandle(), (uint8_t *)&newValue, sizeof(uint16_t));
+    }
+    void poll()
+    {                
+        int X,Y,Z;
+        Lis3dh.read(X,Y,Z);        
+        updateAccelX(X);
+        updateAccelY(Y);
+        updateAccelZ(Z);        
+        
+    }
+private:
+    BLEDevice &ble;
+    ReadOnlyGattCharacteristic<int16_t>  AccelX;
+    ReadOnlyGattCharacteristic<int16_t>  AccelY;
+    ReadOnlyGattCharacteristic<int16_t>  AccelZ;
+};
+
+#endif /* #ifndef __BLE_ACCEL_SERVICE_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/font5x7.h	Wed Jun 24 11:37:11 2020 +0000
@@ -0,0 +1,125 @@
+/*! \file font5x7.h \brief Graphic LCD Font (Ascii Characters). */
+//*****************************************************************************
+//
+// File Name    : 'font5x7.h'
+// Title        : Graphic LCD Font (Ascii Charaters)
+// Author       : Pascal Stang
+// Date         : 10/19/2001
+// Revised      : 10/19/2001
+// Version      : 0.1
+// Target MCU   : Atmel AVR
+// Editor Tabs  : 4
+//
+//*****************************************************************************
+// Modified for use with LPC1114 by Frank Duignan, 6 Sept 2016
+
+
+#ifndef FONT5X7_H
+#define FONT5X7_H
+#include <stdint.h>
+#define FONT_WIDTH 5
+#define FONT_HEIGHT 7
+// standard ascii 5x7 font
+// defines ascii characters 0x20-0x7F (32-127)
+const uint8_t Font5x7[] = {
+    0x00, 0x00, 0x00, 0x00, 0x00,// (space)
+    0x00, 0x00, 0x5F, 0x00, 0x00,// !
+    0x00, 0x07, 0x00, 0x07, 0x00,// "
+    0x14, 0x7F, 0x14, 0x7F, 0x14,// #
+    0x24, 0x2A, 0x7F, 0x2A, 0x12,// $
+    0x23, 0x13, 0x08, 0x64, 0x62,// %
+    0x36, 0x49, 0x55, 0x22, 0x50,// &
+    0x00, 0x05, 0x03, 0x00, 0x00,// '
+    0x00, 0x1C, 0x22, 0x41, 0x00,// (
+    0x00, 0x41, 0x22, 0x1C, 0x00,// )
+    0x08, 0x2A, 0x1C, 0x2A, 0x08,// *
+    0x08, 0x08, 0x3E, 0x08, 0x08,// +
+    0x00, 0x50, 0x30, 0x00, 0x00,// ,
+    0x08, 0x08, 0x08, 0x08, 0x08,// -
+    0x00, 0x60, 0x60, 0x00, 0x00,// .
+    0x20, 0x10, 0x08, 0x04, 0x02,// /
+    0x3E, 0x51, 0x49, 0x45, 0x3E,// 0
+    0x00, 0x42, 0x7F, 0x40, 0x00,// 1
+    0x42, 0x61, 0x51, 0x49, 0x46,// 2
+    0x21, 0x41, 0x45, 0x4B, 0x31,// 3
+    0x18, 0x14, 0x12, 0x7F, 0x10,// 4
+    0x27, 0x45, 0x45, 0x45, 0x39,// 5
+    0x3C, 0x4A, 0x49, 0x49, 0x30,// 6
+    0x01, 0x71, 0x09, 0x05, 0x03,// 7
+    0x36, 0x49, 0x49, 0x49, 0x36,// 8
+    0x06, 0x49, 0x49, 0x29, 0x1E,// 9
+    0x00, 0x36, 0x36, 0x00, 0x00,// :
+    0x00, 0x56, 0x36, 0x00, 0x00,// ;
+    0x00, 0x08, 0x14, 0x22, 0x41,// <
+    0x14, 0x14, 0x14, 0x14, 0x14,// =
+    0x41, 0x22, 0x14, 0x08, 0x00,// >
+    0x02, 0x01, 0x51, 0x09, 0x06,// ?
+    0x32, 0x49, 0x79, 0x41, 0x3E,// @
+    0x7E, 0x11, 0x11, 0x11, 0x7E,// A
+    0x7F, 0x49, 0x49, 0x49, 0x36,// B
+    0x3E, 0x41, 0x41, 0x41, 0x22,// C
+    0x7F, 0x41, 0x41, 0x22, 0x1C,// D
+    0x7F, 0x49, 0x49, 0x49, 0x41,// E
+    0x7F, 0x09, 0x09, 0x01, 0x01,// F
+    0x3E, 0x41, 0x41, 0x51, 0x32,// G
+    0x7F, 0x08, 0x08, 0x08, 0x7F,// H
+    0x00, 0x41, 0x7F, 0x41, 0x00,// I
+    0x20, 0x40, 0x41, 0x3F, 0x01,// J
+    0x7F, 0x08, 0x14, 0x22, 0x41,// K
+    0x7F, 0x40, 0x40, 0x40, 0x40,// L
+    0x7F, 0x02, 0x04, 0x02, 0x7F,// M
+    0x7F, 0x04, 0x08, 0x10, 0x7F,// N
+    0x3E, 0x41, 0x41, 0x41, 0x3E,// O
+    0x7F, 0x09, 0x09, 0x09, 0x06,// P
+    0x3E, 0x41, 0x51, 0x21, 0x5E,// Q
+    0x7F, 0x09, 0x19, 0x29, 0x46,// R
+    0x46, 0x49, 0x49, 0x49, 0x31,// S
+    0x01, 0x01, 0x7F, 0x01, 0x01,// T
+    0x3F, 0x40, 0x40, 0x40, 0x3F,// U
+    0x1F, 0x20, 0x40, 0x20, 0x1F,// V
+    0x7F, 0x20, 0x18, 0x20, 0x7F,// W
+    0x63, 0x14, 0x08, 0x14, 0x63,// X
+    0x03, 0x04, 0x78, 0x04, 0x03,// Y
+    0x61, 0x51, 0x49, 0x45, 0x43,// Z
+    0x00, 0x00, 0x7F, 0x41, 0x41,// [
+    0x02, 0x04, 0x08, 0x10, 0x20,// "\"
+    0x41, 0x41, 0x7F, 0x00, 0x00,// ]
+    0x04, 0x02, 0x01, 0x02, 0x04,// ^
+    0x40, 0x40, 0x40, 0x40, 0x40,// _
+    0x00, 0x01, 0x02, 0x04, 0x00,// `
+    0x20, 0x54, 0x54, 0x54, 0x78,// a
+    0x7F, 0x48, 0x44, 0x44, 0x38,// b
+    0x38, 0x44, 0x44, 0x44, 0x20,// c
+    0x38, 0x44, 0x44, 0x48, 0x7F,// d
+    0x38, 0x54, 0x54, 0x54, 0x18,// e
+    0x08, 0x7E, 0x09, 0x01, 0x02,// f
+    0x08, 0x14, 0x54, 0x54, 0x3C,// g
+    0x7F, 0x08, 0x04, 0x04, 0x78,// h
+    0x00, 0x44, 0x7D, 0x40, 0x00,// i
+    0x20, 0x40, 0x44, 0x3D, 0x00,// j
+    0x00, 0x7F, 0x10, 0x28, 0x44,// k
+    0x00, 0x41, 0x7F, 0x40, 0x00,// l
+    0x7C, 0x04, 0x18, 0x04, 0x78,// m
+    0x7C, 0x08, 0x04, 0x04, 0x78,// n
+    0x38, 0x44, 0x44, 0x44, 0x38,// o
+    0x7C, 0x14, 0x14, 0x14, 0x08,// p
+    0x08, 0x14, 0x14, 0x18, 0x7C,// q
+    0x7C, 0x08, 0x04, 0x04, 0x08,// r
+    0x48, 0x54, 0x54, 0x54, 0x20,// s
+    0x04, 0x3F, 0x44, 0x40, 0x20,// t
+    0x3C, 0x40, 0x40, 0x20, 0x7C,// u
+    0x1C, 0x20, 0x40, 0x20, 0x1C,// v
+    0x3C, 0x40, 0x30, 0x40, 0x3C,// w
+    0x44, 0x28, 0x10, 0x28, 0x44,// x
+    0x0C, 0x50, 0x50, 0x50, 0x3C,// y
+    0x44, 0x64, 0x54, 0x4C, 0x44,// z
+    0x00, 0x08, 0x36, 0x41, 0x00,// {
+    0x00, 0x00, 0x7F, 0x00, 0x00,// |
+    0x00, 0x41, 0x36, 0x08, 0x00,// }
+    0x08, 0x08, 0x2A, 0x1C, 0x08,// ->
+    0x08, 0x1C, 0x2A, 0x08, 0x08 // <-
+};
+
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lis3dh.h	Wed Jun 24 11:37:11 2020 +0000
@@ -0,0 +1,108 @@
+#include <mbed.h>
+SPI spi(P0_6,P0_4,P0_7); // P0_4 = MISO, P0_6 = MOSI, P0_7 = SCK
+DigitalOut LIS3D_CS(P0_3); // Chip select for the LIS3DH : When low SPI mode is enabled
+DigitalIn int1(P0_1);
+class lis3dh
+{
+public:
+    lis3dh() {};    
+    void begin()
+    {
+        LIS3D_CS = 1; // disable SPI mode for a moment
+        spi.format(8,3);
+        spi.frequency(400000);                        
+        
+        LIS3D_CS = 0; // 
+        spi.write(0x1e); // Turn off internal pull-ups as we are using SPI to save power
+        spi.write(0x90); 
+        LIS3D_CS = 1; // 
+        
+        LIS3D_CS = 0; 
+        spi.write(0x1f); // enable the temperature sensor and the ADC
+        spi.write(0xc0);
+        LIS3D_CS = 1; 
+        
+        LIS3D_CS = 0; 
+        spi.write(0x20); // configure chip for 100Hz, high resolution, normal mode, all axes
+        spi.write(0b01110111);
+        LIS3D_CS = 1; 
+        
+        
+        LIS3D_CS = 0; 
+        spi.write(0x23); // Turn on HR mode
+        spi.write(0x88);
+        LIS3D_CS = 1;
+        
+        
+        LIS3D_CS = 0; 
+        spi.write(0x22); // Enable data ready output on INT1 (P0_1)
+        spi.write(0x10);
+        LIS3D_CS = 1; 
+        
+        
+
+        
+    }
+    
+    int who_am_i()
+    {
+        LIS3D_CS = 0; 
+        // Send 0x8f, the command to read the WHOAMI register
+        spi.write(0x8f);    
+        // Send a dummy byte to receive the contents of the WHOAMI register
+        int whoami = spi.write(0x00);
+        LIS3D_CS = 1; 
+        return whoami; // Should return 55 decimal or 33 Hex
+    }
+    
+    int dataReady()
+    {
+        LIS3D_CS = 0; 
+        // Send 0xa7, the command to read the status register (0x27)
+        spi.write(0xa7);    
+        // Send a dummy byte to receive the contents of the register
+        int status = spi.write(0x00);
+        LIS3D_CS = 1; // 
+        /*if (status & 0x08)
+            status = 1;
+        else
+            status = 0;
+        */
+        return int1; // return 1 if data ready
+    }
+    int read(int &X, int &Y, int &Z)
+    {
+        int16_t L,H;
+        int16_t result;
+        LIS3D_CS = 0; 
+        // Send 0x8f, the command to read the WHOAMI register
+        spi.write(0xe8);    
+        // Send a dummy byte to receive the contents of the register
+        L = spi.write(0x00);        
+        // Send a dummy byte to receive the contents of the register
+        H = spi.write(0x00);
+        result = (H << 8) + L;
+        X = result;
+        
+        // Send a dummy byte to receive the contents of the register
+        L = spi.write(0x00);        
+        // Send a dummy byte to receive the contents of the register
+        H = spi.write(0x00);
+        result = (H << 8) + L;
+        Y = result;
+        
+        // Send a dummy byte to receive the contents of the register
+        L = spi.write(0x00);        
+        // Send a dummy byte to receive the contents of the register
+        H = spi.write(0x00);
+        result = (H << 8) + L;
+        Z = result;
+        
+        LIS3D_CS = 1; 
+        
+        return 0;
+    }     
+    
+private:
+
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Wed Jun 24 11:37:11 2020 +0000
@@ -0,0 +1,135 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mbed.h"
+#include "ble/BLE.h"
+#include "LEDService.h"
+#include "accelService.h"
+#include "oled.h"
+#define enable_interrupts() asm(" cpsie i ")
+#define disable_interrupts() asm(" cpsid i ")
+
+
+DigitalOut myled(P0_29);
+
+const static char     DEVICE_NAME[] = "CJMCU-8223";
+static const uint16_t uuid16_list[] = {LEDService::LED_SERVICE_UUID,accelService::ACCEL_SERVICE_UUID};
+accelService *AccelServicePtr;
+LEDService *ledServicePtr;
+
+void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
+{
+    BLE::Instance().gap().startAdvertising();
+}
+
+/**
+ * This callback allows the LEDService to receive updates to the ledState Characteristic.
+ *
+ * @param[in] params
+ *     Information about the characterisitc being updated.
+ */
+void onDataWrittenCallback(const GattWriteCallbackParams *params) {
+    if ((params->handle == ledServicePtr->getValueHandle()) && (params->len == 1)) {
+        myled = *(params->data);
+    }
+}
+void onDataReadCallback(const GattReadCallbackParams *params) {
+    
+}
+/**
+ * This function is called when the ble initialization process has failed
+ */
+void onBleInitError(BLE &ble, ble_error_t error)
+{
+    /* Initialization error handling should go here */
+}
+
+/**
+ * Callback triggered when the ble initialization process has finished
+ */
+void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
+{
+    BLE&        ble   = params->ble;
+    ble_error_t error = params->error;
+
+    if (error != BLE_ERROR_NONE) {
+        /* In case of error, forward the error handling to onBleInitError */
+        onBleInitError(ble, error);
+        return;
+    }
+
+    /* Ensure that it is the default instance of BLE */
+    if(ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
+        return;
+    }
+ 
+    ble.gap().onDisconnection(disconnectionCallback);
+    ble.gattServer().onDataWritten(onDataWrittenCallback);
+    ble.gattServer().onDataRead(onDataReadCallback);
+    bool initialValueForLEDCharacteristic = false;
+    ledServicePtr = new LEDService(ble, initialValueForLEDCharacteristic);
+    int16_t initialValue = 0;
+    AccelServicePtr = new accelService(ble,initialValue);
+
+    /* setup advertising */
+    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
+    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
+    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
+    ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
+    ble.gap().setAdvertisingInterval(100); /* 100ms. */
+    ble.gap().startAdvertising();
+}
+oled Oled;
+int main(void)
+{
+ 
+    int Count=0;
+    Oled.begin();
+    Lis3dh.begin();
+    Oled.print(0,0  ,"Hello");
+    
+
+    BLE &ble = BLE::Instance();
+    ble.init(bleInitComplete);
+    
+    while (ble.hasInitialized()  == false) { 
+        Oled.print(0,0,"BLE init fail");
+        myled = 1;
+        wait(0.2);
+        myled = 0;
+        wait(0.1);
+    
+    /* spin loop */ }
+    Oled.print(0,0,"BLE init done");
+    while (true) {
+        // update the values for the BLE interface
+        AccelServicePtr->poll();
+        int x,y,z;
+        x = 1;
+        y = 2;
+        z = 3;        
+        // show the values on the display
+        if (Lis3dh.dataReady())        
+        {
+            Lis3dh.read(x,y,z);
+            Oled.print(0,0,x/16);
+            Oled.print(0,1,y/16);
+            Oled.print(0,2,z/16);
+        }
+        ble.waitForEvent();
+        
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Wed Jun 24 11:37:11 2020 +0000
@@ -0,0 +1,1 @@
+https://os.mbed.com/users/mbed_official/code/mbed/builds/65be27845400
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nRF51822.lib	Wed Jun 24 11:37:11 2020 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/teams/Nordic-Semiconductor/code/nRF51822/#c90ae1400bf2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/oled.h	Wed Jun 24 11:37:11 2020 +0000
@@ -0,0 +1,179 @@
+// oled.h
+// This class is for the SSD1306 OLED
+// 
+#include <mbed.h>
+#include "font5x7.h"
+I2C i2c(P0_30, P0_0); // SDA is on P0_30, SCL is on P0_0
+class oled 
+{
+
+public: 
+    oled() {};
+    void clear()
+    {
+        for (int i = 0; i < 8; i++)
+        {
+            clearOLEDLine(i);
+        }
+    }
+    void begin()
+    {
+        resetOLED();
+        clear();
+    }
+    void print(int Col, int Row, const char *Text)
+    {
+        // write the supplied text (up to 25 bytes) to the given display line
+        int i;
+        uint8_t RowData[128];
+        for (i = 0; i < 128; i++)
+            RowData[i] = 0;
+        while (*Text) {
+            for (i = 0; i < FONT_WIDTH; i++)
+            {
+                RowData[Col * FONT_WIDTH + i] = Font5x7[FONT_WIDTH * ((*Text) - 32) + i];
+            }
+            Col++;
+            Text++;
+            if (Col > 24)
+                break; // Can't print past end of the screen
+        }
+        writeOLEDLine(Row, RowData);
+    }
+    void print(int Col, int Row, int32_t Value)
+    {
+        char Text[20];
+        int2Text(Text,Value);
+        print(Col,Row,Text);
+    }
+   
+private:
+    void writeOLEDLine(int LineNumber, uint8_t *Values)
+    {
+        // Writes the set of values to the given line number
+        writeOLEDRegister(0x00, 0x21);
+        writeOLEDRegister(0x00, 0);
+        writeOLEDRegister(0x00, 127);
+        writeOLEDRegister(0x00, 0x22);
+        writeOLEDRegister(0x00, LineNumber); // Page address
+        writeOLEDRegister(0x00, 7);
+        writeOLEDBytes(0x40, 128, Values);
+    }
+    uint8_t writeOLEDRegister(uint8_t RegNum, uint8_t Value)
+    {
+        char TXData[2];
+        TXData[0] = RegNum;
+        TXData[1] = Value;
+        return i2c.write(0x3c << 1,(const char *)TXData,2);    
+    }
+    void resetOLED()
+    {
+        // Reset sequence got from https://github.com/adafruit/Adafruit_SSD1306/blob/master/Adafruit_SSD1306.cpp
+        writeOLEDRegister(0x00, 0xae);
+        writeOLEDRegister(0x00, 0xd5);
+        writeOLEDRegister(0x00, 0x80);
+        writeOLEDRegister(0x00, 0xa8);
+        writeOLEDRegister(0x00, 63);
+        writeOLEDRegister(0x00, 0xd3);
+        writeOLEDRegister(0x00, 0);
+        writeOLEDRegister(0x00, 0x40);
+        writeOLEDRegister(0x00, 0x8d);
+        writeOLEDRegister(0x00, 0x14);
+        writeOLEDRegister(0x00, 0x20);
+        writeOLEDRegister(0x00, 0x00);
+        writeOLEDRegister(0x00, 0xa1);
+        writeOLEDRegister(0x00, 0xc8);
+        
+        writeOLEDRegister(0x00, 0xda);
+        writeOLEDRegister(0x00, 0x12);
+        writeOLEDRegister(0x00, 0x81);
+        writeOLEDRegister(0x00, 0xcf);
+        
+        writeOLEDRegister(0x00, 0xd9);
+        writeOLEDRegister(0x00, 0xf1);
+        writeOLEDRegister(0x00, 0xdb);
+        writeOLEDRegister(0x00, 0x40);
+        writeOLEDRegister(0x00, 0xa4);
+        writeOLEDRegister(0x00, 0xa6);
+        writeOLEDRegister(0x00, 0x2e);
+        writeOLEDRegister(0x00, 0xaf);
+    }
+    void clearOLEDLine(int LineNumber)
+    {
+        // Clears the given line (range 0 to 7) on the display
+        // A line is 8 pixels high
+        writeOLEDRegister(0x00, 0x21);
+        writeOLEDRegister(0x00, 0);
+        writeOLEDRegister(0x00, 127);
+        writeOLEDRegister(0x00, 0x22);
+        writeOLEDRegister(0x00, LineNumber); // Page address
+        writeOLEDRegister(0x00, 7);
+        fillOLEDBytes(0x40, 128, 0x00);
+    }
+    
+    
+    uint8_t fillOLEDBytes(uint8_t RegNum, uint8_t Count, uint8_t Value)
+    {
+        // Repeatedly writes the given Value to the OLED memory - useful
+        // for clearing the display
+        uint8_t TXData[Count+1];    
+        int i;
+        TXData[0] = RegNum;
+        for (i = 0; i < Count; i++)
+        {
+            TXData[i + 1] = Value;
+        }
+        return i2c.write(0x3c << 1,(const char *)TXData,Count+1);    
+    }
+    uint8_t writeOLEDBytes(uint8_t RegNum, uint8_t Count, uint8_t *Values)
+    {
+        // Writes the array of up to 128 bytes to the OLED display
+        if (Count > 128)
+            return -1;
+        uint8_t TXData[Count+1];        
+        int i;
+        TXData[0] = RegNum;
+        for (i = 0; i < Count; i++)
+        {
+            TXData[i + 1] = Values[i];
+        }
+        return i2c.write(0x3c << 1,(const char *)TXData,Count+1);    
+    }
+
+    
+    void int2Text(char *Text, int32_t Value)
+    {
+        int index;
+        Text[11]=0;
+        if (Value < 0)
+        {
+            Text[0]='-';
+            Value = -Value;
+        }
+        else
+        {
+            Text[0] = '+';
+        }
+        for (index = 0; index < 10;index++)
+        {
+            Text[10-index]=(Value % 10) + '0';
+            Value = Value / 10;
+        }   
+    }
+    void int2Hex(char *Hex, uint32_t Value)
+    {
+        int temp;
+        int index;
+        Hex[8]=0;
+        for (index = 0; index < 8;index++)
+        {
+            temp = Value % 16;
+            if (temp < 10)
+                temp = temp + '0';
+            else
+                temp = temp + 'A' - 10;
+            Hex[7-index]=temp;
+            Value = Value / 16;
+        }
+    }
+};