Created
August 6, 2020 12:35
-
-
Save ElectricImpSampleCode/eef97cd48f4d7523dd402c6382449234 to your computer and use it in GitHub Desktop.
imp006 Breakout Kit Sample Code: Ultrasonic Raner and Display
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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"); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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