Hi,
I'm using an Attiny85 to count reed switch pulses on 2 pins, then pass the values via I2c to my ESP8266. It's all running off battery so it goes to sleep until one of the pins wakes up via interrupt.
When I get a high pulse frequency on one of the pins, my Master fails to correctly read the I2C. From doing lots of reading online I think it's due to clash between the pin change interrupt and I2C interrupt, but I'm still very new to this and although I've guessed (probably wrongly!) the problem, I don't know how to solve it.
Here is my slave code - is anybody able to have a look and point out what's probably and obvious error to the educated?
// Code for the ATtiny85
#include <TinyWireS.h>
#define I2C_SLAVE_ADDRESS 0x4 // Address of the slave
#include <avr/sleep.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>
const int rainPin = 3; // which pin is rain sensor connected to
const int windPin = 4; // which pin is wind sensor connected to
const int statusLED = 1; //which pin is status LED connected to
const byte chksum1 = 123;
const byte chksum2 = 210;
volatile unsigned int raincount = 0;
volatile unsigned int windcount = 0;
volatile bool thiswind;
volatile bool lastwind = HIGH;
volatile bool thisrain;
volatile bool lastrain = HIGH;
volatile int response=0;
bool debug=false;
volatile int senddata = 1;
void reboot() {
cli();
WDTCR = 0xD8 | WDTO_1S;
sei();
wdt_reset();
while (true) {}
} //reboot
void setup()
{
MCUSR &= ~(1<<WDRF); // reset status flag
wdt_disable();
tws_delay(100);
TinyWireS.begin(I2C_SLAVE_ADDRESS); // join i2c network
TinyWireS.onReceive(receiveEvent);
TinyWireS.onRequest(requestEvent);
pinMode(rainPin, INPUT);
digitalWrite(rainPin, HIGH);
pinMode(windPin, INPUT);
digitalWrite(windPin, HIGH);
//pinMode(statusLED, OUTPUT);
if (debug) {
digitalWrite(statusLED, HIGH);
tws_delay(1000);
digitalWrite(statusLED,LOW);
}
} // setup
void sleep() {
GIMSK |= _BV(PCIE); // Enable Pin Change Interrupts
PCMSK |= _BV(PCINT3); // Use PB3 as interrupt pin
PCMSK |= _BV(PCINT4); // Use PB4 as interrupt pin
ADCSRA &= ~_BV(ADEN); // ADC off
//WDTCR &= ~_BV(WDIE); // DISABLE WATCHDOG ***************PMN HERE*********************
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // replaces above statement
sleep_enable(); // Sets the Sleep Enable bit in the MCUCR Register (SE BIT)
sei(); // Enable interrupts
sleep_cpu(); // sleep
cli(); // Disable interrupts
PCMSK &= ~_BV(PCINT3); // Turn off PB3 as interrupt pin
PCMSK &= ~_BV(PCINT4); // Turn off PB4 as interrupt pin
sleep_disable(); // Clear SE bit
ADCSRA |= _BV(ADEN); // ADC on
//WDTCR |= _BV(WDIE); // Watchdog on
sei(); // Enable interrupts
} // sleep
ISR(PCINT0_vect) {
// DO NOTHING HERE, CATCH EVERYTHING IN LOOP // Count rain gauge bucket tips as they occur
thisrain = digitalRead(rainPin);
if (thisrain != lastrain) { //check if value has changed since last time
if (digitalRead (rainPin) == LOW) {
raincount ++;
//Serial.print("Rain");
}
lastrain = thisrain;
}
thiswind = digitalRead(windPin);
if (thiswind != lastwind) { //check if value has changed since last time
if (digitalRead(windPin) == HIGH) { //value has changed - was it rising edge?
windcount ++;
//Serial.print("Wind");
}
lastwind = thiswind; //switch state ready for next time
}
}
void loop()
{
// This needs to be here
TinyWireS_stop_check();
// Go back to sleep
sleep();
tws_delay(1);
}
// Gets called when the ATtiny receives an i2c request
void requestEvent()
{
/*
TinyWireS.send(chksum1);
TinyWireS.send(lowByte(raincount));
TinyWireS.send(highByte(raincount));
TinyWireS.send(lowByte(windcount));
TinyWireS.send(highByte(windcount));
TinyWireS.send(chksum2);
raincount = 0;
windcount = 0;
*/
// cli();
switch (senddata) {
case 1:
TinyWireS.send(chksum1);
senddata = 2;
break;
case 2:
TinyWireS.send(lowByte(raincount));
senddata = 3;
break;
case 3:
TinyWireS.send(highByte(raincount));
//raincount = 0;
senddata = 4;
break;
case 4:
TinyWireS.send(lowByte(windcount));
senddata = 5;
break;
case 5:
TinyWireS.send(highByte(windcount));
//windcount = 0;
senddata = 6;
break;
case 6:
TinyWireS.send(chksum2);
senddata = 1;
break;
default:
TinyWireS.send(111);
senddata=1;
}
//sei();
}
// Gets called when the ATtiny receives an i2c write slave request
void receiveEvent(uint8_t howMany)
{
cli();
for(int i = 0; i < howMany; i++)
{
// Transmission codes:
// 1 = Reset Rain Sensor
// 2 = Reset Wind Sensor
// 3 = Reboot Rain Sensor
while(TinyWireS.available())
{
response = TinyWireS.receive();
if (response == 1){
raincount = 0;
}
else if (response == 2){
windcount = 0;
}
else if (response == 3) {
reboot();
}
else if (response == 4) {
senddata=1;
}
else {
// DO NOTHING
}
}
}
sei();
}