Hardware:
I have a Uno INT0 connected to a radar sensor digital output active high. Interrupt is attached to trigger on rising edge.
Also connected in parasitic power mode is two temperature sensors DS18B20.
And one analogue input.
And one radio transcever nRF24L01.
Software:
The test software loop is configured to read analogue input, temperatures and transmit any changed data then sleep. An interrupt means the radar has gone active this is registered as a change in data.
Everything works fine, temperatures are sensed, radar detects movement and radio transmits correct data.
The Problem
When the temperatures are sensed it triggers a radar interrupt.
I have traced the issue to the function call:
sensors.requestTemperatures();
Is there some known reason why the OneWire library would set the interrupt flag for INT0?
In case stray capacitance is coupling a spike on the inerrupt connection I have place a 100nF capacitor to ground.
My intention is to have a longer sleep period hence the need to connect the radar to interrupt sleep.
Any ideas would be most welcome.
Code:
#ifndef CONSTANTS_H_INCLUDED
#define CONSTANTS_H_INCLUDED
#include <Arduino.h>
#include <EEPROM.h>
#include "LowPower.h"
#include "printf.h"
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <DallasTemperature.h>
//--- comment to send dbug info to serial console ------------
#define dbserial //
//-------------------------------------------------------------
// Inputs:
#define ONE_WIRE_BUS 4 // Temperature sensor(s)
#define RADAR_ONE 2 // Radar motion sensor
#define ANALOGUE1 A0
// Outputs:
#define RF_CE 9 // nRF24L01P radio transceiver
#define RF_CSN 10
#define LED_GREEN 6 // LED for status
#define LED_RED 5
#define RADIO_VCC 13 // Radio vcc high = 3.3V, low = 0 Volts
// Macros:
#define GREEN_LED(state) { digitalWrite(LED_GREEN, (state)); }
#define RED_LED(state) { digitalWrite(LED_RED, (state)); }
// Flags
#define FLAG_RADAR_A 0b00000001 ; true means radar active
typedef struct {
byte Flags, // senders id
Batt, // analogue input
TxFails; // failed tx attempts (resets daily)
word TemperatureOne, // temp sensor one deg C x 10
TemperatureTwo; // temp sensor two deg C x 10
bool flagTest(byte fn) { return (Flags & fn) > 0; }
void flagSet(byte fn) { Flags |= fn; }
void flagClear(byte fn) { Flags &= ~fn; }
} TRadioData;
#endif
// main.cpp:
#include "vars.h"
//-- nRF24L01 radio --------------------------------------------
TRadioData radioData, lastRadioData;
typedef struct {
byte baseStationNextTx;
} _radioAckData; // ack data sent back from base station
_radioAckData radioAckData;
RF24 radio(RF_CE, RF_CSN); // (CE, CSN) nRF24L01P radio transceiver
// Write radio pipe.
const uint64_t rfWritePipe = 0xF0F0F0F0D3LL;
//-------------------------------------------------------------
// Setup a oneWire instance to communicate with any OneWire devices
// (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
// temperature sensor device addresses
DeviceAddress temperatureSensor1, temperatureSensor2;
//-------------------------------------------------------------
word
loopCount = 0,
txCount = 0;
void setup() {
pinMode(RADAR_ONE, INPUT_PULLUP);
pinMode(RADIO_VCC, OUTPUT);
pinMode(LED_GREEN, OUTPUT);
pinMode(LED_RED, OUTPUT);
Serial.begin(115200);
delay(10);
printf_begin();
analogReference(EXTERNAL); // REF pin is connected to 3V3
delay(1);
//do A-D readings to avoid errors after changing analogReference
for (int i = 0; i < 10; i++)
analogRead(0);
// Start oneWire library for temperature sensors
sensors.begin();
radio.begin();
// note delay between retries is staggered for outside weather and aux sensor modules
radio.setRetries(15, 15); // (delay between retries 0-15 * 250uS, # retries: 0-15)
radio.setPayloadSize(sizeof(radioData));
// enable ack payloads
radio.enableAckPayload();
// data rate
radio.setDataRate(2); // 0 1Mbps; 1 2Mbps; 2 250kbps
radio.setChannel(0x6c); // default 0x4C (76); F0= 2400 + RF_CH [MHz]
//RF24_PA_MIN=-18dBm, RF24_PA_LOW=-12dBm, RF24_PA_MED=-6dBM, and RF24_PA_HIGH=0dBm
radio.setPALevel(RF24_PA_MAX);
radio.enableAckPayload(); // ack payload contains base station next tx time
radio.openWritingPipe(rfWritePipe);
radio.printDetails();
//-----------------------------------------------------------
analogReference(INTERNAL);
//do A-D readings to avoid errors after changing analogReference
for(int i = 0; i < 10; i++)
analogRead(0);
loopCount = 0;
// get addresses of temperature sensors, we have two temperature sensors
if(sensors.getAddress(temperatureSensor1, 0)) {
} else {
Serial.println("Unable to find address temperature sensor 1");
}
if(sensors.getAddress(temperatureSensor2, 1)) {
} else {
Serial.println("Unable to find address temperature sensor 2");
}
radioData.TemperatureOne = 0;
radioData.TemperatureTwo = 0;
radioData.Batt = 0;
radioData.Flags = 0;
lastRadioData = radioData;
delay(50); // allow time for console output
// connect ISR for radar
attachISRs();
}
void loop() {
loopCount++;
readAnalogueInputs();
// every 10 loops or imediately flags have changed (eg radar detection)
if(loopCount % 10 == 0 || lastRadioData.Flags != radioData.Flags) {
GREEN_LED(HIGH); // high led on
readTemperatures();
GREEN_LED(LOW);
if(!hasDataChanged()) {
delay(1);
} else
{
RED_LED(HIGH);
RadioTx();
RED_LED(LOW);
}
}
LowPower.powerDown(SLEEP_500MS, ADC_OFF, BOD_OFF);
}
bool hasDataChanged() {
return (
lastRadioData.TemperatureOne != radioData.TemperatureOne
|| lastRadioData.TemperatureTwo != radioData.TemperatureTwo
|| lastRadioData.Flags != radioData.Flags
|| lastRadioData.Batt != radioData.Batt
);
}
void readTemperatures() {
// call sensors.requestTemperatures() to issue a global temperature
// request to all devices on the bus
sensors.requestTemperatures(); // CAUSES INTERRUPT! Send the command to get temperatures
radioData.TemperatureOne = sensors.getTempC(temperatureSensor1) * 100;
radioData.TemperatureTwo = sensors.getTempC(temperatureSensor2) * 100;
}
void readAnalogueInputs() {
radioData.Batt = map(analogRead(ANALOGUE1), 0, 1023, 0, 255);
}
void radioVcc(bool on) {
// switch power on to radio module
radio.powerUp();
delay(1);
return;
}
bool RadioTx(void) {
radioVcc(HIGH); // turn vcc to 3.3V
txCount++;
if(radio.write(&radioData, sizeof(radioData))) {
// has base station sent us a command in ack payload?
if(radio.isAckPayloadAvailable()) {
// Process ack command
radio.read(&radioAckData, sizeof(radioAckData));
#ifdef dbserial
printf("Ack payload: %d\n", radioAckData.baseStationNextTx);
#endif
} else {
#ifdef dbserial
printf("Ack without payload\n");
#endif
}
lastRadioData = radioData;
} else {
radioData.TxFails++;
#ifdef dbserial
printf("Radio Tx Fails %d\n", radioData.TxFails);
#endif
return false;
}
radio.powerDown();
radioVcc(LOW); // turn vcc to 0 V
radioData.Flags &= ~FLAG_RADAR_A; // Reset radar flag
lastRadioData.Flags &= ~FLAG_RADAR_A;
return true;
}
void ISRRadar() {
radioData.Flags |= FLAG_RADAR_A;
GREEN_LED(LOW);
RED_LED(HIGH); // test only
Serial.println("."); // test only, yes i know no Serial prints in isr desperate times call for desperate measures
RED_LED(LOW);
}
void attachISRs() {
attachInterrupt(digitalPinToInterrupt(RADAR_ONE), ISRRadar, RISING);
}
void detachISRs() {
detachInterrupt(digitalPinToInterrupt(RADAR_ONE));
}