Hi Leute,
vor ab will ich sagen, dass ich schon etwas herumgegooglet habe und es
nach meinem jetzigen Stand der Verständnis so funktionieren müsste.
Folgendes Problem:
Ich muss einen Mikrocontroller programmieren, der je nach
Eingangssignalen PWM-Signale erzeugt und diese an bestimmten Pins
ausgibt.
Die Ausgangspins habe ich global in einem Array definiert sodass ich
einfachen zugriff drauf habe:
static const unsigned char *OUTPUT_ARRAY[] = {
(unsigned char *) 0x05, (unsigned char *) 6, // PB6
(unsigned char *) 0x05, (unsigned char *) 7, // PB7
(unsigned char *) 0x0B, (unsigned char *) 5, // PD5
(unsigned char *) 0x0B, (unsigned char *) 6, // PD6
(unsigned char *) 0x0B, (unsigned char *) 7, // PD7
(unsigned char *) 0x05, (unsigned char *) 0 // PB0
};
Nun muss ich in der Timerinterruptroutine nach gewissen Bedingungen den
Ausgang an diesen Pins 0 bzw. 1 setzen:
(*OUTPUT_ARRAY[i*2]) |= (1 << (int)OUTPUT_ARRAY[i*2 + 1]);
Das funktioniert aber nicht ich bekomme folgende Fehlermeldung:
assignment of read-only location '*OUTPUT_ARRAY[(int)i * 2]'
Kann jemand weiterhelfen?
Is bestimmt ein einfaches Problem :/
Kaan Ayhan schrieb:> Kann jemand weiterhelfen?> Is bestimmt ein einfaches Problem :/
Nun mal ganz langsam. An welchem Mikrocontroller versuchst du dich
überhaupt? Vielleicht kann der das gar nicht.
Ich erklär dir hier mal nur die Fehlermeldung.
Kaan Ayhan schrieb:> Die Ausgangspins habe ich global in einem Array definiert sodass ich> einfachen zugriff drauf habe:>> static const unsigned char *OUTPUT_ARRAY[] = {> ...> };>> (*OUTPUT_ARRAY[i*2]) |= (1 << (int)OUTPUT_ARRAY[i*2 + 1]);>> Das funktioniert aber nicht ich bekomme folgende Fehlermeldung:> assignment of read-only location '*OUTPUT_ARRAY[(int)i * 2]'
Schauen wir mal, was du hier hast:
1
staticconstunsignedchar*OUTPUT_ARRAY[]={...}
2
^OUTPUT_ARRAYistein
3
^Arrayvon
4
^Pointernauf
5
^nur-lesbare
6
^unsignedchar
Also, das, worauf die Pointer zeigen, ist "const" -- nur lesbar. Jetzt
müsstest die Fehlermeldung eigentlich klipp und klar sein.
Am einfachsten ist sicherlich, das "const" wegzulassen. Das
funktioniert, weil die "Pointer", die du zuweist, eh alle non-const
sind:
1
(unsignedchar*)0x05,(unsignedchar*)6,// PB6
Vielleicht hast du aber auch folgendes gemeint:
1
staticunsignedchar*constOUTPUT_ARRAY[]={...}
2
^OUTPUT_ARRAYistein
3
^nur-lesbares
4
^Arrayvon
5
^Pointernauf
6
^unsignedchar
Denn du hast sicher nicht vor, nach dem Initialisieren OUTPUT_ARRAY
selbst zu verändern. Daher kannst du es "const" machen. Aber das muss
man ganz in der Nähe des Namens hinschreiben. Aber das, worauf die
Pointer zeigen, bleibt beschreibbar -- genau was du brauchst.
Apropos Namen: Es wäre gut, wenn du dir angewöhnst, Namen aus nur
Grossbuchstaben für Macros zu reservieren.
Du kannst ganz massiv Code und Zeit sparen, wenn Du bei nur 6 Pins ein
switch/case nimmst.
Dann kann der Compiler CBI/SBI draus machen und muß nicht erst
umständlich Pointer aufdröseln und Bitmasken shiften.
Insbesondere im Interrupt spart man damit auch Push/Pop-Orgien.
Hi,
erstmal danke für die schnellen Antworten.
tom, sry dachte habe das dazugeschrieben.. es handelt sich um einen
ATMega88pa
tictactoe, danke für die super Erklärung. Jetzt funktioniert es genau so
wie ich es haben möchte :)
Peter, ja du hast wohl Recht... die Interruptroutine dauert zu lange,
sodass der nächste Interrupt zu früh kommt. Wird wohl an meinem
Amateurcode liegen.
Wie meinst du das mit der switch-Anweisung? Ich kann mir das nicht so
genau vorstellen wie das aussehen soll.
Eric, wäre deine schreibweise performanter, oder ist das einfach nur die
schönere/professionellere Variante?
So muss ich das ja trotzdem durch eine for-Schleife jagen... die sind
aber wie es ausschaut zu zeitintensiv.
Die Funktion des µC sieht so aus, dass ich 6 digitale In- und Outputpins
und 2 analoge Inputpins habe. An den analogen Eingängen wird die Phase
und das Tastverhältnis eingestellt. Über die digitalen Inputpins kann
der Benutzer festlegen für welche PWM-Ausgänge die Einstellungen
übernommen werden sollen und in meinen 2 Arrays speichere ich mir eben
diese Adressen.
Ich hab hier mal eine leicht abgespeckte Version des Codes (Die Funktion
chooseMag wird hier zwar nicht verwendet aber vielleicht wird für euch
dadurch deutlicher was ich meine)
1
#include<avr/io.h>
2
#include<avr/interrupt.h>
3
4
#define NR_OF_MAGS 6
5
6
// Define new Type for Magnetron
7
structMagnetron{
8
floatfrequency;
9
floatthreshold;
10
floatphase;
11
intcurrentTime;// PWM-Time in Timer-frequency
12
};
13
// Declare Array of Type Magnetron
14
structMagnetronmag[NR_OF_MAGS];
15
// initialize Magnetrons
16
voidinitMag(structMagnetron*mag){
17
mag->frequency=500;
18
mag->threshold=300;
19
mag->phase=0;
20
mag->currentTime=0;
21
}
22
23
// Magnetron PWM Output Pin addresses
24
staticunsignedchar*constoutput_array[]={
25
(unsignedchar*)0x25,(unsignedchar*)6,// PB6
26
(unsignedchar*)0x25,(unsignedchar*)7,// PB7
27
(unsignedchar*)0x2B,(unsignedchar*)5,// PD5
28
(unsignedchar*)0x2B,(unsignedchar*)6,// PD6
29
(unsignedchar*)0x2B,(unsignedchar*)7,// PD7
30
(unsignedchar*)0x25,(unsignedchar*)0// PB0
31
};
32
33
// Magnetron Enable Pin addresses
34
staticconstunsignedchar*ENABLE_ARRAY[]={
35
(unsignedchar*)0x25,(unsignedchar*)1,// PB1
36
(unsignedchar*)0x25,(unsignedchar*)2,// PB2
37
(unsignedchar*)0x25,(unsignedchar*)3,// PB3
38
(unsignedchar*)0x2B,(unsignedchar*)2,// PD2
39
(unsignedchar*)0x2B,(unsignedchar*)3,// PD3
40
(unsignedchar*)0x2B,(unsignedchar*)4// PD4
41
};
42
43
// check witch Magnetrons are choosen to be updated
// System Clock runs in default with 1MHz --> 0.000001 seconds per Tick
104
// Interrupt at Overflow --> 0.000001 * 256 = 0.000256 seconds per Interrupt => 3.90625 kHz
105
sei();// enable global interrupts
106
TCCR0A=0x00;// disable Compare Output Mode, set Timer Mode of Operation to Normal
107
TCCR0B=0x01;// disable Force Output Mode, set Timer Mode of Operation to Normal, set Clock Source to I/O Clock without prescaler
108
TIMSK0|=1<<TOIE0;// enable Timer Interrupt at overflow
109
110
while(1){};// es wird im Moment nur die Timerinterrupt Routine getestet
111
112
return0;
113
}
Wenn das ganze funktioniert, werde ich die Funktionen noch etwas
verschönern und aufteilen, aber erstmal ist mir natürlich die
Funktionalität wichtig.
Ich hoffe ihr könnt mir helfen, den Code zu optimieren.
MFG der Anfänger
Danke jetzt scheint es mir logisch..
Aber ich kann die bib nicht einbinden. Wenn ich #include <sbit.h> mache,
kommt die Fehlermeldung: No such file or directory
Ich hab die Datei im gleichen Ordner, wie das Projekt.
Achja und ich benutze AtmelStudio 6.2.
Kaan Ayhan schrieb:> Eric, wäre deine schreibweise performanter, oder ist das einfach nur die> schönere/professionellere Variante?
* Es spart ein paar bytes,
* Es ist besser lesbar,
* Es braucht keine unnötige casts von Pointer auf normale ints,
* Der von dir beschriebene Fehler tritt nicht auf.
Der Pinzugriff ist jetzt nicht mehr das Problem.
Du hast float im Interrupt und dazu noch float Division.
Wenn das ne PWM werden soll, dann aber nur gaanz laangsaam.
Danke für den Tipp, Markus.
Und Peter, ja ich habe auch gemerkt dass das Problem in dieser Zeile
liegt, doch wie kann ich das Problem lösen? Einfach einen Integer daraus
zu machen wird das Problem ja nicht lösen denke ich... das Problem ist,
dass es ganz ohne Division auch nicht geht. Denn es werden 6 PWM-Signale
erzeugt. Alle werden in der Timer-Frequenz(Timer Interrupt bei Overflow
mit 8bit Timer und 1MHz für eine höhere Frequenz könnte ich natürlich
auch den Interrupt früher setzen) hochgezählt. Nun muss ich ja um die
PWM zu berechnen das Ganze umskalieren. Sprich geteilt durch aktuelle
Frequenz mal erwünschte Frequenz.
Um mit dem Interrupt kein Problem mehr zu haben, hab ich die Funktion
checkPWM() in die main gezogen. Im Interrupt wird nur noch die Variable
currentTime pro Ausgang hochgezählt ( stepPWM() ).
Weiß jemand wie ich das besser machen kann?
Wichtig ist, dass Frequenz und Tastverhältnis für alle Ausgänge
unabhängig von einander variabel sein sollten.
Wenn ich die Frequenz für alle Ausgänge gleich hätte, wäre das ja kein
Problem.
Schau Dir mal andere SW-PWM Varianten an, die machen überhaupt keine
Berechnungen im Interrupt.
Nur Arrayzugriffe, um den nächsten Zählwert laden.
Die Berechnung eines neuen PWM-Wertes erfolgt einmalig in der Mainloop.
Kaan Ayhan schrieb:> Wichtig ist, dass Frequenz und Tastverhältnis für alle Ausgänge> unabhängig von einander variabel sein sollten.
Das kling recht crazy.
Mags Du mal die Anwendung schildern, warum die Frequenz sich ändern muß.
Allgemein ist PWM ja nur Änderung des Mittelwertes.
Danke für den Tipp ich werde es mir morgen anschauen.
Ja der Mikrocontroller soll die Ansteuerung der Netzteile von Magnetrons
übernehmen um den Erhitzungsprozess in einem Mikrowellenofen zu
optimieren. So grob erklärt.
Meint ihr, wenn ich die Einstellung der Frequenz auf "vor den Start"
begrenze, wäre es besser? Wenn man denn keinen anderen Weg findet wäre
das meine Lösung :/