I have tested most of the pieces seperately, however I have run into a problem with the Wire.onReceive event, established to identify when data is received from the I2C master, ceasing to function properly when I enable the RTC code.
The code (with RTC related code commented out) is as follows:
Code: Select all
//
// WiFi Web server display of LIDAR-Lite data (float) recieved via I2C master
// Web-based control of LED via PIN 9
// PCF8523 RTC with adjustment via UDP over WiFi - Currently disabled due to interrupt conflict
// SD logging to WiFi shield w/timestamp - Currently not implemented
// I2C Slave: Adafruit Metro M0 Express, Adafruit WINC1500 WiFi shield, RTC PFC8523
// I2C master: Arduino Uno, LCD Keypad shield, Lidar-Lite
#include <SPI.h>
#include <WiFi101.h>
#include <WiFiUdp.h>
#include <Wire.h>
#include "I2C_Anything.h"
#include "arduino_secrets.h"
//#include "RTClib.h"
//#include <SD.h>
const byte MY_ADDRESS = 2; // Local I2C address
const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message
//const int chipSelect = 4; // CS for SD card
const char* ntpServerName = "time.nist.gov";
char ssid[] = SECRET_SSID; // Network SSID (name)
char pass[] = SECRET_PASS; // Network password (use for WPA, or use as key for WEP)
//char filename[] = "00000000.CSV";
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"};
int keyIndex = 0; // Network key Index number (needed only for WEP)
int status = WL_IDLE_STATUS;
int lastTime = -1;
int lastTime2 = -1;
unsigned int localPort = 8888; // Local port to listen for UDP packets
byte packetBuffer[ NTP_PACKET_SIZE]; // Buffer to hold incoming and outgoing packets
volatile boolean haveData = false;
volatile float length;
IPAddress timeServerIP; // time.nist.gov NTP server address
WiFiServer server(80); // Web server address
WiFiUDP udp;
//RTC_PCF8523 rtc;
void setup()
{
Wire.begin(MY_ADDRESS); // Join i2c bus with address #8
Wire.onReceive(receiveEvent); // Register event for I2C communications (Arduino to Arduino)
Serial.begin(57600); // initialize serial communication
pinMode(9, OUTPUT); // Set the LED control to PIN 9, output
if (WiFi.status() == WL_NO_SHIELD) // Check for the presence of the Adafruit WINC1500 WiFi shield
{
Serial.println("WiFi shield not present");
while (true); // don't continue
}
while ( status != WL_CONNECTED) // attempt to connect to WiFi network:
{
Serial.print("Attempting to connect to Network named: ");
Serial.println(ssid); // Print the network name (SSID);
status = WiFi.begin(ssid, pass); // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
delay(10000); // Wait 10 seconds for connection:
}
printWiFiStatus(); // Connected, so print out the status
getNTPTime();
// initializeRTC();
server.begin(); // Start the web server on port 80
}
void loop()
{
WiFiClient client = server.available(); // listen for incoming clients
if (client) // if you get a client
{
Serial.println("Incoming HTTP client"); // print a message out the serial port
String currentLine = ""; // make a String to hold incoming data from the client
while (client.connected()) { // loop while the client's connected
if (client.available()) { // if there's bytes to read from the client,
char c = client.read(); // read a byte, then
Serial.write(c); // print it out the serial monitor
if (c == '\n') { // if the byte is a newline character
// if the current line is blank, you got two newline characters in a row.
// that's the end of the client HTTP request, so send a response:
if (currentLine.length() == 0)
{
client.println("HTTP/1.1 200 OK"); // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
client.println("Content-type:text/html"); // Send a content-type so the client knows what's coming
client.println("Connection: close"); // the connection will be closed after completion of the response
client.println("Refresh: 5"); // refresh the page automatically every 5 sec
client.println(); // Blank line
// the content of the HTTP response follows the header:
client.print("<br>Click <a href=\"/H\">here</a> turn the LED on pin 9 on<br>");
client.print("Click <a href=\"/L\">here</a> turn the LED on pin 9 off<br>");
if (haveData)
{
client.print("<br>LIDAR-Lite distance = ");
client.print(length);
haveData = false;
} // end if haveData
// The HTTP response ends with another blank line:
client.println();
// break out of the while loop:
break;
}
else { // if you got a newline, then clear currentLine:
currentLine = "";
}
}
else if (c != '\r') { // if you got anything else but a carriage return character,
currentLine += c; // add it to the end of the currentLine
}
// Check to see if the client request was "GET /H" or "GET /L":
if (currentLine.endsWith("GET /H")) {
digitalWrite(9, HIGH); // GET /H turns the LED on
}
if (currentLine.endsWith("GET /L")) {
digitalWrite(9, LOW); // GET /L turns the LED off
}
}
}
client.stop(); // close the connection:
Serial.println("client disconnected");
}
}
void printWiFiStatus()
{
Serial.print("SSID: "); // print the SSID of the network you're attached to
Serial.println(WiFi.SSID());
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: "); // print your WiFi shield's IP address
Serial.println(ip);
long rssi = WiFi.RSSI();
Serial.print("signal strength (RSSI):"); // print the received signal strength:
Serial.print(rssi);
Serial.println(" dBm");
Serial.print("To view server, open a browser at http://"); // print where to go in a browser:
Serial.println(ip);
}
void receiveEvent (int howMany) // called by interrupt service routine when incoming data arrives
{
if (howMany >= (sizeof length))
{
I2C_readAnything (length);
haveData = true;
} // end if have enough data
} // end of receiveEvent
unsigned long sendNTPpacket(IPAddress& address) // send an NTP request to the time server at the given address
{
Serial.println("sending NTP packet...");
memset(packetBuffer, 0, NTP_PACKET_SIZE); // set all bytes in the buffer to 0
// Initialize values needed to form NTP request
// (see URL above for details on the packets)
packetBuffer[0] = 0b11100011; // LI, Version, Mode
packetBuffer[1] = 0; // Stratum, or type of clock
packetBuffer[2] = 6; // Polling Interval
packetBuffer[3] = 0xEC; // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion
packetBuffer[12] = 49;
packetBuffer[13] = 0x4E;
packetBuffer[14] = 49;
packetBuffer[15] = 52;
// all NTP fields have been given values, now
// you can send a packet requesting a timestamp:
udp.beginPacket(address, 123); //NTP requests are to port 123
udp.write(packetBuffer, NTP_PACKET_SIZE);
udp.endPacket();
}
void getNTPTime()
{
Serial.println("Starting UDP");
udp.begin(localPort);
Serial.print("Local port: ");
Serial.println(localPort);
WiFi.hostByName(ntpServerName, timeServerIP);
sendNTPpacket(timeServerIP); // send an NTP packet to a time server
delay(2000); // wait to see if a reply is available
int cb = udp.parsePacket();
if (!cb) {
Serial.println("no packet yet");
}
else {
Serial.print("packet received, length="); // We've received a packet, read the data from it
Serial.println(cb);
udp.read(packetBuffer, NTP_PACKET_SIZE); // Read the packet into the buffer
unsigned long highWord = word(packetBuffer[40], packetBuffer[41]); // The timestamp starts at byte 40 of the received packet and is four bytes,
unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]); // or two words, long. First, extract the two words:
unsigned long secsSince1900 = highWord << 16 | lowWord; // Combine the four bytes (two words) into a long integer
Serial.print("Seconds since Jan 1 1900 = " ); // This is NTP time (seconds since Jan 1 1900):
Serial.println(secsSince1900);
// now convert NTP time into everyday time:
Serial.print("Unix time = ");
const unsigned long seventyYears = 2208988800UL; // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
unsigned long epoch = secsSince1900 - seventyYears; // subtract seventy years:
Serial.println(epoch); // print Unix time:
// print the hour, minute and second:
Serial.print("The UTC time is "); // UTC is the time at BANNED Meridian (GMT)
Serial.print((epoch % 86400L) / 3600); // print the hour (86400 equals secs per day)
Serial.print(':');
if ( ((epoch % 3600) / 60) < 10 )
{
Serial.print('0'); // In the first 10 minutes of each hour, we'll want a leading '0'
}
Serial.print((epoch % 3600) / 60); // print the minute (3600 equals secs per minute)
Serial.print(':');
if ( (epoch % 60) < 10 )
{
Serial.print('0'); // In the first 10 seconds of each minute, we'll want a leading '0'
}
Serial.println(epoch % 60); // print the second
Serial.print("Pacific time is "); // UTC is the time at BANNED Meridian (GMT)
Serial.print(((epoch % 86400L) / 3600) - 7); // print the hour (86400 equals secs per day)
Serial.print(':');
if ( ((epoch % 3600) / 60) < 10 )
{
Serial.print('0'); // In the first 10 minutes of each hour, we'll want a leading '0'
}
Serial.print((epoch % 3600) / 60); // print the minute (3600 equals secs per minute)
Serial.print(':');
if ( (epoch % 60) < 10 )
{
Serial.print('0'); // In the first 10 seconds of each minute, we'll want a leading '0'
}
Serial.println(epoch % 60); // print the second
}
}
//void initializeRTC()
//{
// if (! rtc.begin())
// {
// Serial.println("Couldn't find RTC");
// }
// if (! rtc.initialized()) {
// Serial.println("RTC is NOT running!");
// // following line sets the RTC to the date & time this sketch was compiled
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// // This line sets the RTC with an explicit date & time, for example to set
// // January 21, 2014 at 3am you would call:
// // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
// }
//}
I checked the RTC library and verified that the I2C address used for the RTC is 68, which does not conflict with any of the other devices (Metro (2), Arduino (1), LIDAR-Lite (62)) communicating on the I2C bus.
Any assistance with identifying why the event callbacks are broken when using the RTC would be greatly appreciated.
Rob
PS: I could include code running on the I2C master, however it is also using the I2C_Anything.h code written by Nick Gammon to put the float on the I2C bus.
Code: Select all
// Written by Nick Gammon
// May 2012
#include <Arduino.h>
#include <Wire.h>
template <typename T> int I2C_writeAnything (const T& value)
{
const byte * p = (const byte*) &value;
unsigned int i;
for (i = 0; i < sizeof value; i++)
Wire.write(*p++);
return i;
} // end of I2C_writeAnything
template <typename T> int I2C_readAnything(T& value)
{
byte * p = (byte*) &value;
unsigned int i;
for (i = 0; i < sizeof value; i++)
*p++ = Wire.read();
return i;
} // end of I2C_readAnything