Académique Documents
Professionnel Documents
Culture Documents
Temperature Monitor
FINAL REPORT
APRIL 21,2017
V. Conclusions..8
VI. References.11
1
I. Design Specification
Feature Specification
Accuracy 0.2
Range 0~40
All design specifications were met except for the wireless transmission distance. The
bluetooth connection is stable up until 8 meters. However, as the distance goes farther, the
signal becomes oscillating and is not reliable enough to provide accurate myocardial
temperature readings. This is due mainly to the limitation of bluetooth module. A longer
transmission distance can be acquired with a more robust bluetooth emitting device.
This board was borrowed from the Physiology Lab by courtesy of Professor Widder.
2
2. Analog Technology ATH10KR8BT65 Thermistor
3
5. Miscellaneous Resistors
6. Piezo Speaker
4
Part Name Part Number Price Source Lead Time
Table 2. Part list, part number, price, source, and lead time
1. Circuit Drawing
5
2. Wiring Diagram
3. Mechanical Drawing
Figure 9. Mechanical drawing generated with Autocad. Units are in milimeter (mm).
6
IV. Design Safe & Webpage
Webpage: http://myocardial-temperature-monitor.weebly.com/
V. Conclusion
Problem Solved?
After seven months of hard work, our project finally comes into full shape. According
to validation results, the wireless needle was able to stand on its own even with moderate
maneuvers in the heart. The data is transmitted wirelessly to a computer and displayed
accurately on a computer screen. The alarm goes off when the temperature goes out of the
safe range and stops once it comes back. Therefore, we have completed all the three
features that we promised. To further improve our product, a microcontroller board could
help reduce the size of the current product employed on Arduino board. This product can be
employed in real open-heart surgeries and offer greater flexibility and stability, which is
7
Design Specification Met?
We have met the majority of the design specifications. The only shortcoming is that
our reliable transmission range did not go all the way up to 10 meters. The bluetooth
connection drops off at around 8 meters. That being said, a range of 8 meters shall probably
suffice for most of the operation rooms. We proposed 10 meters out of a bold intention of
covering beyond what is actually needed. Moreover, according to our clients input, a
In hindsight, there are several issues that we could have better dealt with. First, we
did not look as carefully as we should into the differences between various bluetooth
modules. Not until halfway into our programming did we realize nrf8001 may not be the best
fit for our purposes. There are better options such as the Feather product line which would
have enabled more robust wireless connection and more useful libraries. We were blinded
by the price at first and ended up simply purchasing the cheapest. We should have
compared the datasheet and available libraries across different product lines before coming
to a decision.
Second, our choice of the bluetooth receiving program is debatable. For novices to
OSX programming like we were when we started off, a ready-to-use app by courtesy of the
vendor seems definitely a first-choice. But after we have spent days and nights trying to
understand the source code without sufficient comments and figure out which lines to
modify, we realized a tradeoff between an easy start and a hard progress. We could have
paced ourselves and tried to learn some basics of the SWIFT language to begin with. Since
we were only reaching for 2 or 3 simple functions, building an app of our own should not be
too complex. More importantly, we would have been alleviated of the drudgery of having to
Third, one team member later learned from an elective course that designing a
microcontroller board and soldering other electronic would be a viable method. We used to
8
think it was impossible to downsize the microcontroller board with our current knowledge.
Though we are most likely to have a hard time making it work, we might be able to deliver a
Future Directions
Both the hardware and the software have space for improvement. As mentioned
above, the microcontroller board needs to be further downsized. 3D-printing alone might not
be able to make it small enough. We need to look for electronics manufacturer and get quote
for integration services. Ideally, all parts should fit into the needle tube in a fashion that
keeps the centroid close to the penetrating end. Otherwise, the needle would easily fall off.
Our software did work, but the user-interface is still in its crudest form. By far, we have not
put any efforts in designing the UI. In the future, we will make it more visually pleasant as
We honed our programming skills in two common languages, both Arduino and
SWIFT, such as the ability to grasp the data structure of a given program and quickly locate
target functions among hundreds of lines. This skill is especially useful when we start off
from a pre-built program and want to make modifications according to our own needs.
We also apply the knowledge that we have learned in ESE 444 Sensors and actuators,
including Steinhart-Hart equation. We gained some important soft skills, too. We became
familiarized with project management. We learned how to plan ahead and make adjustments
down the way. This precious experience prepared us in advance for industry product
9
Ethical Consideration
Our product is mostly free of ethical concerns since we did not involve any living
tissues throughout the process except the final validation phase. To test performance on
myocardium, we bought a pig heart tissue from a supermarket. Since the butchery is
licensed and the experiment did not produce anything harmful, we are confident that our
procedure is ethical.
Intellectual Property
Intellectual property refers to creations of the mind: inventions; literary and artistic
works; and symbols, names and images used in commerce. There are two categories:
industrial property and copyright.1 Our product belongs to industrial property. According to
invention a product or process that provides a new way of doing something, or that offers a
new technical solution to a problem. Our design of the wireless temperature probe is indeed
myocardial temperature monitor ever existed to date. In terms of definitions, our product is
the first one of its kind and we are supposed to apply for patent. However, unless we
succeed in integrating the Bluetooth module with the surgical needle so that it looks much
less grumpy, our product would not be of real value to surgeons. In a word, though we came
up with the first ever wireless myocardium temperature monitoring, we are not confident
enough of the feasibility and utility of our product. Instead of applying for patent, we prefer to
keep it open sourced so that anyone else interested can contribute to its improvement.
10
V. References
1. http://www.wipo.int/edocs/pubdocs/en/intproperty/450/wipo_pub_450.pdf
2. https://learn.adafruit.com/getting-started-with-the-nrf8001-bluefruit-le-breakout/pinout
3. https://learn.adafruit.com/getting-started-with-the-nrf8001-bluefruit-le-
breakout/hooking-everything-up
4. https://www.uspto.gov/web/offices/com/iip/pdf/brochure_05.pdf
5. https://github.com/adafruit/Adafruit_nRF8001
11
Appendix A. Arduino Firmata Protocol
#include <Servo.h>
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_BLE_Firmata.h>
#include "Adafruit_BLE_UART.h"
// Change this to whatever is the Serial console you want, either Serial or SerialUSB
#define FIRMATADEBUG Serial
// Pause for Serial console before beginning?
#define WAITFORSERIAL true
// Print all BLE interactions?
#define VERBOSE_MODE false
// Pullups on all input pins?
#define AUTO_INPUT_PULLUPS true
Then below, you can edit the list of pins that are available. Remove any pins
that are used for accessories or for talking to the BLE module!
*/
#if defined(__AVR_ATmega328P__)
// Standard setup for UNO, no need to tweak
uint8_t boards_analogiopins[] = {A0, A1, A2, A3, A4, A5}; // A0 == digital 14, etc
uint8_t boards_pwmpins[] = {3, 5, 6, 9, 10, 11};
uint8_t boards_servopins[] = {9, 10};
uint8_t boards_i2cpins[] = {SDA, SCL};
#elif defined(__AVR_ATmega32U4__)
uint8_t boards_analogiopins[] = {A0, A1, A2, A3, A4, A5}; // A0 == digital 14, etc
uint8_t boards_pwmpins[] = {3, 5, 6, 9, 10, 11, 13};
uint8_t boards_servopins[] = {9, 10};
uint8_t boards_i2cpins[] = {SDA, SCL};
#elif defined(__SAMD21G18A__)
#define SDA PIN_WIRE_SDA
#define SCL PIN_WIRE_SCL
uint8_t boards_analogiopins[] = {PIN_A0, PIN_A1, PIN_A2, PIN_A3, PIN_A4, PIN_A5, PIN_A6, PIN_A7}; // A0 == digital 14,
etc
uint8_t boards_pwmpins[] = {3, 4, 5, 6, 8, 10, 11, 12, A0, A1, A2, A3, A4, A5};
uint8_t boards_servopins[] = {9, 10};
uint8_t boards_i2cpins[] = {SDA, SCL};
#define NUM_DIGITAL_PINS 26
#endif
/***********************************************************/
#include "Adafruit_BLE_Firmata_Boards.h"
#include "BluefruitConfig.h"
// Create the bluetooth breakout instance, set the pins in the BluefruitConfig.h file!
Adafruit_BLE_UART bluefruit = Adafruit_BLE_UART(ADAFRUITBLE_REQ, ADAFRUITBLE_RDY, ADAFRUITBLE_RST);
// A small helper
void error(const __FlashStringHelper*err) {
12
FIRMATADEBUG.println(err);
while (1);
}
/*==============================================================================
GLOBAL VARIABLES
============================================================================*/
/* analog inputs */
int analogInputsToReport = 0; // bitwise array to store pin reporting
int lastAnalogReads[NUM_ANALOG_INPUTS];
/* pins configuration */
byte pinConfig[TOTAL_PINS]; // configuration of every pin
byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else
int pinState[TOTAL_PINS]; // any value that has been written
/* timer variables */
unsigned long currentMillis; // store the current value from millis()
unsigned long previousMillis; // for comparison with currentMillis
int samplingInterval = 200; // how often to run the main loop (in ms)
#define MINIMUM_SAMPLE_DELAY 150
#define ANALOG_SAMPLE_DELAY 50
/* i2c data */
struct i2c_device_info {
byte addr;
byte reg;
byte bytes;
};
byte i2cRxData[32];
boolean isI2CEnabled = false;
signed char queryIndex = -1;
unsigned int i2cReadDelayTime = 0; // default delay time between i2c read request and Wire.requestFrom()
Servo servos[MAX_SERVOS];
/*==============================================================================
FUNCTIONS
============================================================================*/
if (theRegister != REGISTER_NOT_SPECIFIED) {
Wire.beginTransmission(address);
#if ARDUINO >= 100
Wire.write((byte)theRegister);
#else
Wire.send((byte)theRegister);
#endif
Wire.endTransmission();
delayMicroseconds(i2cReadDelayTime); // delay is necessary for some devices such as WiiNunchuck
} else {
theRegister = 0; // fill the register with a dummy value
}
13
for (int i = 0; i < numBytes; i++) {
#if ARDUINO >= 100
i2cRxData[2 + i] = Wire.read();
#else
i2cRxData[2 + i] = Wire.receive();
#endif
}
}
else {
if (numBytes > Wire.available()) {
BLE_Firmata.sendString("I2C Read Error: Too many bytes received");
} else {
BLE_Firmata.sendString("I2C Read Error: Too few bytes received");
}
}
/* -----------------------------------------------------------------------------
check all the active digital inputs for change of state, then add any events
to the Serial output queue using () */
void checkDigitalInputs(boolean forceSend = false)
{
/* Using non-looping code allows constants to be given to readPort().
The compiler will apply substantial optimizations if the inputs
to readPort() are compile-time constants. */
for (uint8_t i = 0; i < TOTAL_PORTS; i++) {
if (reportPINs[i]) {
// FIRMATADEBUG.print("Reporting on port "); FIRMATADEBUG.print(i); FIRMATADEBUG.print(" mask 0x");
FIRMATADEBUG.println(portConfigInputs[i], HEX);
uint8_t x = BLE_Firmata.readPort(i, portConfigInputs[i]);
//FIRMATADEBUG.print("Read 0x"); FIRMATADEBUG.println(x, HEX);
outputPort(i, x, forceSend);
}
}
}
// -----------------------------------------------------------------------------
/* sets the pin mode to the correct state and sets the relevant bits in the
two bit-arrays that track Digital I/O and PWM status
*/
void setPinModeCallback(byte pin, int mode)
{
//FIRMATADEBUG.print("Setting pin #"); FIRMATADEBUG.print(pin); FIRMATADEBUG.print(" to ");
FIRMATADEBUG.println(mode);
if ((pinConfig[pin] == I2C) && (isI2CEnabled) && (mode != I2C)) {
// disable i2c so pins can be used for other functions
// the following if statements should reconfigure the pins properly
disableI2CPins();
}
if (BLE_Firmata.IS_PIN_SERVO(pin) && mode != SERVO && servos[BLE_Firmata.PIN_TO_SERVO(pin)].attached()) {
servos[BLE_Firmata.PIN_TO_SERVO(pin)].detach();
}
if (BLE_Firmata.IS_PIN_ANALOG(pin)) {
reportAnalogCallback(BLE_Firmata.PIN_TO_ANALOG(pin), mode == ANALOG ? 1 : 0); // turn on/off reporting
}
if (BLE_Firmata.IS_PIN_DIGITAL(pin)) {
if (mode == INPUT) {
portConfigInputs[pin / 8] |= (1 << (pin & 7));
} else {
14
portConfigInputs[pin / 8] &= ~(1 << (pin & 7));
}
// FIRMATADEBUG.print(F("Setting pin #")); FIRMATADEBUG.print(pin); FIRMATADEBUG.print(F(" port config mask to =
0x"));
// FIRMATADEBUG.println(portConfigInputs[pin/8], HEX);
}
pinState[pin] = 0;
switch (mode) {
case ANALOG:
if (BLE_Firmata.IS_PIN_ANALOG(pin)) {
//FIRMATADEBUG.print(F("Set pin #")); FIRMATADEBUG.print(pin); FIRMATADEBUG.println(F(" to analog"));
if (BLE_Firmata.IS_PIN_DIGITAL(pin)) {
pinMode(BLE_Firmata.PIN_TO_DIGITAL(pin), INPUT); // disable output driver
}
pinConfig[pin] = ANALOG;
lastAnalogReads[BLE_Firmata.PIN_TO_ANALOG(pin)] = -1;
}
break;
case INPUT:
if (BLE_Firmata.IS_PIN_DIGITAL(pin)) {
//FIRMATADEBUG.print(F("Set pin #")); FIRMATADEBUG.print(pin); FIRMATADEBUG.println(F(" to input"));
if (AUTO_INPUT_PULLUPS) {
pinMode(BLE_Firmata.PIN_TO_DIGITAL(pin), INPUT_PULLUP); // disable output driver
} else {
pinMode(BLE_Firmata.PIN_TO_DIGITAL(pin), INPUT); // disable output driver
}
pinConfig[pin] = INPUT;
15
case SERVO:
if (BLE_Firmata.IS_PIN_SERVO(pin))
servos[BLE_Firmata.PIN_TO_SERVO(pin)].write(value);
pinState[pin] = value;
break;
case PWM:
if (BLE_Firmata.IS_PIN_PWM(pin))
analogWrite(BLE_Firmata.PIN_TO_PWM(pin), value);
//FIRMATADEBUG.print("pwm("); FIRMATADEBUG.print(BLE_Firmata.PIN_TO_PWM(pin)); FIRMATADEBUG.print(",");
FIRMATADEBUG.print(value); FIRMATADEBUG.println(")");
pinState[pin] = value;
break;
}
}
}
// -----------------------------------------------------------------------------
/* sets bits in a bit array (int) to toggle the reporting of the analogIns
*/
//void FirmataClass::setAnalogPinReporting(byte pin, byte state) {
//}
void reportAnalogCallback(byte analogPin, int value)
{
if (analogPin < BLE_Firmata._num_analogiopins) {
if (value == 0) {
analogInputsToReport = analogInputsToReport & ~ (1 << analogPin);
//FIRMATADEBUG.print(F("Stop reporting analog pin #")); FIRMATADEBUG.println(analogPin);
} else {
analogInputsToReport |= (1 << analogPin);
//FIRMATADEBUG.print(F("Will report analog pin #")); FIRMATADEBUG.println(analogPin);
}
}
// TODO: save status to EEPROM here, if changed
}
16
// as analog when sampling the analog inputs. Likewise, while
// scanning digital pins, portConfigInputs will mask off values from any
// pins configured as analog
}
/*==============================================================================
SYSEX-BASED commands
============================================================================*/
switch (command) {
case I2C_REQUEST:
mode = argv[1] & I2C_READ_WRITE_MODE_MASK;
if (argv[1] & I2C_10BIT_ADDRESS_MODE_MASK) {
//BLE_Firmata.sendString("10-bit addressing mode is not yet supported");
//FIRMATADEBUG.println(F("10-bit addressing mode is not yet supported"));
return;
}
else {
slaveAddress = argv[0];
}
switch (mode) {
case I2C_WRITE:
Wire.beginTransmission(slaveAddress);
for (byte i = 2; i < argc; i += 2) {
data = argv[i] + (argv[i + 1] << 7);
#if ARDUINO >= 100
Wire.write(data);
#else
Wire.send(data);
#endif
}
Wire.endTransmission();
delayMicroseconds(70);
break;
case I2C_READ:
if (argc == 6) {
// a slave register is specified
slaveRegister = argv[2] + (argv[3] << 7);
data = argv[4] + (argv[5] << 7); // bytes to read
readAndReportData(slaveAddress, (int)slaveRegister, data);
}
else {
// a slave register is NOT specified
data = argv[2] + (argv[3] << 7); // bytes to read
readAndReportData(slaveAddress, (int)REGISTER_NOT_SPECIFIED, data);
}
break;
case I2C_READ_CONTINUOUSLY:
if ((queryIndex + 1) >= MAX_QUERIES) {
// too many queries, just ignore
BLE_Firmata.sendString("too many queries");
break;
}
queryIndex++;
query[queryIndex].addr = slaveAddress;
query[queryIndex].reg = argv[2] + (argv[3] << 7);
query[queryIndex].bytes = argv[4] + (argv[5] << 7);
break;
case I2C_STOP_READING:
byte queryIndexToSkip;
// if read continuous mode is enabled for only 1 i2c device, disable
// read continuous reporting for that device
if (queryIndex <= 0) {
queryIndex = -1;
17
} else {
// if read continuous mode is enabled for multiple devices,
// determine which device to stop reading and remove it's data from
// the array, shifiting other array data to fill the space
for (byte i = 0; i < queryIndex + 1; i++) {
if (query[i].addr = slaveAddress) {
queryIndexToSkip = i;
break;
}
}
if (delayTime > 0) {
i2cReadDelayTime = delayTime;
}
if (!isI2CEnabled) {
enableI2CPins();
}
break;
case SERVO_CONFIG:
if (argc > 4) {
// these vars are here for clarity, they'll optimized away by the compiler
byte pin = argv[0];
int minPulse = argv[1] + (argv[2] << 7);
int maxPulse = argv[3] + (argv[4] << 7);
if (BLE_Firmata.IS_PIN_SERVO(pin)) {
if (servos[BLE_Firmata.PIN_TO_SERVO(pin)].attached())
servos[BLE_Firmata.PIN_TO_SERVO(pin)].detach();
servos[BLE_Firmata.PIN_TO_SERVO(pin)].attach(BLE_Firmata.PIN_TO_DIGITAL(pin), minPulse, maxPulse);
setPinModeCallback(pin, SERVO);
}
}
break;
case SAMPLING_INTERVAL:
if (argc > 1) {
samplingInterval = argv[0] + (argv[1] << 7);
if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) {
samplingInterval = MINIMUM_SAMPLING_INTERVAL;
}
} else {
//BLE_Firmata.sendString("Not enough data");
}
break;
case EXTENDED_ANALOG:
if (argc > 1) {
int val = argv[1];
if (argc > 2) val |= (argv[2] << 7);
if (argc > 3) val |= (argv[3] << 14);
analogWriteCallback(argv[0], val);
}
break;
case CAPABILITY_QUERY:
bluefruit.write(START_SYSEX);
bluefruit.write(CAPABILITY_RESPONSE);
18
//FIRMATADEBUG.print(" 0x"); FIRMATADEBUG.print(START_SYSEX, HEX); FIRMATADEBUG.print(" 0x");
FIRMATADEBUG.println(CAPABILITY_RESPONSE, HEX);
delay(10);
for (byte pin = 0; pin < TOTAL_PINS; pin++) {
//FIRMATADEBUG.print("\t#"); FIRMATADEBUG.println(pin);
if (BLE_Firmata.IS_PIN_DIGITAL(pin)) {
bluefruit.write((byte)INPUT);
bluefruit.write(1);
bluefruit.write((byte)OUTPUT);
bluefruit.write(1);
/*
FIRMATADEBUG.print(" 0x"); FIRMATADEBUG.print(INPUT, HEX);
FIRMATADEBUG.print(" 0x"); FIRMATADEBUG.print(1, HEX);
FIRMATADEBUG.print(" 0x"); FIRMATADEBUG.print(OUTPUT, HEX);
FIRMATADEBUG.print(" 0x"); FIRMATADEBUG.println(1, HEX);
*/
delay(20);
} else {
bluefruit.write(127);
//FIRMATADEBUG.print(" 0x"); FIRMATADEBUG.println(127, HEX);
delay(20);
continue;
}
if (BLE_Firmata.IS_PIN_ANALOG(pin)) {
bluefruit.write(ANALOG);
bluefruit.write(10);
19
//FIRMATADEBUG.println("Analog mapping query");
bluefruit.write(START_SYSEX);
bluefruit.write(ANALOG_MAPPING_RESPONSE);
for (byte pin = 0; pin < TOTAL_PINS; pin++) {
bluefruit.write(BLE_Firmata.IS_PIN_ANALOG(pin) ? BLE_Firmata.PIN_TO_ANALOG(pin) : 127);
}
bluefruit.write(END_SYSEX);
break;
}
}
void enableI2CPins()
{
byte i;
// is there a faster way to do this? would probaby require importing
// Arduino.h to get SCL and SDA pins
for (i = 0; i < TOTAL_PINS; i++) {
if (BLE_Firmata.IS_PIN_I2C(i)) {
// mark pins as i2c so they are ignore in non i2c data requests
setPinModeCallback(i, I2C);
}
}
isI2CEnabled = true;
// is there enough time before the first I2C request to call this here?
Wire.begin();
}
/* disable the i2c pins so they can be used for other functions */
void disableI2CPins() {
isI2CEnabled = false;
// disable read continuous mode for all devices
queryIndex = -1;
// uncomment the following if or when the end() method is added to Wire library
// Wire.end();
}
/*==============================================================================
SETUP()
============================================================================*/
void systemResetCallback()
{
FIRMATADEBUG.println("check check check systemResetCallback used");
// initialize a defalt state
FIRMATADEBUG.println(F("***RESET***"));
// TODO: option to load config from EEPROM instead of default
if (isI2CEnabled) {
disableI2CPins();
}
for (byte i = 0; i < TOTAL_PORTS; i++) {
reportPINs[i] = false; // by default, reporting off
portConfigInputs[i] = 0; // until activated
previousPINs[i] = 0;
}
// pins with analog capability default to analog input
// otherwise, pins default to digital output
for (byte i = 0; i < TOTAL_PINS; i++) {
if (BLE_Firmata.IS_PIN_ANALOG(i)) {
// turns off pullup, configures everything
setPinModeCallback(i, ANALOG);
} else {
// sets the output to 0, configures portConfigInputs
setPinModeCallback(i, INPUT);
}
}
// by default, do not report any analog inputs
analogInputsToReport = 0;
/* send digital inputs to set the initial state on the host computer,
since once in the loop(), this firmware will only send on change */
/*
TODO: this can never execute, since no pins default to digital input
but it will be needed when/if we support EEPROM stored config
20
for (byte i=0; i < TOTAL_PORTS; i++) {
outputPort(i, readPort(i, portConfigInputs[i]), true);
}
*/
}
void setup()
{
if (WAITFORSERIAL) {
while (!FIRMATADEBUG) delay(1);
}
FIRMATADEBUG.begin(9600);
FIRMATADEBUG.println(F("Adafruit Bluefruit nRF8001 Firmata test"));
BLE_Firmata.setUsablePins(boards_digitaliopins, sizeof(boards_digitaliopins),
boards_analogiopins, sizeof(boards_analogiopins),
boards_pwmpins, sizeof(boards_pwmpins),
boards_servopins, sizeof(boards_servopins), SDA, SCL);
void firmataInit() {
FIRMATADEBUG.println(F("Init firmata"));
//BLE_Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION);
//FIRMATADEBUG.println(F("firmata analog"));
BLE_Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);
//FIRMATADEBUG.println(F("firmata digital"));
BLE_Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback);
//FIRMATADEBUG.println(F("firmata analog report"));
BLE_Firmata.attach(REPORT_ANALOG, reportAnalogCallback);
//FIRMATADEBUG.println(F("firmata digital report"));
BLE_Firmata.attach(REPORT_DIGITAL, reportDigitalCallback);
//FIRMATADEBUG.println(F("firmata pinmode"));
BLE_Firmata.attach(SET_PIN_MODE, setPinModeCallback);
//FIRMATADEBUG.println(F("firmata sysex"));
BLE_Firmata.attach(START_SYSEX, sysexCallback);
//FIRMATADEBUG.println(F("firmata reset"));
BLE_Firmata.attach(SYSTEM_RESET, systemResetCallback);
FIRMATADEBUG.println(F("Begin firmata"));
BLE_Firmata.begin();
systemResetCallback(); // reset to default config
}
/*==============================================================================
LOOP()
============================================================================*/
void loop()
{
// Check the BTLE link, how're we doing?
bluefruit.pollACI();
// Link status check
BTLEstatus = bluefruit.getState();
21
if (BTLEstatus == ACI_EVT_CONNECTED) {
FIRMATADEBUG.println(F("* Connected!"));
// initialize Firmata cleanly
firmataInit();
}
if (BTLEstatus == ACI_EVT_DISCONNECTED) {
FIRMATADEBUG.println(F("* Disconnected"));
}
// OK set the last status change to this one
lastBTLEstatus = BTLEstatus;
}
// if not connected... bail
if (BTLEstatus != ACI_EVT_CONNECTED) {
delay(100);
return;
}
// For debugging, see if there's data on the serial console, we would forwad it to BTLE
if (FIRMATADEBUG.available()) {
bluefruit.write(FIRMATADEBUG.read());
}
/* DIGITALREAD - as fast as possible, check for changes and output them to the
BTLE buffer using FIRMATADEBUG.print() */
checkDigitalInputs();
currentMillis = millis();
if (currentMillis - previousMillis > samplingInterval) {
previousMillis += samplingInterval;
/* ANALOGREAD - do all analogReads() at the configured sampling interval */
22
FIRMATADEBUG.print(F("x=")); FIRMATADEBUG.println(x);
float n = 3450 / (-log(1023 / x - 1) + 3450 / d298.15) - 273.15;
if (n > upperRange||n < lowerRange ){
tone(6,500);
delay(100);
noTone(6);
delay(1);
}
FIRMATADEBUG.print(F("n=")); FIRMATADEBUG.println(n);
int currentRead = analogRead(analogPin);
FIRMATADEBUG.print(F("Analog")); FIRMATADEBUG.print(analogPin); FIRMATADEBUG.print(F(" = "));
FIRMATADEBUG.println(currentRead);
BLE_Firmata.sendAnalog(analogPin, n);
BLE_Firmata.sendAnalog(byte(4), n * 100);
//lastAnalogReads[analogPin] = currentRead;
}
//}
}
}
// report i2c data for all device with read continuous mode enabled
if (queryIndex > -1) {
for (byte i = 0; i < queryIndex + 1; i++) {
readAndReportData(query[i].addr, query[i].reg, query[i].bytes);
}
}
Appendix B: Adafruit Bluefruit LE Connect Code
import Foundation
// Constants
private let SYSEX_START: UInt8 = 0xF0
private let SYSEX_END: UInt8 = 0xF7
// Types
enum UartStatus {
case InputOutput // Default mode (sending and receiving pin data)
case QueryCapabilities
case QueryAnalogMapping
}
class PinData {
enum Mode: UInt8 {
case Unknown = 255
case Input = 0 // Don't chage the values (these are the bytes defined by firmata spec)
case Output = 1
case Analog = 2
case PWM = 3
case Servo = 4
}
23
}
// Data
private var uartStatus = UartStatus.InputOutput
private var queryCapabilitiesTimer : NSTimer?
override init() {
super.init()
}
deinit {
cancelQueryCapabilitiesTimer()
}
func start() {
DLog("pinio start");
let notificationCenter = NSNotificationCenter.defaultCenter()
notificationCenter.addObserver(self, selector: #selector(PinIOModuleManager.didReceiveData(_:)), name:
UartManager.UartNotifications.DidReceiveData.rawValue, object: nil)
}
func stop() {
DLog("pinio stop");
let notificationCenter = NSNotificationCenter.defaultCenter()
notificationCenter.removeObserver(self, name: UartManager.UartNotifications.DidReceiveData.rawValue,
object: nil)
24
cancelQueryCapabilitiesTimer()
}
// MARK: Notifications
func didReceiveData(notification: NSNotification) {
if let dataChunk = notification.userInfo?["dataChunk"] as? UartDataChunk {
// DLog("pin io received: \(hexString(dataChunk.data))")
switch uartStatus {
case .QueryCapabilities:
receivedQueryCapabilities(dataChunk.data)
case .QueryAnalogMapping:
receivedAnalogMapping(dataChunk.data)
default:
receivedPinState(dataChunk.data)
break
}
}
}
// Reset Firmata
let bytes:[UInt8] = [0xff]
let data = NSData(bytes: bytes, length: bytes.count)
UartManager.sharedInstance.sendData(data)
}
// Set status
pins = []
self.uartStatus = .QueryCapabilities
self.queryCapabilitiesDataBuffer.removeAll()
// Query Capabilities
let bytes:[UInt8] = [SYSEX_START, 0x6B, SYSEX_END]
let data = NSData(bytes: bytes, length: bytes.count)
UartManager.sharedInstance.sendData(data)
self.queryCapabilitiesTimer = NSTimer.scheduledTimerWithTimeInterval(self.CAPABILITY_QUERY_TIMEOUT,
target: self, selector: #selector(PinIOModuleManager.cancelQueryCapabilities), userInfo: nil, repeats: false)
}
25
}
// Set status
self.uartStatus = .QueryAnalogMapping
self.queryAnalogMappingDataBuffer.removeAll()
func cancelQueryCapabilities() {
DLog("timeout: cancelQueryCapabilities")
endPinQuery(true)
}
// Refresh
delegate?.onPinIODidEndPinQuery(isDefaultConfigurationAssumed)
}
26
}
let pinData = PinData(digitalPinId: pinNumber, isDigital: isInput && isOutput, isAnalog: isAnalog, isPWM:
isPWM)
DLog("pin id: \(pinNumber) digital: \(pinData.isDigital) analog: \(pinData.isAnalog)")
self.pins.append(pinData)
}
pinNumber += 1
}
return true
}
var pinNumber = 0
for i in 2..<endIndex! { // Skip 2 header bytes and end byte
let dataByte = analogData[i]
if dataByte != 0x7f {
27
if let indexOfPinNumber = indexOfPinWithDigitalId(pinNumber) {
pins[indexOfPinNumber].analogPinId = Int(dataByte)
DLog("pin id: \(pinNumber) analog id: \(Int(dataByte))")
}
else {
DLog("warning: trying to set analog id: \(Int(dataByte)) for pin id: \(pinNumber)");
}
}
pinNumber += 1
}
return true
}
for i in 0..<DEFAULT_PINS_COUNT {
var pin: PinData!
if (i == 3 || i == 5 || i == 6) { // PWM pins
pin = PinData(digitalPinId: i,isDigital: true, isAnalog: false, isPWM: false)
}
else if (i >= FIRST_DIGITAL_PIN && i <= LAST_DIGITAL_PIN) { // Digital pin
pin = PinData(digitalPinId: i, isDigital: true, isAnalog: false, isPWM: false)
}
else if (i >= FIRST_ANALOG_PIN && i <= LAST_ANALOG_PIN) { // Analog pin
pin = PinData(digitalPinId: i, isDigital: true, isAnalog: true, isPWM: false)
pin.analogPinId = i-FIRST_ANALOG_PIN
}
// Store
pin.mode = mode
pin.digitalValue = .Low // Reset dialog value when chaning mode
28
pin.analogValue = 0 // Reset analog value when chaging mode
// Write value
let port = UInt8(pin.digitalPinId / 8)
let data0 = 0x90 + port
// Store
pin.analogValue = value
// Send
let data0 = 0xe0 + UInt8(pin.digitalPinId)
let data1 = UInt8(value & 0x7f) //only 7 bottom bits
let data2 = UInt8(value >> 7) //top bit in second byte
29
let data = NSData(bytes: bytes, length: bytes.count)
UartManager.sharedInstance.sendData(data)
return true
}
30
(receivedPinStateDataBuffer[0] <= 0xEF)
// Refresh UI
delegate?.onPinIODidReceivePinState()
}
31
pin.digitalValue = digitalValue
DLog("update pinid: \(digitalId) digitalValue: \(digitalValue)")
}
}
}
// MARK: - Utils
static func stringForPinMode(mode: PinIOModuleManager.PinData.Mode)-> String {
var modeString: String
switch mode {
case .Input:
modeString = "Input"
case .Output:
modeString = "Output"
case .Analog:
modeString = "Analog"
case .PWM:
modeString = "PWM"
case .Servo:
modeString = "Servo"
default:
modeString = "Unkwnown"
}
return modeString
}
switch digitalValue {
case .Low:
valueString = "Low"
case .High:
valueString = "High"
}
return valueString
}
}
32
High Stability Miniature Thermistor
Analog Technologies ATH10KR8B
Note: This thermistor ATH10KR8B is a replacement for
ATH10KR8.
The ATH10KR8B is a high precision glass encapsulated
thermistor. Comparing with conventional epoxy encapsulated
thermistors, ATH10KR8B presents higher long term stability
and wider temperature range. In addition, it has a small size
and short response time. In addition, there are two insulation
versions available, one of which comes with leads covered by
plastic tubing, the ATH10KR8BT65, and the other one, the
ATH10KR8BT65S, is sealed between the head and the
tubing. They can work under up to 140C temperature and
the latter is of liquid resistant.
The ATH10KR8B series can be used to measure the
temperatures for laser diodes, optical components, etc., with
high accuracy and long term stability.
Figure1.1. The physical photo of ATH10KR8B
2352 Walsh Ave., Santa Clara, CA 95051, U. S. A. Tel.: (408) 748-9100, Fax: (408) 748-9111 www.analogtechnologies.com
Copyrights 2000-2016, Analog Technologies, Inc. All Rights Reserved. Updated on 5/4/2016 www.analogti.com 1
High Stability Miniature Thermistor
Analog Technologies ATH10KR8B
cause temperature measurement errors. Figure 3 shows the errors. To avoid the bubbles, use thin epoxy, vibrate the
section view of the 2 stage hole. assembly before curing, and cure the epoxy inside the
mounting hole at high temperature, 80C to 150C,
Thermal Conductive Epoxy depending on the epoxy used and the maximum temperature
3 5 mm assembly components allow.
The thermistor lead wires are made of plain copper and there
is no insulation coating on them, please make sure that they
2 2.5 mm do not touch each other after mounting the thermistor.
Some thermal conductive epoxies are also electrically
1.2 1.5 mm conductive and such epoxies should not be used for mounting
the thermistors, since the lead wires are conductive.
Figure 3. Section View of the 2 Stage Hole Notice: Glass encapsulated cannot be used in water or other
The worst mounting result is that there are air bubbles liquid directly.
trapped inside the thermistor mounting hole. These bubbles
cause thermal sensing time delay and sensing temperature
Resistance Temperature Characteristics
Table 1. ATH10KR8B vs. ATH10KR8
T R_nom () T R_nom ()
(C) ATH10KR8B ATH10KR8 (C) ATH10KR8B ATH10KR8
-55 526240 519911 50 4100 4103
-50 384520 379894 55 3479.8 3482
-45 284010 280697 60 2966.3 2967
-40 211940 209603 65 2539.2 2539
-35 159720 158088 70 2182.4 2182
-30 121490 120372 75 1883 1882
-25 93246 92484 80 1630.7 1629
-20 72181 71668 85 1417.4 1415
-15 56332 55993 90 1236.2 1234
-10 44308 44087 95 1081.8 1079
-5 35112 34971 100 949.73 946.6
0 28024 27936 105 836.4 833.1
5 22520 22468 110 738.81 735.5
10 18216 18187 115 654.5 651.1
15 14827 14813 120 581.44 578.1
20 12142 12136 125 517.94 514.6
25 10000 10000 130 462.59 459.4
30 8281.8 8284 135 414.2 411.1
35 6895.4 6899 140 371.79 368.8
40 5770.3 5774 145 334.51 331.6
45 4852.5 4856 150 301.66 298.9
2352 Walsh Ave., Santa Clara, CA 95051, U. S. A. Tel.: (408) 748-9100, Fax: (408) 748-9111 www.analogtechnologies.com
Copyrights 2000-2016, Analog Technologies, Inc. All Rights Reserved. Updated on 5/4/2016 www.analogti.com 2
High Stability Miniature Thermistor
Analog Technologies ATH10KR8B
T R_nom () T R_nom ()
(C) ATH10KR8B ATH10KR8 (C) ATH10KR8B ATH10KR8
155 272.64 270.0 205 110.51 109.1
160 246.94 244.4 210 101.94 100.7
165 224.14 221.7 215 94.181 93.01
170 203.85 201.6 220 87.144 86.08
175 185.77 183.6 225 807.51 79.78
180 169.61 167.6 230 74.933 74.05
185 155.14 153.3 235 69.631 68.83
190 142.16 140.4 240 64.791 64.08
195 130.49 128.9 245 60.366 59.73
200 119.99 118.5 250 56.316 55.75
2352 Walsh Ave., Santa Clara, CA 95051, U. S. A. Tel.: (408) 748-9100, Fax: (408) 748-9111 www.analogtechnologies.com
Copyrights 2000-2016, Analog Technologies, Inc. All Rights Reserved. Updated on 5/4/2016 www.analogti.com 3
High Stability Miniature Thermistor
Analog Technologies ATH10KR8B
ORDERING INFORMATIONS
Table 2. Part Number of the Thermistors
Part # Description
ATH10KR8BT65 High stability miniature thermistor with leads covered by high temperature plastic tubing
High stability miniature thermistor with leads covered by high temperature plastic tubing and
ATH10KR8BT65S
sealed by epoxy
NOTICE
1. ATI reserves the right to make changes to its products or to discontinue any product or service without notice, and advise
customers to obtain the latest version of relevant information to verify, before placing orders, that information being relied
on is current and complete.
2. All products are sold subject to the terms and conditions of sale supplied at the time of order acknowledgment, including
those pertaining to warranty, patent infringement, and limitation of liability. Testing and other quality control techniques are
utilized to the extent ATI deems necessary to support this warranty. Specific testing of all parameters of each device is not
necessarily performed, except those mandated by government requirements.
3. Customers are responsible for their applications using ATI components. In order to minimize risks associated with the
customers applications, adequate design and operating safeguards must be provided by the customers to minimize inherent
or procedural hazards. ATI assumes no liability for applications assistance or customer product design.
4. ATI does not warrant or represent that any license, either express or implied, is granted under any patent right, copyright,
mask work right, or other intellectual property right of ATI covering or relating to any combination, machine, or process in
which such products or services might be or are used. ATIs publication of information regarding any third partys products
or services does not constitute ATIs approval, warranty or endorsement thereof.
5. IP (Intellectual Property) Ownership: ATI retains the ownership of full rights for special technologies and/or techniques
embedded in its products, the designs for mechanics, optics, plus all modifications, improvements, and inventions made by
ATI for its products and/or projects.
2352 Walsh Ave., Santa Clara, CA 95051, U. S. A. Tel.: (408) 748-9100, Fax: (408) 748-9111 www.analogtechnologies.com
Copyrights 2000-2016, Analog Technologies, Inc. All Rights Reserved. Updated on 5/4/2016 www.analogti.com 4
...
The Arduino Uno is a microcontroller board based on the ATmega328 (datasheet). It has 14 digital
input/output pins (of which 6 can be used as PWM outputs), 6 analog inputs, a 16 MHz crystal oscillator, a
USB connection, a power jack, an ICSP header, and a reset button. It contains everything needed to support
the microcontroller; simply connect it to a computer with a USB cable or power it with a AC-to-DC adapter or
battery to get started.
The Uno differs from all preceding boards in that it does not use the FTDI USB-to-serial driver chip. Instead,
it features the Atmega8U2 programmed as a USB-to-serial converter.
"Uno" means "One" in Italian and is named to mark the upcoming release of Arduino 1.0. The Uno and
version 1.0 will be the reference versions of Arduino, moving forward. The Uno is the latest in a series of
USB Arduino boards, and the reference model for the Arduino platform; for a comparison with previous
versions, see the index of Arduino boards.
Techinal Specifications
Microcontroller ATmega328
Operating Voltage 5V
Supply Voltage (recommended) 7-12V
Maximum supply voltage (not recommended) 20V
Digital I/O Pins 14 (of which 6 provide PWM output)
Analog Input Pins 6
DC Current per I/O Pin 40 mA
DC Current for 3.3V Pin 50 mA
Flash Memory 32 KB (ATmega328) of which 0.5 KB used by bootloader
SRAM 2 KB (ATmega328)
EEPROM 1 KB (ATmega328)
Clock Speed 16 MHz
If you want to give a closer look to this board we advice you to visit the official Arduino UNO page in the
Hardware Section.
1
2