ADXL335 Was vibriert denn da? Signalverarbeitung mit Arduino Nano

Danke Tommy

Schwingungszahl" = (Anzahl der positiven Amplituden / Messdauer) * 60 Sekunden

Falscher Ansatz bei den kleinen Frequenzen: wenn die konstant periodisch kommen dann die Periodendauer messen, sonst geht das in die Hose.

Wie lassen sich einzelne Auslenkungen des Sensors zählen?

Würde ich digital angehen mit vorgeschaltetem Komparator. Viel einfacher in der Auswertung, siehe meine Einleitung.

Der Button steuert über ein Interrrupt den Start der Messung

Schon wieder ein Interrupt-Fetischist :smiling_imp:
Braucht kein Mensch für eine Buttonabfrage, aber ist auch nicht verboten.

Nach betätigen des Tasters beginnt ein Timer zu laufen bis die Messdauer erreicht wurde. Wärend der Messung werden die analog Werte des Beschleunigungssensor ausgelesen

Wie gesagt, falscher Ansatz. Starte die Messung bei der ersten Flanke und zähle die Zeit für n-Flanken.

Viele Wege führen nach Rom, ich würde diesen wählen. Alternativen sind aber wie ein Interrupt für eine Tasterabfrage nicht verboten.

Hallo Klaus,

Falscher Ansatz bei den kleinen Frequenzen: wenn die konstant periodisch kommen dann die Periodendauer messen, sonst geht das in die Hose.

Das war eindeutig zu beobachten ja^^ Danke für den Anstoß Lösungen in einer anderen Ecke zu suchen!
Bezüglich Komparator muss ich mich erst einlesen, deswegen werde ich mich in den nächsten Tagen damit beschäftigen, und mich wieder melden.

Schon wieder ein Interrupt-Fetischist :smiling_imp:
Braucht kein Mensch für eine Buttonabfrage, aber ist auch nicht verboten.

:stuck_out_tongue_closed_eyes: eigentlich hätte ich für die Abfrage der funktionen im loop() teil Scherze erwartet. Aber ich hatte Probleme mit if Abfragen von Buttons in der Vergangenheit..deswegen das Interrupt.
Aber gut dass es noch mehr Möglichkeiten zu entdecken gibt.

Danke
Gruß Ardukus

Zählen von Spitzen kann sehr ungenau werden, wenn man die Oberwellen nicht schon vor der Digitalisierung rausgefiltert hat. Ansonsten hilft fast nur noch FFT zur Ermittlung der Grundfrequenz.

Schönen Sonntag zusammen.

Bezüglich des Pojekts wollte ich mich zurückmelden und ein kleines Update wiedergeben:

Nach dem sehr nützlichen Hinweis von Klaus_ww konnte ich wieder einen Fortschritt machen.
@Klaus_ww wenn du mir deine Adresse per pw schickst und du gerne bier trinkst lass ich dir gerne ein six pack zukommen :wink:

Nach der recherche von Komparatorschaltungen bin ich kurzerhand über die analogComp.h Library gestoßen, welche die steuerung des internen Komparator an pin D6 & D7 des Arduino Nanos erlaubt.

Nach kurzem umschreiben funzt die Flankensteuerung eigentlich sehr gut, jedoch stehen die Test nächste Woche noch an.

Hiermal der code

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "analogComp.h"

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

//-----------------------------------ADXL 335--------------------------------
const int zpin = A0;
volatile boolean enableLed = false; //used to check if the interrupt has raised

//------------Bedienung----------------
const int buttonPin = 2;     // the number of the pushbutton pin
const int ledPinMessung =  12;      // the number of the LED pin

//------------------------ variablen fuer entprellen----------------
volatile unsigned long alteZeit=0, entprellZeit=40;
volatile int buttonCounter = 0;

// variablen fuer zeitnehmung
unsigned long startMillis;  
unsigned long currentMillis;

float period = 10.0;
int f = 0;

int Acounter = 0;
int newAcounter = 0;
int S = 0;


double t = 0;
double a = millis();
double c ;

int go = 0;

 
void setup() 
{
  Serial.begin(230400);
  analogComparator.setOn(AIN0, AIN1); //we instruct the lib to use voltages on the pins
  analogComparator.enableInterrupt(changeStatus, RISING); //we set the interrupt and when it has to be raised
  
  pinMode(zpin, INPUT);
  pinMode(buttonPin, INPUT); 
  digitalWrite(buttonPin, HIGH);
  attachInterrupt(0, start_ISR, RISING);

  pinMode(ledPinMessung, OUTPUT);
  digitalWrite(ledPinMessung, LOW);
  
  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // Address 0x3D for 128x64
  display.clearDisplay();  

  homeScreen();
  int z = analogRead(zpin);
  Serial.print(z);
}

void homeScreen ()
{
  display.clearDisplay();
  //item
  display.setCursor(0,0);
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.print("Ergebnis");
  //periode  
  display.fillRect(97,0,60,15,WHITE);
  display.setCursor(97,4);
  display.setTextSize(1);
  display.setTextColor(BLACK);
  display.print(period); 
  display.drawLine(0, 15 , 127,15 , WHITE);
  //Schwingungszahl auf Schläge pro Minute
  display.setCursor(0,25);
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.print("S:");
  display.setCursor(20,17);
  display.setTextSize(4);
  display.setTextColor(WHITE);
  display.print(S);
  display.setCursor(97,22);
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.print("Amp."); 
  display.drawLine(92, 32 , 120 , 32 , WHITE);
  display.setCursor(97,35);
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.print("min"); 
  //Schwingungszahl bezogen auf ADXL335
  display.setCursor(0,48);
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.print("x:");
  display.print(newAcounter);
  
  
  display.display(); 
}

void meassuring() 
{
  display.clearDisplay();
  //item
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(0,0);
  display.print("Messung");
  //periode  
  display.fillRect(97,0,60,15,WHITE);
  display.setCursor(97,4);
  display.setTextSize(1);
  display.setTextColor(BLACK);
  display.print(period); 
  display.drawLine(0, 15 , 127,15 , WHITE);
  //Schwingungszahl bezogen auf ADXL335
  display.setCursor(0,25);
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.print("x:");
  display.setCursor(20,17);
  display.setTextSize(4);
  display.setTextColor(WHITE);
  display.print(Acounter);
  display.setCursor(97,22);
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.print("Amp."); 
  display.drawLine(92, 32 , 120 , 32 , WHITE);
  display.setCursor(97,35);
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.print("per."); 
  //---------------------------------
  display.display();
  //analogComparator.enableInterrupt();
  
  while(t <= period)
  {
    c = millis();    
    t = (c - a) / 1000;
    display.fillRect(0,55,127,14,WHITE);
    display.setTextSize(1);
    display.setTextColor(BLACK);
    display.setCursor(39,56);
    display.print("t:");
    display.print(t);
    display.print("sec");  
    display.display();

    if(enableLed)
    {
      Acounter++;
      enableLed = false;
      delay(10);
    }

    
    
    display.setCursor(17,17);
    display.fillRect(17,17,75,33,BLACK);
    display.setCursor(20,17);
    display.setTextSize(4);
    display.setTextColor(WHITE);
    display.print(Acounter);
  }
  newAcounter = Acounter /  2;
  S = (newAcounter / period) * 60;
  Acounter = 0;
  go = go -1;
  t = 0.000;

  
   
}

void loop() 
{
  //analogComparator.disableInterrupt();
  
  if (go == 0 )
  {
  homeScreen();
  }
  if(go == 1 )
  {
  meassuring();
  }

  Serial.println(S);
}

void start_ISR() 
{
  if((millis() - alteZeit) > entprellZeit)
  { 
    // innerhalb der entprellZeit nichts machen
    
    go++;
    
    alteZeit = millis(); // letzte Schaltzeit merken
    a = millis();
   }         
   
}

void changeStatus() {
    enableLed = true; //let's inform the main loop that the condition has been reached by the analog comparator
}

Jedoch gib ich mich noch nicht zufrieden, ich möchte den Ansatz der Periodentauer messung noch umsetzen bzw beide Verfahren: Frequenzmessung und Amplitudenmessung vereinen.

Das Problem, das sich beim Ändern des Ansatzes ergibt ist folgendes:
Laut meinem Verständiss bräuchte mann zwei Schwellspannungen die überwacht werden. Mein Ansatz war es zwei interrupts gleichzeitig über den Komparator laufen zu lassen, einen für RISING einen für FALLING. Leider spricht der Interrupt nicht an und meine Vermutung ist, dass immer nur ein interrupt möglich ist.

Vl hat noch jemand eine Idee oder Anmerkung wie sich ein Abwarten der negativen Halbwelle möglich ist.

Gruß
Markus

Für Leute die ebenso die Anleitung für die Ansteuerung des internen Komparators suchen hier gehts zur Library:

http://forum.arduino.cc/index.php?topic=158657.0

Hier noch der code für eine Messung der Periodentauer:

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "analogComp.h"

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

//-----------------------------------ADXL 335--------------------------------
const int zpin = A0;
volatile boolean positivState = false; //used to check if the interrupt has raised
volatile boolean negativState = false; //used to check if the interrupt has raised

//------------Bedienung----------------
const int buttonPin = 2;     // the number of the pushbutton pin
const int ledPinpositiv =  8;      // the number of the LED pin
const int ledPinnegativ =  12;      // the number of the LED pin

//------------------------ variablen fuer entprellen----------------
volatile unsigned long alteZeit=0, entprellZeit=40;
volatile int buttonCounter = 0;

// variablen fuer zeitnehmung
unsigned long startMillis;  
unsigned long currentMillis;

int AMP = 10;
int f = 0;

int Acounter = 0;
int newAcounter = 0;
int S = 0;
int x = 0;


double t = 0;
double a = millis();
double c ;

int go = 0;

 
void setup() 
{
  Serial.begin(230400);
  analogComparator.setOn(AIN0, AIN1); //we instruct the lib to use voltages on the pins
  analogComparator.enableInterrupt(positivWave, RISING); //we set the interrupt and when it has to be raised
  analogComparator.enableInterrupt(negativWave, FALLING);

   
  pinMode(zpin, INPUT);
  pinMode(buttonPin, INPUT); 
  digitalWrite(buttonPin, HIGH);
  attachInterrupt(0, start_ISR, RISING);

  pinMode(ledPinpositiv, OUTPUT);
  digitalWrite(ledPinpositiv, LOW);
  pinMode(ledPinnegativ, OUTPUT);
  digitalWrite(ledPinnegativ, LOW);
  
  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // Address 0x3D for 128x64
  display.clearDisplay();  

  homeScreen();
  int z = analogRead(zpin);
  Serial.print(z);
}

void homeScreen ()
{
  display.clearDisplay();
  //item
  display.setCursor(0,0);
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.print("Ergebnis");
  //periode  
  display.fillRect(97,0,60,15,WHITE);
  display.setCursor(97,4);
  display.setTextSize(1);
  display.setTextColor(BLACK);
  display.print(AMP); 
  display.drawLine(0, 15 , 127,15 , WHITE);
  //Schwingungszahl auf Schläge pro Minute
  display.setCursor(0,25);
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.print("t:");
  display.setCursor(20,17);
  display.setTextSize(4);
  display.setTextColor(WHITE);
  display.print(t);
  display.setCursor(97,22);
  /*display.setTextSize(1);
  display.setTextColor(WHITE);
  display.print("Amp."); 
  display.drawLine(92, 32 , 120 , 32 , WHITE);
  display.setCursor(97,35);
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.print("min"); 
  */
  //Schwingungszahl bezogen auf ADXL335
  display.setCursor(0,48);
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.print("x:");
  display.print(newAcounter);
  
  
  display.display(); 
}

void meassuring() 
{
  display.clearDisplay();
  //item
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(0,0);
  display.print("Messung");
  //periode  
  display.fillRect(97,0,60,15,WHITE);
  display.setCursor(97,4);
  display.setTextSize(1);
  display.setTextColor(BLACK);
  display.print(AMP); 
  display.drawLine(0, 15 , 127,15 , WHITE);
  //Schwingungszahl bezogen auf ADXL335
  display.setCursor(0,25);
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.print("x:");
  display.setCursor(20,17);
  display.setTextSize(4);
  display.setTextColor(WHITE);
  display.print(x);
  display.setCursor(97,22);
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.print("Amp."); 
  display.drawLine(92, 32 , 120 , 32 , WHITE);
  display.setCursor(97,35);
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.print("per."); 
  //---------------------------------
  display.display();
  //analogComparator.enableInterrupt();

  analogComparator.waitComp(1000);
  while ( Acounter <= AMP)
  {
    c = millis();    
    t = (c - a) / 1000;
    display.fillRect(0,55,127,14,WHITE);
    display.setTextSize(1);
    display.setTextColor(BLACK);
    display.setCursor(39,56);
    display.print("t:");
    display.print(t);
    display.print("sec");  
    display.display();

     if (positivState)
     {
      Acounter++;
      digitalWrite(ledPinpositiv,HIGH);
      positivState = false;       
     }
     if (negativState)
     {
      //Acounter--;
      digitalWrite(ledPinnegativ,HIGH);
      negativState = false;       
     }

     
      Serial.println(x);
      //Serial.println(enableLed);
      digitalWrite(ledPinpositiv,LOW);
      digitalWrite(ledPinnegativ,LOW);
      
      display.setCursor(17,17);
      display.fillRect(17,17,75,33,BLACK);
      display.setCursor(20,17);
      display.setTextSize(4);
      display.setTextColor(WHITE);
      display.print(Acounter);
      }
  
  
    
  
  newAcounter = Acounter /  2;
  S = (newAcounter / AMP) * 60;
  Acounter = 0;
  go = go -1;
  //t = 0.000;
  x = 0;
  
   
}

void loop() 
{
  //analogComparator.disableInterrupt();
  
  if (go == 0 )
  {
  homeScreen();
  }
  if(go == 1 )
  {
  meassuring();
  }

  //Serial.println(S);
}

void start_ISR() 
{
  if((millis() - alteZeit) > entprellZeit)
  { 
    // innerhalb der entprellZeit nichts machen
    
    go++;
    
    alteZeit = millis(); // letzte Schaltzeit merken
    a = millis();
   }         
   
}

void positivWave() 
{
    positivState = true;
    digitalWrite(ledPinpositiv,HIGH);    
}

void negativWave() 
{
    negativState = true;
    digitalWrite(ledPinnegativ,HIGH);    
}

Als Referenzspannung wurden ca. 1,6 Volt mittels Poti eingestellt, der Beschleunigungssensor liefert ca. 1,5 Volt in Ruhe Lage.

@Klaus_ww wenn du mir deine Adresse per pw schickst und du gerne bier trinkst lass ich dir gerne ein six pack zukommen :wink:

Hey, sehr nett - aber ich trink mal gern ein Gläschen auf Deinen Erfolg wenn das Teil so läuft wie Du es möchtest :smiley:

Laut meinem Verständiss bräuchte mann zwei Schwellspannungen die überwacht werden

Richtig: eine Schwelle ab der ein HIGH erkannt wird, und eine mit Abstand darunter die als LOW erkannt wird. Den Abstand nennt man Hysterese.
Ich kenne die Komparatorfunktion beim arduino nicht (nur, dass es sie gibt) und ich baue meine Komparatoren einfach per Hardware auf. Zehngangpoti für die Einstellung und man muss nicht mehr am Code rumfummeln.
Aber wie sagte ich schon mal: viele Wege führen nach Rom.

Hey, sehr nett - aber ich trink mal gern ein Gläschen auf Deinen Erfolg wenn das Teil so läuft wie Du es möchtest :smiley:

Auch Gut :slight_smile:

Richtig: eine Schwelle ab der ein HIGH erkannt wird, und eine mit Abstand darunter die als LOW erkannt wird. Den Abstand nennt man Hysterese.
Ich kenne die Komparatorfunktion beim arduino nicht (nur, dass es sie gibt) und ich baue meine Komparatoren einfach per Hardware auf. Zehngangpoti für die Einstellung und man muss nicht mehr am Code rumfummeln.
Aber wie sagte ich schon mal: viele Wege führen nach Rom.

Da ich keine Möglichkeit zur Hysteresen Verwendung im integrierten Komp. finde möchte ich auch eine Hardwarelösung probieren. Zu welcher Komponente würdest du greifen?

74LM595 Schmitt Trigger

oder
LM714 operational Amp

Danke
Gruß
Ardukus

Ich nehm immer dem LM393, DIP8 ist klein und gross genug für entspanntes arbeiten.

Hallo,

der 741 ist eigendlich für +-15 Volt gebaut. man kann Ihn aber auch mit einer Spannung betreiben. Allerdings geht der Ausgang bis 1,5 V unterhalb der Versorgungsspannung.

wenn Du den also mit 5V betreiben willst geht der Ausgang von 1,5-3,5V etwa , also nicht so optimal. Es gibt allerdings OP die sind dafür besser geeignet. Kenn ich aber nicht, es gibt aber Leute hier die wissen das.

Heinz

LM393, hat glaub ich schon jemand erwähnt 8)

Hallo,

jetzt weiss ich es auch, stimmt das Ding wurde vor einiger Zeit schon mal hier erwähnt, In Verbindung mit einer Lamda Sonde richtig ?

Heinz

der 741 ist eigendlich für +-15 Volt gebaut. man kann Ihn aber auch mit einer Spannung betreiben. Allerdings geht der Ausgang bis 1,5 V unterhalb der Versorgungsspannung.

Da die Komponenten auch irgendwann "stanalone" laufen sollten, ist er ws ungeeignet da hast du recht

LM393 klingt ja wirklich gut :slight_smile:
Anbei die Pin Belegung.
Folgende Annahme:

1 Out = digitales High wenn 1IN+ größer 1IN-
2 1 IN - = positiver Schwellwert
3 1 IN+ = Vergleichsspannung
4 GND

8 Vcc = 3V
7 Out2 = digitales High wenn 2IN+ kleiner 2IN-
6 2IN- = neagativer Schwellwert
5 2IN + = Vergleichsspannung

LM393.PNG

Üblicherweise wird eine Hysterese mit einer positiven Rückkopplung implementiert. Dafür reicht 1 OpAmp.

Üblicherweise wird eine Hysterese mit einer positiven Rückkopplung implementiert. Dafür reicht 1 OpAmp

und wie realisiere ich das mit einem (oder 2 ?) LM393- Komparator?

Genauso. Zur Referenzspannung (positiver Eingang) etwas Ausgangsspannung addieren, und schon hat man Hysterese.

Stimmt, danke, ein LM393 sind zwei opamp.
Als Beispiel für positive Rückkopplung = Hysterese z.B. hier:

Gefunden bei www.elcircuit.com

Als Anregung wenn du es doch Softwareseitig machen möchtest: Dieser Codefetzen unten zählt bei mir die Flanken (in dem Fall nur steigend) eines digitalen Rechtecksignals. Wenn du statt HIGH und LOW abfragst, ob der analoge Wert größer oder kleiner irgendeines Wertes ist, könntest du die Nulldurchgänge doch mit beliebiger Hysterese zählen. Oder hab ich was übersehen? War nur mein erster Gedanke und den Code hatte ich wie gesagt parat aus dem einfacheren, digitalen Pendant zu deinem Anwendungsfall.

bool Status = digitalRead(2);
   

if(letzterStatus == LOW && Status == HIGH){
  Flanken++;
}

   letzterStatus = Status;

Hallo Leute,

Als Anregung wenn du es doch Softwareseitig machen möchtest:

Danke @Mahimus, da die LM393 IC noch bis zum Wochenende auf dem Weg zu mir sind hab ich die Hysterese auf der Softwareseite mal ausprobiert.

Hier der Auszug aus dem Hauptteil:

int sensorValue1 = analogRead(sensorPin);
    float voltage1 = sensorValue1 * (5.0 / 1023.0);

    
    
      if (voltage1 <= lowerTR )
      {
      digitalWrite(ledPinnegativ, HIGH);
      digitalWrite(ledPinpositiv, LOW);
      digitalWrite(ledPinmitte1, LOW);
      digitalWrite(ledPinmitte2, LOW);
      hold = false;
      }
  

      if ((voltage1 >= lowerTR) && (voltage1 <= upperTR))
      {
      digitalWrite(ledPinnegativ, LOW);
      digitalWrite(ledPinpositiv, LOW);
      
      digitalWrite(ledPinmitte1, HIGH);
      digitalWrite(ledPinmitte2, HIGH);
      }

      if(voltage1 >= upperTR && hold == false)
      {
      digitalWrite(ledPinnegativ, LOW);
      digitalWrite(ledPinpositiv, HIGH);
      digitalWrite(ledPinmitte1, LOW);
      digitalWrite(ledPinmitte2, LOW);
      Acounter ++;
      hold = true;
      }

Gruß Ardukus