Hilfe: kontinuierliche Sensorwertabfrage um DAC einzustellen

Hallo, für einen späteres Projekt ( Lichtmessung mittels Photodiode und Transimpedanzverstärker = Sensorkalibration) möchte ich vorher in einfacher Form ein Sensor Projekt mit Arduino Mega 2560 realisieren:

Einstellen eines D/A- Wandler ( Microchip MCP 4921 12 Bit) um eine definierte Spannung an einem Ausgang zu erreichen und zu halten.

Am Ausgang ( Led rot, Kollektor Transistor) sollen z.B. genau 2 V anliegen.
Da jedoch meinen Analogeingang A0 vom Mega auf 5v zu GND bezogen ist ergeben sich an der Collektor-Emmiterspannung errechnete 3 V(5v-2V=3V)
Daher soll am Analogeingang A0 3V anliegen um meine gewünschte 2 V zu haben.
Das entspricht einem Digitalwert von: 614 (: 3/(5 V Ref / 1023) = 613,8 =>614)

Der DAC soll dann die Basisspannung des Transistor soweit erhöhen ( und zwar in Hochgeschwindigkeit) bis meine gewünschten 2V am Analogeingang herrschein und dann so stehen bleiben sollen.

Mein Sketchcode habe ich angefangen und komme nicht weiter und hoffe auf eure Hilfe!

(Hinweis: SPI und DAC funktionieren, Definierte Ausgangsspannung des DAC " AnalogOutput1.setValue() gehen auch)

#include <SPI.h> // SPI Lib
#include “AH_MCP4921.h” // DAC Lib
AH_MCP4921 AnalogOutput1(51,52,53); // SPI Ausgänge Mega
#define AI1 A1 //define analog input pin DAC
int sensorPin = A0; // zu lesende Spannung am Analogeingang Mega
int i = 0;
int j = 0;
int sensorValue = 0; // variable (Bitwert der Spannung)

void setup() {
AnalogOutput1.setValue(0); // DAC U = 0V
pinMode(AI1,INPUT); //Voltage measurement pin
sensorValue = analogRead(sensorPin); // gelesene Spannung (Bitwert)
{
if (sensorValue <614)
{ i++;
AnalogOutput1.setValue(i);
}
}
}

//*****************************************************************
void loop() {}

so habs hinbekommen, allerdings dauert es ein bischen. wenn ich mit +=20 inkrementiere , dauert es ca 100 ms , bis mein wert erreicht ist, jemand ein Tipp wie es schneller geht? Oszi zeigt bei Clock vom DAC 64kHz beim arbeiten an.

void setup() { 

  AnalogOutput1.setValue(0);     //set voltage to zero
  pinMode(AI1,INPUT);            
  Serial.begin(9600);            
  int analogPin= A0;
  int val = 0;    // analog pin  oV
  float v ;
  int sensor = 0;
  int i = 0;
  val = analogRead(A0);
  
  while (val>614)      //abfrage ob Analogpin 614 bits hat / 3 v
{
  if (val>614)
  {i+=20;
  AnalogOutput1.setValue(i);
  val = analogRead(A0);
       
   Serial.println(";");                         //monitor Ausgang mit Umrechnung auf Volt
   float g = 0.0048828125 ;
   float f = val;
   float v = f *g;
   Serial.print(v);
   
  
}}} 

//*****************************************************************
void loop() { }

Wenn du den ADC per Hand ansteuerst, statt mit analogRead() kannst du um ein mehrfaches schneller messen. Vor allem durch die Einstellung des Prescalers des ADC Takts (je niedriger, desto schneller).

Versuchs mal hiermit: http://forum.arduino.cc/index.php?topic=160703.msg1203755#msg1203755 http://forum.arduino.cc/index.php?topic=160703.msg1205225#msg1205225 (da steht ne Korrektur für einen Teil des Codes. Sehr wichtig)

Siehe Seite 292ff: http://www.atmel.com/images/doc2549.pdf

Das ADSC Bit (AD Start Conversion) im ADCSR startet eine Konvertierung. In dem Code oben wird das in Setup gemacht damit das ständig läuft. Wenn du jede Konvertierung einzeln starten willst musst du ADATE (Auto Trigger Enable) auf 0 lassen.

Der Code setzt auch die Genauigkeit auf 8 Bit herab. Das ist ein klein wenig schneller, aber wenn dir das nicht ausreicht musst du ADLAR (AD Left Adjust) auf 0 lassen und erst ADCL und danach ADCH auslesen (Seite 294).

Was ist denn mit "per Hand" gemeint? Ich muss doch analogRead nehmen, weill ich den DAC in Anhängig der gemessenen Spannung einstellen muss....

Du musst nicht analogRead() verwenden. Das ist lediglich eine Funktion der Arduino IDE, die das ganze stark vereinfacht. Man kann den ADC aber auch direkt mit den AVR Funktionen ansteuern (genauso wie alle anderen Teile des Prozessors auch, z.B. Timer oder Port Register), was dann schneller geht und wesentlich flexibler ist, aber eben auch komplizierter. Da musst du dann eine Reihe von Bits in bestimmten Registern per Hand setzen und auslesen. Wenn du analogRead() machst, geschieht das im Hintergrund. Aber wenn man es selbst macht kann man noch andere Dinge tun wie den Takt des ADCs erhöhen. Oder man kann nur ein, statt zwei, Datenregister auslesen(8 Bit statt 10 Bit), was auch etwas schneller ist.

Du musst dich nur entscheiden ob die den ADC ständig laufen lassen willst (Auto-Trigger + Free Running Mode wie im verlinkten Code) oder jede Konversion einzeln starten willst.

aha klingt nicht verkehrt, nagut dann muss ich wohl noch das Datenblatt studieren, um sämtliche stellschrauebn zwecks Speed zu verstellen

Du musst dich nur entscheiden ob die den ADC ständig laufen lassen willst (Auto-Trigger + Free Running Mode wie im verlinkten Code) oder jede Konversion einzeln starten willst.

das war mir jetzt zuviel, bzw hab ich nicht ganz geschnallt.

Probiers erst mal so wie es da steht. Den Code aus dem ersten Link mit der Korrektur aus dem zweiten. Das sollte schon mal laufen. Vielleicht reicht das schon ohne große Modifikation. Der Eingang sollte Standard-mäßig auch A0 sein.

Dann macht der ADC glaube ständig Konvertierungen und überschreibt jedesmal die Daten-Register mit dem neuen Ergebnis. Das ist in diesem Fall wahrscheinlich ok. Wenn du aber jede Konvertierung einzeln per Hand aktivieren willst (ähnlich wie bei AnalogRead) musst du das Auto-Trigger Bit auf 0 (der Standard-Wert) lassen. Aber mach es wie gesamt erst mal ohne Modifikationen.

Wenn du da mit Google suchst findest du da auch Anleitungen dazu. z.B. hier: http://www.marulaberry.co.za/index.php/tutorials/code/arduino-adc/

Wie du da siehst kann man auch den Pre-Scaler runter setzen und dann immer noch analogRead() machen. Das wäre für dich einfacher. Da steht aber auch, dass man ab mehr als 250 kHz (Pre-Scaler kleiner 64) nur noch 8 Bit Auflösung verwenden sollte und das geht dann nicht mehr mit analogRead()