Arduino+Messschieber+delay

Hallo,

ich bin den Anweisungen dieser Seite gefolgt um einen Messschieber an den Arduino anzuschließen, nach einigem hin und her lief das ganze dann auch mit dem Beispiel Code hier.

Als Augabe habe ich einige binäre Zahlenreihen, die so aussehen:

1,0,0,0, 1,0,1,1, 1,1,1,0, 0,0,0,0, 0,0,0,0, 0,0,0,0
1,0,0,0, 1,0,1,1, 1,1,1,0, 0,0,0,0, 0,0,0,0, 0,0,0,0
1,0,0,0, 1,0,1,1, 1,1,1,0, 0,0,0,0, 0,0,0,0, 0,0,0,0

Das sind meine Messergebnisse Binär. Die zweite bis 17 Stelle ergibt in umgekehrter Reihenfolge meine Messung in mm/100.

Ich würde jetzt gerne die Messergebnisse in einer Funktion auslesen lassen, also den Code aus Loop in eine Funktion namens zum Beispiel caliper() verschieben, um dann mein Messergebnis zurückgeben zu lassen.

Ich hab das rein experimentell mal so aufgebaut, dass ich in der Zeile, die für den Zeilenumbruch sorgt (an der Stelle, wo die Übertragung vom Messschieber abgeschlossen ist) einen char* namens measure zurück gebe. In der Variabel befinden sich die 1&0 aneinandergehängt.

Leider habe ich (wie nicht anders erwartet) kein Ergebnis…

Bevor ich das ganze versucht habe in eine andere Funktion umzulagern, hat die Methode mit dem char* funktioniert.

Meine Idee ist, dass der Fehler irgendwie mit dem Zählen der vergangenen Mikrosekunden zusammenhängt und ich deswegen kein Ergebnis bekomme?

Ich hoffe auf Hilfe :slight_smile:

//Simple Digital Calliper Reader
//See http://j44industries.blogspot.com/

// Pin Declarations
int dataIn = 11;
int clockIn = 12;

// Variables

int clock = 1;
int lastClock = 1;

unsigned long time = 0;
unsigned long timeStart = 0;
int out = 0;


void setup() {
  // Pin Set Up
  pinMode(dataIn, INPUT);     
  pinMode(clockIn, INPUT);  


  Serial.begin(115200);
  Serial.println("Ready: ");
}



void loop(){
  Serial.println(caliper());
}

char* measure;

char* caliper(){

  lastClock = clock;
  clock = digitalRead(clockIn);

  if (lastClock == 1 && clock == 0){
    out = digitalRead(dataIn)+digitalRead(dataIn)+digitalRead(dataIn); // Tripple sampling to remove glitches
    if((micros() - time) > 800){
      //Serial.println(" ");
      return measure;
      measure="";
      
    }
    else if((micros() - time) > 400){
     // Serial.print("  ");
    }

    if (out > 1){
     // Serial.print("1");
      strcat(measure,"1");
    }
    else{
      //Serial.print("0");
      strcat(measure,"0");
    }
    //Serial.print(",");
    time = micros();
  }
}

Sorry, aber den Code kann man fast nicht lesen.

Bitte setze diesen in Code-Tags (Schaltfläche “</>”) hier rein.

Dann wird das für uns einfacher.
Danke

Ist geschehen. Hab die Buttons verwechselt. Sorry!

patmro:
Ist geschehen. Hab die Buttons verwechselt. Sorry!

Prima, danke

patmro:
Das sind meine Messergebnisse Binär. Die zweite bis 17 Stelle ergibt in umgekehrter Reihenfolge meine Messung in mm/100.

Ich würde jetzt gerne die Messergebnisse in einer Funktion auslesen lassen, also den Code aus Loop in eine Funktion namens zum Beispiel caliper() verschieben, um dann mein Messergebnis zurückgeben zu lassen.

Und warum nimmst Du dann zum Auslesen nicht diesen Code (Pins ggf. anpassen):

int i;

int sign;

long value;

float result;

int clockpin = 4;  

int datapin = 5;

unsigned long tempmicros;

 

 

void setup() {

  Serial.begin(9600);

  pinMode(clockpin, INPUT);

  pinMode(datapin, INPUT);

}



 void loop () {

  while (digitalRead(clockpin)==HIGH) {} //if clock is LOW wait until it turns to HIGH

  tempmicros=micros();

  while (digitalRead(clockpin)==LOW) {} //wait for the end of the HIGH pulse

  if ((micros()-tempmicros)>500) { //if the HIGH pulse was longer than 500 micros we are at the start of a new bit sequence

    decode(); //decode the bit sequence

  }

}

 

void decode() {

  sign=1;

  value=0;

  for (i=0;i<23;i++) {

    while (digitalRead(clockpin)==HIGH) { } //wait until clock returns to HIGH- the first bit is not needed

    while (digitalRead(clockpin)==LOW) {} //wait until clock returns to LOW

    if (digitalRead(datapin)==LOW) {

      if (i<20) {

        value|= 1<<i;

      }

      if (i==20) {

        sign=-1;

      }

    }

  }

  result=(value*sign)/100.00;    

  Serial.println(result,2); //print result with 2 decimals

  delay(1000);

}

Von dieser Seite: Arduino reads digital caliper - martin's useless and useful creations

Für mich sieht der Code so aus als wenn da direkt float Gleitkommazahlen in hundertstel Millimeter auf Serial ausgegeben werden.

Weil dieser Code nicht funktioniert. Abgesehen davon, dass die abfrage >500 nicht stimmen kann, weil 400 Mikrosekunden der richtige Wert ist, gibt der Code nach Anpassung nur Quatsch aus. (Und vor Anpassung gar nichts)

32767 111111111111111
-8193 10000000000001
-129 -1
-16385 100000000000001

Das sind die einzigen Werten (in Dezimal) die er mit ausgibt. Ich hab mal geschaut, was das in Binär wäre um ein Muster zu erkennen.

Jedenfalls habe ich dieses Beispiel natürlich auch gesehen und probiert, nur leider funktioniert es nicht.

Erstaunlich dass dein Code überhaupt etwas ausgibt.

Du schreibst hemmungslos in den Speicher, ohne einen Puffer zu benutzen.

Deine caliper Routine gibt nur ab und an etwas zurück...

Was mir aber am meisten fehlt ist irgendeine Art von Schleife mit der die Bits eingesammelt werden.

Die Konversion der Bits ist simpel, vielleicht könnte so etwas besser funktionieren

//Simple Digital Calliper Reader
//See http://j44industries.blogspot.com/

// Pin Declarations
const byte dataIn = 11;
const byte clockIn = 12;

void setup() {
  // Pin Set Up
  pinMode(dataIn, INPUT);
  pinMode(clockIn, INPUT);

  Serial.begin(115200);
  Serial.println("Ready: ");
}

void loop() {
  Serial.println(caliper(), 2);
}

unsigned long caliper() {
  int clock = 1;
  int lastClock = 1;
  unsigned long time = 0;
  unsigned long lRet = 0;

  while (true) {
    lastClock = clock;
    clock = digitalRead(clockIn);

    if (lastClock == 1 && clock == 0) {
      byte out = digitalRead(dataIn) + digitalRead(dataIn) + digitalRead(dataIn); // Tripple sampling to remove glitches
      if ((micros() - time) > 800) {
        break;
      }
      lRet >>= 1;  // bisheriges Muster ein bit nach unten shiften
      if (out > 1) {
        lRet |= 0x80000000ul; // oberstes bit setzen
      }
      time = micros();
    }
  }
  return lRet >> 9; // 24 bit empfangen, also ein byte(8) und das eine bit(1)
}

Ich möchte nur eben darauf hinweisen, dass das nicht MEIN code ist :smiley: (auch wenn ichs selber nicht besser hinbekommen hätte)

Ich muss deinen Vorschlag morgen einmal ausprobieren, vielen dank.

Wer hat sich denn dann an dem Code versucht? :wink:

Sag ihm/ihr mal er/sie solle sich das mit char* noch mal ansehen,
pointer sind zwar schön, sollten aber auf etwas Sinnvolles zeigen.

pointer = ""; ist keine Methode um einen Puffer zu löschen.

Statements hinter einem return werden nie ausgeführt.

Im Originalcode war loop() die Schleife, die ich in deinem Code vermisst habe.

Das Vorzeichen ist in meinem Vorschlag noch enthalten,
(die Bitpositionen und die Bitreichenfolge sollte aber stimmen)
für ein korrektes Ergebnis müsstest du das noch auswerten.
Bei nur positiven Messwerten sollte der Wert 1/100mm entsprechen.

Whandall:
Wer hat sich denn dann an dem Code versucht? :wink:

Achso, ich dachte du meintest den ursprünglichen Code, die Veränderungen gehen natürlich auf meine Kappe.

Immer daran denken, dass auch eigener Speicher an der Stelle ist, wo der Pointer hinzeigt.

In deinem Original hattest du das übersehen.

Oder nimm einen char Array

char Puffer[32];

  Puffer[0] = 0; // leeren
  *Puffer = 0;   // alternativ, völlig gleichbedeutend

  Puffer[4] = 'a';
  *(Puffer+4) = 'a';

Einen Array kannst du als konstanten Pointer betrachten, man ihn nicht einfach incrementieren oder woanders hinzeigen lassen,
aber durchaus in arithmetischen Ausdrücken benutzen.

Wenn es immer um ein und den selben Puffer geht ist ein Array sinnvoller, weil weniger fehleranfällig.

Hallo,

bevor überhaupt etwas richtig passiert, muß

a) eine Pegelanpassung von 1,5V auf 5V vorhanden sein > Komparator aufbauen.
b) benötigt man ein paar Versuche und vorallendingen Bsp., damit man erstmal weis welches Protokoll der Meßschieber hat. Haste ein Oszi oder einen Logikanalyzer?
c) dein Binär Bsp. oben, welches Maß soll dem entsprechen in [mm]?

Erst dann kann man seine Funktion schreiben für mehr Automatisierung.

d) werden "Arduino Komfortbefehle" wie digitalRead eh zu langsam sein

Wenn Dein Meßschieber wirklich das Sylvac Protokoll nutzt, dann mußt Du erstmal den Startimpuls vom Takt mit definierter Pause einfangen. Ab dem Zeitpunkt weist du sicher, jetzt gehts los, jetzt kommen die Daten. Die Daten mußte dann hintereinander einlesen. Aber wie gesagt, digitalRead ist dafür zu langsam.

Doc_Arduino:
Hallo,

bevor überhaupt etwas richtig passiert, muß

a) eine Pegelanpassung von 1,5V auf 5V vorhanden sein > Komparator aufbauen.

:heavy_check_mark:

Doc_Arduino:
b) benötigt man ein paar Versuche und vorallendingen Bsp., damit man erstmal weis welches Protokoll der Meßschieber hat.

:heavy_check_mark:

Doc_Arduino:
c) dein Binär Bsp. oben, welches Maß soll dem entsprechen in [mm]?

Siehe mein erster Beitrag:

Das sind meine Messergebnisse Binär. Die zweite bis 17 Stelle ergibt in umgekehrter Reihenfolge meine Messung in mm/100.

Was dann glaube ich 1,25mm waren (Bin gerade bei der Arbeit und kanns nicht testen, nur nachrechnen)

Doc_Arduino:
Erst dann kann man seine Funktion schreiben für mehr Automatisierung.

:heavy_check_mark:

Doc_Arduino:
d) werden "Arduino Komfortbefehle" wie digitalRead eh zu langsam sein

Warum zu langsam? Ich meine, es funktioniert doch? Ich erhalte doch ein zufriedenstellendes Messergebnis mit dem Beispiel der verlinkten Seite? Oder meinst du, dass das Auslagern in eine Funktion nicht funktioniert? Das hätte ich gerne erklärt.

Doc_Arduino:
Wenn Dein Meßschieber wirklich das Sylvac Protokoll nutzt,

Ich glaube, es ist das Mitutoyo Protokoll, wird jedenfalls in den Kommentaren der verlinkten Seite erwähnt.

Doc_Arduino:
dann mußt Du erstmal den Startimpuls vom Takt mit definierter Pause einfangen. Ab dem Zeitpunkt weist du sicher, jetzt gehts los, jetzt kommen die Daten. Die Daten mußte dann hintereinander einlesen.

Da bin jetzt dran :slight_smile:

Doc_Arduino:
Aber wie gesagt, digitalRead ist dafür zu langsam.

Versteh ich immer noch nicht.

Ich bin in den letzten Tagen leider nicht dazu gekommen, weiter zu machen aber mache mich heute Abend da mal wieder ran. Ich habe hier unter anderem gelesen, dass jemand eine Schleife in meiner Funktion vermisst, was ich absolut einleuchtend finde und heute Abend einmal ausprobieren muss. (Plus die anderen "kleinen" Fehler die ich ausmerzen muss)

Versteh ich immer noch nicht.

Die Arduino digial Funktionen fressen um die 150 Prozessor Takte.
Wenn du die direkten Port Zugriffe verwendest reicht eine handvoll Takte.

Weißt du zufällig, wo ich das nachschlagen könnte?

Was?

Das Datenblatt des Prozessors zeigt dir die Anschlüsse und Ports...

Hier ist das UNO Pinout:

Beim Prozessor sind immer 8 Pins zu einem Port zusammengefasst. Und diese sind mit Buchstaben B, C, D bezeichnet. Diese Namen siehst du bei den gelben Kästchen. z.B. Pin 9 = PB1 = Port B, Pin 1

Jeder Port hat 3 Register:
DDRn = Richtungsregister
PORTn = Ausgangsregister
PINn = Eingangsregister

Was du brauchst ist letzteres. Um PB1 zu lesen macht man einfach das:

if (PINB & (1 << PB1))
{
}

oder:

if (PINB & _BV(PB1))

Wichtig: bei dieser Variante auf keinen Fall auf LOW oder HIGH abfragen! Das geht nicht da HIGH 1 ist und man abfragen muss ob irgendein Bit gesetzt ist

Von Muecke gab es da doch mal gut funktionierenden Code. In Funktionen gekapselt und mit direktem Port-Zugriff

patmro:
Weißt du zufällig, wo ich das nachschlagen könnte?

Die Zahlen von Combie sind viel zu hoch gegriffen.

Ein digitalRead dauert auf beispielsweise einem UNO zwischen knapp 4µs (kein PWM Pin) bis knapp 5µs (PWM Pin), und auf einem MEGA zwischen knapp 5µs (kein PWM Pin) und knapp 6µs (PWM Pin).

Anbei ein kleines Testprogramm zum Messen des Zeitbedarfs für digitalRead():

const int pin=2;
const unsigned int loops=10000;

volatile byte b=1;

unsigned long timeNoDigitalRead()
{
  int sum=0;
  unsigned long  time =micros();
  for (int i=0;i<loops;i++)
  {
    sum= sum+b;
    /* digitalRead(pin) */;
  }
  return micros()-time;
}

unsigned long timeWithDigitalRead()
{
  int sum=0;
  unsigned long  time =micros();
  for (int i=0;i<loops;i++)
  {
    sum= sum+b;
    digitalRead(pin);
  }
  return micros()-time;
}



void setup() {
  unsigned long t1=timeNoDigitalRead();
  unsigned long t2=timeWithDigitalRead();
  Serial.begin(9600);
  Serial.println("Benchmark test digitalRead()");
  Serial.print(loops);Serial.println(" loops");
  Serial.print("no digital Read [us]   :  ");Serial.println(t1);
  Serial.print("with digital Read [us] :  ");Serial.println(t2);
  Serial.print("Each digitalRead()[us] :  ");Serial.println((float)(t2-t1)/loops);
}

void loop() {
}

Du kannst damit ja selbst mal messen, mit verschiedenen Boards und mit sowohl PWM-Pins und auch Nicht-PWM-Pins.

Die auf diese Weise durch Zeitvergleich über 10000 Schleifendurchläufe ermittelte Zeit ist übrigens etwas größer als die tatsächlich benötigte Zeit, denn die Zeitmessung schließt die ständigen Timer0-Interrupts im System mit ein. Ungefähr einmal pro Millisekunde (ca. alle 1000µs) findet einmal ein Timer0-Interrupt statt, der auch ca. 4µs dauert. D.h. von 1000µs Programmlaufzeit (brutto) stehen Dir eigentlich stets nur ca. 996µs (netto) tatsächlich zur Verfügung, den Rest verbrät das Arduino Core-System bereits für Timer0-Interrupts, um die Funktionen delay(), delayMicroseconds(), millis() und micros() zur Verfügung zu stellen.

Es sind ca. 60 Takte:
http://www.billporter.info/2010/08/18/ready-set-oscillate-the-fastest-way-to-change-arduino-pins/

Ich habe schon gelesen dass digitalRead() hier reichen würde. Bei Malerlein weiß ich aber noch dass er gesagt hatte dass es nicht geht. Ich weiß aber nicht ob das 100%ig stimmt, denn ihm fehlte vielleicht auch die Erfahrung das korrekt einzuschätzen

Wunderbare Weiterbildungsanregungen, die ich hier bekomme. Danke dafür an alle.

Mich interessiert jetzt aber immer noch warum combie behauptet, dass digitalRead() nicht funktionieren kann, wenn ich doch vor mir ein sichtbares und stimmiges Ergebnis gehabt habe, beim Testen des Beispielcodes.

Ist es denn jetzt legitim mit digitalRead() weiter zu arbeiten? Scheint ja doch schnell genug zu sein.