Arduino Micro - Problem bei simultan SPI und I2C?

Hallo!

Ich versuche ein kleines Projekt aufzusetzen, in welchem ich Feinstaub-, Ozon-/NO2-/CO-, und ein paar Wetterdaten (Licht, Temp, Feuchte) mit einem Arduino Mikro auslesen möchte und auf dem PC in einer .csv Datei speichern will.

Mein Equipment:
Gassensoren → AlphaSense B-Serie (http://www.alphasense.com/index.php/air/products/)
Feinstaub → AlphaSense OPC-N3 (http://www.alphasense.com/index.php/products/optical-particle-counter/)
Temp., rel.Feuchte + AD-Wandlung → Adafruit BME280, ADS1115
Licht → GY1145 mit dem SI1445
Als Stromversorgung habe ich eine exterme Power-Bank (Krisdonia 25Ah), welche genug Strom liefert.

Die Kommunikation Arduino Mikro mit den Sensoren läuft ab:

  • Feinstaubsensor OPC-N3 per SPI
  • alle anderen Sensoren via I2C

Jetzt habe ich alle Komponenten einzeln getestet und sie funktionieren wie geplant.

Wenn ich aber alle Sensoren simultan am Arduino Mikro habe, sie also nacheinander auslesen möchte, dann passiert folgendes:

1.) Der loop läuft ohne den “SPI”-Teil ab, so ca. 7-9 mal - bedeutet, ich lese alle Sensor-Daten (bis auf den Feinstaub) mehrfach aus, und erst nach einer undefinierten Zeit messe ich die Feinstaub-Daten aus dem OPC-N3 (via SPI).

Gesamter Code ist im 1.Kommentar zu finden.

Ich bin für alle Tipps sehr dankbar, bin noch unerfahren mit Arduinos :smiley:

PS: im Loop() der auskommentierte Debugging-Versuch von mir mit if(Serial.available()>0) sollte doch eigentlich die Funktion performMeasurement() sobald ich etwas in den seriellen Monitor eintippe nur einmal aufrufen, oder? Damit dachte ich, kann ich das Problem lösen. Leider misst mein Arduino trotz dieser Einschränkung einfach weiter :o und hängt sich auf. Der dann auftretende Fehler ist im angehängten Bild zu sehen- falls mir das jemand erklären könnte, wäre ich wahnsinnig dankbar :slight_smile:

Vielen Dank!

Ich kann deinen Sketch nicht sehen, wo ist der versteckt ?

Einige Dinge musste ich wegen der 9000 Zeichen wegkürzen :), hoffe es ist dennoch verständlich.

#define Batteriemessung A3

#define REF_VOLTAGE 5.0
#define PIN_STEPS 1024.0

float vout = 0.0, vin = 0.0;
float R1 = 160000.0; // resistance R1 (= 160 KOhm)
float R2 =  70000.0; // resistance R2 (= 70 KOhm)
int rawValue = 0;
int Fotowiderstand= A2;
int sensorWert_Fotowiderstand = 0;

#include "Adafruit_SI1145.h"
Adafruit_SI1145 uv = Adafruit_SI1145();

int measurementInterval = 1000;
int numberData = 60;
int sleepTime = measurementInterval/numberData ;
unsigned long counter = 0L;

#include <Wire.h>
#include <SPI.h>

#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

#define BME_SCK 13
#define BME_MISO 12
#define BME_MOSI 11
#define BME_CS 10

#define SEALEVELPRESSURE_HPA (1013.25)

Adafruit_BME280 bme; // I2C

unsigned long delayTime;

#include <Adafruit_ADS1015.h>
Adafruit_ADS1115 ads1115_1 (0x48); // construct an ads1115 at address 0x48
Adafruit_ADS1115 ads1115_2 (0x49); // construct an ads111 at address 0x49

//OPC-N3

#include <avr/wdt.h>

#define FirmwareVer "OPC-N3-02(UNOr3)(res divider on SS)"

#define ArduinoUNO

#define opSerial Serial

#define BaudRate 9600

#define SPI_OPC_busy 0x31
#define SPI_OPC_ready 0xF3


unsigned long currentTime;
unsigned long cloopTime;
unsigned char SPI_in[86], SPI_in_index, ssPin_OPC;

void setup() {

pinMode(Batteriemessung, INPUT);
analogReference (INTERNAL); // INTERNAL = 1.1v

ads1115_1.setGain (GAIN_TWO);
ads1115_2.setGain (GAIN_TWO);

//Start of measurement
  Serial.begin(9600);
  
  bme.begin();
  ads1115_1.begin();
  ads1115_2.begin();

  uv.begin();

 wdt_reset(); 
  wdt_enable(WDTO_8S);

  for (unsigned char i=2;i<11;i++)
  {
    digitalWrite(i, HIGH); //Initiate pin HIGH
    pinMode(i, OUTPUT); //Set pin as output
  }

  delay(1000);

  
  opSerial.begin(BaudRate);

 
  SPI.begin();

  ssPin_OPC = 10;
  wdt_reset(); 
  InitDevice();
  wdt_reset(); 

  currentTime = millis();
  cloopTime = currentTime; 

}

void loop() {

  if (Serial.available()>0){
    
    performMeasurement();
    Serial.flush();
    Serial.read();
    }
}

void performMeasurement(){
  
counter = counter + 1;

Serial.print(counter);
Serial.print(",");

 rawValue = analogRead(Batteriemessung);
    vout = (rawValue * REF_VOLTAGE) / PIN_STEPS;
    vin = vout / (R2 / (R1 + R2));
    if (vin < 0.09) {
        vin = 0.0;
    }
    
    Serial.print(vin);
    Serial.print(",");
  
//Gas-Berechnung...


// wait the sleeptime
delay(sleepTime);
}

//Berechnung Wetterdaten


//Berechnung LIcht


//=============OPC-N3====================

 //Initialize parameters
  temp_integral=0;
  humidity_integral=0;
  PM_A_integral=0;
  PM_B_integral=0;
  PM_C_integral=0;
  
  wdt_reset(); //Reset watchdog timer

  currentTime = millis();
  if (currentTime >= cloopTime)
  {

      
    cloopTime += 60000;

    wdt_reset();

      ssPin_OPC = 10;


      StartOPC();

      wdt_reset();

      unsigned long GetHistTime = millis(); //Set initial GetHistTime
      for (byte i=0; i<10; i++)
      {
        delay(1000);
        ReadOPChist(); //Read OPC histogram data
        if (i != 0) {
          //Print time since start (millis() returns an unsigned long of number of ms since program started. It wraps around in ~50 days.)
          //opSerial.print(millis());
          SaveIntegralData(opSerial); 
        }
        wdt_reset(); //Reset watchdog timer
      }
  
  Serial.print(temp_smooth);
  Serial.print(",");
  Serial.print(humidity_smooth);
  Serial.print(",");
  Serial.print(PM_A_smooth);
  Serial.print(",");
  Serial.print(PM_B_smooth);  
  Serial.print(",");
  Serial.print(PM_C_smooth); 
  Serial.println(";");

      StopOPC(); 
  }
}



//============Mikrofon-Funktionen=================

// Find the Peak-to-Peak Amplitude Function
int findPTPAmp(){
// Time variables to find the peak-to-peak amplitude
   unsigned long startTime= millis();  // Start of sample window
   unsigned int PTPAmp = 0; 
   unsigned int Amplitude = 0;

// Signal variables to find the peak-to-peak amplitude
   unsigned int maxAmp = 0;
   unsigned int minAmp = 1023;

// Find the max and min of the mic output within the 50 ms timeframe
   while(millis() - startTime < sampleTime) 
   {
      micOut = analogRead(mic);
      if( micOut < 1023) //prevent erroneous readings
      {
        if (micOut > maxAmp)
        {
          maxAmp = micOut; //save only the max reading
        }
        else if (micOut < minAmp)
        {
          minAmp = micOut; //save only the min reading
        }
      }
   }

//=============OPC-N3-Funktionen==================

void InitDevice (void)
{
  wdt_reset();

  StartOPC(); 
  wdt_reset(); 


void ReadOPChist (void)
{
  GetReadyResponse(0x30);
  for (SPI_in_index=0; SPI_in_index<86; SPI_in_index++)
  {
    delayMicroseconds(10);
    SPI_in[SPI_in_index] = SPI.transfer(0x01); 
  }
  SetSSpin(HIGH);
  SPI.endTransaction();
  delay(10);
}


void DiscardSPIbytes (byte NumToDiscard)
{
  for (SPI_in_index=0; SPI_in_index<NumToDiscard; SPI_in_index++)
  {
    delayMicroseconds(10);
    SPI.transfer(0x01); //Value of outgoing byte doesn't matter
  }
}


void StartOPC (void)
{
  GetReadyResponse(0x03);
  SPI.transfer(0x07); //Turn ON laser power
  SetSSpin(HIGH);
  SPI.endTransaction();
  delay(10);

  delay(1000); 
  
  GetReadyResponse(0x03);
  SPI.transfer(0x03); //Turn ON fan DAC
  SetSSpin(HIGH);
  SPI.endTransaction();
  delay(10);

  for (byte i=0; i<5; i++)
  {
    wdt_reset(); //Reset watchdog timer
    delay(1000);
  }
}

void StopOPC (void)
{
  GetReadyResponse(0x03);
  SPI.transfer(0x06); //Turn OFF laser power
  SetSSpin(HIGH);
  SPI.endTransaction();
  delay(10);

  GetReadyResponse(0x03);
  SPI.transfer(0x02); //Turn OFF fan DAC
  SetSSpin(HIGH);
  SPI.endTransaction();
  delay(10);
}

void GetReadyResponse (unsigned char SPIcommand)
{
  unsigned char Response;

  SPI.beginTransaction(SPISettings(300000, MSBFIRST, SPI_MODE1));

  Response = SPI.transfer(SPIcommand);
  delay(1);  //wait 1ms

  do
  {
    SetSSpin(LOW);
    unsigned char Tries = 0;
    do
    {
      Response = SPI.transfer(SPIcommand);
      if (Response != SPI_OPC_ready) delay(1); //wait 1ms
    }
    while ((Tries++ < 20) && (Response != SPI_OPC_ready));

    if (Response != SPI_OPC_ready)
    {
      if (Response == SPI_OPC_busy)
      {
        SetSSpin(HIGH);
       
        wdt_reset();
        delay(2000); //wait 2s
      }
      else
      {
        
        SetSSpin(HIGH);
        
        SPI.endTransaction();
        
        wdt_reset();
        delay(6000);
        wdt_reset();
        SPI.beginTransaction(SPISettings(300000, MSBFIRST, SPI_MODE1));
      }
    }
  }
  while ((Response != SPI_OPC_ready) && (Serial.available()==0)); 
  delay(10);

  wdt_reset();
}


unsigned int MODBUS_CalcCRC(unsigned char data[], unsigned char nbrOfBytes)
{
  #define POLYNOMIAL_MODBUS 0xA001 //Generator polynomial for MODBUS crc
  #define InitCRCval_MODBUS 0xFFFF //Initial CRC value

  unsigned char _bit; // bit mask
  unsigned int crc = InitCRCval_MODBUS; // initialise calculated checksum
  unsigned char byteCtr; // byte counter

  // calculates 16-Bit checksum with given polynomial
  for(byteCtr = 0; byteCtr < nbrOfBytes; byteCtr++)
  {
    crc ^= (unsigned int)data[byteCtr];
    for(_bit = 0; _bit < 8; _bit++)
    {
      if (crc & 1) //if bit0 of crc is 1
      {
        crc >>= 1;
        crc ^= POLYNOMIAL_MODBUS;
      }
      else
        crc >>= 1;
    }
  }
  return crc;
}

float ConvSTtoTemperature (unsigned int ST)
{
  return -45 + 175*(float)ST/65535;
}

float ConvSRHtoRelativeHumidity (unsigned int SRH)
{
  return 100*(float)SRH/65535;
}

float ConvPM (float PM)
{
  return (float)PM;
}


void SetSSpin (bool pinState) //pinState is HIGH or LOW
{
  digitalWrite(ssPin_OPC, pinState); 
}

void SaveIntegralData (Stream &port)
{
 //Berechnung Werte

Der dann auftretende Fehler ist im angehängten Bild zu sehen-

Da sehe ich vielleicht einen Bug der IDE, aber keinen Fehler im Programm des Micro.

Ein typisches Problem: I2C Pullup