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
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.
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
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.
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
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...
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.
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!
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
> 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...)
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.
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
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.
@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..
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.
Danke euch alle, hat schon mit Ergebniss = ADC; geklaapt. viel,viel................Dank
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.
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:-(
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
> 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.
> 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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.