All, suggestions please how I can figure this problem.
I have an ATtiny84 continuously monitoring some weather sensors. It is also an i2c slave, communicating the readings back to the master which happens to be a WeMos d1 mini, which is essentially an ESP8266-12E.
Every few seconds, the master requests the readings by sending a 1-byte code. The slave responds with 8 bytes of sensor data. This works well for anything from 30s to 1~2 mins before the problem occurs. Then the data gets messed up, and stays that way for a similar period, before either righting itself again, or getting even more messed up. Bytes in the data get shunted into the wrong sequence, as though one or more extra bytes have been inserted or lost
Some background: I have been using the WeMos very successfully with several other types of i2c sensor (Bmp180 etc) without and sign of this issue. The weather sensors are of a simple type, involving magnets & reed switches, so they are really just like push-buttons. I have tried 4K7 pull-ups on SDA & SCL, and without, it makes no difference. The i2c lines less than 100mm long.
Slave/tiny84 sketch:
/*
* Weather Station i2c Slave
* PaulRB
* March 2016
*/
#include "TinyWireS.h"
//#include <avr/sleep.h>
#define I2C_SLAVE_ADDR 0x26
#define WIND_DIR_SENSOR A3
#define WIND_SENSOR_ENABLE 1
#define WIND_SPEED_SENSOR 2
#define RAIN_SENSOR 0
#define LED_BUILTIN 8
long windDirTot;
int windDirCount;
int windDirPrev;
int windDir;
int rainRate;
int windSpeed;
int windSpeedCount = 0;
int windGustCount = 0;
int prevWindSpeedSensor = HIGH;
int prevRainSensor = HIGH;
unsigned long maxWindGust;
unsigned long lastWindGustTime;
unsigned long lastWindDirTime;
int rainCount;
unsigned long lastReportTime;
int readingNow;
const int reading[] = {158, 183, 221, 297, 387, 459, 556, 652, 741, 812, 850, 904, 945, 975, 985, 1023};
const int compass[] = {292, 247, 270, 337, 315, 22, 0, 202, 225, 67, 45, 157, 180, 112, 135, 90};
void setup() {
//bitSet(PRR, PRTIM1); // power-off Timer 1
//set_sleep_mode(SLEEP_MODE_IDLE);
pinMode(WIND_SENSOR_ENABLE, OUTPUT);
pinMode(LED_BUILTIN, OUTPUT);
TinyWireS.begin(I2C_SLAVE_ADDR);
}
void loop() {
unsigned long timeNow = millis();
// Check for request from i2c master
if (TinyWireS.available() > 0) {
// Read the request, discard
while (TinyWireS.available() > 0) TinyWireS.receive();
// Send all sensor data to master
TinyWireS.send(highByte(windDir));
TinyWireS.send(lowByte(windDir));
TinyWireS.send(highByte(windSpeed));
TinyWireS.send(lowByte(windSpeed));
TinyWireS.send(highByte(maxWindGust));
TinyWireS.send(lowByte(maxWindGust));
TinyWireS.send(highByte(rainRate));
TinyWireS.send(lowByte(rainRate));
}
// Check windspeed sensor
pinMode(WIND_SPEED_SENSOR, INPUT_PULLUP);
if (digitalRead(WIND_SPEED_SENSOR) != prevWindSpeedSensor) {
windSpeedCount++;
windGustCount++;
prevWindSpeedSensor = !prevWindSpeedSensor;
}
pinMode(WIND_SPEED_SENSOR, INPUT);
// Check rain sensor
pinMode(RAIN_SENSOR, INPUT_PULLUP);
if (digitalRead(RAIN_SENSOR) != prevRainSensor) {
rainCount++;
prevWindSpeedSensor = !prevWindSpeedSensor;
}
pinMode(RAIN_SENSOR, INPUT);
// Time to check for wind gust?
unsigned long windGustPeriod = timeNow - lastWindGustTime;
if (windGustPeriod >= 3000) {
//digitalWrite(LED_BUILTIN, HIGH);
lastWindGustTime += 3000;
// Calculate wind gust speed, in Km/hr, over period of 6s
// Note: 1 rotation per second = 2.4 Km/hr
// 2 rising edges per rotation, so 1 rising edge per millisecond = 1,200 Km/hr
unsigned long windGustSpeed;
if (windGustPeriod > 0) windGustSpeed = 1200UL * windGustCount / windGustPeriod; else windGustSpeed = 0;
// New highest wind gust?
if (windGustSpeed > maxWindGust) maxWindGust = windGustSpeed;
// Zero gust count for next period
windGustCount = 0;
//digitalWrite(LED_BUILTIN, LOW);
}
// Time to check wind direction sensor?
if (timeNow - lastWindDirTime >= 100) {
lastWindDirTime += 100;
// Enable sensor only to take reading. Reduces current
bitClear(PRR, PRADC); // power-on ADC
bitSet(ADCSRA, ADEN); // Enable ADC
digitalWrite(WIND_SENSOR_ENABLE, HIGH);
readingNow = analogRead(WIND_DIR_SENSOR);
digitalWrite(WIND_SENSOR_ENABLE, LOW);
bitClear(ADCSRA, ADEN); // Disable ADC
bitSet(PRR, PRADC); // power-off ADC
// Translate analog reading into compass direction
// Can be one of 16 values, but there could be some
// analog noise, so the reading[] array contains values
// mid-way between the possible readings.
int i;
for (i = 0; i < 16 && readingNow >= reading[i]; i++);
int windDirNow = compass[i];
// Check if sensor has swept through 0 degrees, moving in either direction
if (windDirNow - windDirPrev > 180) windDirNow -= 360;
if (windDirPrev - windDirNow > 180) windDirNow += 360;
// Update total and count of data points for calculating average
windDirTot += windDirNow;
windDirCount++;
windDirPrev = windDirNow;
}
// Time to update the report?
unsigned long reportPeriod = timeNow - lastReportTime;
if (reportPeriod >= 30000UL) {
// Calculate time since last report was sent
lastReportTime += 30000UL;
// Calculate average wind direction over the reporting period
if (windDirCount > 0) windDir = windDirTot / windDirCount; else windDir = 0;
while (windDir >= 360) windDir -= 360;
while (windDir < 0) windDir += 360;
// Zero the count & total for next period
windDirTot = 0;
windDirCount = 0;
// Calcualate average wind speed, in Km/hr, over reporting period
// Note: 1 rotation per second = 2.4 Km/hr
// 2 rising edges per rotation, so 1 rising edge per millisecond = 1,200 Km/hr
if (reportPeriod > 0) windSpeed = 1200UL * windSpeedCount / reportPeriod; else windSpeed = 0;
// Zero wind speed sensor count for next period
windSpeedCount = 0;
// Report highest wind gust speed, in Km/hr, over reporting period
// Zero max wind gust for next reporting period
maxWindGust = 0;
// Report rainfall rate in mm/hr
// One count = 0.011" of rain
// One count per millisecond = 0.011 * 25.4 * 1000 * 60 * 60 = 1005840mm/hr
if (reportPeriod > 0) rainRate = 1005840UL * rainCount / reportPeriod; else rainRate = 0;
// Zero rain sensor count for next period
rainCount = 0;
}
//sleep_enable();
//sleep_mode(); // System actually sleeps here
//sleep_disable(); // System continues execution here
}