Forum: Mikrocontroller und Digitale Elektronik ADC mit Bascom 8bit ?


von Lordnicon (Gast)


Lesenswert?

Hallo ihr guten...

Ich muss die Wissen den hier mal mit meiner Frage Nerven.

Ich möchte den ADC meines Atmega644 etwas beschleunigen, momentan 
braucht er für das Abfragen eines ADC Wertes ( Getadc(0) ) ca 0.1ms laut 
Oszi.

Der Atmega läuft mit 20Mhz ...

Hier mal mein Bascom Code:

'CONTROLER BESTIMMEN
 $regfile = "m644def.dat"


 'STACKANWEISUNGEN 
-------------------------------------------------------------
 $framesize = 64
 $swstack = 40
 $hwstack = 48

 'FREQUENZ DES VERWENDETEN QUARZES 
---------------------------------------------
 $crystal = 20000000

 Enable Interrupts


 'DER ANALOG- DIGITAL CONVERTER WIRD EINGESTELLT UND AKTIVIERT 
-----------------
 Config Adc = Single , Prescaler = Auto , Reference = Avcc
 Start Adc

 'PIN ZUM PRÜFEN DER LAUFZEITEN
 Config Pind.6 = Output
 timecut Alias Portd.6


Do

 X = Getadc(0)

 Toggle timecut

Loop

------------------------------------------------------------------------ 
--


Nun meine Frage, wie kann ich es ermöglichen das der ADC Schneller 
Arbeitet als jetzt ? Dafür müsste ich doch rein Theoretisch den 
Prescaler manuell einstellen auf einen entsprechenden Wert oder ?

Dann hätte ich noch eine frage was den 8bit Betrieb angeht ...
Wenn ich den ADC beschleunige werden die letzten 2 bit ( beim 10 bit 
betrieb ) ja ungenauer ! Mir würde auch eine 8 bit auflösung des ADC`s 
reichen, aber wie genau stellt man das eine und fragt die werte dann 
auch ab ?!

Kann ich mir das mit dem 8 bit Modus auch wirklich so vorstellen das 0V 
= 0 und 5V = 255 und nicht 1023 ist ???

Ich wäre euch für eine unterstützung echt dankbar !!!

von Karl H. (kbuchegg)


Lesenswert?

Lordnicon schrieb:

> Nun meine Frage, wie kann ich es ermöglichen das der ADC Schneller
> Arbeitet als jetzt ? Dafür müsste ich doch rein Theoretisch den
> Prescaler manuell einstellen auf einen entsprechenden Wert oder ?

Die Frage ist, was eine Prescaler Einstellung von Auto eigentlich macht. 
Ich kann mir nicht vorstellen, dass sich dazu in der BASCOM-Hilfe nichts 
findet.

> betrieb ) ja ungenauer ! Mir würde auch eine 8 bit auflösung des ADC`s
> reichen, aber wie genau stellt man das eine und fragt die werte dann
> auch ab ?!

Auch dazu wirst du sicherlich in der BASCOM Hilfe fündig

> Kann ich mir das mit dem 8 bit Modus auch wirklich so vorstellen das 0V
> = 0 und 5V = 255 und nicht 1023 ist ???

Yep.

> Ich wäre euch für eine unterstützung echt dankbar !!!

Falls du in der BASCOM Hilfe nichts findest (was ich mir nicht 
vorstellen kann), dann bleibt immer noch das Datenblatt des Prozessors. 
Man kann auch in BASCOM die Konfigurationsregister direkt einstellen.

Aber erst mal solltest du deine Hausaufgaben machen und die Hilfe 
konsultieren.

von Helmut L. (helmi1)


Lesenswert?

>Kann ich mir das mit dem 8 bit Modus auch wirklich so vorstellen das 0V
>= 0 und 5V = 255 und nicht 1023 ist ???

Es bleibt bei 1024 Schritten aufloesung. Nur die beiden unteren Bits 
sind ungenauer. Teil das Ergebnis durch 4 und du hast deine 8 Bit 
Aufloesung.

Gruss Helmi

von Hannes L. (hannes)


Lesenswert?

Das Problem ist, dass Bascom's GETADC(n) als Funktion arbeitet und das 
Argument (Kanal-Nummer) erst dann übergibt, wenn es eigentlich bereits 
das Ergebnis haben will. Dies erfordert Wartezeit.

Das lässt sich umgehen, indem man auf GETADC() verzichtet und den ADC 
wie ein ASM-Programmierer benutzt. Man wählt den Kanal, startet ihn und 
kümmert sich wieder um andere Dinge, die getan werden müssen. Später 
dann schaut man mal im ADC-Register nach dem Ergebnis. Braucht man nur 
einen Kanal, dann lässt man den ADC im Hintergrund frei laufen oder von 
einem anderen Ereignis triggern (schau mal ins Datenblatt Deines 
Mega644, dessen ADC kann bedeutend mehr, als Bascom an Unterstützung 
bietet). Braucht man mehrere Kanäle, so fragt man den ADC zyklisch ab 
(ADCC-Interrupt oder nebenbei im Timer-Interrupt), sichert sein Ergebnis 
in einem Array, setzt nach dem Auslesen den neuen Kanal, startet den ADC 
neu und widmet sich während der Wandlung den übrigen Arbeiten.

Ist alles kein Problem und geht wunderbar, man muss nur bereit sein, auf 
einige kontraproduktive Befehle und Funktionen von Bascom zu verzichten.

...

von Lordnicon (Gast)


Lesenswert?

Hallo an euch

Also zum Prescaler steht in der Bascom Hilfe folgendes:

>The prescaler divides the internal clock by 2,4,8,16,32,64 or 128
>Because the ADC needs a clock from 50-200 KHz
>The AUTO feature, will select the highest clockrate possible

Nun nehme ich an das der Prescaler von Bascom Automatisch auf 128 
eingestellt wird und damit bei 20Mhz eine Abtastfrequenz von ca. 156 Khz 
eingestellt wird ..
Nun habe ich aber schon mehrfach gelesen das man den ADC auch mit mehr 
als 200Khz betreiben kann, aber dann die 10 Bit genauigkeit darunter 
leidet ...


Was den 8bit betrieb angeht findet man in der Bascomhilfe leider 
nichts... bzw. Ich finde da einfach nichts zu ....


>>Kann ich mir das mit dem 8 bit Modus auch wirklich so vorstellen das 0V
>>= 0 und 5V = 255 und nicht 1023 ist ???

>Es bleibt bei 1024 Schritten aufloesung. Nur die beiden unteren Bits
>sind ungenauer. Teil das Ergebnis durch 4 und du hast deine 8 Bit
>Aufloesung.


Also was mir zur ungenauigkeit des 10 bit betriebes vorschwebt ist 
folgendes... wenn ich jetzt meinen ADC wegen mir nicht mit 156 Khz 
abtasten lasse ( Auto Prescaler ) sondern Manuell mit einem Prescaler 
von
32 ( 625 Khz ), was bedeutet das für meine Werte ?
Im Datenblatt steht das der ADC +-2 LSB Absolute Accuracy hat, leider 
verstehe ich nicht genau was das bedeutet.
Aber wie Weit könnten die Werte den Abweichen? Hat da schon jemand 
erfahrung mit gemacht ?

Wenn ich z.B. 2.5V Anlege müsste ich ja Theoretisch einen ADC Wert von 
511 erhalten. Wenn ich den ADC nun aber Hochtakte und die Genauigkeit 
von 10 Bit nichtmehr sauber eingehalten werden kann, mit welchen Werten 
wäre dann zu rechnen ?!?! 511 +- 20 oder so in der Art !!!

Sorry das ich mich ein bisschen dämlich ausdrücke, aberichussleider 
immer alles begründet und verdeutlicht haben...



Also ich möchte jaauch selber zur lösungmeines Problems beitragen, 
desswegen möchte ich hier meinen Gedankengang gradeNiederschreiben!


Wenn ich jetzt hergehe und den Prescaler auf 32 einstelle, läuft der ADC 
mit ca 625 Khz , aber die Genauigkeit wird leiden ... wenn ich jetzt den 
Ausgelesenen ADC Wert durch 4 Teile ( um 8 Bit zu erhalten ) Teile ich 
ja auch den evtl. vorhandenen Messfehler durch 4 ( sehe ich das richtig 
). Meine Messgeschwindigkeit Steigt aberauch um Faktor 4 an ??!!!??? ... 
Somit würde ein Messzyklus nichtmehr 100µs sondern nurnoch 25µs 
brauchen..




Was Assembler befehle angeht bin ich leider völliger neuling....

von Hannes L. (hannes)


Lesenswert?

> Was Assembler befehle angeht bin ich leider völliger neuling....

Es geht nicht um Assembler-Befehle, es geht um das Benutzen des 
System-Register ADMUX, ADCSRA, ADCSRB, ADCL und ADCH, ferner auch noch 
DIDR0.

Das sind nämlich die Schnittstellen zum ADC, in denen einzelne Bits 
bestimmte Schalterwirkung haben, andere Bitgruppen Zahlen 
repräsentieren. Um das zu verstehen, brauchst Du kein ASM zu lernen 
(obwohl das keinesfalls schaden würde), sondern nur im Datenblatt die 
Funktion des ADC und besonders seiner (oben aufgezählten) Register 
nachzulesen (und zu verstehen).

Bascom bietet zwar die Funktion GETADC(), die taugt aber im Alltag nix, 
da sie zuviel Zeit vertrödelt. Denn sie muss:

- den zu messenden Kanal einschalten (Kanalnummer und Referenzquellen-
  Nummer in ADMUX schreiben)
- den ADC starten (ADEN und ADSC im Steuerregister ADCSRA setzen, sowie
  den Vorteiler in ADCSRA einstellen)
- warten, bis das Bit ADIF in ADCSRA gesetzt ist, was das vereinbarte
  Zeichen ist, dass der ADC fertig ist und ein Ergebnis hat
- das Ergebnis aus ADCL und ADCH auslesen und dem aufrufenden Programm
  zurückgeben.

Das Problem dabei ist, dass die Programmabarbeitung solange warten muss, 
bis das Ergebnis vorliegt, das ist nunmal bei "Funktionsaufruf" so. Es 
verlangt aber keiner, dass Du diese Funktion benutzt. Stattdessen kannst 
Du die Handgriffe selbst in Programmcode formulieren und zur rechten 
Zeit ausführen.

Angenommen, Du brauchst nur einen ADC-Eingang 8-bittig zu messen. Dann 
schreibst Du Die Mess-Quelle schon bei der Initialisierung in ADMUX. Im 
Register ADMUX findest Du (beim Mega644) 2 REFS-Bits, 5 MUX-Bits und das 
Bit ADLAR. Die REFS-Bits bestimmen die Referenzspannungsauswahl, siehe 
Tabelle 21-3 des Datenblatts. ADLAR bestimmt die Ausrichtung des 
Resultats, bei gesetztem Bit wird linksbündig ausgerichtet, die oberen 8 
Bits stehen dann in ADCH, was das Auslesen des 8-Bit-Messwertes 
erleichtert und beschleunigt (der ADC misst aber trotzdem 10-bittig, die 
unteren 2 Bit liegen dann in ADCL und verfaulen, weil sie keiner 
abholt). Mit den MUX-Bits wird angegeben, welcher Kanal gemessen werden 
soll, siehe Tabelle 21-4 des Datenblatts. Du baust Dir nun das 
gewünschte Bitmuster zusammen und schreibst es in ADMUX. Das erfordert 
keinerlei missverständlichen CONFIG-Kram, sondern nur eine einfache 
Zuweisung. Da Bascom leider nur die Registernamen kennt, nicht aber die 
Bitnamen, musst Du auf die symbolischen Bitnamen verzichten und das 
Bitmuster numerisch angeben (was den Code gegenüber ASM oder C 
unübersichtlich macht und oftmals Protest aus der C-Liga bewirkt...). 
ADC0 gegen AVcc 8-Bittig gemessen ergibt dann folgende Initialisierung 
für ADMUX:

 ADMUX = &b01100001
              ^^^^^--- Mess-Quelle 0 laut Tabelle 21-4
             ^-------- linksbündige Ausgabe (ADLAR)
           ^^--------- AVcc als Referenz laut Tabelle 21-3

Du hast also mit einer einzigen Zuweisung Referenz, Kanal und Format 
eingestellt. Ist das nicht viel eindeutiger als das Config-Geraffel?

Ebenso gehst Du mit ADCSRA vor, das enthält den Vorteiler und weitere 
Bits zum Schalten und Steuern. Mit einer Zuweisung konfigurierst und 
startest Du den ADC. Wird nur eine Quelle gemessen, dann lohnt sich der 
Freerun-Mode, also das Setzen von ADATE (heißt bei älteren AVRs ADFR), 
dann klappert der ADC nach dem Starten im Hintergrund vor sich hin und 
kann irgendwann mal nebenher ausgelresen werden, ohne dass das Programm 
dabei warten muss. Für ADC0 gegen AVcc 8-Bittig gemessen ergibt dann 
folgende Initialisierung für ADCRSA:

 ADCSRA = &b11100110
                 ^^^--- Vorteiler 64 (Tabelle 21-5)
                ^------ kein Interrupt aktivieren
               ^------- Interrupt-Flag ist hier nicht relevant
              ^-------- Free-Run, siehe ADCSRB
             ^--------- ADC starten
            ^---------- ADC einschalten

Der Vorteiler hängt von der Taktfrequenz des AVRs ab, er soll so gewählt 
werden, dass der ADC mit 50kHz bis 200kHz getaktet wird. Er braucht 
(ohne Umschaltung der Quellen) 13 Takte für eine Wandlung, hat also 
Vorteiler mal 13 Takte ein neues Ergebnis, das so lange in ADCL und ADCH 
verfügbar ist, bis es vom nächsten Ergebnis überschrieben wird. Un nun 
das neueste Ergebnis zu erfahren, muss dein Programm es nur auslesen:

 wert = ADCH

Wobei "wert" als Byte dimensioniert sein sollte. Da dies wieder nur eine 
einfache Zuweisung ist, kostet das keinerlei Wartezeit. Und solltest Du 
(durch ungünstige Programmplanung) den Wert zu oft abfragen, dann 
bekommst Du den alten Wert eben nochmal, solange noch kein neuer 
ermittelt wurde.

Ähnliches wie beim ADC wirst Du bei den Timern entdecken. Die Timer der 
neueren Controller können viel mehr als Bascom per Config-Geraffel 
bietet. Schau Dir das Datenblatt an, das ist verbindlich, verzichte auf 
den Config-Kram und greife durch einfache Zuweisungen auf die interne 
Peripherie der AVRs zu, Du wirst sehen, dass damit das Programmieren 
auch in Bascom bedeutend einfacher und stressfreier wird.

...

von Lordnicon (Gast)


Lesenswert?

Hallo Hannes

Mensch vielen Dank für die Tolle Erklärung.... Das nenne ich doch mal 
eine ausführliche erklärung .....


Also um es zu Konkretisieren, ich muss 2 ADC Werte haben ( Später 
könnten es auch 4 werden ... )


Dann könnte mein Programm so aussehen ?!

'CONTROLER BESTIMMEN
 $regfile = "m644def.dat"


 'STACKANWEISUNGEN
-------------------------------------------------------------
 $framesize = 64
 $swstack = 40
 $hwstack = 48

 $crystal = 20000000


 'ADC EINSTELLEN ( NICHT IM FREERUN )
 ADCSRA = &b11000110

 'VORAUSWAHL VOM ADC 0 WOMIT DAS PROGRAMM BEGINNT
 ADMUX = &b01100000

 'PIN ZUM PRÜFEN DER LAUFZEITEN
 Config Pind.6 = Output
 timecut Alias Portd.6


Do

 X = ADCH

 'JETZT UMSCHALTEN ZUM ADC CHANNEL 1
 ADMUX = &b01100001

 'NUN MACHE ICH IRGENDWAS DAMIT DER ADC MIN 13 TAKTE ZEIT HAT DAS NEUE
 'ERGEBNIS BEREIT ZU STELLEN

 ......
 .....
 ....
 ...
 ..
 .

 'NUN HOLE ICH DAS ERGEBNISS VON CHANNEL 1 AB
 Y = ADCH

 'JETZT WIEDER UMSCHALTEN ZUM ADC CHANNEL 0
 ADMUX = &b01100000

 ......
 .....
 ....
 ...
 ..
 .


Loop


KANN ICH DAS SO RICHTIG VERSTEHEN ???

Und der Wert den ich da abhole ist dann 8bit 0V = 0 und 5V = 255 ?????

von Hannes L. (hannes)


Lesenswert?

> KANN ICH DAS SO RICHTIG VERSTEHEN ???

Vermutlich nicht...

>  'ADC EINSTELLEN ( NICHT IM FREERUN )
>  ADCSRA = &b11000110

>  'VORAUSWAHL VOM ADC 0 WOMIT DAS PROGRAMM BEGINNT
>  ADMUX = &b01100000

Falsch herum. Immer erst den Multiplexer einstellen, dann den ADC 
einschalten, sonst schaltest Du ihm ja die Quelle unterm Hintern um, was 
den ersten Messwert (ohne FreeRun gibt es keinen zweiten) verfälschen 
kann.

> X = ADCH

> 'JETZT UMSCHALTEN ZUM ADC CHANNEL 1
> ADMUX = &b01100001

> 'NUN MACHE ICH IRGENDWAS DAMIT DER ADC MIN 13 TAKTE ZEIT HAT DAS NEUE
> 'ERGEBNIS BEREIT ZU STELLEN

Es sind nicht 13 Controllertakte, sondern 13 ADC-Takte. Das ist viel 
Zeit.

Ich sehe hier auch noch ein Problem. Du arbeitest mit maximalem Takt und 
dem größten DIL-AVR und hast eine Mainloop ohne Bremse. Soll das Teil in 
Echtzeit eine Rakete steuern?? Ich komme meist mit kleinen AVRs aus, 
takte sie selten höher als 3,6864 oder 7,3728 MHz (meist nutze ich die 
internen 1MHz) und kann damit die meisten Aufgaben lösen.

Wie oft und wozu brauchst Du die Messwerte?
Was soll das Ding eigentlich machen?

Ohne diese Info ist keine optimale Strategie möglich.

...

von Hannes L. (hannes)


Lesenswert?

Hier mal als Beispiel ein Auszug aus einem Mega8-Programm, dass den ADC5 
als Eingang für 2 Taster nimmt.

In der Init (unter Anderem):
1
Admux = &B01100101                      'ADC_5 linksbündig gegen Vcc messen
2
Adcsra = &B11100110                     'ADC freilaufend mit Vorteiler 1:64
3
4
Ocr1a = Reload                          'Timer1-Zählumfang für 20ms
5
Tccr1b = &B00001010                     'CTC-Modus mit Vorteiler 1:8
6
7
Enable Oc1a                             'Timer1-CompareA-Interrupt freigeben
8
Enable Urxc                             'UART-RXC-Interrupt freigeben
9
Enable Interrupts                       'Interrupts global freigeben

In der Mainloop werden nur bedingte Jobs aufgerufen:
1
Do                                      'Hauptschleife
2
  If Rix > 9 Then Neutelegramm          'neues Telegramm eingetroffen? - ja...
3
  If Neutext = 1 Then Gibaus            'Textausgebe erforderlich? - ja...
4
  If Tame = 1 Then                      'Menütaste gedrückt?
5
    Reset Tame                          'Tastendruck entwerten
6
    Incr Mp                             'Menüpunkt hoch
7
    Mp = Mp And 3                       'und auf 0..3 begrenzen
8
    If Mp = 3 Then Relais_aus           'Akku entfernen um Strom einzustellen
9
  End If
10
  If Tago = 1 Then                      'Go-Taste gedrückt?
11
    Reset Tago                          'Tastendruck entwerten
12
    Select Case Mp                      'in Menüpunkt
13
      Case 0                            '"Fazit"
14
        Incr Weka                       'Wert-Kategorie hoch
15
        If Weka > 5 Then Weka = 1       'und begrenzen
16
      Case 1 To 2                       'Schnelladen
17
        Anu = 1                         'Start mit Akku 1
18
        Set Mp.2                        'Laden aktivieren (Mp= 5 oder 6)
19
      Case 3                            'Strom einstellen
20
        Tazz = Taz(mp)                  'Tastendauer Tiny26-Taste
21
        Set T26taste                    'Tiny26-Taste einschalten
22
    End Select
23
  End If
24
Loop

Die ADC-Abfrage erfolgt in der Timer-ISR:
1
Zeittakt:                               'ISR, Timer1CompareA (20ms)
2
  Dim Itmp As Byte                      'temp in ISR
3
  Dim Taste As Byte                     'Tasten-Nummer
4
  If Timout <> 0 Then                   'wenn Telegramm-Timeout aktiv ist,
5
    Decr Timout                         'Timeout herunterzählen
6
    If Timout = 0 Then Set Fertig       'abgelaufen? - ja, melden
7
  End If
8
  Itmp = Adch                           'ADC 8bittig lesen
9
  Select Case Itmp                      'welche Taste?
10
    Case 120 To 136                     'Menü-Taste
11
      Taste = 1
12
    Case 160 To 180                     'Go-Taste
13
      Taste = 2
14
    Case Else                           'keine gültige Taste
15
      Taste = 0
16
  End Select
17
  If Taste <> Tas Then                  'wenn Tastendruck anders
18
    If Taste = Tao Then                 'ist Taste = vorheriger Wert
19
      Incr Prz                          'Prellzähler hoch
20
      If Prz > 5 Then                   'Prellzeit erreicht?
21
        Tas = Taste                     'ja, Taste übernehmen
22
        If Taste = 1 Then Set Tame      'Menü-Taste
23
        If Taste = 2 Then Set Tago      'Go-Taste
24
      End If
25
    Else
26
      Prz = 0                           'Prellzähler löschen
27
      Tao = Taste                       'akt. Taste als Vorwert übernehmen
28
    End If
29
  End If
30
  If Tazz <> 0 Then                     'wenn Tiny26-Tastenzeit läuft
31
    Decr Tazz                           'Tastenzeit herunterzählen
32
    If Tazz = 0 Then Reset T26taste     'abgelaufen? - ja, Taste aus
33
  End If
34
  If Wartez <> 0 Then                   'Akku-Umschaltung
35
    Decr Tazz                           'Wartezeit herunterzählen
36
    If Wartez = 0 Then Relais_ein       'abgelaufen? - ja, Relais ein
37
  End If
38
Return                                  'fertig, zurück...

Nur mal so als Denkanstoß...

...

von Lordnicon (Gast)


Lesenswert?

Hallo Hannes ...

Also was will ich mit dieser Anwendung machen ...

Es handelt sich dabei um eine Safety für ein Lasersystem ..

Die beiden ADC Werde sind Feedbackwerte des Galvo systems, Es soll also 
Laufend und möglichst Schnell überprüft werden ob das System noch Läuft 
..

Signale ( Sinus, Dreieck, Trapetz förmige Signalverläufe ) Dann soll 
innerhalb 5 - 25 millisekundne entschieden werden ob das System 
Abgeschaltet werden muss oder ob die Parameter eingehalten wurden ...


Ausserdem will ich Ranges festlegen in denen die laser grundsätzlich 
ausgeschaltet werden müssen ( Safe Areas ... z.B Puplikum ). Da die 
Signale bis zu 500Hz Schnell laufen muss das Ganze sehr zügig von 
Statten gehen !

Wenn du Geduld und Interesse hast können wir das Thema gerne vertiefen, 
ich würde mich wahnsinnig über Hilfe freuen ...

Mfg:

von Hannes L. (hannes)


Lesenswert?

Es wäre schön, wenn Du versuchen würdest, Deutsch mit mir zu 
reden/schreiben. Denn mit meinen 6 Jahrzehnten habe ich es nicht so mit 
den coolen Anglizismen.

Gut, dann brauchst Du erstmal eine schnelle Bereitstellung der ADC-Werte 
mehrerer Quellen im Hintergrund. Dazu müssen erstmal die Eckpunkte 
geklärt werden.

Wieviele Bewegungs-Achsen müssen überwacht werden?

Es bringt nämlich nix, klein anzufangen und später "aufbohren" zu 
wollen.

Gehen wir in der ersten Betrachtung von 4 Achsen aus, deren Steuerwerte 
auf den ADC-Messbereich angepasst vorliegen. Legen wir diese auf ADC0 
bis ADC3. Es reicht 8 Bit Auflösung. Der AVR läuft mit 20 MHz. Der 
ADC-Takt soll im Interesse einer schnellen Wandlung möglichst nah am 
Limit (200 kHz) sein. Es stehen Vorteiler 64 und 128 bereit. Bei VT=128 
erreichen wir nur 156,25 kHz, schöpfen also das Limit nicht aus. Bei 
VT=64 erreichen wir 312,5 kHz, das erscheint mir bereits etwas 
"übertaktet", da werden die Messwerte schon arg zittern. Mit 16 MHz 
Controllertakt und VT=64 wäre 250 kHz ADC-Takt erreichbar, was ich für 
8-Bit-Messung für akzeptabel halte.

Gehen wir also erstmal von 250 kHz ADC-Takt aus. Der ADC müsste dann im 
Interrupt-Betrieb laufen und in der ISR folgende Aufgaben erledigen:
1
isr_adc_complete:
2
wert(idx) = adch
3
incr idx
4
if idx > 4 then 
5
  idx = 1
6
  set neuwert
7
endif
8
admux = muxwert(idx)
9
adcsra = adcstart
10
return

Dazu müssen natürlich die beiden Arrays "wert()" und "muxwert()" sowie 
der Index "idx" global (als Byte) dimensioniert (und mit 1 
initialisiert) werden und das Array "muxwert()" mit den benötigten 
Bitmustern für ADMUX gefüllt werden. Auch die Konstante "adcstart" muss 
vordefiniert werden, also das Bitmuster zum Starten einer ADC-Wandlung 
mit Interruptunterstützung enthalten. Dann brauchst Du noch eine 
Variable vom Typ Boolean, die ich hier "neuwert" genannt habe. Ich nutze 
zu solchen Zwecken meist die Variable "merker" vom Typ Byte und benenne 
(mit Alias) die Bits einzeln zu Merkern.

Der ADC wird also nach jeder Messung in den Interrupt verzweigen, den 
Messwert sichern, den Index erhöhen und begrenzen, auf die neue 
Messquelle umschalten und den ADC wieder starten. Nach jeder kompletten 
Runde setzt er den Merker "neuwert".

Die Mainloop prüft nun nur den Merker "neuwert" und verzweigt zu einer 
SUB, wenn "neuwert" gesetzt ist. Diese Sub löscht (resettet) "neuwert" 
wieder (der der Arbeitsauftrag wird ja erledigt) und erledigt die 
Überprüfungen der Grenzbereiche der 4 ADC-Werte. Dazu nutzt die SUB das 
Array "wert()", darf aber nicht die Variable "idx" benutzen, die ist für 
die ISR als Schrittzähler reserviert. In wert(1) steht dann der Wert von 
ADC0, in wert(2) der Wert von ADC1 (bzw. der Wert der an "muxwert(2)" 
gemessen wurde).

Die Mainloop (bzw. deren Jobs) bekommt auf diese Weise fast die volle 
Rechenzeit des Controllers, da nirgends auf den ADC gewartet werden 
muss.

Nun ein paar Zeitbetrachtungen dazu:
Wir gingen von 250kHz ADC-Takt (16MHz Quarz, ADC-Vorteiler=64) aus. Das 
sind bei 13 Takten je Wandlung und einer kleinen Pause, weshalb ich 14 
Takte rechne, etwa 17,857 kHz. Eine Runde macht 4 Messungen, das sind 
etwa 4,46 kHz bzw. 224 µs pro Runde. Das ist mehr als ausreichend, um 
rechtzeitig auf Stillstand oder verbotene Bereiche reagieren zu können.

Rechnen wir es nochmal für 20 MHz Quarz und ADC-Vorteiler 128 durch:
Das sind 156,25 kHz ADC-Takt. Macht bei 14 Takten 11,16 kHz Samplerate. 
Auf 4 Kanäle verteilt bleibt 2,79 kHz Samplerate pro Kanal, bzw. eine 
Runde dauert 358,4 µs. Die ADC-Werte kommen hier zwar etwas langsamer 
rein, dafür hast Du aber mehr Rechenzeit pro Runde und die Werte zappeln 
nicht so stark, denn der ADC läuft im "grünen Bereich" ist also nicht 
übertaktet.

So, ich hoffe, Du hast genügend Denkanstöße bekommen. Schau Dich mal bei 
RN-Wissen um, da sollen allerhand brauchbare Beispiele zu finden sein. 
Ich kann Dir aber keine konkreten Links geben, ich interessiere mich 
nicht dafür, da ich hauptsächlich in Assembler programmiere.

Viel Erfolg
...

von Lordnicon (Gast)


Lesenswert?

Hallo Hannes


Ich bedankemich bei dir auf jeden fall schonmal für diese mehr als 
ausführliche Hilfestellung, ich werde mir jetzt mal alles zu gemüte 
führen und darüber nachdenken wie ich das am besten umsetzen kann !
Wobei du mir ja schon sehr weiter geholfen hast...

Es sollte mehr von solchen Leuten geben die sich zeit für eine sehr gute 
erklärung nehmen...


Vvviiiiieeeelllleeeennnn Dank erstmal ...

Mfg:

von Klaus D. (kolisson)


Lesenswert?

Hallo Autor:  Hannes Lux (hannes) ,

ich möchte hier als Leser deines Beitrages mal hervorheben,
dass Deine Ausführungen super gut sind.

Als langjähriger Bascom-Nutzer habe ich auch schon oft die Erfahrungen 
gemacht, dass bei Verwendung einiger config Statements nicht immer das
passiert, was man eigentlich möchte.
Wenn ich also mal eben schnell etwas in Bascom zusammenkloppe und am 
Ende
nicht das richtige rauskommt fange ich zunächst an , die logische Bombe 
in meinen Gedankengängen zu suchen.
Wenn ich dann nach mehrmaliger intensiver Prüfung meiner Idee immer zu 
dem Schluss komme, dass der fehler eigentlich nicht bei mir liegt, fange 
ich an
das Bascom zu verdächtigen.

Durch Umschreiben des Programmes und der intensiven Nutzung der 
entsprechenden Kontrollregister kommt man der sache dann sehr gut auf 
die Spur.

Die Erfahrung zeigt einfach, dass Bascom voller Fettnäpfchen und 
Fallstricken steckt und man auf der hut sein muss.
Bisher habe ich diese Strategie der Nutzung der Kontrollregister nur bei 
den Timern angewandt und auf meiner "TO-DO-Liste" stand noch die analyse 
des Getadc befehles.
Im endeeffekt hast du mir durch deine Ausführungen aber jetzt schonmal 
einen guten Erkenntnisstand übermittelt.
Es wird mir viel Arbeit sparen.

Danke also .. Hannes


Vielleicht sollte man hier noch erwähnen, dass Bascom beim compilieren 
auch immer ein *.obj File erzeugt. Dieses kann man im AVR-Studio öffnen 
und sehen , was Bascom so anstellt. Dann wird alles viel klarer.
Man kann in AVR-Studio den Bascom Quelltext sehen und das daraus 
resultierende ASM Compilat und es Schritt für Schritt gedanklich 
analysieren.

Manchmal hilft es auch, in den Bascom Quelltext vor und hinter einer 
fragwürdigen Instruktion eine gewisse Anzahl NOP-Befehle einzufügen.
(z.B. 3 stück vor dem Befehl und 5 Stck. dahinter)
diese Marke lässt sich dann leicht auffinden.


Also dann
Libe Grüsse
Klaus

von Hannes L. (hannes)


Lesenswert?

Erstmal danke für die Blumen, es gibt aber auch Leute, die das anders 
sehen...

> Man kann in AVR-Studio den Bascom Quelltext sehen und das daraus
> resultierende ASM Compilat und es Schritt für Schritt gedanklich
> analysieren.

Ich weiß jetzt nicht genau (ich programmiere fast nur in ASM, also mit 
Hammer und Nägeln), aber ich glaube, AVR-Studio kann die Objekt-Datei 
sogar simulieren. Der Simulator ist zwar nicht so schön bunt wie der von 
Bascom, zeigt einem aber schön so manchen logischen Trugschluss.

...

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.