Hallo zusammen ich benötige mal wieder eure Hilfe. Ich nutze das rumpus board (atm168) und möchte hier gerne den Poti auswerten (PC5) und bei einem gewissen wert soll die LED1 (PC4) aufleuchten. Ich hab das AVR-GCC-Tutorial schon zig mal gelesen aber ich will es einfach nicht verstehen... Ich frage das ungern, aber kann mir jemand die paar Zeilen zukommen lassen, damit ich den Code dann zerlegen und lernen kann? DANKE
Was hindert dich daran, die Turorialfunktion zu nehmen?
Gegenfrage: Was verstehst Du und was nicht. Einfacher als im Tutorial geht es kaum. Der Code ist ja fast Zeilenweise kommentiert.
Ok ich glaube es ist am besten, wenn ich den bereits kommentierten Code nochmals kommentiere
1 | /* ADC initialisieren */
|
2 | void ADC_Init(void) { |
3 | |
4 | uint16_t result; |
5 | uint16_t test; |
6 | |
7 | ADMUX = (1<<REFS1) | (1<<REFS0); |
8 | ADCSRA = (1<<ADPS1) | (1<<ADPS0); // Frequenzvorteiler |
"Diese Bits bestimmen den Teilungsfaktor zwischen der Taktfrequenz und dem Eingangstakt des ADC." ATmega48/88/168: 0 - 10MHz @ 2.7V - 5.5V, 0 - 20MHz @ 4.5V - 5.5V steht im DB nur welchen Mhz wert muss ich da jetzt nehmen?
1 | ADCSRA |= (1<<ADEN); // ADC aktivieren |
2 | |
3 | ADCSRA |= (1<<ADFR); // eine ADC-Wandlung |
wenn ich den Eingang PC5 überwachen will würde ADFR passen oder?
1 | while (ADCSRA & (1<<ADFR) ) {} // auf Abschluss der Konvertierung warten |
2 | /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
|
3 | Wandlung nicht übernommen. */
|
4 | result = ADCW; |
5 | }
|
Wenn ich es richtig verstanden habe sollte nun bereits der eingelesene Wert in result stehen?
1 | /* ADC Einzelmessung */
|
2 | uint16_t ADC_Read( uint8_t channel ) |
3 | {
|
4 | // Kanal waehlen, ohne andere Bits zu beeinflußen
|
5 | ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F); |
Was mach ich den dann mit ADMUX das auszulesende bit hatte ich doch vorher mit ADCSRA |= (1<<ADFR); bestimmt ?
1 | ADCSRA |= (1<<ADFR); // eine Wandlung "single conversion" |
2 | while (ADCSRA & (1<<ADFR) ) {} // auf Abschluss der Konvertierung warten |
3 | test = ADCW; // ADC auslesen und zurückgeben |
4 | }
|
5 | ...
|
6 | |
7 | /* Beispielaufrufe: */
|
8 | |
9 | int main() |
10 | {
|
11 | uint16_t adcval; |
12 | ADC_Init(); |
13 | |
14 | while( 1 ) { |
15 | adcval = ADC_Read(0); // Kanal 0 |
16 | // mach was mit adcval
|
17 | |
18 | }
|
19 | }
|
Welche Auflösung habe ich nun? Wie kann ich nun z.b. bei dem wert 4 in der Variable test die LED 1 (PC4) einschalten? Danke euch ;)
Martin *** schrieb: > ATmega48/88/168: 0 - 10MHz @ 2.7V - 5.5V, 0 - 20MHz @ 4.5V - 5.5V steht > im DB Das sind nur die zulässigen Taktfrequenzbereiche. > nur welchen Mhz wert muss ich da jetzt nehmen? Den Takt, den du wirklich für deine CPU ausgesucht hast. Wenn du nichts verändert hast, dann beträgt der Takt 1 MHz (interner RC-Oszillator mit 8 MHz, aber clock prescaler auf 1:8 voreingestellt). >
1 | > ADCSRA |= (1<<ADEN); // ADC aktivieren |
2 | >
|
3 | > ADCSRA |= (1<<ADFR); // eine ADC-Wandlung |
4 | >
|
> > wenn ich den Eingang PC5 überwachen will würde ADFR passen oder? ADFR gibt's beim ATmegaX8 gar nicht. Das war bei den älteren AVRs der "free running mode", bei den aktuellen heißt dieses Bit ADATE (ADC auto-trigger enable), weil außer "free running" noch weitere automatische Trigger möglich sind. Der Kommentar dort passt aber gar nicht, da steht "eine ADC-Wandlung", das würde man durch
1 | ADCSRA = (1<<ADSC); |
erreichen ("SC" = "start conversion")
Damit, welchen ADC-Eingang du abfragst, hat das aber alles nichts zu
tun: das wird im ADMUX festgelegt. Das Datenblatt enthält eine
Tabelle, in der die Zuordnung der Werte aufgeführt ist.
> while (ADCSRA & (1<<ADFR) ) {} // auf Abschluss der
> Konvertierung warten
Siehe oben, das wäre auch wiederum ADSC.
> Wenn ich es richtig verstanden habe sollte nun bereits der eingelesene
> Wert in result stehen?
Ja.
> ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
> [/c]
>
>
> Was mach ich den dann mit ADMUX das auszulesende bit hatte ich doch
> vorher mit ADCSRA |= (1<<ADFR); bestimmt ?
ADMUX und ADCSRA sind zwei völlig verschiedene Dinge.
> Welche Auflösung habe ich nun?
10 Bit.
> Wie kann ich nun z.b. bei dem wert 4 in der Variable test die LED 1
> (PC4) einschalten?
Hast du überhaupt schon mal was in C auf einem Controller gemacht?
C ++ habe ich schon gearbeitet aber jetzt nicht als Programmierer sondern rein als Hobby wie auch das Microcontroller Programmieren. Ich hab nun mal alles etwas (für mich einfacher zu verstehen) gestrickt und eine If hinzugefügt auch wenn ich nicht glaube, dass dies stimmt.
1 | int main() |
2 | {
|
3 | |
4 | uint16_t result; |
5 | |
6 | |
7 | ADMUX = (1<<REFS1) | (1<<REFS0); // interne Referenzspannung nutzen |
8 | ADCSRA = (1<<ADPS1) | (1<<ADPS0); // Frequenzvorteiler |
9 | ADCSRA |= (1<<ADEN); // ADC aktivieren |
10 | DDRD = (1<<PD3); |
11 | |
12 | |
13 | ADCSRA |= (1<<ADSC); // eine ADC-Wandlung |
14 | while (ADCSRA & (1<<ADSC) ) {} // auf Abschluss der Konvertierung warten |
15 | /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
|
16 | Wandlung nicht übernommen. */
|
17 | result = ADCW; |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | while( 1 ) |
24 | {
|
25 | ////////////////////////////////////////////////////////////////////////////////
|
26 | |
27 | |
28 | /* ADC Einzelmessung */
|
29 | uint16_t test; |
30 | |
31 | |
32 | |
33 | |
34 | // Kanal waehlen, ohne andere Bits zu beeinflußen
|
35 | ADMUX = (1<<PC5); |
36 | ADCSRA |= (1<<ADSC); // eine Wandlung "single conversion" |
37 | while (ADCSRA & (1<<ADSC) ) {} // auf Abschluss der Konvertierung warten |
38 | test = ADCW; // ADC auslesen und zurückgeben |
39 | |
40 | |
41 | if(test == 4) { |
42 | PORTD |= (1<<PD3); //LED2 |
43 | }
|
44 | else { |
45 | PORTD &= ~(1<<PD3); //LED2 |
46 | }
|
47 | /////////////////////////////////////////////////////////////////////////////////
|
48 | }
|
49 | }
|
btw. ich nutze den atm168
Martin *** schrieb: > Ich hab nun mal alles etwas (für mich einfacher zu verstehen) gestrickt > und eine If hinzugefügt auch wenn ich nicht glaube, dass dies stimmt. WTF WOZU? Benutz doch die Tutorialroutinen so wie sie sind. Die kopierst du in deinen Source Code einfach rein. Das ist doch nicht so schwer Und dein main sieht dann so aus (auch das findet sich im Tutorialsbeispiel mehr oder weniger)
1 | int main() |
2 | {
|
3 | uint16_t wert; |
4 | |
5 | ADC_Init() |
6 | |
7 | while( 1 ) { |
8 | wert = ADC_Read( 5 ); // weil du vom Kanal 5, also PC5 lesen willst |
9 | |
10 | if( wert > 4 ) |
11 | mach was |
12 | else
|
13 | mach was anderes |
14 | }
|
15 | }
|
Ich versteh gar nicht, was da jetzt so schwer drann sein soll. Ist doch ohnehin alles schon vorgearbeitet. Einzig deine Referenzspannung musst du im ADC_Init noch richtig einstellen, wobei die Einstellung für 'intern Vcc' wahrscheinlich sowieso passt. Was bitte ist an deinem Code jetzt einfacher als an diesem Code. Udnd die 4, die wirst du wahrscheinlich nicht sehen. Du kriegst Werte von 0 bis 1023. Eine 4 kriegst du bei ein paar Millivolt. So genau kannst du ein Poti gar nciht einstellen. Sinnvoller wird für erste Tests wohl eher
1 | if( wert > 512 ) |
2 | mach was |
3 | else
|
4 | mach was anderes |
sein
Martin *** schrieb: > ADCSRA = (1<<ADPS1) | (1<<ADPS0); // Frequenzvorteiler > ADCSRA |= (1<<ADEN); // ADC aktivieren Es gibt keinen Grund, das auf zwei Anweisungen zu verteilen. > ADCSRA |= (1<<ADSC); // eine ADC-Wandlung Du hast noch keinen Kanal im ADMUX gewählt, also misst du ADC0 (alias PC0). > // Kanal waehlen, ohne andere Bits zu beeinflußen > ADMUX = (1<<PC5); Erstens passt 'ohne andere Bits zu beeinflußen' nicht zur Aktion (ADMUX wird komplett neu beschrieben, mit allen Bits), und zweitens ist das vermutlich nicht, was du willst. PC5 hat den Wert 5, also wird hier ADMUX auf 0b00100000 gesetzt, was dir einerseits die bereits ausgewählte ADC-Referenz wieder zunichte macht, und andererseits ADLAR setzt. Vermutlich willst du aber PC5 (alias ADC5) als ADC-Eingang benutzen:
1 | ADMUX = (1<<REFS1) | (1<<REFS0) | PC5; |
> if(test == 4) { > PORTD |= (1<<PD3); //LED2 > } > else { > PORTD &= ~(1<<PD3); //LED2 > } Antwort vom Sender Jerewan: "Im Prinzip ja, aber". Die Wahrscheinlichkeit, dass dein ADC-Ergebnis exakt 4 beträgt, ist ziemlich klein. Du wirst wohl eher einen Vergleich auf "größer/gleich" oder sowas haben wollen.
Soooo nun funktioniert die Schaltung :) Ich danke euch recht herzlich für die Hilfe und eure Geduld :)
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.