Automatisches Arduino-Oszilloskop                 

von Günther Zivny                       
 
                      Elektronik-Labor  Bastelecke  Projekte  Mikrocontoller                        



Download: Arduino_Oszilloskop.zip

Obwohl das Display SSD1306 sehr klein ist, kann man damit recht brauchbare Kurven darstellen. Dieses Oszilloskop benötigt nur sehr wenig Peripherie und hat keine Bedienelemente. Einfach die Messspitze auf den Messpunkt drücken – fertig. Alternativ kann man auch die Messspitze fest anschließen und einen Hardware-Reset machen (Taste auf der Arduino-Platine). Das bringt u. U. ein besseres Ergebnis, denn die Verstärkung und der Offset werden nur in einer Richtung verstellt. Ein einmal erreichter Wert wird nicht mehr zurückgenommen. Damit auch ins Negative gehende Spannungen (Wechselspannungen) dargestellt werden können, wird nach Bedarf eine Gleichspannung (Offset) addiert. Die waagerechte Linie ist die Null-Linie. Spannungen, die nur ins Negative gehen, werden nicht erfasst.

Die roten LEDs zeigen an, welche Verstärkung gerade eingestellt ist.
Die grünen LEDs zeigen den Zeitfaktor an, sie sind als Binärzahl zu verstehen.
Beispiel: Die LEDs 1 und 4 leuchten: 1 + 4 = 5,   25 = 32:   32ms / Teilstrich.
Die Skalierung erlaubt nur eine grobe Abschätzung der Werte.
Spannungsmessbereich: 400 mV … 16 V oder +/- 200 mV … +/-5 V
Frequenzbereich: 10 Hz … 1400 Hz (Sinus).

Bei sehr kleinen Frequenzen dauert es länger, bis die richtige Einstellung gefunden ist. Es funktioniert auch nicht immer perfekt. Man kann den Einstellvorgang am Bildschirm verfolgen und durch Abheben der Messspitze auch abbrechen. In der Regel wird dann das aktuelle Bild eingefroren, manchmal verschwindet es aber auch. Wenn man über etwa 1400 Hz hinaus geht, erhält man krakelige Linien. Häufig erscheint auch ein Bild, das an eine Schwebung (schwankende Amplitude) erinnert. Erstaunlich oft erhält man aber auch schöne Sinuslinien, die auf Oversampling beruhen. Das geht bis über 10 kHz, allerdings wird die Amplitude dann durch den 0.68 nF-Kondensator schon stark abgeschwächt.

 

Prinzip des Oversampling: Es wird pro Periode nur ein Messwert ermittelt, allerdings jeweils ein wenig verschoben. Die Messwerte können sich auch auf noch mehr Perioden verteilen.

 

Beschreibung des Programms

Um ein stehendes Bild zu erzeugen, wird normalerweise gewartet, bis die zu messende Spannung einen Schwellenwert erreicht, dann startet der Strahl. Hier wird das stehende Bild auf andere Art erreicht: Es werden immer 64 Punkte gemessen, aber nur 32 pro Bildschirm verwendet. In den ersten 32 Messwerten wird der kleinste Wert ymin gesucht. Bei diesem Wert startet die Kurve am linken Bildschirmrand, unabhängig davon, wann dieser Wert im Scan auftritt. Das funktioniert nur, wenn in den ersten 32 Messwerten mindestens eine vollständige Periode eines periodischen Signals auftritt. Nichtperiodische Signale können nicht dargestellt werden.


Damit auch ins Negative gehende Spannungen (Wechselspannungen) dargestellt werden können, wird bei Bedarf eine Gleichspannung (Offset) zum Signal addiert. Die Offset-Spannung kann maximal 5 V betragen. Der Verstärkungsfaktor wird so bestimmt, dass die Kurve nicht über den Bildschirmrand hinausgeht.

Die Zeitablenkung beginnt mit dem schnellsten Wert und wird dann schrittweise reduziert, bis eine vollständige Periode auf dem Bildschirm dargestellt wird. Das funktioniert so: In der ersten Hälfte des Bildschirms wird der Maximalwert ymax gesucht. Wenn dieser auf der Trennlinie liegt, wird eine langsamere Zeitablenkung eingestellt, sodass ein größerer Zeitabschnitt dargestellt wird.

 

Wenn man am Frequenzgenerator mit einer kleinen Frequenz beginnt und die Frequenz steigert, dann wird die Zeitablenkung nicht angepasst. Wenn man dagegen mit einer hohen Frequenz startet und diese langsam verringert, dann passt die Automatik die Zeitablenkung so an, dass immer mindestens eine volle Periode dargestellt wird.

Beispielbilder:

 

Sinuswechselspannung mit Mittellinie.


Fehlabtastung durch zu kleine Abtastrate.


Eigentlich saubere Rechteckspannung wird mit schrägen Flanken und abgerundeten Ecken dargestellt.


Überwiegend im Negativen verlaufende RC-Ladelinie, aber mit kleinem positiven Anteil. Ausschließlich negative Werte werden nicht erfasst.


//automatisches Oszilloskop

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
#define ADC_PIN A0
#define SAMPLES 64 //2*32!

uint16_t y[SAMPLES];
uint8_t trigPos = 0, V = 10, FLAG, i, ii, n, SR = 1, p = 0;
uint16_t ymin, ymax, offset = 0 ;
int x;
//............................................................

void setup() {
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();

pinMode(11,OUTPUT); //PWM1
pinMode(2,OUTPUT);
pinMode(3,OUTPUT);
pinMode(4,OUTPUT);
pinMode(5,OUTPUT);
pinMode(6,OUTPUT);
pinMode(7,OUTPUT);
pinMode(8,OUTPUT);
pinMode(9,OUTPUT);
}
//..........................................................
void loop() {

Mark:

FLAG = 1;

for(i = 0; i < SAMPLES; i++){ //Samples = Anzahl Messpunkte: 64
for (n = 0; n < SR; n++){ //SR = sampling rate: jede n-te Messung wird gespeichert
y[i] = analogRead(ADC_PIN);
}
}

ymax = 0;
ymin = 1024;

//......................
while (FLAG == 1) {
ymax = 0;
ymin = 1024;

for (i = 0; i < SAMPLES/2; i++) { //32 Messpunkte = Bildschirm
if (ymin > y[i]*V) {
ymin = y[i]*V; //ymin suchen
trigPos = i;
}
if(ymax < y[i]*V) { //ymax suchen
ymax = y[i]*V;
n = i; //ymax = y{n]
}
}
if (ymax < 1024) {
FLAG = 0; //while verlassen, Kurve stößt nicht oben an
}
else {
FLAG = 1; //Verstärkung reduzieren
V = V/2;
}
} //Ende while.................................

if ((y[n]<=6) & (y[n+1]<=6)) { //wenn kein input...
FLAG = 1;
V = 10; SR = 1; offset = 0; p = 0; //Zurücksetzen, wenn kein Input
analogWrite(11,0); //PWM = 0
delay(500);
goto Mark; //zurück an Anfang
}
//..............................................................
if (V==10) {digitalWrite(5,HIGH);} else {digitalWrite(5,LOW);}
if (V==5) {digitalWrite(4,HIGH);} else {digitalWrite(4,LOW);}
if (V==2) {digitalWrite(3,HIGH);} else {digitalWrite(3,LOW);}
if (V==1) {digitalWrite(2,HIGH);} else {digitalWrite(2,LOW);}
if (V==0) {V = 1;}
//...........................................

//Kurve mit neuer Verstärkung
for (i = 0; i < SAMPLES; i++) {
y[i] = y[i] * V;
}

//Kurve verschieben (offset) (Hardware!)
if (ymin <= 0) {
offset = offset + 51;
if (offset > 255) {offset = 255;}
analogWrite(11,offset);
}
delay(1000); //zur Spannungsstabilisierung nach offset

x = ymin-ymax; //bei sehr kleiner Frequenz, um von SR = 1 wegzukommen
x = abs(x);
if (x < 20 * V) {SR = SR*2; p = p+1;}
if (SR == 0) {SR = 128; p = 7;} //bei Überlauf


//Zeitablenkung optimieren
ymax = 0;
for (i = trigPos; i<=(trigPos+15); i++){ //+15 = halber Bildschirm
if (ymax < y[i]) {
ymax = y[i];
ii = i;
}
}
if (ii == (trigPos+15)) {
SR = SR*2;
p = p + 1;
}
if (SR == 0) {SR = 128; p = 7;}; //bei Überlauf

//SR mit LEDs anzeigen
if ((p & 1) == 1) {digitalWrite(6,HIGH);} else {digitalWrite(6,LOW);}
if ((p & 2) == 2) {digitalWrite(7,HIGH);} else {digitalWrite(7,LOW);}
if ((p & 4) == 4) {digitalWrite(8,HIGH);} else {digitalWrite(8,LOW);}

// Kurve zeichnen.....................................................
display.clearDisplay();

for ( i = trigPos; i < (trigPos + SAMPLES/2 - 1); i++) {
uint8_t y1 = map(y[i], 0, 1023, SCREEN_HEIGHT - 1, 0);
uint8_t y2 = map(y[i+1], 0, 1023, SCREEN_HEIGHT - 1, 0);

display.drawLine(4*(i-trigPos), y1, 4*(i-trigPos+1), y2, SSD1306_WHITE);
// 4*32 = 128 (Bildschirmbreite)
}

//Null-Linie zeichnen
int x1 = offset * 19 * V;
x1 = x1/255;
display.drawLine(0, 63-x1, 128, 63-x1, SSD1306_WHITE);

//Markierungen zeichnen, y-Ache
display.drawLine(0, 0, 3, 0, SSD1306_WHITE);
display.drawLine(0, 16, 3, 16, SSD1306_WHITE);
display.drawLine(0, 32, 3, 32, SSD1306_WHITE);
display.drawLine(0, 48, 3, 48, SSD1306_WHITE);
display.drawLine(0, 63, 3, 63, SSD1306_WHITE);
//x-Achse
display.drawLine(37, 63, 37, 60, SSD1306_WHITE);
display.drawLine(75, 63, 75, 60, SSD1306_WHITE);
display.drawLine(112,63, 112, 60, SSD1306_WHITE);
//.............

display.display(); //Display aktivieren
} //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::


Arduino-Oszilloskop upgrade und Mini-TestLab

von Günther Zivny    



Firmware-Download: Oszilloskop_upgrade.zip

Mit dieser erweiterten Version können wesentlich höhere Frequenzen dargestellt werden. Die kleinste Spannung Umin, die größte Spannung Umax und die Frequenz werden jetzt als Zahlen auf den Bildschirm geschrieben, sodass die Anzeige-LEDs entfallen können (sie können aber auch weiterhin benützt werden). Zusätzlich gibt es noch einen in der Frequenz einstellbaren Rechteckgenerator als Signalquelle, sodass man das Ganze als ein vom PC unabhängiges Mini-Testlab bezeichnen kann.

Oszilloskop

Um eine Sinuslinie ordentlich zeichnen zu können, braucht es mindestens 8 Stützpunkte. Der A/D-Wandlungszyklus dauert etwa 0,11 ms, sodass die kürzeste Signalperiode 0,88 ms, entsprechend 1,1 kHz ist. Zur Not geht auch noch etwas mehr. Laut dem bekannten Abtasttheorem genügen im Grenzfall schon zwei Stützpunkte pro Periode, woraus sich eine theoretische Grenzfrequenz von 4,8 kHz ergibt. Das ist aber für unsere Zwecke hier nicht umsetzbar. Wie schon in meinem vorhergehenden Beitrag beschrieben, kann man durch Unterabtastung auch wesentlich höhere Frequenzen mit dem Oszilloskop darstellen, wenn jede Periode oder auch nur jede n-te Periode nur einmal abgetastet wird. Voraussetzung ist, dass die Abtastperiode ungefähr ein ganzzahliges Vielfaches der Signalperiode ist. Je nachdem, ob die Abtastperiode etwas länger oder etwas kürzer als die Signalperiode ist, läuft die Zeitachse wie gewohnt von links nach rechts oder aber umgekehrt von rechts nach links, die Kurve erscheint also gespiegelt.

Es hat sich nun aber gezeigt, dass die vorhandene Stufung der Abtastintervalle ausreicht, um lückenlos alle Frequenzen darzustellen. Wo die obere Grenzfrequenz ist, konnte ich mit meinen Mitteln nicht ausprobieren; 100 kHz waren problemlos möglich. Allerdings wird die Anzeige dann zunehmend instabil. Wenn sich eine brauchbare Darstellung ergibt, kann man das Bild durch Abheben der Messspitze einfrieren.Um das auszunutzen, war nur eine kleine Ergänzung der Software nötig. Wenn zu viele Perioden am Bildschirm dargestellt werden, erscheint hinter der Frequenzanzeige ein „u“ und signalisiert, dass sich das Programm jetzt im Unterabtast-Modus befindet. Jetzt werden der Reihe nach alle Abtastfrequenzen durchgewechselt und man kann am Bildschirm das Ergebnis sehen. Wenn sich ein brauchbares Bild ergibt, stoppt der Vorgang. Wenn nicht, wiederholt sich das Ganze. Durch Abheben der Messspitze kann man den Vorgang abbrechen. Die Frequenzanzeige funktioniert nur bis maximal etwa 4200 Hz, danach kommt der A/D-Wandler nicht mehr mit und es werden unbrauchbare Werte angezeigt. Wenn das „u“ erscheint, ist die Frequenzanzeige also mit Vorsicht zu betrachten. Hintergrund: Der A/D-Wandler muss mindestens einen Wert über der Mittellinie erwischen. Wenn das Signal nur sehr geringe Anteile über der Mittellinie hat, ist die Grenzfrequenz niedriger. Bei den höheren Frequenzen macht sich der 0.68 nF-Kondensator bemerkbar: Sinuslinien werden in der Amplitude reduziert, andere Signalformen werden verformt dargestellt. Ich habe den Kondensator im Schaltplan schaltbar gemacht. Wenn es „ohne“ funktioniert, ist es in Ordnung. Bei niederen Frequenzen kann der Kondensator nützlich sein, um eventuell vorhandene Spannungsspitzen zu unterdrücken. Der kleine 15 pF-Kondensator dient zur Kompensation der Eingangskapazität. Das ist notwendig geworden, um auch mit höheren Frequenzen hantieren können.

 

Rechteckgenerator

Im Hintergrund läuft ein Rechteckgenerator ständig mit, das Signal erscheint an Pin 9. Der Einstellbereich beträgt 8 Hz bis 3906 Hz. Damit die Frequenzen bequem einstellbar sind, empfiehlt es sich, zwei Potentiometer für die Grob- und Feineinstellung vorzusehen. Die Frequenzen können allerdings nicht stufenlos eingestellt werden, denn der frequenzbestimmende Parameter OCR1A steht im Nenner eines Bruchs. Somit ist die Periodendauer T proportional zu OCR1A, die Frequenzen aber machen am oberen Ende große Sprünge. Es ist:

f = 8 000 000 /(1024 * (OCR1A+1)) [Hz].

Also:
OCR1A = 1 -> f = 3906 Hz
OCR1A = 2 -> f = 2604 Hz
OCR1A = 3 -> f = 1953 Hz
usw.

Am unteren Ende ist die Auflösung dagegen besser als 0,1 Hz. Das lässt sich nicht ändern. Die Potentiometerspannung wird nichtlinear bewertet, damit sich das vorgegebene Frequenzraster gut einstellen lässt.

Wichtig:
- Wenn das Signal keine negativen Anteile hat, kann man den „-“ -Eingang des Oszilloskops mit GND verbinden und das Rechtecksignal direkt ankoppeln (Beispiel 1 und 2).
- Wenn das anzuzeigende Signal dagegen negative Anteile hat, muss man das Null-Potential belastbar machen, im einfachsten Fall mit einem Emitterfolger (Beispiel 3).

Eine etwas aufwändigere Alternative ist die galvanische Trennung des Testobjekts vom Arduino mittels Optokoppler (Beispiel 4). Man benötigt eine eigene Spannungsquelle. Der Optokoppler verhält sich selber wie ein RC-Glied und muss belastet werden. Der beste Lastwiderstand ist etwa R=100 Ohm.  Man bleibt bei den Versuchen am besten unter 1 kHz.

Synchronisation mit der Rechteckfrequenz:
Wenn man den Pin 13 = high macht, wird die Zeitachse mit der Rechteckfrequenz synchronisiert. Diese Betriebsart ist vorteilhaft, wenn man mit der Rechteckspannung arbeitet, weil sich das Bild schneller aufbaut und stabiler ist. Hier gibt es keinen Unterabtastmodus.

Beispiele:

1. Darstellung des eigenen Rechtecksignals im Unterabtastmodus „u“, direkte Ankopplung:
Umin = 0.0 V, Umax = 5.0 V, gemessene Frequenz 3908Hz, darunter Generatorfrequenz 3906Hz.
Bei 3906 Hz beträgt die Periodendauer 0,25 ms, es passen also 4 Perioden in eine Millisekunde. Da die Torzeit in Millisekunden gemessen wird, schwankt die Frequenzanzeige etwas (deshalb die verschwommene Darstellung).
 

 

2. Direkte Ankopplung: Spannungsverlauf am Kondensator eines RC-Glieds. Das Programm schaltete fälschlicherweise in den Unterabtastmodus, was aber nichts ausmacht.
 

 
3. Belastbares Nullpotential durch Emitterfolger („-“ -Oszilloskopeingang an der Basis):
Spannungsverlauf am Widerstand eines RC-Glieds (mit negativen Spannungsanteilen). Bild siehe Beispiel 4.

 

4. Galvanische Trennung von Arduino und Testobjekt durch Optokoppler: Spannungsverlauf am Widerstand eines RC-Glieds. Die absoluten Spannungsspitzen werden naturgemäß nicht immer erfasst. Auf dem kleinen Bildschirm sehen die Bilder deutlich besser aus als in der Großaufnahme.

 

 //Oszilloskop mit Zahlen und Unterabtastung und mit Rechteckgenerator

#include <math.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
#define ADC_PIN A0
#define SAMPLES 64 //2*32!


uint16_t impulsZaehler = 0;
unsigned long letzteMessung = 0;
unsigned long frequenz;

uint16_t y[SAMPLES];
uint8_t trigPos = 0, V = 10, FLAG, i, ii, n, SR = 1, p = 0, ix, offst;
int16_t ymin, ymax, ymaxx, offset = 0, y0;
int x;
boolean u, SYN;

void setup() {
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setTextSize(1);

pinMode(2,OUTPUT);
pinMode(3,OUTPUT);
pinMode(4,OUTPUT);
pinMode(5,OUTPUT);
pinMode(6,OUTPUT);
pinMode(7,OUTPUT);
pinMode(8,OUTPUT);
pinMode(9,OUTPUT); //Rechteck
pinMode(10,INPUT); //Rechteck
pinMode(11,OUTPUT); //PWM1
pinMode(12,OUTPUT);
pinMode(13,INPUT); //Synchron-Modus
u = false; //Anzeige Unterabtastmodus

// Rechteckgenerator................................................
// Pin 9 (OC1A) ist Ausgang. Arduino Uno Hardware-Timer-Ausgang

TCCR1A = _BV(COM1A0); // OC1A bei jedem Compare-Match toggeln
TCCR1B = _BV(WGM12) | _BV(CS12) | _BV(CS10); // CTC-Modus, Prescaler 1024
OCR1A = 500; // Startwert, später über Poti
}
//Ende setup..........................................................

void loop() {

Mark:

FLAG = 1;

//.................................................................................
//Rechteckgenerator: Frequenzeingabe über Poti 0...1024............................
//Frequenzberechnung:
//Frequenz = 16 MHz/(2 × Prescaler × (OCR1A + 1))

noInterrupts();

float adc = float (analogRead(A2)); //Rechteckgenerator-Einstellung
adc = adc/102.4;
adc = pow(2, adc); //2 hoch adc
//if (adc == 0) {adc = 1;}
adc = 1024/adc;
uint16_t ocr = uint16_t (adc);

OCR1A = ocr; //bis 3906 Hz

interrupts();
//.................................................................................

SYN = digitalRead(13); //Wenn Pin 13 = high,
if (SYN) {TSYN();} else { //dann synch. mit Rechteck Sub TSYN()
//sonst variable Abtastung
for(i = 0; i < SAMPLES; i++){ //Samples = Anzahl Messpunkte: 64
for (n = 0; n < SR; n++){ //SR = sampling rate: jede n-te Messung wird gespeichert
y[i] = analogRead(ADC_PIN);
}
} //Ende for
} //Ende if else.............................................................

ymax = 0;
ymin = 1024;

while (FLAG == 1) {
ymax = 0;
ymin = 1024;

for (i = 0; i < SAMPLES/2; i++) { //32 Messpunkte = Bildschirm
if (ymin > y[i]*V) {
ymin = y[i]*V; //ymin suchen
trigPos = i;
}
if(ymax < y[i]*V) { //ymax suchen
ymax = y[i]*V;
n = i; //ymax = y{n]
}
}
if (ymax < 1000) {
FLAG = 0; //while verlassen, Kurve stößt nicht oben an
}
else {
FLAG = 1; //Verstärkung reduzieren
V = V/2;
}
} //Ende while............................................................

if ((y[n]<=6) & (y[n+1]<=6)) { //wenn kein input...
FLAG = 1;
V = 10; SR = 1; offset = 0; p = 0; //Zurücksetzen, wenn kein Input
analogWrite(11,0); //PWM = 0
u = false; //Anzeige Unterabtastmodus
delay(500);
goto Mark; //zurück an Anfang
}
//..............................................................
if (V==10) {digitalWrite(5,HIGH);} else {digitalWrite(5,LOW);} //Anzeige der Verstärkung
if (V==5) {digitalWrite(4,HIGH);} else {digitalWrite(4,LOW);}
if (V==2) {digitalWrite(3,HIGH);} else {digitalWrite(3,LOW);}
if (V==1) {digitalWrite(2,HIGH);} else {digitalWrite(2,LOW);}
if (V==0) {V = 1;}
//.............................................................

//Kurve mit neuer Verstärkung
for (i = 0; i < SAMPLES; i++) {
y[i] = y[i] * V;
}

//Kurve verschieben (offset) (Hardware!)
if (ymin <= 0) {
offset = offset + 51;}
if (offset > 235) {offset = 235;}
analogWrite(11,(offset+20)); //+20 = Korrekturwert wg. Spannungsteiler und 10k shunt

delay(500); //zur Spannungsstabilisierung nach offset

//Frequenzmessung....................................................
impulsZaehler = 0;
y0 = (ymax + ymin)/2; // Mitte = Null
Frequenz(); //Sub Frequenz() Rückgabe: frequenz

//Ende Frequenzmessung...............................................

int offst = analogRead(A1); //genauen offset-Wert ermitteln

if(!SYN){Unterabtastung();} //nur wenn Pin 13 = SYN = low, dann mit Sub Unterabtastung

x = ymin-ymax; //bei sehr kleiner Frequenz, um von SR = 1 wegzukommen
x = abs(x);
if (x < 20 * V) {SR = SR*2; p = p+1;}
if (SR == 0) {SR = 128; p = 7;} //bei Überlauf

if (!SYN) {TAUTO();} //wenn Pin 13 = low, dann automatische Abtastfrequenz

//Display Anzeige::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
int miny = (ymin/V*16 - offst*5); //16 Volt = 1024
int maxy = (ymax/V*16 - offst*5); //5 V = 1024

display.clearDisplay();

display.setCursor(10,0); //Umin
float xx1 = float(miny); //Wandlung int nach float
xx1 = xx1/1024;
display.print(xx1,1); //eine Nachkommastelle

display.setCursor(50, 0); //Umax
xx1 = float(maxy);
xx1 = xx1/1024;
display.print(xx1,1);

display.setCursor(90,0); //Frequenz
display.print(frequenz);

//display print Generator-Frequenz
//uint16_t GenFrequ = 8000000/(1024 * (OCR1A+1));
uint16_t GenFrequ = 8000000UL / (1024UL * (OCR1A+1)); //lt. KI, UL = unsigned long 32 bit
display.setCursor(90,10);
display.print(GenFrequ);

if (u){ //bei Unterabtast-Modus
display.setCursor(120,0);
display.print('u');}
else {display.print(' ');}

// Kurve zeichnen.....................................................
if (SYN){trigPos = 0;}

for ( i = trigPos; i < (trigPos + SAMPLES/2 - 1); i++) {
uint8_t y1 = map(y[i]-(20*10/32), 0, 1023, SCREEN_HEIGHT - 1, 0); //- Korrektur*Vorteiler
uint8_t y2 = map(y[i+1]-(20*10/32), 0, 1023, SCREEN_HEIGHT - 1, 0);

display.drawLine(4*(i-trigPos), y1, 4*(i-trigPos+1), y2, SSD1306_WHITE);
// 4*32 = 128 (Bildschirmbreite)
}

//Null-Linie zeichnen
//int x1 = (offset+20) * 19 * V; //+20 = Korrekturwert, offset = 0...255
uint16_t x1 = offst/4 * 19 * V; //1024 = 5V, 63 = 16V, 19,7 = 5V
x1 = x1/247; //19.7/1024 = 19/4/247
display.drawLine(0, 63-x1, 128, 63-x1, SSD1306_WHITE);

display.display(); //Display aktivieren

} //............ENDE loop......................................

//Frequenzmessung
void Frequenz() {
unsigned long letzteMessung = millis();
unsigned long jetzt = letzteMessung;
boolean bbb;

impulsZaehler = 0;

while (jetzt - letzteMessung <= 1000) { //1000 ms Torzeit

uint16_t aaa = y0 + 20;

bbb = true;
while (bbb) { //bleibt gefangen, solange aaa überhalb y0 UND Torzeit nicht zu Ende
aaa = analogRead(A0)* V;
jetzt = millis();
bbb = (aaa >= y0) && (jetzt - letzteMessung <= 1000);
}

impulsZaehler++; //beim Nulldurchgang zählen

bbb = true;
while(bbb) { //bleibt gefangen, solange aaa unter y0+20 UND Torzeit nicht zu Ende
aaa = analogRead(A0)* V;
jetzt = millis();
bbb = (aaa <= (y0 + 20)) && (jetzt - letzteMessung <= 1000);
}

jetzt = millis();
} //Ende while

frequenz = impulsZaehler; // Ergebnis: frequenz
} //Ende Sub Frequenz.................................................

void TSYN() { //Rechtecksynronisation: andere Zeitablenkung
int T = 8 *(OCR1A+1); //Periodendauer des Rechtecksignals in µs: t = 128*(OCR1A+1)
//Punktabstand: T = t/16 = 8*(OCR1A+1)
int mics = T - 110; //110 µs = A/D-Wandler-Zyklus
if(mics <= 0) {mics = 0;}

while(digitalRead(10)== HIGH) {}
while(digitalRead(10)== LOW) {} //Warten, solange Pin 9 = Pin 10 = LOW (Synchronisation mit Generator)

for (i = 0; i<SAMPLES; i++){
y[i] = analogRead(ADC_PIN);
delayMicroseconds(mics); //Abtastperiode verlängern
//Abtastperiode: (110 + mics). Signalperiode; t = (110+mics)*16
} //Ende for
}; //Ende TSYN........................... ..............................


void TAUTO(){ //automatische Zeitablenkung
ymaxx = 0;
for (i = trigPos; i<=(trigPos+15); i++){ //+15 = halber Bildschirm
if (ymaxx < y[i]) {
ymaxx = y[i];
ii = i;
}
}
if (ii == (trigPos+15)) {
SR = SR*2;
p = p + 1;
}
if (SR == 0) {SR = 128; p = 7;}; //bei Überlauf

//SR mit LEDs anzeigen
if ((p & 1) == 1) {digitalWrite(6,HIGH);} else {digitalWrite(6,LOW);}
if ((p & 2) == 2) {digitalWrite(7,HIGH);} else {digitalWrite(7,LOW);}
if ((p & 4) == 4) {digitalWrite(8,HIGH);} else {digitalWrite(8,LOW);}
}

//........ Unterabtastung .............................
void Unterabtastung() {
//Anzahl der Perioden ix pro Bildschirm (= Nulldurchgänge)ermitteln
y0 = (ymax + ymin)/2; // Mitte = Null

ix = 0;

for (i = 0; i<SAMPLES/2; i++) {
boolean v1 = y[i] > y0;
boolean v2 = y[i+1] <= y0;

if (v1 && v2) {
ix++; //ix = Anzahl der Nulldurchgänge
}
}

if (ix > 6) { //wenn Anzahl der Nulldurchgänge größer 6
u = true;
SR = SR*2; //längere Abtastrate
p = p + 1;
if (SR == 0) {SR = 1; p = 0;} //bei Überlauf, neue Runde

//nochmal scannen
for(i = 0; i < SAMPLES; i++){ //Samples = Anzahl Messpunkte: 64
for (n = 0; n < SR; n++){ //SR = sampling rate: jede n-te Messung wird gespeichert
y[i] = analogRead(ADC_PIN);
}
}
//Kurve mit neuer Verstärkung V
for (i = 0; i < SAMPLES; i++) {
y[i] = y[i] * V;
}
}
}
//.......................Ende Unterabtastung....................

//Ende Programm:::::::::::::::::::::::::::::::::::::::::::::::::






Elektronik-Labor  Bastelecke  Projekte  Mikrocontoller