Forum: Mikrocontroller und Digitale Elektronik Hilfe bei Atmega32 Initialisierung


von AVR_NOOB (Gast)


Lesenswert?

Hallo Forum.

Ich habe folgendes Problem und weiß nicht wo mein Fehler liegt.

Hier sehr Ihr meine Initialisierung für einen Atmega 32.
1
//===================================================================================
2
//  Initialisierungsfunktion
3
//===================================================================================
4
5
void init(void)
6
{
7
8
9
nop();        // nop-Funktion verhindert �berspringen des Folgebefehls
10
11
DDRD  = 0x80 ;       // Port D als Eing�nge Port PD7 Ausgang
12
13
nop();
14
15
PORTD = 0x68 ;       // Pull-up Widerst�nde f�r PD6..PD5 aktivieren
16
17
nop();
18
19
DDRC  = 0xFF ;       // Port C als Ausg�nge
20
21
nop();
22
23
PORTC = 0x00 ;       // Pull-up Widerst�nde aus
24
25
nop();
26
27
DDRA  = 0x02 ;       // Port A als Eing�nge PORTA1 is Ausgang
28
29
nop();
30
31
PORTA = 0xFC ;       // Pull-up Widerst�nde f�r PA7...PA2 aktivieren
32
33
nop();
34
35
DDRB = 0xF3;// Port PB2 PB3 Eing�nge
36
37
nop();
38
39
PORTB = 0xF3;// Pullup f�r PB2 PB3 deaktiviert rest an
40
41
nop();
42
43
SFIOR &= (0<<ACME); //AIN1 Comparator negativ Eingang
44
45
nop();
46
47
ACSR = 0b00010000; //Comparator Einstellungen
48
49
nop();
50
51
ACSR &= (0<<ACIE); //Comparator Interrupt Disable
52
53
nop();
54
55
ADCSRA = 0b10111111; //ADC an usw. Prescaler 64
56
57
nop();
58
59
ADMUX = 0b01100000; //Channel 0 Eingang AREF Kondensator da??
60
61
nop();
62
63
ADCSRA |= (1<<ADSC); //AD-Wandler
64
65
nop();
66
67
//while(ADCSRA & (1<<ADSC)); //Dummy Sample
68
69
//nop();
70
71
//TCCR2 =((0<<FOC2)|(1<<WGM20)|(1<<WGM21)|(0<<COM21)|(0<<COM20)|(0<<CS22)|(0<<CS21)|(1<<CS20));//setup PMW, no prescaler
72
73
TCCR2 = 0b01001001; 
74
75
nop();
76
77
sei(); //Interrupts an
78
79
nop();
80
81
}

Neben einigem anderen möchte ich das er mir die Spannung an AIN0 und 
AIN1 vergleicht und den Komparator Ausgang entsprechen schaltet.
Desweiteren soll er an PA0 (Analogchannel 0) eine Spannung messen. 
Referenzspannung ist dabei AVCC.

Und er soll mir an PD7 (OC2) eine PWM ausgeben. D = 50% und f müssten 
grob 56kHz sein mit der Initialisierung. Als Quarz hängt ein 14MHz dran.

Da ich aber bisher nie etwas mit AVR zu tun hatte weiß ich nicht ob die 
Initialisierung so stimmt. Zum einen wird nie die ISR der AD-Wandlung 
ausgeführt (getestet mit PIN Toggeln) zum anderen gibt er nie eine PWM 
aus wenn ich bei TCCR2 |= (1<<COM20); schreibe. Wo liegt mein Fehler?

von Walter T. (nicolas)


Lesenswert?

AVR_NOOB schrieb:
> nop();        // nop-Funktion verhindert �berspringen des Folgebefehls

OK, die erste Zeile sagt mir: Arbeite erst dies hier durch:
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial
und stell die Frage danach neu.

von Kaj (Gast)


Lesenswert?

Was sollen die ganzen nop? Ein Befehl kann nicht einfach so übersprungen 
werden...Warum sollte das auch passieren?
Eine 0 kann man (in C/C++) nicht schieben! 1 schieben und dann negieren.
Bleib bei einer einheitlichen schreibweise für werte.
Auch wenn es auskommentiert ist: etwas mit 0 verodern ergibt keinen 
sinn...

Grüße

von Karl H. (kbuchegg)


Lesenswert?

AVR_NOOB schrieb:

> Wo liegt mein Fehler?

... das deine Schreibweise beschissen unübersichtlich sind und du zu 
viel auf einmal willst.
Nimm ein Teilgebiet nach dem anderen in Betrieb und nicht alles auf 
einmal.

von AVR_NOOB (Gast)


Lesenswert?

Also die nop() sind wegen dem blöden Simulator im AVR Studio drin. Da 
überspringt der Simulator nämlich mal gern ein paar der Befehle.

Desweiteren habe ich den Code leider von meinen Vorgängern bekommen. 
Dementsprechend waren die nop() drin.

Das mit der 1 nicht schieben war es glaube ich. Ich hatte bisher wenn 
dann mal mit PIC zu tun und dort muss man nichts schieben. Da kann man 
direkt 1 oder 0 mit dem entsprechenden Registerstellen namen 
hineinschrieben.

Das mit dem 0 verodern. Habe ich aus einem Tutorial aus google 
kopiert...

von Karl H. (kbuchegg)


Lesenswert?

AVR_NOOB schrieb:
> Also die nop() sind wegen dem blöden Simulator im AVR Studio drin. Da
> überspringt der Simulator nämlich mal gern ein paar der Befehle.

Quatsch.
Schalt den Optimizer vom Compiler ab, wenn du eine 1:1 Entsprechung der 
Debugger-Anzeige und deines Programmtextes brauchst.

: Bearbeitet durch User
von Cyblord -. (cyblord)


Lesenswert?

Der Simulator ist einfach eine Pest. Grade unbedarfte Nutzer nehmen den 
immer, obwohl das genau diejenigen sind, welche die Finger davon lassen 
sollten.
Meist macht dann der Simulator mehr Probleme als die eigentliche 
Aufgabe.

von AVR_NOOB (Gast)


Lesenswert?

OK, das mit 1 schieben war es leider nicht.
Hab jetzt über all wo ich ne 0 haben möchte Register &= ~(1<<pin);
geschrieben. Geht leider trotzdem nicht. Weder Interrupt noch PWM.

von Kaj (Gast)


Lesenswert?

AVR_NOOB schrieb:
> Ich hatte bisher wenn
> dann mal mit PIC zu tun und dort muss man nichts schieben. Da kann man
> direkt 1 oder 0 mit dem entsprechenden Registerstellen namen
> hineinschrieben.

Bei AVR musst du nicht schieben, geht auch ohne.


AVR_NOOB schrieb:
> Also die nop() sind wegen dem blöden Simulator im AVR Studio drin.

Der Simulator ist überhaupt nicht blöd, der ist sogar ziemlich geil, 
sofern man weis was man tut. Einfach die Compiler optimierung 
ausschalten.


AVR_NOOB schrieb:
> Desweiteren habe ich den Code leider von meinen Vorgängern bekommen.

Wenn du den nochmal siehst, einfach dezent verprügeln, für den Code...


AVR_NOOB schrieb:
> Das mit dem 0 verodern. Habe ich aus einem Tutorial aus google
> kopiert...

Wenn du etwas mit 0 veroderst, gibt es als resultat immer das, was 
vorher an entsprechender Position stand. Ist also blödsinn und kann 
weggelassen werden.

Ist das alles was du an Code hast? Wenn du nochmehr Code hast, bitte als 
Dateianhang posten.

Grüße

von AVR-NOOB (Gast)


Angehängte Dateien:

Lesenswert?

Im Anhang ist der gesamte Code.

Ist für ein selbstbau Pedelec mit selbstbau Controller.

An manchen stellen hab ich schon rumgefuhrwerkt aber entsprechend dem 
übergebenen Code auch nicht viel auf Schönheit geachtet.

Der Motor dreht sich und es geht alles bis auf den Bremschopper.

Ist mit Blockkommutierung und ner Analogen 2-Pkt Stromregelung.

Was halt fehlt ist, ich messe über einen Spannungsteiler den 
Zwischenkreis.
Wenn da die Spannung zu hoch wird, soll die PWM angehen. Diese Taktet 
einen Mosfet mit entsprechendem Bremswiderstand...

Und da hängt es noch. Der Komparator wird noch so beschaltet das wenn 
der Pedalsensor eine Spannung ausgibt die höher als der andere Eingang 
des Komparators ist wird entsprechend erst kommutiert..

Da dieser Sensor noch fehlt ist es eine while(1) bzw while(0) schleife.

Ebenso ist der Soll-Spannungswert des ZK noch nicht eingetragen.

von AVR-NOOB (Gast)


Lesenswert?

Achja die nop() werden am Schluss alle entfernt!
Auf jedenfall die in der ISR.

Außerdem ist wie man sieht die PWM von Anfang an aktiv und der Pin 
toggle in der ISR.

Beides wird am Schluss noch abgeändert. Ist zum testen. Einen Debugger 
gibt es nämlich nicht. Kann nur flashen dann rausnehmen und in die 
Schaltung stecken und dann wieder testen...

von AVR_NOOB (Gast)


Lesenswert?

Hat keiner ne Idee warum die Initialisierung nicht richtig ist?

von AVR_NOOB (Gast)


Lesenswert?

Achso und wie geht das bei AVR ohne shiften?

von Rudolph (Gast)


Lesenswert?

AVR_NOOB schrieb:
> Achso und wie geht das bei AVR ohne shiften?

Erstmal wird da garnichts geschoben, das sind Konstanten die durch den 
Prä-Prozessor ausgrechnet werden.
Bestenfalls kann man die Schreibweise als unnötig kompliziert bemängeln.

Die Bits sind in den Includes definiert:

/* PA7-PA0 = ADC7-ADC0 */
/* PORTA */
#define PA7     7
#define PA6     6
#define PA5     5
#define PA4     4
#define PA3     3
#define PA2     2
#define PA1     1
#define PA0     0

Genauso könnte man sich eigene Includes schnitzen die Inkompatibel zum 
Rest der Welt das anders definieren.

#define PAX7     0x80
#define PAX6     0x40
#define PAX5     0x20
#define PAX4     0x10
#define PAX3     0x08
#define PAX2     0x04
#define PAX1     0x02
#define PAX0     0x01

Ehrlich gesagt verstehe ich den tieferen Sinn hinter den aktuellen 
Definitionen auch nicht.

PORTA = (1<<PA7) | (1<<PA5) | (1<<PA3);
PORTA = PAX7 | PAX5 | PAX3;

Da fragt man sich schon, was das soll.

Aber naja, ist eben so, entweder schreibt man das wie alle anderen auch 
oder man baut halt Code den man nirgendwo posten kann, weil er nicht zum 
Standard kompatibel ist.

von Cyblord -. (cyblord)


Lesenswert?

Rudolph schrieb:
>
> Da fragt man sich schon, was das soll.
>
> Aber naja, ist eben so, entweder schreibt man das wie alle anderen auch
> oder man baut halt Code den man nirgendwo posten kann, weil er nicht zum
> Standard kompatibel ist.

Eventuell wirs dir klarer wenn du dir überlegst wie einfach man aus Pin 
2, die Bitmaske (1<<2) bekommen kann. Und dann überlegst du dir, wie man 
im Gegenzug aus einer gegegebenen Bitmaske z.B. 0x80, wieder die 
Pinnummer bekommen könnte.

von Rudolph (Gast)


Lesenswert?

Ach ja, das hier:
>TCCR2 =((0<<FOC2)|(1<<WGM20)|(1<<WGM21)|(0<<COM21)|(0<<COM20)|(0<<CS22)|(0<<CS 
21)|(1<<CS20));//setup  PMW, no prescaler

Macht schon Sinn, da stehen dann nämlich erstmal alle acht Bits des 
Registers und man kann schnell mal eben was setzen oder löschen.
Copy, Paste, anpassen.
Und wie geschrieben, das wird sowieso durch den Prä-Prozessor aufgelöst.

von Rudolph (Gast)


Lesenswert?

cyblord ---- schrieb:
> Und dann überlegst du dir, wie man
> im Gegenzug aus einer gegegebenen Bitmaske z.B. 0x80, wieder die
> Pinnummer bekommen könnte.

Wofür?
Mir fällt jetzt gerade kein Fall ein wo ich z.B. PA7 direkt verwenden 
würde.

von AVR_NOOB (Gast)


Lesenswert?

Hab ich denn nen Fehler in der Initialisierung bei der PWM / ADC und 
Komparator?

von g457 (Gast)


Lesenswert?

> Hab ich denn nen Fehler in der Initialisierung bei der PWM / ADC und
> Komparator?

Ja. Aber der Code ist grausam, was die Fehlersuche nicht unbedingt 
erleichtert. ..schon mal darüber nachgedacht ihn in lesbar neu zu 
schreiben?

von Karl H. (kbuchegg)


Lesenswert?

Lieder muss ich g457 recht geben.

Der Code ist zum einen grausam formatiert, zum anderen ist er irgendwie, 
wie soll man das nennen, auf maximale Code-Konfusion hin geschrieben. 
Die wensentliche Idee, wie das alles funktioniert, ist nicht wirklich 
erkennbar. Zudem sind die Kommentare nicht wirklich hilfreich, eher das 
Gegenteil: sie sind genau so, wie Kommentare nicht sein sollen. Sie 
erzählen mir nichts, was ich nicht sowieso schon im Code selber lesen 
könnte.
Der ganze Code ist nicht Fisch, nicht Fleisch. Der Autor hat sich 
keinerlei Mühe gegeben, dass sich die Programm-Idee leicht 
nachvollziehen lässt. Zudem sind da einige handwerkliche Patzer drinnen, 
die nicht sein müssen.


> Da ich aber bisher nie etwas mit AVR zu tun hatte weiß ich nicht
> ob die Initialisierung so stimmt.

Wenn das so ist, dann würde ich dir empfehlen, erst mal vor alle 
Einzelkopmponenten einzelne Testprogramme zu schreiben. Also ein 
Programm, mit dem du den ADC testest, ein anderes Programm mit dem du 
den Komperator testest, eines für die PWM, usw.
Und dann schnappst du dir den Originalcode und vergleichst da mal mit 
den Dingen, die du in den Testprogrammen gelernt hast.

> Zum einen wird nie die ISR
> der AD-Wandlung ausgeführt (getestet mit PIN Toggeln)

Das wundert mich nicht wirklich. Oder doch? Man weiß es nicht, denn so 
etwas
1
ADCSRA = 0b10111111; //ADC an usw. Prescaler 64
2
ADMUX = 0b01100000; //Channel 0 Eingang AREF Kondensator da??
ist natürlich Gift für die Nachvollziehbarkeit der ADC-Einstellungen. 
Ist da jetzt ein Autotrigger eingestellt oder nicht?
Ich hab jetzt aber ehrlich gesagt auch keine Lust, mir das aus dem 
Datenblatt zusammenzusuchen. Deine Kommentare in allen Ehren, aber es 
wäre vernünftig, vor die Konfiguration einer jeden Teilkomponente einen 
Blockkommentar einzufügen, in dem aufgeschlüsselt ist, welche 
Konfiguration für die Komponente eigentlich angestrebt wird.
Und natürlich die Verwendung von Bit-Namen anstelle der Binärzahlen. 
Binärzahlen sind an dieser Stelle nicht nur schlecht zu lesen und 
nachzuvollziehen, sie sind auch fehleranfällig.

Wenn da am ADC kein Autotrigger eingestellt ist, dann wundert mich das 
nicht, dass der ADC nichts tut. Der ADC beginnt zu arbeiten, sobald man 
das ADSC in ADCSRA setzt. Der ADC macht dann seine Arbeit und wenn er 
fertig ist, setzt er dieses Bit wieder zurück. Bei dir wird zusätzlich 
dann auch noch ein Interrupt ausgelöst (hoffe ich zumindest. wie gesagt: 
Binärschreibweise interessiert mich bei den Konfigurationsregistern 
nicht, die müsste man erst mal auseinanderpfriemeln). In der ISR 
passiert alles möglich - die Hälfte aller Anweisungen ist völlig unnötig 
- aber eines passiert dort nicht: ADSC wird nicht erneut gesetzt. Und 
auch sonst nirgendwo anders im Code. Damit hat der ADC eine 1-mal Aktion 
gemacht und ist dann wieder ruhig.
Unter der Annahme, das da kein Autotrigger im Spiel ist, ist mir ehrlich 
gesagt auch nicht wirklich klar, wozu das überhaupt über Interrupt 
laufen muss. Grund sehe ich dafür nicht wirklich. Die Hauptschleife ist 
umfangreich genug, so dass man nach Abschluss einer Messung die nächste 
Messung triggern kann, deren Ergebnis dann beim nächsten Durchlauf durch 
die Hauptschleife vor liegt.
Aber wie gesagt: da die Codeidee kaum erkennbar ist, es nicht leicht zu 
erschliessen ist, wie die Einzelkomponenten eigentlich zusammenarbeiten 
sollen, kann es natürlich auch sein, das es einen extrem guten Grund für 
zb den ADC Interrupt gibt, den ich nur nicht sehe.

> zum anderen
> gibt er nie eine PWM aus

Auch hier: das ist alles so im Code versteckt, dass es maximal schwierig 
ist nachzuvollziehen unter welchen Bedingungen die PWM überhaupt 
eingeschaltet wird und unter welchen Bedingungen nicht. Die grausliche 
und unübersichtliche Formatierung ist dann nur noch das Tüpfelchen auf 
dem i.

von AVR_NOOB (Gast)


Lesenswert?

Der ADC läuft im Freerunning Modus.
Er soll kontinuierlich die Zwischenkreisspannung messen.
Sobald eine Wandlung fertig ist wird der Wert in einer Variablen 
gespeichert und das Flag gesetzt.

In der Hauptschleife (die möglichst schnell laufen soll, daher ISR damit 
nur wenn eine Messung fertig ist die If Anweisung erfüllt ist und die 
Funktion chopper() nur ausgeführt werden soll wenn eine Messung auch 
wirklich fertig ist.

Wenn Chopper() aufgerufen wird, wird die gemessene Spannung mit einem 
Sollwert verglichen. Wenn der gemessene größer ist soll die PWM 
angeschaltet werden. Wenn der gemessene kleiner ist wird die PWM wieder 
ausgeschaltet.

Die PWM taktet einen Mosfet der den Zwischenkreis über einen 
Bremschopper zu GND verbindet.
Sozusagen wenn die Spannung im Zwischenkreis zu hoch ist wird der 
Zwischenkreis belastet.

PWM wird also nur in Chopper() genutzt.
Der ADC Wert nur in der ISR.

Und natürlich in init().

Der ganze Rest des Codes läuft. Dort können also keine Fehler sein.

von Karl H. (kbuchegg)


Lesenswert?

AVR_NOOB schrieb:
> Der ADC läuft im Freerunning Modus.
> Er soll kontinuierlich die Zwischenkreisspannung messen.
> Sobald eine Wandlung fertig ist wird der Wert in einer Variablen
> gespeichert und das Flag gesetzt.
>
> In der Hauptschleife (die möglichst schnell laufen soll, daher ISR damit
> nur wenn eine Messung fertig ist die If Anweisung erfüllt ist und die
> Funktion chopper() nur ausgeführt werden soll wenn eine Messung auch
> wirklich fertig ist.

1
int main()
2
{
3
  ...
4
5
  while( 1 )
6
  {
7
    ...
8
9
    if( !(ADCSRA & ( 1 << ADSC )) )  // ist die ADC Messung abgeschlossen?
10
    {
11
      chopper( ADCH );          // den Messwert verarbeiten
12
      ADCSRA |= ( 1 << ADSC );  // nächste Messung starten
13
    }
14
15
    ...
16
}

verbraucht in Summe mit Sicherheit weniger Zeit, als dein ganzer 
Interrupt Klimbim samt Free-Running Modus und 3 Millionen globale 
Variablen und Flags.
Abfragen musst du sowieso. Ob du jetzt eine Flag-Variable abfragst oder 
gleich das ADCSRA Register ist Jacke wie Hose.

Edit:
Nach genauerem Überlegen geht sogar die direkte ADCSRA Abfrage schneller 
als das globale Flag. Und zwar auf einem Mega32 deutlich schneller.

: Bearbeitet durch User
von AVR_Noob (Gast)


Angehängte Dateien:

Lesenswert?

Hier nochmal alles aufgeräumt und umgebaut.
Die Test Funktionen werden später rausgeschmissen.
Konnte es noch nciht durch den Compiler jagen. Deswegen können noch 
Fehler drin sein.

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.