/* Metronome Program * for Collaborative Mesh Networking class * by Rob Faludi * www.faludi.com * version 1.0.1 */ #include // add the EEPROM library so that time code can periodically be written to non-volatile memory int ledPin = 13; // declare pin for the LED int buzzerPin = 4; // declare a pin for the buzzer int buzzerSwitch = 5; // declare a pin for the buzzer control switch int tickLength = 500; // how long a tick should last, in milliseconds unsigned long sendTime = 0; // used to store the last time a tick was sent int beatCount = 4; // how many beats to count, in a cycle int beat = 0; // used to store the current beat number unsigned long timeCode = 0; // used to store the current time code value int feedbackTimer = 200; // used to set the length of audiovisual feedback, in milliseconds void setup() { pinMode(ledPin, OUTPUT); // initializes LED output pinMode(buzzerPin, OUTPUT); // initialze buzzer output Serial.begin(9600); // turn on the serial port if (tickLength < feedbackTimer) { feedbackTimer = tickLength; // feedback should be no longer than the tick length } blinkLED(ledPin,2,100); setupXBee(); timeCode = EEPROM.read(0); // read the first byte of last stored time code from non-volatile memory timeCode = timeCode + (EEPROM.read(1) << 8); // read the second byte of last stored time code from non-volatile memory timeCode = timeCode + (EEPROM.read(2) << 16); // read the third byte of last stored time code from non-volatile memory timeCode = timeCode + (EEPROM.read(3) << 24); // read the fourth byte of last stored time code from non-volatile memory beat = EEPROM.read(4); // read the last stored beat from non-volatile memory } void loop() { if (millis() - sendTime >= tickLength) { // if it's time to send out a tick... sendTime = millis(); // mark the current time if (timeCode % 100 == 0) { Serial.print("beat: "); Serial.print(beat + 1); // send the current beat number Serial.print(" timecode: "); Serial.print(timeCode +1); // send the current time code Serial.print("\n\r"); } Serial.print("*"); // print the start byte Serial.print(beat+1, BYTE); // print the beat byte Serial.print(timeCode & 0xFF, BYTE); // print first byte of time code Serial.print((timeCode >> 8) & 0xFF, BYTE); // print second byte of time code Serial.print((timeCode >> 16) & 0xFF, BYTE); // print third byte of time code Serial.print((timeCode >> 24) & 0xFF, BYTE); // print fourth byte of time code Serial.print("\n\r"); // finish with carriage return and linefeed if (digitalRead(buzzerSwitch) == HIGH) { // if the buzzer is switched on buzz(buzzerPin, 2500, feedbackTimer/2); // buzz the buzzer at 2500Hz for 1/2 the feedback timer } blinkLED(ledPin,1,feedbackTimer/2); // blink the LED once for the remainder of the feedback timer beat = (beat+1) % beatCount; // iterate the beat count timeCode++; // iterate the time code if (timeCode % 500 == 0) { // only write the time code every few minutes due to limitations on # of read/write cycles EEPROM.write(0, timeCode & 0xFF); // write the first byte of time code to the EEPROM memory on the chip EEPROM.write(1, (timeCode >> 8) & 0xFF); // write the second byte of time code to the EEPROM memory on the chip EEPROM.write(2, (timeCode >> 16) & 0xFF); // write the third byte of time code to the EEPROM memory on the chip EEPROM.write(3, (timeCode >> 24) & 0xFF); // write the fourth byte of time code to the EEPROM memory on the chip EEPROM.write(4, beat); // write the current beat to the EEPROM memory on the chip } } } void setupXBee() { boolean success = false; int ctr = 0; while (success == false && ctr < 100) { // blink the status LED blinkLED(ledPin, 2, 250); // an arbitrary byte to wake up the XBee //Serial.print("X"); //delay(1100); // put the XBee in command mode Serial.print("+++"); delay(1100); // wait for a response from the XBee for 2000 ms, or start // over with setup if no valid response comes // set the PAN (personal area network) ID number // set the MY (16 bit address) // set the Destination High to 0x0 // set the Destination Low (16 bit address) // exit command mode (using a Serial.printLN to end the command with a linefeed) Serial.println("ATRE,ID333A,MY0,DH0,DLFFFF,CN"); if (checkFor("OK", 1000)) { // if an OK was received then continue success = true; } else { success = false; } ctr++; } } ///////////////////////////////// UTILITY FUNCTIONS ////////////////////////////////////////// // this function checks for a specific response on the serial port // it accepts a string to look for and a timeout in milliseconds int checkFor(char* desiredResponse, int timeout) { int result = 0; int length = 40; char incomingResponse[41]; memset(incomingResponse,0,length); // initialize all incomingResponse string positions to null char inByte = NULL; long startTime = millis();//makes the start time = to now char* ptr_incomingResponse = incomingResponse; // while we haven't timed out or gotten back the string that we are looking for while (millis() - startTime < timeout && strstr(incomingResponse,desiredResponse) == NULL ) { //strstr compares strings if (Serial.available() > 0) { // if there are any bytes waiting to be read inByte = Serial.read(); // read one byte if (incomingResponse > ptr_incomingResponse-length) { // if we haven't read in 80 characters yet *ptr_incomingResponse = inByte; // put the byte into the current position in the string ptr_incomingResponse++; // advance to the next position in the string } else { //move the last char to be next to last, and so forth until we reach the end of the array. for (int i = 0; i < length; i++) { incomingResponse[i] = incomingResponse[i+1]; } incomingResponse[length-1] = inByte; // put the byte into the current position in the string } } } if (strstr(incomingResponse,desiredResponse) != NULL ) { // if the desired string is found result = 1; } else { result = 0; } return result; } // this function blinks the an LED light as many times as requested void blinkLED(int targetPin, int numBlinks, int blinkRate) { for (int i=0; i