Go Down

Topic: Rechtecksignal funktioniert nicht (Read 1 time) previous topic - next topic

19joe91

Hallo Leute,
ich versuche gerade ein Rechtecksignal zwischen 8kH (125µs) und 20kH (50µs) zu erzeugen. Dazu noch ein um 90° phasenverschobenes mit gleicher Frequenz.
Wenn ich die Frequenz fix vorgebe, funktioniert es, sobald ich jedoch die Frequenz variabel (über Potentiometer) mache, nicht mehr. Und ich komm einfach nicht dahinter warum...

Code: [Select]
int Red=13;
int Green=12;
int statRed=LOW;
int statGreen=HIGH;
unsigned long previousMicro=0;
unsigned long previousMicro2=0;
unsigned long currentMicro=micros();
unsigned long interval;
unsigned long wait=interval/2;
int sensorPin = A1;
int sensorValue;
int sensorMin=0;
int sensorMax=1023;


void setup()
{
  pinMode(Red,OUTPUT);
  pinMode(Green,OUTPUT);
  //Serial.begin(9600);
}

void loop()
{
  unsigned long currentMicro=micros();

  sensorValue = analogRead(sensorPin);
  sensorValue = map (sensorValue, sensorMin, sensorMax, 125, 50);
  interval=sensorValue;

  //Serial.println(interval);


  if(currentMicro-previousMicro>interval)
  {
    previousMicro=currentMicro;

    if(statRed==LOW)
    {
      statRed=HIGH;
      digitalWrite(Red,statRed);
    }
    else
    {
      statRed=LOW;
      digitalWrite(Red,statRed);
    }
  }
  if(currentMicro-previousMicro2>interval)
  {
    previousMicro2=currentMicro;

    if (currentMicro=wait)
    {

      if(statGreen==LOW)
      {
        delay(wait);
        statGreen=HIGH;
        digitalWrite(Green,statGreen);
      }
      else
      {
        delay(wait);
        statGreen=LOW;
        digitalWrite(Green,statGreen);
      }
    }
  }
}


Vielen Dank schon mal für die Hilfe!
mfg Joe

michael_x

Code: [Select]
   if (currentMicro=wait)

sollte wenn überhaupt, wohl was anderes sein.

Was du mit delay() bei 50 µs Zyklus-Zeiten machen willst, verstehe ich auch nicht.

50µs sind schon knapp für "normale Arduino" Programmierung, das ist eher was für Timer.
Zumal wenn du in loop ein analogRead hast, was allein ca. 100 µs braucht.

AWOL

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

Serenifly

#3
Sep 02, 2013, 04:14 pm Last Edit: Sep 02, 2013, 05:39 pm by Serenifly Reason: 1
Wie gesagt, dauert die AD-Wandlung ihre Zeit. Das ist ein langsamer Sukzessive Approximations Wandler. Kann man etwas schneller machen wenn man den Wandler-Takt erhöht. Der Prescaler steht standarmäßig auf 128 und man kann ihn auf 64 herabsetzen damit der Takt doppelt so hoch ist (das sind aber immer noch ca. 60µs !):
http://www.marulaberry.co.za/index.php/tutorials/code/arduino-adc/

Für noch höhere Geschwindigkeit muss man theoretisch auch die Auflösung auf 8 Bit herabsetzen. Aber laut der Seite sind auch noch mit 10 Bit und Prescaler 32 (ca. 35µs) und sogar 16 (ca. 20µs) noch gute Resultate erzielbar und du brauchst es sowieso nicht so genau.


Du solltest dafür auch entweder Port Manipulation verwenden oder mindestens DigitalWriteFast:
http://code.google.com/p/digitalwritefast/

Ein Port toggeln geht auch mit weniger Code so (aber auch nicht schneller!):
digitalWrite(Red, !statRed)

Am schnellsten geht es wenn man eine 1 auf das entsprechende Bit des Port-Eingangsregisters PINx schreibt. Das braucht nur ein oder zwei Taktzyklen. Siehe Datenblatt Seite 77.

Oder mach dir mal Gedanken ob du die beiden Signale nicht mit einem Timer erzeugen kannst.

michael_x

Um ein Poti einzulesen, muss man nicht analogRead() schneller machen.

Was man machen könnte, wäre nicht auf ein Ergebnis warten...


Aber 20 µs sollte man besser mit Timern hinkriegen ( direkte Port-Manipulation wäre auch nicht verkehrt, stimmt ).

TERWI

Ich würd's auch nur per Timer machen.
Du musst nur die Registerwerte korrekt setzen und einen Out auf COMxA1 und den 2. Out auf COMnA0 +A1 setzen.
Dann erzeugt ein Timer die passenden Frequenzen invertiert an 2 Ausgängen.
Mit dem passenden Prescaler und nem 16 Bit-Timer geht da schon was.
Vor allendingen belastet das dein Programm nicht und du kannst auch schneller als 20KHz werden.
... und digitalWrite & Co. und etwaige delays entfällt völlig.
To young to die - never to old for rock'n roll

Serenifly


Was man machen könnte, wäre nicht auf ein Ergebnis warten...

Stimmt. Da musst er sich aber damit beschäftigen den ADC per Hand zu bedienen.

ADC Interrupt Enable Bit ADIE im ADCSRA Register setzten. Dann die Wandlung mit dem ADC Start Conversion Bit ADSC starten. Und in der ISR die Daten-Register ADCL und ADCH auslesen.

udoklein

Ich habe sowas ähnliches schon mal in meinem Blog breitgetreten:

http://blog.blinkenlight.net/experiments/measurements/flexible-sweep/

Nur wird dort die Frequenz über die serielle Schnittstelle eingestellt. Das Problem ist aber das selber: das Auslesen und Auswerten der seriellen Schnittstelle ist zu langsam als man in der Zeit selber einen Takt erzeugen könnte --> deshalb mache ich das per Timer. Auf die gleiche Weise könnte man auch 2 Timer benutzen. Alternativ könnte man die Interrupts auch mit der doppelten Frequenz auslösen und den die 2 Kurven dann in Software ausgeben.
Check out my experiments http://blog.blinkenlight.net

Go Up