Bascom ADC Werte auf ein Display ausgeben

  • Friedenstaube
    "Es gibt keinen Weg zum Frieden, denn Frieden ist der Weg." - Mahatma Gandhi

Holger

Mitglied
2 Jul 2012
37
0
6
73
Sprachen
Hallo an die Runde,

mein zweizeiliges Display habe ich eingebunden. Nun möchte ich ADC Werte anzeigen. Ich habe auch schon unter den FQA's gesucht aber nichts gefunden.
Bisher habe ich es so versucht,
Code:
---------------------------------------------------------------------------------------------
'ADC-Werte-einlesen
'Hardware: Poti1 an PC5/ADC5
'          MAX232 an PD0/PD1, Nullmodemkabel zum PC
'-------------------------------------------------------
$regfile = "m8def.dat"                                      'ATmega8-Deklarationen
$crystal = 3686400                                          'Quarz: 3,6864 MHz
$baud = 2400                                                'Baudrate zum PC: 2400 Baud


'
Dim Wert1 As Word
Dim Senden As Word                                          'Variable deklarieren
'
Config Lcdpin = Pin , Db4 = Portd.4 , Db5 = Portd.5 , Db6 = Portd.6 , _
                       Db7 = Portd.7 , E = Portd.3 , Rs = Portd.2

Config Lcd = 16 * 2
Cursor Off

Cls


Locate 1 , 4
Lcd "ADC einlesen"

Locate 2 , 5
Lcd Senden

Locate 2 , 12
Lcd "2"

Ddrc = &B00000000                                           'PC7...PC0=0: PortC-Pins auf Eingang
Config Timer1 = Timer , Prescale = 64
On Timer1 Anzeigen
Enable Timer1
Enable Interrupts

Config Adc = Single , Prescaler = Auto , Reference = Avcc
Start Adc

Do

Wert1 = Getadc(5)



Senden = Str(wert1)

Loop

Anzeigen:
Print Senden
Return

End
-----------------------------------------------------------------

aber es will nicht klappen.


Ihr wißt sicher wo mein Fehler liegt.

Gruß Holger
 

LotadaC

Sehr aktives Mitglied
22 Jan 2009
3,505
65
48
Marwitz
Sprachen
  1. BascomAVR
  2. Assembler
Ja.

Du läßt einmal "senden" auf dem LCD ausgeben, da ist die Variable aber noch gar nicht initialisiert.
In Deiner Hauptschleife wird immer wieder eine Messung an Kanal 5 durchgeführt, das ergebnis "Wert1" (Variable) zugewiesen. Danach weist Du das dann (nochmal) der Variable "senden" zu.(*)
Eine weitere Ausgabe auf dem Display veranlaßt Du aber nie.

P.S.: Bascom ist keine objektorientierte Programmiersprache.

Edit (*): sollte senden dann nicht ein String sein (kein word)?
 

caargoo

Mitglied
1 Jul 2008
55
0
6
Sprachen
  1. BascomAVR
Hallo!

Ergänzend zum Vorhergesagten: Ist die Hilfe zu "STR()" so schwer zu verstehen?

Senden MUSS eine Stringvariable sein!

MfG
 

Holger

Mitglied
2 Jul 2012
37
0
6
73
Sprachen
Hallo,
danke für die Hilfe. Jetzt hat es geklappt.

Schönen Sonntag.
Gruß
Holger
 

Cassio

Aktives Mitglied
29 Okt 2008
4,027
17
38
Region Hannover
Sprachen
  1. BascomAVR
danke für die Hilfe. Jetzt hat es geklappt.


Hallo!

Ja und was hast du nun alles geändert, damit es klappt? :hmmmm:

Wäre nett und fair, wenn du hier nun auch den funktionierenden Code mit ein paar Erklärungen einstellen würdest.


Gruß,
Cassio
 

Holger

Mitglied
2 Jul 2012
37
0
6
73
Sprachen
Hallo Cassio,

es war keine Trägheit und ich wollte meine Info auch nicht vorenthalten. -Ich ging nur davon aus, dass es zu einfach und zu unintressant sei.

Hier nun meine letzte Version:
Code:
-----------------------------------------------------------------------------------------------------------------------------------
'ADC-Werte-einlesen
'Hardware: Poti1 an PC5/ADC5
'          MAX232 an PD0/PD1, Nullmodemkabel zum PC
'-------------------------------------------------------
$regfile = "m8def.dat"                                      'ATmega8-Deklarationen
$crystal = 3686400                                          'Quarz: 3,6864 MHz
$baud = 9600                                                'Baudrate zum PC: 9600 Baud


'
Dim Wert1 As Word

Config Lcdpin = Pin , Db4 = Portd.4 , Db5 = Portd.5 , Db6 = Portd.6 , _
                       Db7 = Portd.7 , E = Portd.3 , Rs = Portd.2

Config Lcd = 16 * 2
Cursor Off

Cls

Ddrc = &B00000000                                           'PC7...PC0=0: PortC-Pins auf Eingang
Config Timer1 = Timer , Prescale = 64
On Timer1 Anzeigen
Enable Timer1
Enable Interrupts

Config Adc = Single , Prescaler = Auto , Reference = Avcc
Start Adc

Do

Wert1 = Getadc(5)

Loop

Anzeigen:

Locate 1 , 4
Lcd "ADC einlesen"

Locate 2 , 5
Lcd "Wert1=  " ; Wert1




Print Getadc(5)
'Print Version()                                             ' gibt den Erstellungszeitpunkt im Format MM-DD-YY hh:nn:ss im Terminal aus
'Print Version(1)                                            ' gibt den Erstellungszeitpunkt im europäischen Format DD-MM-YY hh:nn:ss aus
Return

End
------------------------------------------------------------------------------------------------------------------------------------


Bisher war ich mehr mit der Einrichtung der Hard- und Software beschäftigt. Jetzt fange ich langsam an, mir über die Programmierung Gedanken zu machen.
Als nächstes möchte ich Gleichströme messen und die Verbräuche auf einer externen Karte speichern. Unter FQA habe ich auch schon Anregeungen gefunden. Ich möchte aber mit einem normalen Shunt arbeiten ( den kann ich mir selbst erstellen), Auslegung 1 mV = 1 A. Das dürfte auch kein so großes Problem sein. Nur weiß ich noch nicht wie ich es hinbekomme wenn sich die Polarität des Shunts ändert. Es gibt ja auch Atmegas mit symetrischen und unsymetrischen ADC Eingängen. Wäre das wohl eine Lösung?

Gruß
Holger
 

Cassio

Aktives Mitglied
29 Okt 2008
4,027
17
38
Region Hannover
Sprachen
  1. BascomAVR
Hallo Holger!

Eine "Lösung" ist eigentlich selten uninteressant. :wink:

Wenn ich mir dein Programm da oben aber so ansehe dann weiß ich schon, warum ich nach der "Lösung" gefragt habe. :cool:
Ich kann dir nur den Tipp geben, bevor du dich mit den nächsten Schritten beschäftigst solltest du den obigen Code noch mal optimieren.

Versuch dich ein wenig in den AVR reinzudenken und was er genau macht.
Momentan "läuft" dein Programm wie du dir das gedacht hast.
Wenn du aber auf dieses Programm nun aufsetzt, dann wirst du ggf. bald Schiffbruch erleiden.

Als Tipp zum Ansatz der Optimierungsuche gebe ich dir mal das Wort "Geschwindigkeit". :wink:
Versuch doch mal herauszufinden wann und wie oft deine LCD-Anzeige pro Sekunde aktualisiert wird,
wie oft der ADC in deinem Programm pro Sekunde abgefragt wird und
wie lange der AVR zur Ermittlung eines ADC-Wertes überhaupt benötigt.


Grüße,
Cassio
 

Holger

Mitglied
2 Jul 2012
37
0
6
73
Sprachen
Das ist so eine Sache mit den Gedanken; wenn es denn die eigenen sein sollen!

Hallo Cassio,

danke für die Hinweise. Ja- ich habe versucht mir Gedanken zu machen. Wie ich vorher schon geschrieben habe bin ich aber Anfänger. Es taucht die Frage auf, ob ich bereits in der Lage bin eigene Gedanken zum Ablauf durchzuführen. Mit dem Datenblatt habe ich mich bereits teilweise auseinander gesetzt. Nach einiger Zeit verstand ich auch was Register sind und zum Teil was man mit den Registern macht. Ich versuche mich einzulesen, möchte aber nicht blind, das gelesene ohne es zu verstehen abkupfern. Ich bin also auf Hilfe angewiesen und für diese, wenn sie dann etwas erklärt wird, dankbaR:
Nun zu meinen Gedanken:
Ich könnte die Baudrate erhöhen auf 38400. Das ist doch aber nur für die USAT.
Sollte ich den Timer ganz rausnehmen und stattdessen mit dem ADC Interrup arbeiten? Eventuell dann in den Registern ADMUX, ADCSRA und SREG die entsprechenden Bits setzen?
Ich könnte natürlich auch den Timer herab oder herauf setzen. Worauf bezog sich dein Hinweis aus "Geschwindigkeit" war ich zu langsam oder zu schnell?

Gruß
Holger
 

LotadaC

Sehr aktives Mitglied
22 Jan 2009
3,505
65
48
Marwitz
Sprachen
  1. BascomAVR
  2. Assembler
Zur Baudrate: ja, das betrifft den (Hardware-)UART. Dazu noch folgender Hinweis:
Verwendest Du im Programm einfach so den Befehl Print (oder auch Input ?), initialisiert Bascom für Dich die Schnittstelle (vorher). Da mußt Du Dich also nicht drum kümmern. Heißt, Bascom beschreibt die UART-Controll und Statusregister für Dich. Dabei verwendet es die voreingestellten Optionen (->Hauptmenü...). Auch die dort vorgegebene Baudrate, es sei denn die wird durch die Direktive $Baud=blablub außer Kraft gesetzt, dann gilt blablub. Aber eben nur, wenn das UART auch irgendwann verwendet wird.
Die Zuweisung baud=trallala hingegen beschreibt direkt die beiden Baudratenregister (abhängig vom angegebenem Takt), unabhängig davon ob und wann das UART überhaupt verwendet wird.

Zu den Zeit-Hinweisen:
Du aktualisierst Dein Display in etwa jede Sekunde; dann wird das, zuletzt in Wert1 abgespeicherte ADC-Result angezeigt.
In Deiner Hauptschleife weist Du wert1 ununterbrochen neue ADC-Ergebnisse zu (getadc arbeitet etwa so: es wird eine Conversion angestoßen. Dann wartet das Programm (leere bedingte Schleife), bis das ADC-Interrupt-Flag gesetzt wird (polling). Ist dies der Fall, wird das Ergebnis zurückgegeben (an wert1), und das Flag gelöscht. Eine Einzelwandlung braucht AFAIR 25 ADC-Takte. Welchen Prescaler Bascom da jetzt konkret verwendet (auto), weiß ich nicht, da Atmel für volle Auflösung (10bit) max 200kHz empfiehlt, würde ich davon ausgehen. Dann würde eine Wandlung also eine achtel Millisekunde brauchen. Da Deine Hauptschleife nix anderes macht, weist Du also wert1 (über den Daumen gepeilt) in einer Sekunde 8000mal einen neuen Wert zu.
Einer davon wird ausgegeben.

In der ISR des Timerüberlaufes sind alle anderen Interrupts gesperrt. Du läßt in dieser Daten aufs LCD pumpen, was verhältnismäßig lange dauert. Außerdem stößt Du hier nochmal (!) eine neue Wandlung an, wartest das Ergebnis ab, und schreibst dieses (2Bytes) über den UART. auch das dauert. Wenn das für andere Interrupts kritisch werden könnte, setzt man sich normalerweise in der TOV-ISR einen Merker (Flag), welches man dann im Hauptprogramm in aller ruhe auswerten kann. Bei der Displayausgabe wirds nicht auf ein paar Mikrosekunden Latenz ankommen, woanders vielleicht schon...
(Während der ISR steht natürlich auch dein Hauptprogramm - insofern stimmen die 8000 da oben dann nicht, aber die Tendenz sollte klar sein.)

Noch ein etwas anspruchsvollerer Hinweis: Man kann den ADC auch in einen Endlosbetrieb versetzen, dann werden im Hintergrund quasi ununterbrochen neue Wandlungen angestoßen, das jeweils letzte Ergebnis ist aus den Ergebnisregistern ablesbar. Inwiefern sich das mit getadc oä bequem initialisieren läßt, weiß ich nicht - Du kannst aber die ADC-Steuerregister selbst entsprechend setzen.

P.S.: das letze "end" ist übrigens sinnloser Code. Da wird dann eine Endlosschleife angelegt (ggf vorher noch Interrupts deaktiviert (end. ?)). Diese kann (darf!) aber nie erreicht werden. Nach der Initialisierung läuft alles entweder innerhalb der geschlossenen Hauptschleife ab, oder in Interrupt-Service-Routinen, welche sauber mit einem Return abgeschlossen sein müssen. Ebenso wäre das bei Subroutinen.
 

FreeVEE

Mitglied
30 Aug 2009
81
0
6
Sprachen
Hallo Cassio,


Ich könnte natürlich auch den Timer herab oder herauf setzen. Worauf bezog sich dein Hinweis aus "Geschwindigkeit" war ich zu langsam oder zu schnell?

Gruß
Holger

Hallo,

also wenn ich Cassio richtig verstanden habe :confused:, dann meint er eher die Aktuallisierungsrate des LCD.
Das LCD ist eher langsam und muss nicht aktuallisiert werden, wenn der ADC-Wert sich NICHT ändert.
Oder anders gesagt: das LCD sollte nur bei Änderung des ADC-Werts aktuallisiert werden.
Dies kann man mit Hilfe einer "geschickten" Abfrage und eines Flags (z.B. LCD_refresh = 1) erfolgen.


MfG

FreeVee
 

Holger

Mitglied
2 Jul 2012
37
0
6
73
Sprachen
Hallo
und danke für die Antworten. Das zu verarbeiten wird eine gewisse Zeit dauern. Ich bin dabei, falle allerdings in der kommenden Woche wegen Abwesenheit aus.
Ich werde mich aber wieder melden.

Gruß
Holger
 

Cassio

Aktives Mitglied
29 Okt 2008
4,027
17
38
Region Hannover
Sprachen
  1. BascomAVR
Hallo Holger!

So in etwa wie es LotadaC und FreeVEE geschrieben haben, habe ich es gemeint. :wink:

Ich hatte zwar geschrieben, dass du dich gedanklich in den AVR versetzen sollst meinte damit aber nicht, dass du nun unzählige Seiten Datenblatt studieren musst. :cool:

Natürlich ist es lobenswert, wenn du dir das Datenblatt zum AVR mal genauer ansiehst.
Als Anfänger mit BASCOM könnte das aber zur Zeit kontraproduktiv sein.


Nimm einfach dein Programm und schau es dir noch mal genau an.
Was macht dein Programm eigentlich?
Es durchläuft permanent die DO-LOOP Schleife, so wie es auch sein soll.
Was passiert in dieser Haupt-Arbeitsschleife?

Du verwendest einen Quarz von über 3,6MHz.
Nun fragt sich, wie schnell wird damit die DO-LOOP Schleife durchlaufen?


Nun noch der Timer, der das LCD aktualisiert.
Wie schnell wird durch den Timer das LCD aktualisiert?

Anschließend fragst du dich, muss das alles so oft in einer Sekunde sein, oder wann macht es wirklich Sinn? :wink:

Sobald du für dich herausgefunden hast wann das alles Sinn macht, versuch das Programm entsprechend zu ändern.


Es scheitern immer wieder gute Ideen von neuen Usern (Anfänger) am richtigen Timing alle Komponenten und des gesamten Programms.
Aus dem Grunde sollte du jetzt zu Beginn einfach ein kleines Gespür, oder die richtige Denkweise dafür entwickeln. :wink:


Grüße,
Cassio
 

Holger

Mitglied
2 Jul 2012
37
0
6
73
Sprachen
Hallo Cassio,

meine Do-Loop Schleife wird 3,6 mill. mal in der Sekunde durchlaufen?! Das heißt die Abfrage nach dem Wert wir ebenso oft erstellt. Für die Wandlung wird eine gewisse Zeit benötigt. Der ADC Teiler steht auf 128,
Bedeutet das 3686400 / 128 = 28800 / 25 ADC-Takte 1152 Wandlungen pro Sek.
Das wäre in diesem Fall für mich viel zu viel.
Ist es dann richtig, dass ich nach der Abfrage eine Wartezeit eingefügt habe?
Oder wäre es sinnvoller eine Einzelwandlung durch einen Interrupt (Timer0) anzustoßen?
Mein überarbeitetes Programm sieht jetzt so aus.
Code:
-----------------------------------------------------------------------------------------------------------------------------------------
'ADC-Werte-einlesen
'Dateiname: ADC-Werte-einlesen3.bas

'-------------------------------------------------------
'Hardware: Poti1 an PC5/ADC5
'          MAX232 an PD0/PD1, Nullmodemkabel zum PC
'-------------------------------------------------------
$regfile = "m8def.dat"                                      'ATmega8-Deklarationen
$crystal = 3686400                                          'Quarz: 3,6864 MHz


Dim Wert1 As Word


Config Lcdpin = Pin , Db4 = Portd.4 , Db5 = Portd.5 , Db6 = Portd.6 , _
                       Db7 = Portd.7 , E = Portd.3 , Rs = Portd.2

Config Lcd = 16 * 2
Cursor Off

Cls

Ddrb = &B11111111
Portb = &B00000000

Ddrc = &B00000000
                                                              'PC7...PC0=0: PortC-Pins auf Eingang
Config Timer1 = Timer , Prescale = 64                       '3686400/65535/64=,88 sek
On Timer1 Anzeigen
Enable Timer1
Enable Interrupts

Config Adc = Single , Prescaler = 128 , Reference = Avcc
Start Adc


Do

Wert1 = Getadc(5)
Waitms 500

Loop

Anzeigen:
Cls


Locate 1 , 4
Lcd "ADC einlesen"

Locate 2 , 5
Lcd "Wert1=  " ; Wert1



Print Getadc(5)

Return
------------------------------------------------------------------------------------------------------------------------------

Gruß
Holger
 

TommyB

Team Bitschubse
17 Mai 2010
2,151
80
48
38
127.0.0.1 ;)
Sprachen
  1. C#
  2. VB.Net
  3. LunaAVR
  4. Assembler
  5. Python
meine Do-Loop Schleife wird 3,6 mill. mal in der Sekunde durchlaufen?!

Nein! :)
Die 3,6MHz sagen den CPU Takt an (ich nenne es jetzt mal so). Sprich der Controller kann maximal 3,6 Millionen Befehle pro Sekunde abarbeiten. Allerdings zählt das natürlich nur für die Befehle die auch in 1 Zyklus abgearbeitet werden können; einige brauchen auch 2 oder 3. Die Rede ist hier aber von reinen CPU Befehlen, nicht Code Zeilen in Bascom :)

Ein einfaches Do : Loop braucht allein schon mal 2-3 Zyklen pro Durchlauf, ohne Inhalt. Also sind wir jetzt schon runter auf ca. 1mill, je nach Controller :)
Dann kommt ja noch der Inhalt dazu. GetADC arbeitet soweit ich weiß (und hier geschrieben worden ist) mit polling. Sprich der stößt die Messung an und wartet dann so lange bis der ADC fertig ist (wieder in einer do:loop, nur mit Abfrage ob fertig drin). Dann kommt noch das Wait mit 500ms (quasi eine for:next Schleife). Also (ganz grob geschätzt) läuft deine Schleife nur 1,9x die Sekunde durch. Davon ab ist der Controller die ganze Zeit am arbeiten (blöd für batteriebetriebene Anwendungen).

Ich persönlich würde mal anraten einfach ein paar kleine Projekte in Assembler zu machen (nicht unbedingt dieses). Das hilft doch schon sehr die "Innereien" des AVR zu verstehen, zumindest war es bei mir so. Wobei ich (um ehrlich zu sein) seitdem auch kein Bascom mehr verwende ^^

Und nutz doch bitte nächstes Mal mal das [ code ] Tag für deinen Quelltext :) (im Editor das # Symbol). Das macht es etwas übersichtlicher, ohne dass ein Moderator Hand anlegen muss ;)


ps.: @Dirk: Euer Shout Smiley ist abgehaun :)
 

Cassio

Aktives Mitglied
29 Okt 2008
4,027
17
38
Region Hannover
Sprachen
  1. BascomAVR
Ist es dann richtig, dass ich nach der Abfrage eine Wartezeit eingefügt habe?


Hallo Holger!

Es ging mir nicht darum, dass du dein Programm künstlich verlangsamst.
Gerade ein Wait-Befehl ist extrem ungünstig, weil der AVR in der "Wait-Zeit" absolut gar nichts machen kann. :wink:

Ich wollte dich also einfach mal etwas zum Nachdenken bewegen.
Gerade wenn du den Temperaturwert nur alle ein bis zwei Sekunden aktuell benötigst, solltest du mit einem Timer arbeiten.
Dann wäre es obendrein doch noch sinnvoll wenn dein LCD nur dann aktualisiert wird, wenn es auch tatsächlich etwas zum Aktualisieren gibt.

An deiner Stelle würde ich nun versuchen das Programm so zu ändern, dass der Timer nicht permanent das LCD befeuert.......
und obendrein die ADC-Konvertierung nicht künstlich abgebremst wird (und damit den ganzen AVR blockiert).

Gleichzeitig solltest du dich noch fragen, wofür du unbedingt so eine hohe Systemfrequenz benötigst?
Würde nicht der interne 1MHz Takt für dein Vorhaben ausreichen?


Grüße,
Cassio
 

Holger

Mitglied
2 Jul 2012
37
0
6
73
Sprachen
Hallo Cassio,

jetz habe ich mir Gedanken gemacht :confused:und einmal versucht das von Euch vorgeschlagene umzusetzen.

Das ist dabei rausgekommen:

Code:
'ADC-Werte-einlesen
'Dateiname: ADC-Werte-einlesen4.bas

'-------------------------------------------------------
'Hardware: Poti1 an PC5/ADC5
'          MAX232 an PD0/PD1, Nullmodemkabel zum PC
'-------------------------------------------------------
$regfile = "m8def.dat"                                      'ATmega8-Deklarationen
$crystal = 3686400                                          'Quarz: 3,6864 MHz
$baud = 9600


Config Lcdpin = Pin , Db4 = Portd.4 , Db5 = Portd.5 , Db6 = Portd.6 , _
                       Db7 = Portd.7 , E = Portd.3 , Rs = Portd.2
Config Lcd = 16 * 2
Cursor Off

Cls


Ddrb = &B11111111
Ddrc = &B00000000                                           'PC7...PC0=0: PortC-Pins auf Eingang


On Timer1 Ontimer1                                          'Interrupt-Routine für Timer1-Overflow
                                                            'Bis 0..2: Timer Takt ist Quarz/64 =
Tccr1b = &B00000011                                         ',87 sek pro Impuls
Timsk.toie1 = 1                                             ' Timer1-Overflow-Interrupt ein
Sreg.7 = 1                                                  'Globale Interrupfreigabe


Admux = &B01100000                                          'Bit 6und 7 =01=AVCC ist Refenzspannug
                                                            'Bit 5 =1=nur 8 Bit Genauigkeit
                                                            'Bit4 nicht belegt
                                                            'Bit 3...0 = 0000 =Pin ADC0 = PC0

Adcsra.2 = 1                                                'Bits 2..0 = AVRClock/128
Adcsra.1 = 1
Adcsra.0 = 1


Do :                                                        'noch leer
Loop


Ontimer1:
Adcsra.7 = 1                                                'Bit 7 =1=ADC an
Adcsra.6 = 1                                                'Bit 6 =1=ADC gestartet
Adcsra.5 = 0                                                'Bit 5 =0 jede Messung wird einzeln gestartet

Locate 1 , 1
Lcd "Temperatur  " ; Adch

Print Adch                                                  'nur für Kontrollfunktion (entfällt)

Toggle Portb.2                                              'nur für Kontrollfunktion (entfällt)




Return

Ich habe es probiert und das Programm läuft. Die Frage ist, ob das jetzt der richtige Weg ist.

Gruß
Holger
 

LotadaC

Sehr aktives Mitglied
22 Jan 2009
3,505
65
48
Marwitz
Sprachen
  1. BascomAVR
  2. Assembler
Eher ungünstig ist Dein Zugriff auf das ADCSRA. Zum festlegen des Prescalers greifst Du auf die 3 Bits einzeln zu. es werden nacheinander die drei Bits gesetzt (Bascom optimiert das meiner Meinung nach nicht). Sowas sollte generell mit Bedacht geschehen. Außerdem muß man sich vor Augen führen, was das an ggf an Flash, und an Zeit kostet. Wäre ADCSRA nicht direkt Bit-adressierbar, würde erst der Inhalt von ADCSRA in ein Rechenregister geladen werden, dieses dann mit der Bitmaske manipuliert werden, und das Ergebnis dann zurückgeschrieben werden. Read-Modify-Write. 3 Takte. Das ganze dreimal. Da ADCSRA aber Adresse 0x06 hat, ist SBI anwendbar (BASCOM kann das auch). SBI braucht 2 Takte, zusammen also 6.

Außerdem aktivierst Du den ADC erst beim ersten Timerinterrupt, dann setzt Du das Bit bei jedem weiteren nochmal (SBI), obwohl es da immer noch gesetzt ist. Ebenso mußt Du ADFR nicht explizit löschen (ADCSRA.5=0 -> CBI), schon gar nicht bei jedem Interrupt. Sinniger wäre meiner Meinung nach, als Initialisierung ADEN und die Prescalerbits in einem Rutsch zu setzen (die anderen gleichzeitig zu löschen) - als RMW-Operation, und im Timerinterrupt dann nur noch die Singleconversion anzustupsen (ADSC).

Zweitens gibst Du direkt nach diesem Start des ADC das ergebnis aus. Ich weiß jetzt nicht, ob Dich der Zeitbedarf der Displayausgabe überhapt retten kann (also das Ausgeben von "Temperatur " das Laden des ADCH-Inhaltes hinreichend verzögert), oder ob Dein Display (und danach auch der UART) einfach nur die Ergebnisse des letzten Durchlaufes ausgibt. Ob das ein Problem ist, ist egal - wäre das beabsichtigt?
(sobald Du mit ADSC=1 eine Conversion gestartet hast, beginnt der ADC mit der Wandlung. Diese dauert 25 (Singleconversion/erste Conversion) ADC-Takte (welche sich über den ADC-Prescaler aus dem Systemtakt ableiten). Ist er fertig, landet das Ergebnis in den beiden Result-Registern, und es wird ADIF (in ADCSRA) gesetzt (was einen "ADC-hat-fertig-Interrupt" auslösen kann). Währenddessen arbeitet Dein Programm aber weiter!)

Drittens blockiert die Displayausgabe innerhalb der ISR komplett Dein Programm, uU werden also zwischendurch weitere Timerinterrupts verschluckt (hab Deine TOV-Frequenz jetzt nicht durchgesehen). Normalerweise setzt man hier erstmal nur einen Merker (Flag), und wertet diesen dann (per If-Abfrage) in der Hauptprogrammschleife aus.

(Spoiler: noch eleganter wäre es, den ADC-Interrupt miteinzubeziehen...)

so, keine Zeit mehr... muß wech...
 

Holger

Mitglied
2 Jul 2012
37
0
6
73
Sprachen
Guten Morgen,
danke für die Hinweise. Das mit den drei einzelnen Bits auf das ADCSRA war eine Unsicherheit von mir. Mir war ein Bit, wie im Datenblatt beschrieben, nicht klar. Daher habe ich dann die Bits einzeln gesetzt. Ich werde das ändern.
Auch über den Zeitbedarf habe ich mir Gedanken gemacht. Ich wollte einige Pausentakte setzen, habe es aber dann erst einmal so probiert.
Es sollte eigentlich so werden:
Timer programmieren, ADC starten,über den Timerinterrupt Conversion auslösen, nach der Conversion das Ergebnis auf LCD.
Aber wie bereits geschrieben bin ich in den Anfängen.
Noch eine Frage. Was ist SBI.
Gruß
Holger
 

TommyB

Team Bitschubse
17 Mai 2010
2,151
80
48
38
127.0.0.1 ;)
Sprachen
  1. C#
  2. VB.Net
  3. LunaAVR
  4. Assembler
  5. Python
Noch eine Frage. Was ist SBI.
Das ist ein Assembler Befehl der ein (!) Bit in einem In/Out Register (wie PORTB) setzt (1). CBI wäre das Gegenteil (Bit auf 0 setzen).
SBI - Set Bit in I/O Register

Description:
Sets a specified bit in an I/O register. This instruction operates on the lower 32 I/O registers - addresses 0-31.

Sowas ist häufig sinnvoller wenn man nur 1 oder 2 Bits verändern möchte, weil wenn du mehrere Bits auf einmal ändern möchtest immer erst der aktuelle Wert gelesen wird, dann logisch verknüpft und wieder zurück geschrieben werden muss. Funktionieren tut natürlich beides, ist nur die Frage was schneller ist (und ob man, grade bei Bascom, so weit optimieren möchte / muss).
 

LotadaC

Sehr aktives Mitglied
22 Jan 2009
3,505
65
48
Marwitz
Sprachen
  1. BascomAVR
  2. Assembler
Die andere Sache ist wie angedeutet die, daß diese Einzelbits dann wirklich nacheinander(!) gesetzt werden. Alse auch nacheinander ihre Wirkung eintritt. In Deinem Fall da oben wird also erst ADPS2, danach ADPS1, danach ADPS0 gesetzt. Wenn Bascom dafür je ein SBI verwendet, geschieht das in 3 aufeinanderfolgenden doppelten Takten -> der Prescaler ist also ertmal 2 Tkte lang 32, dann 2 Takte lang 64, dann 128. Da der ADC hier aber eh noch aus ist, hat das noch keinen Effekt - in anderen Situationen kann das aber anders sein.

Statt der Pause kannst Du auch da bereits erwähnte ADIF pollen (in einer Schleife abfragen, bis es gesetzt wurde), und beim weitermachen löschen. Aber auch diese Lösung blockiert durch die Warteschleife Dein Programm.
Auf den ADCC-Interrupt hatte ich ja schon hingewiesen, andererseits könnte man den ADC auch in den Dauerlauf schicken, mit dem Timer äquitemporale :)p->Dino) Meldungen aschicken lassen ("'ne Sekunde is rum"-Flag), und im Hauptprogramm dann bei gesetztem Flag (IF...?) das/die Result-Register auslesen.
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)