Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
imp006 Breakout Kit Sample Code: Ultrasonic Raner and Display
// Register an handler to deal with incoming 'trigger'
// messsages from the device -- it just logs the event
device.on("trigger", function(isCut) {
if (isCut) server.log("Beam cut");
});
enum TM1637_LED_CLASS_CONSTANTS {
ADDR_AUTO = 0x40,
CMD_SET_ADDR = 0xC0,
CMD_DISP_CTRL = 0x88,
// Character constants
BLANK_CHAR = 16,
MINUS_CHAR = 17,
DEGREE_CHAR = 18,
CHAR_COUNT = 19,
// Display specific constants
LED_MAX_ROWS = 4
}
/**
* Hardware driver for Seeed Grove 4-digit LED.
*
* Availibility Device
* @author Tony Smith (@smittytone)
* @license MIT
*
* @class
*/
class TM1637 {
/**
* @property {string} VERSION - The library version
*/
static VERSION = "1.0.0";
// *********** Private Properties **********
_digits = null;
_buffer = null;
_clk = null;
_dio = null;
_brightness = 2;
_showColon = false;
/**
* Initialize the segment LED
*
* @constructor
*
* @param {imp::hardwar::pin} dataPin - The imp pin connected to Grove WHITE
* @param {imp::hardwar::pin} clockPin - The imp pin connected to Grove YELLOW
*
* @returns {instance} The instance
*/
constructor(dataPin, clockPin) {
// 'dataPin' and 'clockPin' are the imp API hardware.pin
// objects connected to, respectively, the Grove white and
// yellow lines. We set these initally LOW
_clk = clockPin;
_dio = dataPin;
_clk.configure(DIGITAL_OUT, 0);
_dio.configure(DIGITAL_OUT, 0);
// _buffer stores the character matrix values for each row of the display
//
// buffer index 0 1 2 3
// [ ] [ ] [ ] [ ]
// character - - . - -
// [ ] [ ] . [ ] [ ]
_buffer = blob(TM1637_LED_CLASS_CONSTANTS.LED_MAX_ROWS);
// '_digits' stores character matrices for 0-9, A-F, blank and minus
_digits = "\x3F\x06\x5B\x4F\x66\x6D\x7D\x07\x7F\x6F"; // 0-9
_digits += "\x5F\x7C\x58\x5E\x7B\x71"; // A-F
_digits += "\x00\x40\x63"; // Space, minus, degree signs
}
/**
* Clear each row in the segment LED buffer. Requires 'display()' to be called
*
* @returns {instance} this
*/
function clear() {
for (local i = 0 ; i < TM1637_LED_CLASS_CONSTANTS.LED_MAX_ROWS ; i++) {
_buffer[i] = TM1637_LED_CLASS_CONSTANTS.BLANK_CHAR;
}
return this;
}
/**
* Set the specified segment LED buffer row to a given character. Requires 'display()'
*
* @param {integer} [digit] - The display digit to be written to (0 - 4)
* @param {integer} [number] - The integer required (0 - 16, 0x00 - 0x0F)
*
* @returns {intance} this
*/
function writeNumber(digit, number) {
if (digit < 0 || digit >= TM1637_LED_CLASS_CONSTANTS.LED_MAX_ROWS) return null;
if (number < 0 || number > 15) return null;
_buffer[digit] = _digits[number];
return this;
}
/**
* Set or unset the segment LED display's central colon symbol
*
* @param {bool} [showColon] - Whether the central colon should be lit. Default: true
*
* @returns {instance} this
*/
function setColon(set = true) {
if (typeof set != "bool") set = true;
_showColon = set;
return this;
}
/**
* Write the segment LED buffer to the display
*/
function display() {
// Signal the start of data
_start();
_writeByte(TM1637_LED_CLASS_CONSTANTS.ADDR_AUTO);
_stop();
// Signal the data
_start();
_writeByte(TM1637_LED_CLASS_CONSTANTS.CMD_SET_ADDR);
for (local i = 0 ; i < TM1637_LED_CLASS_CONSTANTS.LED_MAX_ROWS ; i++) {
_writeByte(_buffer[i] + (_showColon ? 0x80 : 0x00));
}
_stop();
// Tell the display to update
_start();
_writeByte(TM1637_LED_CLASS_CONSTANTS.CMD_DISP_CTRL + _brightness);
_stop();
}
// *********** Private Functions **********
/**
* Write a single byte to the display
*
* @param {int} data — The 8-bit value to write
*
* @returns {int} The ACK value
*
* @private
*/
function _writeByte(data) {
// Write a single byte to the display, signalling its bits
// LSB first out on the line
data = data & 0xFF;
for (local i = 0 ; i < 8 ; i++) {
_clk.write(0);
_dio.write(data & 0x01 ? 1 : 0);
data = data >> 1;
_clk.write(1);
}
// What follows is the signalling required by the TM1637
_clk.write(0);
_dio.write(1);
_clk.write(1);
_dio.configure(DIGITAL_IN);
_delay();
local ack = _dio.read();
if (ack == 0) _dio.configure(DIGITAL_OUT, 0);
_delay();
_dio.configure(DIGITAL_OUT, 0);
_delay();
// Return whether the data was ACK'd
return ack;
}
/**
* Delay for 50 microseconds
*
* @private
*/
function _delay() {
imp.sleep(0.00005);
}
/**
* Send START signal (both pins go low)
*
* @private
*/
function _start() {
_clk.write(1);
_dio.write(1);
_dio.write(0);
_clk.write(0);
}
/**
* Send STOP signal (both pins go high)
*
* @private
*/
function _stop() {
_clk.write(0);
_dio.write(0);
_clk.write(1);
_dio.write(1);
}
}
enum GROVE_ULTRA_CLASS_CONSTANTS {
TIMEOUT_SHORT = 1000,
TIMEOUT_LONG = 10000
}
/**
* Hardware driver for Seeed Ultrasonic Ranger.
*
* Availibility Device
* @author Tony Smith (@smittytone)
* @license MIT
*
* @class
*/
class GroveUltrasonic {
/**
* @property {string} VERSION - The library version
*/
static VERSION = "1.0.0";
// *********** Private Properties **********
_pin = null;
_debug = false;
/**
* Initialize the segment LED
*
* @constructor
*
* @param {imp::hardwar::pin} yellowPin - The imp pin connected to Grove YELLOW
* @param {bool} debug - Should show extra debug info
*
* @returns {instance} The instance
*/
constructor(yellowPin, debug = false) {
_pin = yellowPin;
_debug = typeof debug == "bool" ? debug : false;
}
/**
* Get the current detected range in centimeters
*
* @returns {int} The range in centimeters
*/
function distanceCentimeters() {
// Configure renager's SIG pin as an output
// and trigger a reading by sending a pulse
// (just) longer than 10us (after a 2us pause)
_pin.configure(DIGITAL_OUT, 0);
_delay(2);
_pin.write(1);
_delay(12);
_pin.write(0);
// Now set SIG as an input to receive the reading
local pulseLength = _measurePulse();
if (_debug) server.log("Pulse duration: " + pulseLength + " us");
if (pulseLength > 0) {
local distance = pulseLength.tofloat() / 58.0;
if (_debug) server.log(" Distance: " + distance + " cm");
return distance;
} else {
// Error condition
return 0;
}
}
// ********** PRIVATE FUNCTIONS **********
/**
* Pause for a specific period of time in microseconds
*
* @param {int} period — The number of microseconds to wait
*
* @private
*/
function _delay(period) {
local start = hardware.micros();
local current = 0;
do {
current = hardware.micros();
} while (current - start < period);
}
/**
* Measure the duration of a signal pulse from the ranger.
* This is proportional to the detected range
*
* @returns {float} The pulse duration in microseconds, or 0 for error
*
* @private
*/
function _measurePulse() {
// Set SGL pin to input
_pin.configure(DIGITAL_IN);
local start = hardware.micros();
local count = 0;
// Pre-signal pulse
do {
if (_pin.read() == 1) break;
count += 1;
} while (count < GROVE_ULTRA_CLASS_CONSTANTS.TIMEOUT_SHORT);
if (count >= GROVE_ULTRA_CLASS_CONSTANTS.TIMEOUT_SHORT) return 0;
// Start of pulse
local pulseStart = hardware.micros();
count = 0;
do {
if (_pin.read() == 0) break;
count += 1;
} while (count < GROVE_ULTRA_CLASS_CONSTANTS.TIMEOUT_LONG);
if (count >= GROVE_ULTRA_CLASS_CONSTANTS.TIMEOUT_LONG) return 0;
// End of pulse
local pulseEnd = hardware.micros();
// Check for too long a pre-pulse period
if (pulseStart - start > 530) return 0;
// Return the pulse length
return pulseEnd - pulseStart;
}
}
// Instantiate the sensor library
sensor <- GroveUltrasonic(hardware.pinN);
// Instantiate LED library
led <- TM1637(hardware.pinU, hardware.pinT);
// Power gate Grove
hardware.pinXU.configure(DIGITAL_OUT, 1);
// Convert an integer to a BCD representation
function toBCD(a) {
local hs = a.tostring();
local i = 0;
foreach (c in hs) {
local n = c - '0';
if (n > 9) n = ((n & 0x1F) - 7);
i = (i << 4) + n;
}
return i;
}
function loop() {
// Take a distance reading
local gap = sensor.distanceCentimeters().tointeger();
// Ping the agent when the range is under 21cm
if (gap > 0 && gap < 21) agent.send("trigger", true);
// Show the gap on the display
local bcd = toBCD(gap);
led.writeNumber(0, (bcd & 0xF000) >> 12);
led.writeNumber(1, (bcd & 0x0F00) >> 8);
led.writeNumber(2, (bcd & 0xF0) >> 4);
led.writeNumber(3, (bcd & 0x0F));
led.setColon(false).display();
// Wake in 1 second and take a fresh reading
imp.wakeup(0.5, loop);
}
// Start the loop
loop()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment