Forum: Mikrocontroller und Digitale Elektronik free running


von espoir (Gast)


Lesenswert?

Hallo,

ich wollte der free running benutzen, aber mein Englisch nicht so gut
und komme ich nicht zu recht, ich weisse nicht welsche register und so
einsetzen.
ich benutze den ATtiny45, C-programmierung.
die Sachen steht 137-140

Danke euch

von TravelRec. (Gast)


Lesenswert?

Free Running ist in den seltensten Fällen sinnvoll - das gezielte
Starten und Auslesen des A/D Converters halte ich persönlich für
vernünftiger - muß aber nicht so sein.

von espoir (Gast)


Lesenswert?

Hallo travelRec,

ja das problem, ich lese aus ein einzige Kanal von AD-Wandler, und ich
warte eine Zeit dazwischen, aber leider klppt nicht.
mit Brack-point fonktinniert schon aber mit normal Lauf wird immer
gleich wert gespeichert.
ich habe dise Frage schon gestellet aber bis jetzt habe ich kein Lösung
gekriegt, das wegen habe ich an free running gedacht.

Danke

von TravelRec. (Gast)


Lesenswert?

Was genau klappt denn nicht? Der ADC wird gestartet, wenn das Bit6 in
ADCSRA gesetzt wird und wenn es wieder 0 wird, ist der Wert in ADCH und
ADCL gültig. Zudem kann nach erfolgter Wandlung ein Interrupt ausgelöst
werden und dann startet man den ADC eben wieder neu. Das manuelle
Starten im Programm hat den Vorteil, daß man dann immer genau weiß was
der ADC macht und wann man mit einem gültigen Rückgabewert rechen kann
- besonders bei zeitkritischen Sachen.

von espoir (Gast)


Lesenswert?

Hallo TravelRec,

ja! ich lese den Werte an AD-Wandler, und zwischen zwei messungen soll
ich einige Zeit Warten.
Als Algurithmus habe ich so gemacht:
ADC_init(): in dieser fkt wird AD-Wandler eingeschaltet(Enable),und den
Kanal ausgewählt.
Spannug_Umsetzer(): in dieser fkt wird AD_Wandler gestartet,prescaler
auswählen, durch ein While-Schleife wird gewartet, bis das Bit ADSC auf
Null wieder gesetz,dann liefert die fkt den ADCL+(ADCH<<8)zurück.
in main fkt, rufe ich den fkt Spannung_unsetzen() auf, und zwar in eine
for-Schleife (läuft 20 mal), um das Ergebniss in einem Feld zu
speicheren.
das Problem wird in alle Element die gleiche Wert gespeichert. obwohl
mit Breack- Point funktionniert schon.
ich verstehe auch nicht so ganz, was du mit nach erfolgter Wandlung ein
Interrupt auslösen, wie fonktionniert das.

Danke

von johnny.m (Gast)


Lesenswert?

Bitte poste doch mal den Code, sonst kann Dir hier niemand wirklich
helfen (außer mit Vermutungen).

Du solltest übrigens, wenn Du schon in C programmierst, nicht ADCL und
ADCH separat einlesen, sondern das 16-Bit-Register ADC (bzw. ADCW bei
manchen Compilern) benutzen. Das ist jedenfalls anwendungssicherer als
das was Du oben geschrieben hast...

Der ADC besitzt einen Interrupt, den man zur Auswertung des Ergebnisses
benutzen kann. Wie das mit den Interrupts funktioniert, steht in der
Doku und im Tutorial auf dieser Seite...

von espoir (Gast)


Angehängte Dateien:

Lesenswert?

Danke erst mal,
an diesem Prroblem Stehe schon seit 2 Wochen, d.h. habe alle meine
ideen ausprobiert, mit Interrupt verstehe das nicht so ganz, ob
wirklich wirckung hat.
Am besten schicke ich dir meinen code die Sachen Konkret zu
diskutieren.
übrigens ich lese nicht den ADCL und ADCH separat.

von Rahul (Gast)


Lesenswert?

unsigned int digital_wert,i;

   digital_wert =5.4894 * Druck;
   digital_wert = digital_wert + 57.294;


Wie soll das gehen?
Integer-Zahlen kennen keine Nachkommastellen!

von espoir (Gast)


Lesenswert?

Hallo,
diese fkt hat nicht mit meine Frage zu tun, intersirt mich jetzt nur
adc_init,spannug umsetzen und die for schleife.
und ich glaube du weisst nicht mal meine Frage!
und nur als Erklärung, wenn man solche deklaration machen, d.h. er
kriegt nicht ein Nachkommazahlen sondern ein Ganz Zahal.
und wie habe ich gesagt das war nicht die Frage.

Danke

von johnny.m (Gast)


Lesenswert?

> while(count<time);

Was soll das bewirken? Da Du augenscheinlich nicht mit Interrupts
arbeitest macht es keinen Sinn, eine Warteschleife zu machen mit einem
Vergleich zweier Variablen, die sich überhaupt nicht ändern können. Da
gibts nämlich nur zwei Möglichkeiten:

1. Die Bedingung ist zum Zeitpunkt der while()-Anweisung falsch, was
dazu führt, dass die Schleife gar nicht durchlaufen wird, also völlig
wirkungslos bleibt.
2. Die Bedingung ist wahr, was dazu führt, dass die Schleife nie wieder
verlassen wird, da sich ja keine der beiden Variablen ändern kann.

Das kann so schon mal nicht funktionieren. Abgesehen davon sehe ich
nirgends eine Anweisung, die count inkrementiert...

Und wie oben schon gesagt: Auf jeden Fall sicherstellen, dass ADCL und
ADCH in der richtigen Reihenfolge ausgelesen werden. Das geht am Besten
mit Zugriff auf das entsprechende 16-Bit-Register.

Für Wartezeiten solltest Du Bibliotheksfunktionen benutzen. Dafür gibts
die schließlich. Bitte schreib noch, welchen Compiler Du nutzt (ich
tippe mal auf AVR-GCC...)

von johnny.m (Gast)


Lesenswert?

BTW: Das was Du machen willst ist eigentlich ein klarer Fall für den ADC
Auto Trigger, am besten über ein Compare-Ereignis vom Timer, der im
CTC-Modus laufen sollte. Das geht am Besten, wenn Du den Timer nicht
für andere Zwecke bereits verplant hast (Das Programm sieht jedenfalls
nicht danach aus). Stelle den Timer so ein, dass er jeweils nach der
gewünschten Wartezeit ein Compare-Ereignis macht und frage den
AD-Wandler mit dem dazugehörigen Interrupt ab. Musst dann nur dran
denken, in der AD-Wandler-Interrupt-Routine das Compare-Flag zu
löschen. Dann kannste Dir den ganzen Mist mit Wartezeiten über
Zeitschleifen (die oft vom Compiler wegoptimiert werden) sparen und
kriegst auf jeden Fall ein sinnvolles Ergebnis.

von espoir (Gast)


Lesenswert?

hallo johnny,
nur um klar zu sein.
>>void int_timer0(void)
{
  //PORTB=0x17;
  count++;
  TCNT0 = 173;
  TCCR0B = (1<<CS02)|(1<<CS00);
}
in diese fkt wird ein interrupt nach 10 ms ausgelöst, aber ich brauche
ein verschiedene zeit, dafür habe ich die fkt wait,also als parameter
gebe ich ein timer ab, und dann läuft in while schleifebis count=time
ist,bei auslösung den interupt wird den cout incremebtiert.
ADCL und ADCH sind schon in richtige Reihen folege, weil das schon mit
beack-point fonktionniert.
als compiler benutze ich den iccavr, und der mikrocontroller ATtiny45.
das probleme ist bei normal Lauf wird im feld(alle element) die gleiche
werte gespeichert.
mit dein 2. antwort komme ich jetzt nicht so Klar.

danke dir für deine Geduld

von Rahul (Gast)


Lesenswert?

Ich kenne mich zwar nicht mit iccavr aus, aber wenn

void int_timer0(void)
{
  //PORTB=0x17;
  count++;
  TCNT0 = 173;
  TCCR0B = (1<<CS02)|(1<<CS00);
}

eine Interrupt-Routine sein soll, würde ich vermuten, dass da noch ein
#pragma fehlt.
In der main.c steht dann ja auch

//void int_timer0(void);
//#pragma interrupt_handler int_timer0:iv_TIMER0_OVF

wobei das ja auskommentiert ist.

von Simon K. (simon) Benutzerseite


Lesenswert?

@Rahul: Ich selber benutze dieses #pragma nicht. Ich mache das immer mit
INTERRUPT(...._INT){..}

@espoir:
"übrigens ich lese nicht den ADCL und ADCH separat."
Sondern? Genau das machst du doch hier
1
Ergebnis=(ADCL+(ADCH<<8));

Wiegesagt:
1
Ergebnis = ADC;
 müsste genausogut funktionieren.
Unter Umständen sogar besser..

von johnny.m (Gast)


Lesenswert?

Ah so. Hab das glatt übersehen, weil die ISR-Syntax vom ICCAVR
anscheinend ein wenig zu unauffällig ist... Wenn Du eine feste Zeit
erzeugen willst (eben z.B. die 10ms) dann betreibe den Timer doch im
CTC-Modus. Er wird dann bei Auftreten eines Compare-Ereignisses
automatisch zurückgesetzt. Du brauchst dann keinen Reload-Wert in TCNTx
zu schreiben. Außerdem kannst Du das Compare-Ereignis dann auch noch als
Auto-Trigger-Quelle für den ADC nutzen.

Ich habe allerdings gerade bei einem Blick ins Datenblatt festgestellt,
dass da anscheinend ein Fehler drin ist. In der Tabelle für die Auto
Trigger-Quellen steht nicht, WELCHER der beiden Timer den ADC triggern
kann. Am besten ausprobieren.

Wenn Du längere Zeiten brauchst oder es unbedingt ohne Auto Trigger
machen willst, dann deklariere eine globale Zählvariable, die in der
Timer Compare ISR inkrementiert und abgefragt wird. Dann könntest Du
z.B. wenn Du alle 50 ms einen Wert einlesen willst, alle 5 Interrupts
den ADC manuell starten. Die Auswertung sollte aber dann mit dem ADC-
Interrupt geschehen. Der ADC muss dazu natürlich für 'Single
Conversion' konfiguriert sein.

von johnny.m (Gast)


Lesenswert?

Mit 'übersehen' meinte ich natürlich den Interrupt....

von espoir (Gast)


Lesenswert?

Danke euch alle, hat schon mit Ergebniss = ADC; geklaapt.
viel,viel................Dank

von Simon K. (simon) Benutzerseite


Lesenswert?

Wahrscheinlich hat der Compiler deinen Code so übersetzt, dass ADCH und
ADCL in falscher Reihenfolge eingelesen wurden. (Ja, da gibts ne
Reihenfolge, die einzuhalten ist).

Super.

von johnny.m (Gast)


Lesenswert?

Naja, deshalb war das ja so ziemlich das erste, was ich vermutet habe
(siehe Posting von 12:06). Ist eigentlich ein Fehler, den viele am
Anfang machen (entweder, weil sie das Datenblatt nicht gründlich genug
gelesen haben oder weil sie tatsächlich glauben, dass der C-Compiler
immer schön von links nach rechts übersetzt; dem ist aber überhaupt
nicht so... In diesem Fall wird nämlich vermutlich zuerst der Inhalt
der inneren Klammer übersetzt und genau das ist der springende Punkt)
Aber auf mich hört ja keiner:-(

von Dennis Kleine-Beck (Gast)


Lesenswert?

Ja, ICC ist da etwas eigenwillig.
Alternativ hätte es mit

unsigned int ADC_temp=0;

ADC_temp = ADCL;            // read out ADCL register
ADC_temp += (ADCH << 8);    // read out ADCH register

geklappt.

Dennis

von johnny.m (Gast)


Lesenswert?

> Ja, ICC ist da etwas eigenwillig...

Ich denke mal, dass das nicht ICC-spezifisch ist. Andere Compiler
machen das u.U. genauso. Dafür gibts ja die 16-Bit-Zugriffe. Da weiß
man, dass irgendjemand sich da mal Gedanken zu gemacht hat und dass das
sicher funktioniert.

von Dennis Kleine-Beck (Gast)


Lesenswert?

> Da weiß man, dass irgendjemand sich da mal Gedanken zu gemacht hat

Dein Wort in Gottes Ohr! ;-)

Du hast Recht! Zur Vollständigkeit sei noch angemerkt, dass (mit
ICCAVR)

ADC_temp = ADC;

ganze 10 Bytes weniger Programmcode benötigt, als mein Bsp. mit

ADC_temp = ADCL;            // read out ADCL register
ADC_temp += (ADCH << 8);    // read out ADCH register

Dennis

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.