//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?
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
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.
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...
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.
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.
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.
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 AVRmusst 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
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.
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...
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.
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.
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.
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.
> 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?
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
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.
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.
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
intmain()
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.
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.