Atmega328P Analog-Read (sei()) "friert Controller ein"

OP #4782999
Lesenswert?
• ▲
▼
Hallo Forum,

ich habe ein Problem mit meiner Schaltung/meinem Code.
Eigentlich möchte ich von einem Potentiometer analog lesen um die 
Blinkgeschwindigkeit einer LED zu beeinflussen.
Das funktioniert nicht, da die Variable "speed" nie geändert wird.
Nach dem ersten Durchlauf der "while" in der Funktion "loop()" hängt 
sich mein Atmega auf. Wenn ich den Funktionsaufruf von "sei()" entferne, 
läuft der Loop erwartungsgemäß durch.

Der Poti funktioniert einwandfrei (getestet mit Multimeter).
Falls es hilft, kann ich auf ein Foto meiner Schaltung hochladen, aber 
ich vermute den Fehler eher im Code selbst.

Habt ihr eine Idee?

Grüße, Chris

Hier mein Code:
1
#ifndef F_CPU
2
#define F_CPU 16000000UL
3
#endif
4

5

6
#include <avr/io.h>
7
#include <avr/interrupt.h>
8
#include <util/delay.h>
9

10
void loop(void);
11
int read_analog();
12

13
int speed = 0;
14

15
int main(void) {
16
  DDRD = (1<<PORTD0) | (1<<PORTD1) | (1<<PORTD2);
17
  ADMUX = (1 << REFS0) | (1 << MUX2) | (1 << MUX0);
18
  ADCSRA = (1 << ADEN ) | (1 << ADIE) | (1 << ADPS0) | (1 << ADPS1) | (1 << ADPS2);
19
  DIDR0 = (1 << ADC5D);
20
  read_analog();
21
  sei(); // <--- problem
22
  loop();
23
  return 0;
24
}
25

26
void delay_ms_own(int ms) {
27
  while(ms > 0) {
28
    _delay_ms(1);
29
    ms--;
30
  }
31
}
32

33
void loop() {
34
  while (1) {
35
    PORTD |= (1<<PORTD2 );
36
    delay_ms_own(100);
37
    PORTD &= ~(1<<PORTD2);
38
    delay_ms_own(100);
39
    PORTD |= (1<<PORTD2 );
40
  }
41
}
42

43
int read_analog() {
44
  ADCSRA |= (1 << ADSC);
45
  return 0;
46
}
47

48
ISR(ADC_vect) {
49
  speed = ADC;
50
  read_analog();
51
}
Gast #4783042
Lesenswert?
• ▲
▼
> hängt sich mein Atmega auf
Wie äußert sich das?

> da die Variable "speed" nie geändert wird
Und wie das? Ich sehe nur eine Zuweisung an speed, aber sonst nichts, 
keine Abfrage darauf bzw. Weiterverarbeitung.
Gast #4783069
Lesenswert?
• ▲
▼
> Du vermischt hier Arduino Code mit normalen C-Code.

Der Arduino Style ist deutlich zu sehen, aber er hat keine Arduino 
Library eingebunden und keine Arduino Funktion verwendet.

Das "return 0" am Ende der main() Funktion ist fachlich korrekt, wenn 
auch beim avr-gcc ausnahmsweise unnötig.

>> hängt sich mein Atmega auf
> Wie äußert sich das?

Ist das nicht offensichtlich? Er wird wohl an PD2 eine LED angeschlossen 
haben, die aufhört, zu blinken.
OP #4783092
Lesenswert?
• ▲
▼
Thomas E. schrieb:
> Er stürzt ab, wenn der Interrupt ausgeführt wird. Da die richtige ISR
> vorhanden ist, tippe ich mal auf einen falsch eingestellten Controller.

Das hilft mit leider nicht weiter. Was genau kann da falsch eingestellt 
sein?

S. Landolt schrieb:
> Wie äußert sich das?

Der Inhalt der "while"-Schleife in der Funktion "loop()" wird nur einmal 
ausgeführt und nicht wie durch die "while(1)" zu erwarten unendlich oft.
Sprich: die LED schaltet sich an, nach 100 Millisekunden aus, nach 
weiteren 100ms wieder an und danach bleibt sie angeschalten.

S. Landolt schrieb:
> Und wie das? Ich sehe nur eine Zuweisung an speed, aber sonst nichts,
> keine Abfrage darauf bzw. Weiterverarbeitung.

Ich würde die Variable "speed" gerne verwenden. Den lesenden Zugriff 
baue ich ein sobald es funktioniert. Man könnte zB. sowas machen:
1
while (1) {
2
  PORTD |= (1<<PORTD2 );
3
  delay_ms_own(speed);
4
  PORTD &= ~(1<<PORTD2);
5
  delay_ms_own(speed);
6
}
Das bringt mir allerdings aktuell nichts, weil sich der Controller wie 
gesagt aufhängt. Dass die Variable derzeit nur geschrieben, aber nicht 
gelesen wird, ist mir klar.

Stefan U. schrieb:
> Da wir das gerade erst hatten:
>
> Hast du eventuell beim linken die MCU Angabe vergessen? In diesem Fall
> würde unter anderem die Sprungtabelle für die ISR Routinen fehlen.

Ich bin ziemlich unerfahren. Kannst du mir sagen wie ich das in Atmel 
Studio 7 erreichen kann?

Stefan U. schrieb:
> Ist das nicht offensichtlich? Er wird wohl an PD2 eine LED angeschlossen
> haben...

Korrekt. An PD2 ist eine LED.
Gast #4783114
Lesenswert?
• ▲
▼
> LED ... an, nach 100 Millisekunden aus, nach
> weiteren 100ms wieder an
Das ist doch aussagekräftiger als "friert ein" und "hängt sich auf".

Auch wenn ich mir darauf keinen Reim machen kann; sollte die ADC-ISR 
wirklich, wie von zweien vermutet, in einen Reset münden, so kann doch 
der ADC nicht so lange benötigen.
Gast #4783132
Lesenswert?
• ▲
▼
>> Hast du eventuell beim linken die MCU Angabe vergessen?

> Ich bin ziemlich unerfahren. Kannst du mir sagen wie ich das in
> Atmel Studio 7 erreichen kann?

Gar nicht. Das kann Dir nur passieren, wenn du "manuell" auf der 
Kommandozeile compilierst oder ein fehlerhaftes Makefile verwendest. 
Atmel Studio benutzt normalerweise kein Makefile.

Und du hast ganz sicher den richtigen Mikrocontroller-Typ für den 
Compiler eingestellt? Gibt der Compiler irgendwelche Hinweise dazu aus, 
oder gar Warnmeldungen?

Hast du AVCC angeschlossen? Hast du vielleicht Abblock-Kondensatoren 
(nahe zum Mikrocontroller) vergessen?
#4783133
Lesenswert?
• ▲
▼
Chris K. schrieb:
> Das hilft mit leider nicht weiter. Was genau kann da falsch eingestellt
> sein?

Hast du das schon kontrolliert?

Wenn du für einen anderen Controller kompilierst, und da wärest du 
wahrlich nicht der erste, wird eine für deinen Controller nicht passende 
Interrupt-Vektor-Tabelle angelegt. Dann springt das Programm sonstwo 
hin, nur nicht in die ADC-ISR.
OP #4783188
Lesenswert?
• ▲
▼
Ich habe einen Teil des Codes falsch kopiert:
Der Inhalt der "while" sieht eigentlich so aus:
1
if(speed) {
2
  PORTD |= (1<<PORTD2 );
3
  delay_ms_own(speed);
4
  PORTD &= ~(1<<PORTD2);
5
  delay_ms_own(speed);
6
}
Ich habe das "if" absichtlich nicht mit kopiert, weil ich es für 
bedeutungslos hielt. Der Ausdruck wird sowieso immer "true" sein, war 
meine Annahme.

Nach wiederholtem Programmieren des Controllers blinkt jetzt gar nichts 
mehr.
Wenn ich allerdings die "if" zu
1
if(1) //always true
ändere und alles andere gleich lasse, funktioniert alles wie erwartet.
Die LED blinkt und durch das Verstellen des Potentiometer schneller oder 
langsamer.

Wieso löst die "if" nicht auf "true" auf wenn ich nur "speed" als 
Condition angebe?
#4783224
Lesenswert?
• ▲
▼
Chris K. schrieb:
> S. Landolt schrieb:
>> Kommt jetzt Brummbär zum Zuge mit dem 'volatile'?
>
> Das war's.
>
1
> volatile int speed = 0;
2
>
> löst das Problem.
>
> Kann mir das jemand genauer erläutern?
> Ich verstehe nicht wieso hier ein Unterschied entsteht.
Ohne volatile bekommt der Code in loop nichts davon mit das der Wert 
in einer ISR geändert wurde. Mit volatile wird der Wert jedesmal von 
der entsprechenden Speicherstelle neu geholt.

Sascha
#4783250
Lesenswert?
• ▲
▼
Der Compiler weiß nicht, dass speed in der ISR geändert wird, denn er 
kann nicht erkennen, wann oder ob die ISR überhaupt ausgeführt wird.

Für den Compiler steht da also nur:
1
int speed = 0;
2
...
3

4
if(speed) {
5
...

Das kann er auch gleich wegoptimieren.

Das "volatile" sagt ihm, dass speed auch außerhalb von main geändert 
werden kann.
Gast #4783257
Lesenswert?
• ▲
▼
Schon, aber wie passt das zu:

Chris K. schrieb:
> Wenn ich allerdings die "if" zu
> if(1) //always true
> ändere und alles andere gleich lasse, funktioniert alles wie erwartet.
> Die LED blinkt und durch das Verstellen des Potentiometer schneller oder
> langsamer.

Hier kommt doch speed angeblich irgendwie rüber, ganz ohne volatile.
OP #4783263
Lesenswert?
• ▲
▼
Thomas E. schrieb:
> Chris K. schrieb:
>> Ich habe einen Teil des Codes falsch kopiert:
>> Der Inhalt der "while" sieht eigentlich so aus:
>
> Also haben wir hier die ganze Zeit auf falschem Code rumgeraten?
>
> Kopf - Tisch. Dreimal.

S. Landolt schrieb:
>> Kopf - Tisch. Dreimal.
> Soviel zum Thema "offensichtlich".

Entschuldigt. Das war klar fehlendes Wissen meinerseits.
Aber dafür fragt man schließlich in einem Forum.
Auch wenn mein initialer Post das Problem nicht dargestellt hat.

np r. schrieb:
> Der Compiler weiß nicht, dass speed in der ISR geändert wird, denn
> er
> kann nicht erkennen, wann oder ob die ISR überhaupt ausgeführt wird.
>
> Für den Compiler steht da also nur:int speed = 0;
> ...
>
> if(speed) {
> ...
>
> Das kann er auch gleich wegoptimieren.
>
> Das "volatile" sagt ihm, dass speed auch außerhalb von main geändert
> werden kann.


Danke für die Klärung. Das macht natürlich Sinn.
#4783280
Lesenswert?
• ▲
▼
Chris K. schrieb:
> Aber dafür fragt man schließlich in einem Forum.

Ja, aber mit dem kompletten Code.

Zu den typischen Anfängerfehlern gehört das Weglassen/Vergessen von 
"volatile" und, das allerdings nicht nur bei Anfängern, das generelle 
Ausschließen von Fehlern: "Nein, daran kann es gar nicht liegen." Oder: 
"Daß da ein Fehler liegt, hätte ich niemals gedacht."
Fatal ist es, wenn beides auch noch zusammenkommt.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren