/* pebble_test_all_sensors * ~~~~~~~~~~~~~ * Mashup by Marc MERLIN from different examples (by others) from * aiko_node and other aiko pebble examples to exercise all the sensors. * Some of my code should move to libraries, but for now it's in here. * Button 1 resets the time counter. * Button 2 makes the led flashing to be relative to light on the light sensor. * Button 3 makes the led flashing to be relative to potentiometer. * (LED refers to the red LED next to the LCD controller, which may * be under your LCD board if you have it fully sitting on top of the * pebble board) * * Holding buttons 2 and 3 also flip relays 1 and 2 at the frequency of LED * flashing. * * Based on aiko_node and others: Copyright (c) * 2009 by Geekscape Pty. Ltd. Documentation: * http://groups.google.com/group/aiko-platform Documentation: * http://geekscape.org/static/arduino.html License: GPLv3. * http://geekscape.org/static/arduino_license.html Version: 0.3 * --------------------------------------------------------------------- * See Google Docs: "Project: Aiko: Stream protocol specification" * Currently requires an Aiko-Gateway. * --------------------------------------------------------------------- * * Third-Party libraries * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * These libraries are not included in the Arduino IDE and need to be * downloaded and installed separately. * * - LiquidCrystal (now included as part of Arduino 0017 onwards) * http://arduino.cc/en/Reference/LiquidCrystal * * - One-Wire (look for "most recent version" text for download link) * http://www.arduino.cc/playground/Learning/OneWire * * - NewSoftSerial (download is at the bottom of the web page) * http://arduiniana.org/libraries/newsoftserial * * - PString http://arduiniana.org/libraries/pstring * */ #include #include #include using namespace Aiko; using namespace Device; #define PIN_LCD_STROBE 2 // CD4094 8-bit shift/latch #define PIN_LCD_DATA 3 // CD4094 8-bit shift/latch #define PIN_LCD_CLOCK 4 // CD4094 8-bit shift/latch #define PIN_ONE_WIRE 5 #define PIN_LIGHT_SENSOR 0 #define LED_PIN 13 #define PIN_RELAY_1 6 #define PIN_RELAY_2 7 byte relay1State = LOW; byte relay2State = LOW; // -------------------------- #include OneWire oneWire(PIN_ONE_WIRE); // Maxim DS18B20 temperature sensor byte oneWireInitialized = false; #define ONE_WIRE_COMMAND_READ_SCRATCHPAD 0xBE #define ONE_WIRE_COMMAND_START_CONVERSION 0x44 #define ONE_WIRE_COMMAND_MATCH_ROM 0x55 #define ONE_WIRE_COMMAND_SKIP_ROM 0xCC #define ONE_WIRE_DEVICE_18B20 0x28 #define ONE_WIRE_DEVICE_18S20 0x10 int temperature_whole = 0; int temperature_fraction = 0; // -------------------------- void setup() { Serial.begin(38400); pinMode(PIN_RELAY_1, OUTPUT); pinMode(PIN_RELAY_2, OUTPUT); Events.addHandler(clockHandler, 1000); Events.addHandler(temperatureSensorHandler, 1100); Events.addHandler(potentiometerHandler, 100); Events.addHandler(LDRHandler, 100); Events.addHandler(buttonHandler, 100); Events.addHandler(buttonHandler2, 100); Events.addHandler(TimeLCDHandler, 1000); Events.addHandler(MiscLCDHandler, 100); // handler will toggle relay if button 2 or 3 is held for an average of .5s // Let's do better and call it at the time our LED flashes so that we // can vary the speed // Events.addHandler(pebbleRelayHandler, 500); Events.addHandler(pebbleLCDLEDHandler, 100); Events.addHandler(blinkHandler, 50); } void loop() { Events.loop(); } byte LedLEDFlashMode = 0; int ldr; byte second = 0; byte minute = 0; byte hour = 0; void clockHandler(void) { if ((++ second) == 60) { second = 0; if ((++ minute) == 60) { minute = 0; if ((++ hour) == 100) hour = 0; // Max: 99 hours, 59 minutes, 59 seconds } } } void LDRHandler(void) { ldr = analogRead(PIN_LIGHT_SENSOR); } /* -------------------------------------------------------------------------- */ /* LCD KS0066 4-bit data interface, 3 Arduino pins and MC14094 8-bit register * http://www.datasheetsite.com/datasheet/KS0066 * * MC14094 input: Arduino digital pin 2=Clock, pin 4=Data, pin 7=Strobe * MC14094 output: Q8=DB4, Q7=DB5, Q6=DB6, Q5=DB7, Q4=E, Q3=RW, Q2=RS, Q1=None * http://www.ee.mut.ac.th/datasheet/MC14094.pdf * * +--------------------------------------------+ * | Arduino (ATMega 168 or 328) | * | D02 D03 D04 | * +----+-------------+-------------+-----------+ * |4 |5 |6 * |1 |2 |3 * +----+-------------+-------------+-----------+ * | Strobe Data Clock | * | MC14094 8-bit shift/latch register | * | Q8 Q7 Q6 Q5 Q4 Q3 Q2 Q1 | * +----+----+----+----+----+----+----+----+----+ * |11 |12 |13 |14 |7 |6 |5 |4 * |11 |12 |13 |14 |6 |5 |4 * +----+----+----+----+----+----+----+---------+ * | DB4 DB5 DB6 DB7 E RW RS | * | LCD KS0066 | * +--------------------------------------------+ */ byte lcdInitialized = false; int pebbleLedStatus = true; int LEDFlashLoopCounter=0; // LCD pin bit-patterns, output from MC14094 -> LCD KS0066 input #define LCD_ENABLE_HIGH 0x10 // MC14094 Q4 -> LCD E #define LCD_ENABLE_LOW 0xEF // Enable (high) / Disable (low) #define LCD_RW_HIGH 0x20 // MC14094 Q3 -> LCD RW #define LCD_RW_LOW 0xDF // Read (high) / Write (low) #define LCD_RS_HIGH 0x40 // MC14094 Q2 -> LCD RS #define LCD_RS_LOW 0xBF // Data (high) / Instruction (low) Select // LCD Commands #define LCD_COMMAND_CLEAR 0x01 // Clear display #define LCD_COMMAND_HOME 0x02 // Set DD RAM address counter to (0, 0) #define LCD_COMMAND_ENTRY_SET 0x06 // Entry mode set #define LCD_COMMAND_DISPLAY_SET 0x0C // Display on/off control #define LCD_COMMAND_FUNCTION_SET 0x28 // Function set #define LCD_COMMAND_SET_DDRAM_ADDRESS 0x80 // Set DD RAM address counter (row, column) #define LCD_SECOND_ROW 0x40 // Second row literal byte lcdSetup[] = { // LCD command, delay time in milliseconds LCD_COMMAND_HOME, 50, // wait for LCD controller to be initialized LCD_COMMAND_HOME, 50, // ditto LCD_COMMAND_FUNCTION_SET, 1, // 4-bit interface, 2 display lines, 5x8 font LCD_COMMAND_DISPLAY_SET, 1, // turn display on, cursor off, blinking off LCD_COMMAND_CLEAR, 2, // clear display LCD_COMMAND_ENTRY_SET, 1 // increment mode, display shift off }; void lcdInitialize(void) { pinMode(PIN_LCD_CLOCK, OUTPUT); pinMode(PIN_LCD_DATA, OUTPUT); pinMode(PIN_LCD_STROBE, OUTPUT); byte length = sizeof(lcdSetup) / sizeof(*lcdSetup); byte index = 0; while (index < length) { lcdWrite(lcdSetup[index ++], false); delay(lcdSetup[index ++]); } lcdInitialized = true; } void lcdWrite( byte value, byte dataFlag) { digitalWrite(PIN_LCD_STROBE, LOW); byte output = value >> 4; // Most Significant Nibble if (dataFlag) output = (output | LCD_RS_HIGH) & LCD_RW_LOW; // Command or Data ? for (byte loop1 = 0; loop1 < 2; loop1 ++) { // First MSN, then LSN for (byte loop2 = 0; loop2 < 3; loop2 ++) { // LCD ENABLE LOW -> HIGH -> LOW output = (loop2 == 1) ? (output | LCD_ENABLE_HIGH) : (output & LCD_ENABLE_LOW); // The Pebble has a status LED on an unused pin of the LCD controller. // This is how you toggle it -- merlin if (pebbleLedStatus) { output = output | 0x80; } else { output = output & 0x7F; } shiftOut(PIN_LCD_DATA, PIN_LCD_CLOCK, LSBFIRST, output); digitalWrite(PIN_LCD_STROBE, HIGH); delayMicroseconds(10); digitalWrite(PIN_LCD_STROBE,LOW); } delay(1); output = value & 0x0F; // Least Significant Nibble if (dataFlag) output = (output | LCD_RS_HIGH) & LCD_RW_LOW; // Command or Data ? } } void lcdClear(void) { lcdWrite(LCD_COMMAND_CLEAR, false); delay(2); } // First 2 rows are 0 and 1. // Last 2 rows are 0 offset 20 and 1 offset 20. void lcdPosition( byte row, byte column) { if (row == 1) row = LCD_SECOND_ROW; lcdWrite(LCD_COMMAND_SET_DDRAM_ADDRESS | row | column, false); delayMicroseconds(40); } void lcdWriteString( char message[]) { while (*message) lcdWrite((*message ++), true); } // checks out how many digits there are in a number int estimateDigits(int nr) { int dec = 10; int temp = 1; int div = nr/dec; while (div > 0) { dec *= 10; div = nr/dec; temp++; } return temp; } // Raise number to power int pow(int base, int expo) { int temp = 1; for (int c = 1; c <= expo; c++) { temp *= base; } return temp; } // this function help us to write numbers // with more than one digit void lcdWriteNumber(int nr, int digits) { for (int i = digits-1; i >= 0; i--) { int dec = pow(10,i); int div = nr/dec; lcdWrite(div+48, true); if (div > 0) { nr -= div*dec; } } } void lcdWriteNumber(int nr) { int value = nr; if (value < 0) { lcdWrite('-', true); value = - nr; } int digits = estimateDigits(value); lcdWriteNumber(value, digits); } void temperatureSensorHandler(void) { // total time: 33 milliseconds byte address[8]; byte data[12]; byte index; if (! oneWire.search(address)) { // time: 14 milliseconds // Serial.println("(error 'No more one-wire devices')"); oneWire.reset_search(); // time: <1 millisecond return; } if (OneWire::crc8(address, 7) != address[7]) { // sendMessage("(error 'Address CRC is not valid')"); return; } if (address[0] != ONE_WIRE_DEVICE_18B20) { // sendMessage("(error 'Device is not a DS18B20')"); return; } if (oneWireInitialized) { byte present = oneWire.reset(); // time: 1 millisecond oneWire.select(address); // time: 5 milliseconds oneWire.write(ONE_WIRE_COMMAND_READ_SCRATCHPAD); // time: 1 millisecond for (index = 0; index < 9; index++) { // time: 5 milliseconds data[index] = oneWire.read(); } if (OneWire::crc8(data, 8) != data[8]) { // sendMessage("(error 'Data CRC is not valid')"); return; } int temperature = (data[1] << 8) + data[0]; int signBit = temperature & 0x8000; if (signBit) temperature = (temperature ^ 0xffff) + 1; // 2's complement int tc_100 = (6 * temperature) + temperature / 4; // multiply by 100 * 0.0625 temperature_whole = tc_100 / 100; temperature_fraction = tc_100 % 100; Serial.print("(temperature "); if (signBit) Serial.print("-"); Serial.print(temperature_whole); Serial.print("."); if (temperature_fraction < 10) Serial.print("0"); Serial.print(temperature_fraction); Serial.println(" C)"); lcdPosition(1, 0); lcdWriteString("Temperature: "); lcdWriteNumber((int) temperature_whole); lcdWriteString("."); if (temperature_fraction < 10) lcdWriteString("0"); lcdWriteNumber((int) temperature_fraction); lcdWriteString(" C"); } // Start temperature conversion with parasitic power oneWire.reset(); // time: 1 millisecond oneWire.select(address); // time: 5 milliseconds oneWire.write(ONE_WIRE_COMMAND_START_CONVERSION, 1); // time: 1 millisecond // Must wait at least 750 milliseconds for temperature conversion to complete oneWireInitialized = true; } void TimeLCDHandler(void) { if (lcdInitialized == false) { lcdInitialize(); lcdClear(); } lcdPosition(0, 2); lcdWriteString("Clock:"); lcdPosition(0, 8); if (hour < 10) lcdWriteString("0"); lcdWriteNumber((int) hour); lcdWriteString(":"); if (minute < 10) lcdWriteString("0"); lcdWriteNumber((int) minute); lcdWriteString(":"); if (second < 10) lcdWriteString("0"); lcdWriteNumber((int) second); } void MiscLCDHandler(void) { lcdPosition(0, 20); lcdWriteString("Pot: "); lcdWriteNumber(potentiometerValue); if (potentiometerValue < 10) lcdWriteString(" "); if (potentiometerValue < 100) lcdWriteString(" "); if (potentiometerValue < 1000) lcdWriteString(" "); lcdPosition(0, 30); lcdWriteString("But: "); //lcdWriteNumber(buttonValue); lcdWriteString(buttonstr); lcdPosition(1, 20); lcdWriteString("Light: "); lcdWriteNumber(ldr); lcdWriteString(" "); lcdPosition(1, 32); // Show whether flash speed is based on LDR or Potentiometer if (LedLEDFlashMode == 0) lcdWriteString("LED: LDR"); if (LedLEDFlashMode == 1) lcdWriteString("LED: Pot"); static boolean on = HIGH; digitalWrite(LED_PIN, on); on = !on; } void pebbleLCDLEDHandler(void) { int LEDFlashSource = potentiometerValue; LEDFlashLoopCounter++; if (LedLEDFlashMode == 0) LEDFlashSource = ldr; // 0 -> 1024 goes to 0 -> 16 LEDFlashSource /= 64; if (LEDFlashLoopCounter % (16 - LEDFlashSource) == 0) { pebbleLedStatus = !pebbleLedStatus; // write a dummy character off screen to toggle the LED lcdPosition(0, 19); lcdWriteString(" "); pebbleRelayHandler(); } } void buttonHandler2(void) { if (buttons[0]) { second = 0; minute = 0; hour = 0; } if (buttons[1]) { // flash frequency is light sensitive LedLEDFlashMode = 0; } if (buttons[2]) { // flash frequency is controlled by potar LedLEDFlashMode = 1; } } void pebbleRelayHandler(void) { if (buttons[1]) { relay1State = ! relay1State; digitalWrite(PIN_RELAY_1, relay1State); } if (buttons[2]) { relay2State = ! relay2State; digitalWrite(PIN_RELAY_2, relay2State); } }