Hello everybody,
I use a Nodemcu as SPI Master to request data (integer value) from an Arduino Nano (SPI slave).
In order to save power consumption I set the Nano in powerDown mode and put the Nodemcu in reset mode. Every x seconds the Nodemcu wakes up and pulls a digital pin too high that triggers an interrupt at the Nano to wake it up. After a short delay I request the data via SPI.
The communication works very good as long as I do not set the Nano into powerDown mode.
But if I am doing the Nano sends only garbage most of the time (a constant number).
I assume, that the Nano and the Nodemcu are out of sync after waking up.
Is there a way to re-sync them?
//#include <Wire.h>
#include "LowPower.h"
#include <SPI.h>
// Input Pins
const int WakeupPin_ESP8266 = 3;
const int RainCounterPin = 2;
// Debug
#define LEDPin 5
// SPI connection
volatile byte command = 0;
// Rain counter variable
volatile unsigned int RainCounter = 0;
volatile unsigned long lastRainCount = 0;
// RainCounter
bool lastRainState = false;
unsigned long lastCount = 0;
const unsigned long T_debounce_ms = 10;
void setup() {
Serial.begin(115200);
Serial.println("Startup");
// Interrupt (External from ESP8266)
pinMode(WakeupPin_ESP8266, INPUT);
pinMode(RainCounterPin, INPUT);
attachInterrupt(digitalPinToInterrupt(WakeupPin_ESP8266), Wakeup_ISR, RISING);
attachInterrupt(digitalPinToInterrupt(RainCounterPin), Rain_ISR, RISING);
// Debug
pinMode(LEDPin,OUTPUT);
digitalWrite(LEDPin,HIGH);
// Setup SPI
SPI_init();
}
void loop() {
bool AllowSleepRC = false;
bool RainState = digitalRead(RainCounterPin);
if(RainState && !lastRainState && (millis()-lastCount)>T_debounce_ms)
{
// State changed to true
// Count up
lastCount = millis();
RainCounter++;
Serial.print("Rain Counter: ");Serial.println(RainCounter);
}
lastRainState = RainState;
if((millis()-lastCount)>T_debounce_ms && !RainState)
AllowSleepRC = true;
Serial.println(digitalRead(WakeupPin_ESP8266));
bool AllowSleepWU = false;
if (digitalRead(WakeupPin_ESP8266) == LOW)
{
AllowSleepWU = true;
}
if(AllowSleepWU && AllowSleepRC)
{
digitalWrite(LEDPin,LOW);
delay(10);
LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
// SPI_init();
digitalWrite(LEDPin,HIGH);
}
}
// SPI interrupt routine
ISR (SPI_STC_vect)
{
cli();
byte c = SPDR;
if(c=='r')
{
SPDR = RainCounter;
}
sei();
}
void Wakeup_ISR()
{
}
void Rain_ISR()
{
}
void SPI_init()
{
pinMode(MISO, OUTPUT);
SPCR |= bit(SPE); /* Enable SPI */
SPCR |= bit(SPIE);
}
I would like to believe that you have areusing NodeMCU as SPI Master and the sketch you have posted is for the Master. If so, why --
MISO pin is configured as OUTPUT? Should it not be an INPUT line?
Moreover, where is the SS (Slave Select) line of Master? It must be asserted LOW to enable the SPI Port of the Slave.
Where is the SPI.begin() code for the Master to create/enable SPI Port?
Please, post the codes/sketch of NANO.
Hello Golam Mostafa,
thanks for your reply.
In fact this is the code of the Slave (Nano).
The Nano counts the impulses coming from a rain sensor and sends it to the master if requested.
The code in the main loop makes a debouncing of the digital input signal.
So, post the sketch that you have written for NodeMCU-Master.
This is the master code:
#include <Wire.h>
#include <BH1750.h>
// Wifi library
#include <ESP8266WiFi.h>
// SPI connection (to external Arduino)
#include <SPI.h>
// MQTT library
#include <PubSubClient.h>
// DHT22 sensor (temperature / humidity)
#include <Adafruit_Sensor.h>
#include <DHT.h>
#include <DHT_U.h>
// Sensor settings
// Light sensor
BH1750 lightMeter(0x23);
float lux;
// Rain sensor
#define RainSensorWakeupPin D1
// DHT22
#define DHTPIN D2 // Digital pin connected to the DHT sensor
#define DHTTYPE DHT22 // DHT 22 (AM2302)
DHT_Unified dht(DHTPIN, DHTTYPE);
float Temperature;
float Humidity;
bool failureTemperature = false;
bool failureHumidity = false;
// Wifi settings
char ssid[] = "Kabenja"; // your network SSID (name)
char pass[] = "dmkblsmden5e95k"; // your network password
const char* mqtt_server = "192.168.178.25";
// MQTT variables
WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
int value = 0;
// MQTT topics
#define outTopicLux "nodeMCU/WeatherStation/Lux"
#define outTopicTemperature "nodeMCU/WeatherStation/Temp"
#define outTopicHumidity "nodeMCU/WeatherStation/Humidity"
#define outTopicRain "nodeMCU/WeatherStation/Rain"
void setup(){
Serial.begin(115200);
Serial.println("Setup");
Serial.setTimeout(2000);
// Wait for serial to initialize.
while(!Serial) { }
// DHT22 setup
dht.begin();
// Wakeup Pin for Rain Counter
pinMode(RainSensorWakeupPin, OUTPUT);
// SPI
// pinMode(SS, OUTPUT); // DEBUG
// digitalWrite(SS, HIGH); // ensure SS stays high for now
SPI.begin ();
// Slow down the master a bit
// SPI.setClockDivider(SPI_CLOCK_DIV8);
// setup_wifi();
// Wifi Settings
WiFi.mode(WIFI_STA);
WiFi.hostname("ESP8266-WeatherStation");
// Connect or reconnect to WiFi
if(WiFi.status() != WL_CONNECTED){
Serial.print("Attempting to connect to SSID: ");
Serial.println(ssid);
while(WiFi.status() != WL_CONNECTED){
WiFi.begin(ssid, pass); // Connect to WPA/WPA2 network. Change this line if using open or WEP network
Serial.print(".");
delay(5000);
}
Serial.println("\nWifi Connected.");
}
// Initialize the I2C bus (BH1750 library doesn't do this automatically)
Wire.begin(D4,D3); // SDA , SCL
// On esp8266 you can select SCL and SDA pins using Wire.begin(D4, D3);
// begin returns a boolean that can be used to detect setup problems.
if (lightMeter.begin(BH1750::CONTINUOUS_HIGH_RES_MODE)) {
// Serial.println(F("BH1750 Advanced begin"));
}
else {
Serial.println(F("Error initialising BH1750"));
}
// Setup MQTT
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
}
void loop() {
// MQTT
if (!client.connected()) {
reconnect();
}
client.loop();
// Light measurement
lux = lightMeter.readLightLevel();
Serial.println("");
Serial.print("Light: ");
Serial.print(lux);
Serial.println(" lx");
// Wakeup Rain Counter Atmel
digitalWrite(RainSensorWakeupPin, HIGH);
Serial.println("Wakeup Rain Counter");
delay(50);
// Receive data
transferAndWait('r');
delay(50);
byte RainCounter = transferAndWait('a');
// digitalWrite(SS, HIGH);
Serial.print("Rain Counter: ");Serial.println(RainCounter);
// delay(100);
digitalWrite(RainSensorWakeupPin, LOW);
dtostrf(RainCounter, 3, 0, msg);
client.publish(outTopicRain, msg);
// Read DHT22 (Temperature and Humidity)
ReadTemperature();
ReadHumidity();
if(!failureTemperature)
{
char msg[50];
dtostrf(Temperature, 3, 2, msg);
client.publish(outTopicTemperature, msg);
Serial.print("Msg: ");Serial.println(msg);
}
if(!failureHumidity)
{
char msg[50];
dtostrf(Humidity, 3, 2, msg);
client.publish(outTopicHumidity, msg);
}
char msg[50];
dtostrf(lux, 3, 2, msg);
client.publish(outTopicLux, msg);
delay(120);
ESP.deepSleep(5e6);
delay(100);
}
// SPI transer and receive
byte transferAndWait (const byte what)
{
byte a = SPI.transfer (what);
delayMicroseconds (20);
Serial.print("Received: ");Serial.println(a);
return a;
} // end of transferAndWait
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
// Switch on the LED if an 1 was received as first character
if ((char)payload[0] == '1') {
digitalWrite(BUILTIN_LED, LOW); // Turn the LED on (Note that LOW is the voltage level
// but actually the LED is on; this is because
// it is active low on the ESP-01)
} else {
digitalWrite(BUILTIN_LED, HIGH); // Turn the LED off by making the voltage HIGH
}
}
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Create a random client ID
String clientId = "ESP8266-WeatherStation";
clientId += String(random(0xffff), HEX);
// Attempt to connect
if (client.connect(clientId.c_str())) {
Serial.println("connected");
// Once connected, publish an announcement...
// ... and resubscribe
// client.subscribe("inTopic");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void ReadTemperature()
{
// Read temperature
sensors_event_t event;
dht.temperature().getEvent(&event);
if (isnan(event.temperature)) {
Serial.println(F("Error reading temperature!"));
failureTemperature = true;
}
else {
failureTemperature = false;
Temperature = event.temperature;
Serial.print(F("Temperature: "));
Serial.print(Temperature);
Serial.println(F("°C"));
}
}
void ReadHumidity()
{
// Read humidity
sensors_event_t event;
dht.humidity().getEvent(&event);
if (isnan(event.relative_humidity)) {
Serial.println(F("Error reading humidity!"));
failureHumidity = true;
}
else {
failureHumidity = false;
Humidity = event.relative_humidity;
Serial.print(F("Humidity: "));
Serial.print(Humidity);
Serial.println(F("%"));
}
}
Can you pass the SPI connection diagram between NANO and NodeMCU. I mean:
NANO (DPin-10, 11, 12, 13) -------> NodeMCU (what Pin)? Are they: CMD, SDI, SDO, CLK respectively?
I have this type of NodeMCU:
I use the same NodeMCU.
Here my connections (sorry for the bad drawing).
It is about a year that I have not done any project with my NodeMCU -- even I have forgotten which GPIO (2) is connected with the built-in LED near the MCU/WiFi Module of the Board. I have to first check that the Board is working. After a lot of search in the net and subsequent experiment, I have found the GPIO-2 (D4) which connects the LED. Anyway, the Board is working. There is another LED on my near the UART/USB converter chip -- do you know which GPIO-pin is connected with the LED?
Now, I am building your NodeMCU-NANO Project to look into the SPI problem in deepSleep/powerDown mode.