加速度计显示
上一篇我们运用了开发板的几个服务和特性来显示了板子的名称这次我们将使用加速度器来显示板子的X、Y、Z轴二栋坐标。
代码展示
 var selected_device;
 var connected_server;
 var connected = false;
 var services_discovered = false; //在第5课上添加
 var notifications_enabled = false;
 //在第5课上添加以下内容
 var has_accelerometer_service = false;
 var has_accelerometer_data = false;
 var has_led_service = false;
 var has_led_matrix_state = false;
 var has_device_information_service = false;
 var has_model_name_string = false;
 // service UUIDs
 ACCELEROMETER_SERVICE = ‘e95d0753-251d-470a-a062-fa1922dfa9a8’;
 LED_SERVICE = ‘e95dd91d-251d-470a-a062-fa1922dfa9a8’;
 DEVICE_INFORMATION_SERVICE = ‘0000180a-0000-1000-8000-00805f9b34fb’;
 // characteristic UUIDs
 ACCELEROMETER_DATA = ‘e95dca4b-251d-470a-a062-fa1922dfa9a8’;
 LED_MATRIX_STATE = ‘e95d7b77-251d-470a-a062-fa1922dfa9a8’;
 MODEL_NUMBER_STRING = ‘00002a24-0000-1000-8000-00805f9b34fb’;
 // cached characteristics
 var led_matrix_state;
 var model_number_string;
 var accelerometer_data;
//
 var service_count;
 var services_discovered;
 var characteristics_discovered;
 var characteristic_count ;
 function discoverOrdisconnectDevices()
 {
 console.log(“discoverDevicesOrDisconnect”);
 if (!connected)
 discoverDevices();
 else
 {
 selected_device.gatt.disconnect();
 }
 }
 function setNotificationsStatus(status) {
 notifications_enabled = status;
 document.getElementById(‘status_notifications’).innerHTML = status;
 }
 function onDisconnected()
 {
 console.log(“onDisconnected”);
 resetUI();
 }
 function discoverDevices()
 {
 console.log(“discoverDevices”);
 var options = {acceptAllDevices:true,
 optionalServices: [DEVICE_INFORMATION_SERVICE, ACCELEROMETER_SERVICE, LED_SERVICE] //在第5节课上添加
 }
 navigator.bluetooth.requestDevice(options)
 .then(device => {
 console.log(‘> Name:’ + device.name);
 console.log(‘> Id:’ + device.id);
 console.log(‘> Connected:’ + device.gatt.connected);
 selected_device = device;
 console.log(selected_device);
 connect();
 })
 .catch(error => {
 alert(‘ERROR:’ +error);
 console.log(‘ERROR:’ + error);
 });
 }
 function connect()
 {
 console.log(“connecting”);
 selected_device.gatt.connect()
 .then(
 function (server) //表示连接成功
 {
 console.log(“Connected to” + server.device.id);
 console.log(“Connected=” + server.connected);
 selected_device.addEventListener( ‘gattserverdisconnected’,onDisconnected); // 在第4课基础上添加的函数
 connected_server = server;
 discoverSvcsAndChars(); ////在第5课基础上添加的函数
 setConnectedStatus(true); // 在第3课基础上添加的函数,设置电脑蓝牙的当前连接状态
 },
 function (error) //表示连接失败
 {
 console.log(“ERROR:could not connct-“ + error);
 alert(“ERROR:could not connct-“ + error);
 setConnectedStatus(false); // 在第3课基础上添加的函数,设置电脑蓝牙的当前连接状态
 }
 );
 }
 function setConnectedStatus(status) // 在第3课基础上添加的函数,设置电脑蓝牙的当前连接状态
 {
 connected = status;
 document.getElementById(‘status_connected’).innerHTML = status;
 if (status == true)
 {
 document.getElementById(‘btn_scan’).innerHTML = “Disconnect”;
 }
 else
 {
 document.getElementById(‘btn_scan’).innerHTML = “Discover Devices”;
 }
 }
 function setDiscoveryStatus(status)
 {
 services_discovered = status;
 document.getElementById(‘status_discovered’).innerHTML = status;
 }
 function resetUI() // 在第4课基础上添加的函数
 {
 setConnectedStatus(false);
 setDiscoveryStatus(false); // 在第5课基础上添加的函数
 setNotificationsStatus(false);
 }
 function discoverSvcsAndChars() //在第5课基础上添加的函数
 {
 console.log(“discoverSvcsAndChars server=” + connected_server);
 connected_server.getPrimaryServices()//调用函数去获取BBC上的相应的服务
 .then(services => //对服务进行判断
 {
 has_accelerometer_service = false;
 has_led_service = false;
 has_device_information_service = false;
 services_discovered = 0;
 service_count = services.length; //发现BBC板服务的个数
 console.log(“Got “ + service_count + “ services”);
 services.forEach(service => //对已发现的所有服务进行判断
 {
 if (service.uuid == ACCELEROMETER_SERVICE)
 {
 has_accelerometer_service = true;
 }
 if (service.uuid == LED_SERVICE)
 {
 has_led_service = true;
 }
 if (service.uuid == DEVICE_INFORMATION_SERVICE)
 {
 has_device_information_service = true;
 }
 console.log(‘Getting Characteristics for service ‘ + service.uuid);
 service.getCharacteristics() //获取相应服务的所有特性
 .then(characteristics =>
 {
 console.log(‘> Service: ‘ + service.uuid);
 services_discovered++; //发现一个就加一
 characteristics_discovered = 0;
 characteristic_count = characteristics.length; //特性的个数
 characteristics.forEach(characteristic => //对已发现的特性进行判断
 {
 characteristics_discovered++;
 console.log(‘>> Characteristic: ‘ + characteristic.uuid);
 if (characteristic.uuid == ACCELEROMETER_DATA)
 {
 accelerometer_data = characteristic; //把发现的相应特性保存到相应变量中
 has_accelerometer_data = true;
 }
 if (characteristic.uuid == LED_MATRIX_STATE)
 {
 led_matrix_state = characteristic;
 has_led_matrix_state = true;
 }
 if (characteristic.uuid == MODEL_NUMBER_STRING)
 {
 model_number_string = characteristic;
 has_model_name_string = true;
 }
 if (services_discovered == service_count && characteristics_discovered == characteristic_count)
 {
 console.log(“FINISHED DISCOVERY”);
 setDiscoveryStatus(true);
 //setDiscoveryStatus(true);
 }
 });
 });
 });
 });
 }
 function randomLEDs()//第六节课添加
 {
 console.log(“randomLEDs”);
 //state validation
 if (!connected)
 {
 alert(“Error: Discover and connect to a device before using this function”);
 return
 }
 if (!services_discovered)//有没有发现所有服务
 {
 alert(“Error: Service discovery has not yet completed”);
 return
 }
 if (!has_led_service)
 {
 alert(“Error: The connected device does not contain the LED service”);
 return
 }
 if (!has_led_matrix_state)//led灯的特性有没有被发现的一个标记变量
 {
 alert(“Error: The connected device does not contain the LED matrix state characteristic”);
 return;
 }
 var led_array = [0, 0, 0, 0, 0];
 //math.random():0~1 math.floor(x):返回小于等于x的最大整数
 led_array[0] = Math.floor(Math.random() * 32);
 led_array[1] = 1;
 led_array[2] = 2;
 led_array[3] = 3;
 led_array[4] = 4;
 var led_matrix_data = new Uint8Array(led_array);
 led_matrix_state.writeValue(led_matrix_data.buffer)//控制板子上灯亮灭
 .then(_ => {
 console.log(‘LED matrix state changed’);
 })
 .catch(error => {
 console.log(‘Error: ‘ + error);
 alert(‘Error: ‘ +error); return;
 });
 }
function readModelNumber() {
console.log(“readModelNumber”);
// state validation
if (!connected) {
 alert(“Error: Discover and connect to a device before using this function”);
 return;
}
if (!services_discovered) {
 alert(“Error: Service discovery has not yet completed”);
 return;
}
if (!has_device_information_service) {
 alert(“Error: The connected device does not contain the device information service”);
 return;
}
if (!has_model_name_string) {
 alert(“Error: The connected device does not contain the model name string characteristic”);
 return;
}
model_number_string.readValue()
 .then(value => {
 data = new Uint8Array(value.buffer);
 model_number_string = new TextDecoder(“utf8”).decode(data);
 console.log(model_number_string);
 document.getElementById(“model_number”).innerHTML = model_number_string;
})
 .catch(error => {
 console.log(‘Error: ‘ + error);
 alert(‘Error: ‘ + error);
 return;
});
}
function toggleAccelerometerNotifications() {
console.log(“toggleAccelerometerNotifications”);
if (!connected) {
 alert(“Error: Discover and connect to a device before using this function”);
 return;
}
if (!services_discovered) {
 alert(“Error: Service discovery has not yet completed”);
 return;
}
if (!has_accelerometer_service) {
 alert(“Error: The connected device does not contain the accelerometer service”);
 return;
}
if (!has_accelerometer_data) {
 alert(“Error: The connected device does not contain the accelerometer data characteristic”); return;
}
if (!notifications_enabled) {
accelerometer_data.startNotifications()
 .then(_ => {
 console.log(‘accelerometer notifications started’);
 setNotificationsStatus(true);
 accelerometer_data.addEventListener(‘characteristicvaluechanged’, onAccelerometerData);
})
 .catch(error => {
 console.log(‘Error: ‘ + error);
 alert(‘Error: ‘ + error);
 return;
});
}
else
{
 accelerometer_data.stopNotifications()
 .then(_ => {
 console.log(‘accelerometer notificaions stopped’);
 setNotificationsStatus(false);
 accelerometer_data.removeEventListener(‘characteristicvaluechanged’, onAccelerometerData);
 })
 .catch(error => {
 console.log(‘Could not stop accelerometer_data notifications: ‘ + error);
 });
}
}
function onAccelerometerData(event)
{
 console.log(“onAccelerometerData”);
 buffer = event.target.value.buffer;
 dataview = new DataView(buffer);
 X = dataview.getUint16(0, true);
 Y = dataview.getUint16(2, true);
 Z = dataview.getUint16(4, true);
 console.log(“X=” + X + “, Y=” + Y + “, Z+” + Z); document.getElementById(“accelerometer_data”).innerHTML = “X=” + X + “, Y=” + Y + “, Z=” + Z;
}
效果如下图:

代码精炼
首先 添加变量(用来跟踪通知订阅的状态)
var notifications_enabled = false;
二 添加函数
function setNotificationsStatus(status) { notifications_enabled = status; document.getElementById(‘status_notifications’).innerHTML = status; }
三 订阅和接收通知只能在我们与设备连接时执行。我们还需要检查连接的设备是否包含所要求的相关的服务和特征,然后我们才试图启用有关该特征的通知。按钮调用toggleAccelerometerNotifications()函数,函数如下:
function toggleAccelerometerNotifications() {
console.log(“toggleAccelerometerNotifications”);
if (!connected) {
 alert(“Error: Discover and connect to a device before using this function”);
 return;
}
if (!services_discovered) {
 alert(“Error: Service discovery has not yet completed”);
 return;
}
if (!has_accelerometer_service) {
 alert(“Error: The connected device does not contain the accelerometer service”);
 return;
}
if (!has_accelerometer_data) {
 alert(“Error: The connected device does not contain the accelerometer data characteristic”); return;
}
if (!notifications_enabled) {
accelerometer_data.startNotifications()
 .then(_ => {
 console.log(‘accelerometer notifications started’);
 setNotificationsStatus(true);
 accelerometer_data.addEventListener(‘characteristicvaluechanged’, onAccelerometerData);
})
 .catch(error => {
 console.log(‘Error: ‘ + error);
 alert(‘Error: ‘ + error);
 return;
});
}
else
{
 accelerometer_data.stopNotifications()
 .then(_ => {
 console.log(‘accelerometer notificaions stopped’);
 setNotificationsStatus(false);
 accelerometer_data.removeEventListener(‘characteristicvaluechanged’, onAccelerometerData);
 })
 .catch(error => {
 console.log(‘Could not stop accelerometer_data notifications: ‘ + error);
 });
}
}
当然,通知也有启用和禁用,这取决于当前的订阅状态,代码也在上面其中。其中accelerometer_data.addEventListener(‘characteristicvaluechanged’,onAccelerometerData);这两句在这个函数启到一个监听的作用,一旦状态发生变化就会调用onAccelerometerData这个函数,该函数是用来显示X、Y、Z这三个轴的值添加onAccelerometerData函数,它将在每次收到通知时被调用。事件处理程序接收一个事件对象,将附加到事件对象目标值的ArrayBuffer中
function onAccelerometerData(event)
{
 console.log(“onAccelerometerData”);
 buffer = event.target.value.buffer;
 dataview = new DataView(buffer);
 X = dataview.getUint16(0, true);
 Y = dataview.getUint16(2, true);
 Z = dataview.getUint16(4, true);
 console.log(“X=” + X + “, Y=” + Y + “, Z+” + Z); document.getElementById(“accelerometer_data”).innerHTML = “X=” + X + “, Y=” + Y + “, Z=” + Z;
}