Conflicto I2C y modo sleep Resuelto

Hola

Estoy en un proyecto en el que hay un giroscopio y un gps, controlados por un arduino nano v3.
Como la fuente de energía va a ser una batería, quisiera que entrara en el modo sleep durante un minuto.
Pero soy incapaz de que entre en el modo sleep. La comunicación I2C del GPS neo6m provoca que se despierte. Lo he deducido al deconectar el gps y ver que funciona, y de otro foro.
Estoy usando la librería LowPower.h, la cual es muy sencilla.
tenéis alguna idea???

Este es mi código:

# include  <MPU6050_tockn.h>    //Librería para MPU6050 con auto calibración 
# include  <Wire.h>             //Librería para el control del bus I2C
# include <SoftwareSerial.h>    //Librería para puerto serie
# include <TinyGPS.h>           //Librería para el NEO6M
# include <LowPower.h>           //Librería para modo sleep

TinyGPS gps;                     //Declaramos el objeto GPS
SoftwareSerial softSerial(4, 3); //Declaramos el pin 4 Tx del GPS y 5 Rx del GPS

MPU6050 mpu6050(Wire);

//Declaramos la variables para GPS
bool newData = false;
unsigned long chars;
unsigned short sentences, failed;
unsigned long start;

//Declaración de otras variables
int tsleep = 2;
int i = 0;
int n = 0;




//================================================================================================
//*************************************************************************************************
/*
        =======================================
                      MÓDULO GPS NEO6M
        =======================================
*/
void leergps () {

  newData = false;

  // Intenta recibir secuencia durante un segundo
  for (start = millis(); millis() - start < 1000;)
  {
    while (softSerial.available())
    {
      char c = softSerial.read();
      if (gps.encode(c)) // Nueva secuencia recibida
        newData = true;
    }
  }

  if (newData == true)
  {
    float flat, flon;
    unsigned long age;
    gps.f_get_position(&flat, &flon, &age);
    Serial.print("LAT=");
    Serial.print(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flat, 6);
    Serial.print(" LON=");
    Serial.print(flon == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flon, 6);
    Serial.print(" SAT=");
    Serial.print(gps.satellites() == TinyGPS::GPS_INVALID_SATELLITES ? 0 : gps.satellites());
    Serial.print(" PREC=");
    Serial.print(gps.hdop() == TinyGPS::GPS_INVALID_HDOP ? 0 : gps.hdop());
  }

  gps.stats(&chars, &sentences, &failed);
  Serial.print(" CHARS=");
  Serial.print(chars);
  Serial.print(" SENTENCES=");
  Serial.print(sentences);
  Serial.print(" CSUM ERR=");
  Serial.println(failed);
}

//****************************************************************************************************************
/*
        =======================================
                      MÓDULO GIROSCOPIO
        =======================================
*/
void leergiroscopio () {

  for (start = millis(); millis() - start < 1000;)            //Mantiene el bucle un tiempo t = 10 00 =1 s
  {                                                           //Realiza una rafaga de lecturas de tiempo t.
    mpu6050.update(); //para realizar la toma de lecturas

    Serial.print("Temp: ");
    Serial.println(mpu6050.getTemp());

    Serial.print("Angulo X: ");             //TEXTO PANTALLA
    Serial.print( mpu6050.getAngleX());
    Serial.print("Angulo Y: ");             //TEXTO PANTALLA
    Serial.print( mpu6050.getAngleY());
    Serial.print("Angulo Z: ");             //TEXTO PANTALLA
    Serial.println( mpu6050.getAngleZ());
  }
}




//================================================================================================================

void setup() {

  Serial.begin(115200);                        //Es para ver por el ordenador ahora
  softSerial.begin(9600);                      //Iniciamos el puerto serie del gps

  //Configuración del sensor MPU6050
  //MPU6050 mpu6050(Wire, 0.1, 0.9);          // Si no se quiere ajustar el sensor MPU6050
  mpu6050.begin();
  //mpu6050.calcGyroOffsets(true);             //Calibración del sensor MPU6050, pero si se conoce la calibración mpu6050.setGyroOffsets (1.45, 1.23, -1.32);
  // No mover el MPU6050 durante 5 segundos.
  mpu6050.setGyroOffsets (0.66, 0.54, -0.19);


}

//=================================================================================================================

void loop() {

  Serial.println(" Yaaaaaaaa .  ");
  Serial.println( n );
  
  
 
  
  for ( i = 0 ;  i  <  tsleep ; i++) {                    //Duerme al arduino un tiempo 8*n segundos
         LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
  }

  delay(100);

  if (n == 4) {
    leergps();
    leergps();
    n = 0;
  }
  n++;

  leergiroscopio();




}


//FIN

cuando lo pones a dormir solo invocas el apagado del ADC

LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);

Y asi hay tresmodos de despertar un Arduino del modo Sleep:

Interrupciones hardware
Timers y WDT que es un timer un tanto peculiar
UART o puerto serie.

Justamente tu GPS lo hace.

Estas son las opciones disponibles en la librería

/*******************************************************************************
* Name: idle
* Description: Putting ATmega328P/168 into idle state. Please make sure you
*			         understand the implication and result of disabling module.
*
* Argument  	Description
* =========  	===========
* 1. period   Duration of low power mode. Use SLEEP_FOREVER to use other wake
*				up resource:
*				(a) SLEEP_15MS - 15 ms sleep
*				(b) SLEEP_30MS - 30 ms sleep
*				(c) SLEEP_60MS - 60 ms sleep
*				(d) SLEEP_120MS - 120 ms sleep
*				(e) SLEEP_250MS - 250 ms sleep
*				(f) SLEEP_500MS - 500 ms sleep
*				(g) SLEEP_1S - 1 s sleep
*				(h) SLEEP_2S - 2 s sleep
*				(i) SLEEP_4S - 4 s sleep
*				(j) SLEEP_8S - 8 s sleep
*				(k) SLEEP_FOREVER - Sleep without waking up through WDT
*
* 2. adc		ADC module disable control:
*				(a) ADC_OFF - Turn off ADC module
*				(b) ADC_ON - Leave ADC module in its default state
*
* 3. timer2		Timer 2 module disable control:
*				(a) TIMER2_OFF - Turn off Timer 2 module
*				(b) TIMER2_ON - Leave Timer 2 module in its default state
*
* 4. timer1		Timer 1 module disable control:
*				(a) TIMER1_OFF - Turn off Timer 1 module
*				(b) TIMER1_ON - Leave Timer 1 module in its default state
*
* 5. timer0		Timer 0 module disable control:
*				(a) TIMER0_OFF - Turn off Timer 0 module
*				(b) TIMER0_ON - Leave Timer 0 module in its default state
*
* 6. spi		SPI module disable control:
*				(a) SPI_OFF - Turn off SPI module
*				(b) SPI_ON - Leave SPI module in its default state
*
* 7. usart0		USART0 module disable control:
*				(a) USART0_OFF - Turn off USART0  module
*				(b) USART0_ON - Leave USART0 module in its default state
*
* 8. twi		TWI module disable control:
*				(a) TWI_OFF - Turn off TWI module
*				(b) TWI_ON - Leave TWI module in its default state
*

Asi que si usas SLEEP_FOREVER no despertará con nada, salvo si usas una interrupcion externa para tal efecto.

O deshabilita USART0_OFF - Turn off USART0 pero para tu caso ya que usas SoftwareSerial

Este ejemplo despierta con una interrupción en pin 2 con nivel bajo. Puedes usar lo que gustes.

Muchas gracias por contestarme.

Los diferentes tipos de interrupciones los conozco.

El problema que tengo, es que el arduino no entra en modo sleep debido a que la comunicación I2C del GPS me lo despierta, al generar algún tipo de interrupción. Pero quiero que se mantenga dormido durante 8 segundos.
Pero no se entra en el modo sleep o entra y se sale inmediatamente.
¿Que podría hacer?

Ni con las siguientes instrucciones se duerme:

        LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
          LowPower.idle(SLEEP_8S, ADC_OFF, TIMER2_OFF, TIMER1_OFF, TIMER0_OFF, 
                SPI_OFF, USART0_OFF, TWI_OFF);

Tu GPS no es usa I2C sino que usa la comunicación por el puerto virtual usando SoftwareSerial.

while (softSerial.available())
    {
      char c = softSerial.read();

El problema es como bloquearlo porque la opcion que bloquea es para la USART y no para un puerto virtual.
Debes ver si hay un comando que bloquee el uso de SoftwareSerial.

Acabo de ver que SoftwareSerial no puede detenerse y alguien con tumismo problema sugiere usar AltSoftSerial
Si lo miras es basicamente similar pero cuenta con una opción para detener el uso del puerto que se llama :end de modo que si tu puerto softSerial lo podrías detener con softSerial.end() usando esta librería que te acabo de mencionar.

Prueba a ver.

Muchas gracias.

he encontrado la siguiente función para desactivar la comunicación serie:

softSerial.end();

Pero no soy capaz de volver a activarla.

Por lo que optado por hacer una especie de relé mediante un transistor mosfet, que corte la corriente antes de entrar en el modo sleep.

Así lo he solucionado.

Se activa con el mismo nombre del operador y luego

softSerial.begin(9600);

como tenías en el setup.

EDITO: Buscando para un problema que tengo con SoftwareSerial y manejo de varios puertos virtuales me topé con esto.

#include <SoftwareSerial.h>

// define the digital pins to use as RX and TX for two
// software serial connections
const int RX1 = 8;
const int TX1 = 9;
const int RX2 = 10;
const int TX2 = 11;

// create SoftwareSerial objects
SoftwareSerial SoftSerialOne(RX1,TX1);
SoftwareSerial SoftSerialTwo(RX2,TX2);

void setup(void) {
// setup the software serial pins
pinMode(RX1, INPUT);
pinMode(RX2, INPUT);
pinMode(TX1, OUTPUT);
pinMode(TX2, OUTPUT);
}

void loop(void) {
SoftSerialOne.begin(9600); // begin communication on the first 
// software serial channel
SoftSerialOne.print("Hello World"); // send something
SoftSerialOne.end(); // end communication on the first software
// serial channel
SoftSerialTwo.begin(9600); // begin communication on the second 
// software serial channel
SoftSerialTwo.print("Hello World"); // send something
SoftSerialTwo.end(); // end communication on the second software
// serial channel
}

Aca se ve como detiene uno e inicia otro.

Muchas gracias.

Ya funciona correctamente. Activa y desactiva a voluntad.

Conoces alguna forma o comando que desactive la corriente en los pines de 3,3v y 5v. Que utilizamos para alimentar los sensores.

La mejor manera es conseguir un MOSFET Canal P y desactivarlo junto con esto que estuvimos viendo.
Es lo que se usa en todos lados. EL Mosfet de bajo Rds hará de switch del senso suponiendo que uses sensores que consumen mas que lo que un pin de Arduino puede entregar, o sea +40mA. Si estan por debajo simplemente lo alimentas con un pin y listo.

Se mas puntual (qué modelos, corrientes de consumo) con los sensores involucrados.