Skip to content

Instantly share code, notes, and snippets.

@smittytone
Last active August 29, 2015 13:57
Show Gist options
  • Save smittytone/9524970 to your computer and use it in GitHub Desktop.
Save smittytone/9524970 to your computer and use it in GitHub Desktop.
Sample code showing the use of I2C with the Electric Imp
// Print light reading trigger URL
server.log("Sensor Agent URL: " + http.agenturl());
// Define funtions
function requestHandler(request, response)
{
// Handle an incoming web request for a reading
try
{
device.send("sense", true);
response.send(200, "OK");
}
catch (ex)
{
response.send(500, "Internal Server Error: " + ex);
}
}
// Register the HTTP handler
http.onrequest(requestHandler);
// Configure the Adafruit/TAOS TSL2561 light sensor
// Note: Imp I2C command values are strings with
// the \x escape character to indicate a hex value
const TSL2561_COMMAND_BIT = "\x80"; // Command register. Bit 7 must be 1
const TSL2561_CONTROL_POWERON = "\x03"; // Power on setting
const TSL2561_CONTROL_POWEROFF = "\x00"; // Power off setting
const TSL2561_REGISTER_TIMING = "\x81"; // Access timing register
const TSL2561_REGISTER_ADC0_LSB = "\xAC"; // LSB of sensor's two-byte ADC value
const TSL2561_REGISTER_ADC1_LSB = "\xAE"; // MSB of sensor's two-byte ADC value
const TSL2561_GAIN_HIGH = "\x01"; // Gain to high
const TSL2561_GAIN_LOW = "\x00"; // Gain to low
// Note: Imp I2C address values are integers
const TSL2561_ADDR_LOW = 0x29; // ADDR pin ground
const TSL2561_ADDR_HIGH = 0x49; // ADDR pin 3v3
const TSL2561_ADDR_FLOAT = 0x39; // ADDR pin floating
// Lux calculation constants
const LUX_SCALE = 14; // scale by 2^14
const RATIO_SCALE = 9; // scale ratio by 2^9
const B1C = 0x0204;
const M1C = 0x01ad;
const B2C = 0x0228;
const M2C = 0x02c1;
const B3C = 0x0253;
const M3C = 0x0363;
const B4C = 0x0282;
const M4C = 0x03df;
const B5C = 0x0177;
const M5C = 0x01dd;
const B6C = 0x0101;
const M6C = 0x0127;
const B7C = 0x0037;
const M7C = 0x002b;
const B8C = 0x0000;
const M8C = 0x0000;
const K1C = 0x0043;
const K2C = 0x0085;
const K3C = 0x00c8;
const K4C = 0x010a;
const K5C = 0x014d;
const K6C = 0x019a;
const K7C = 0x029a;
const K8C = 0x029a;
// DEFINE FUNCTIONS
function calculate_lux(ch_0, ch_1)
{
// Calculate the luminosity based on ADC Channel 0 (visible + IR) and
// Channel 1 (IR) values. Returns the luminosity. Assumes sensor
// integration time is 13ms, gain is 16x
local ch_scale = 29975;
local channel_0 = (ch_0 * ch_scale) >> 10;
local channel_1 = (ch_1 * ch_scale) >> 10;
local ratio_1 = 0;
if (channel_0 != 0) ratio_1 = (channel_1 << (RATIO_SCALE + 1)) / channel_0;
// Round the ratio value
local ratio = (ratio_1 + 1) >> 1;
local b = 0;
local m = 0;
if ((ratio >= 0) && (ratio <= K1C))
{b=B1C; m=M1C;}
else if (ratio <= K2C)
{b=B2C; m=M2C;}
else if (ratio <= K3C)
{b=B3C; m=M3C;}
else if (ratio <= K4C)
{b=B4C; m=M4C;}
else if (ratio <= K5C)
{b=B5C; m=M5C;}
else if (ratio <= K6C)
{b=B6C; m=M6C;}
else if (ratio <= K7C)
{b=B7C; m=M7C;}
else if (ratio > K8C)
{b=B8C; m=M8C;}
local temp = ((channel_0 * b) - (channel_1 * m));
// Do not allow a negative lux value
if (temp < 0) temp = 0;
temp += (1 << (LUX_SCALE - 1));
// Strip off fractional portion
local lux = temp >> LUX_SCALE;
return lux;
}
function read_sensor_adc_0(i2c)
{
local word = i2c.read(i2c_addr, TSL2561_REGISTER_ADC0_LSB, 2);
local lumo = (word[1] << 8) + word[0];
return lumo;
}
function read_sensor_adc_1(i2c)
{
local word = i2c.read(i2c_addr, TSL2561_REGISTER_ADC1_LSB, 2);
local lumo = (word[1] << 8) + word[0];
return lumo;
}
function get_lumo(bool_value)
{
if (bool_value)
{
// Set command focus to ADC 0
i2c.write(i2c_addr, TSL2561_REGISTER_ADC0_LSB);
local lumo_0 = read_sensor_adc_0(i2c);
server.log("Light level: " + lumo_0);
i2c.write(i2c_addr, TSL2561_REGISTER_ADC1_LSB);
local lumo_1 = read_sensor_adc_1(i2c);
server.log("IR level: " + lumo_1);
local lux = calculate_lux(lumo_0, lumo_1);
server.log("Lux: " + lux);
}
}
// PROGRAM START POINT
// Set up alias for i2c and set bus to 100kHz
i2c <- hardware.i2c12;
i2c.configure(CLOCK_SPEED_100_KHZ);
// Set sensor's address by shifting 7-bit address 1 bit leftward as per imp I2C spec
i2c_addr <- TSL2561_ADDR_FLOAT << 1;
// Set command focus to the control register
i2c.write(i2c_addr, TSL2561_COMMAND_BIT);
// Send power up command
i2c.write(i2c_addr, TSL2561_CONTROL_POWERON);
// Check the power is on: this will return string '3' or '51' if it is
local result = i2c.read(i2c_addr, TSL2561_CONTROL_POWERON, 1);
server.log("Power check: "+ result[0]);
// Set command focus to the timing register
i2c.write(i2c_addr, TSL2561_REGISTER_TIMING);
// Set gain to low
i2c.write(i2c_addr, TSL2561_GAIN_HIGH);
// Register a handler for "sense" messages from the agent
agent.on("sense", get_lumo);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment