Servus,
Also ich hab ein wenig C-Code geschrieben und jetzt versuche ich ihn
noch zu Optimieren. Und genau das ist der Punkt an dem ich euch um
Vorschläge bitte, da ich noch nicht sehr lange Programmiere.
Folgender Code soll abwechselnd auf OC0A und OC0B eine Sinus-Halbwelle
ausgeben. Zusätzlich soll Pin 4 gepollt werden und im Falle eines
Tastendrucks soll dann Pin 2 abgeschalten werden. Wobei beachtet werden
muss, dass Pin 4 beim Einschalten gedrückt sein wird und dabei nicht als
Ausschaltbefehl gewertet werden soll.
uint8_toc_sel=0;// speichert welcher PWM-Ausgang aktiv ist. ( 0->OC0A; 1->OR0B )
10
uint8_tpresscount=0;// Dient dem entprellen von S1, sodass nicht das einschalten als ausschalten gewertet wird.
11
uint8_ton=0;// Wird 1 sobald S1 losgelassen wird. Der Chip ist damit offiziel an.
12
13
intmain(void){
14
OCR0A=0;// Pulsweite von OC0A auf 0
15
OCR0B=0;// Pulsweite von OC0B auf 0
16
TCCR0A=(1<<COM0A1)|(1<<COM0B1)|(1<<WGM01)|(1<<WGM00);// 2 x non Inverting PWM, Fast PWM Mode
17
TCCR0B=(1<<CS00);// Prescaler: 1
18
TIMSK0=(1<<TOIE0);// Interrupt on TOP einschalten
19
DDRB=(1<<PB0)|(1<<PB1)|(1<<PB2);// PB0 (OC0A), PB1 (OC0B) und PB2 als Ausgang
20
PORTB=(1<<PB2);// PB2 auf 1 setzen, Rest auf 0.
21
sei();// Interrups aktivieren
22
23
MCUCR=(1<<SE);// Sleepmode: idle, + enable
24
25
while(1)
26
asm("SLEEP");// in Pausen schlafen geht.
27
28
return0;
29
}
30
31
ISR(TIM0_OVF_vect){
32
MCUCR&=~(1<<SE);// Sleepmode disable; Datenblatt S.32, in den letzten 3 Zeilen
33
counter+=summand;// Sinustabelle rauf/runter zählen. Kann man ein uin8_t mit einem int8_t addieren?
34
35
if(oc_sel)// Wenn oc_sel == 1 dann ist OC0B gerade an der Reihe seine Halbwelle abzulaufen
36
OCR0B=sinustabelle[counter];
37
else// ansonsten ist OC0A dran.
38
OCR0A=sinustabelle[counter];
39
40
if(counter>ANZAHL-2)// Wenn das letzte Element der Sinustabelle erricht ist,
41
summand=-1;// Sinustabelle wieder zurück laufen
42
if(counter<1){// Wenn wieder beim ersten Element der Sinustabelle angekommen,
43
summand=+1;// Sinustabelle wieder vorwärts laufen
44
oc_sel^=0b00000001;// Auf anderen OC0_ Ausgang umschalten. Stimmt das? wird hier zwischen 0 und 1 hin und her geschalten? Oder müsste da "0b10000000" stehen?
45
}
46
47
if(PINB&(1<<PB4)&&on){// Wenn Pin 4 mit V+ verbunden ist und vorher schonmal auf GND war.
48
presscount++;// Zählen wie lange gedrückt wird.
49
if(presscount>250){// wenn lange genug, dann ist mögliches Prellen auch vorbei (Wichtig beim loslassen des Tasters beim einschalten)
Was heisst den "Optimieren"?
Ist das Programm zu langsam oder zu groß?
So wie das Programm angelegt ist liegt die Sinustabelle im RAM, wo sie
vom Startup-Code aus dem Flash hin kopiert wird. Sie belegt also Platz
im RAM und im Flash.
Ist ANZAHL die Größe der Tabelle? Es ginge sowas:
Einige Variablen werden nur in der ISR verwendet und müssen nicht global
sein. Folgendes ist zwar nicht optimaler, aber klarer zum Verständnis,
weil die Gültigkeitsbereiche nicht großer sind als nötig:
1
ISR(...)
2
{
3
staticuint8_tcounter=0;
4
staticint8_tsummand=1;
5
...
Sleepmode braucht nicht deaktiviert zu werden.
Das wäre eine Sicherheitsmaßnahme, wenn keine Brownout-Erkennung
aktiviert ist und der µC bei niedriger Spannung wild rumhupfpt und ne
SLEEP trifft.
TCCR0A kann direkt beschrieben werden mit =, du kennst den Wert der rein
soll. Schreib ihn rein, das ist klarer und knapper als &= oder |=.
Erstmal Danke. Diese Art von Vorschlägen habe ich gesucht. Profikniffe
halt. Weder ist das Programm zu groß noch zu langsam, aber ich wills
halt "verschönern" und dabei was lernen.
Johann L. wrote:
> So wie das Programm angelegt ist liegt die Sinustabelle im RAM, wo sie> vom Startup-Code aus dem Flash hin kopiert wird. Sie belegt also Platz> im RAM und im Flash.
In welchem Schritt passiert denn das?
> Ist ANZAHL die Größe der Tabelle? Es ginge sowas:
Richtig. Danke für deinen Definitionstip.
>
Könnte ich nicht sinwert sparen, indem ich direkt OCR0A mit
pgm_read_byte(...) überschriebe?
Und das "&" steht da um die SPeicheraddresse von sinustabelle[..] zu
bekommen richitg?
> Einige Variablen werden nur in der ISR verwendet und müssen nicht global> sein. Folgendes ist zwar nicht optimaler, aber klarer zum Verständnis,> weil die Gültigkeitsbereiche nicht großer sind als nötig:
stehen sie der Funktion dann auch bei jedem Neuaufruf noch mit dem Alten
wert zur Verfügung? Und würde sie dann nich bei jedem Funktionsaufruf
neu im RAM angelegt werden?
> Sleepmode braucht nicht deaktiviert zu werden.>> Das wäre eine Sicherheitsmaßnahme, wenn keine Brownout-Erkennung> aktiviert ist und der µC bei niedriger Spannung wild rumhupfpt und ne> SLEEP trifft.
Das ganze wird zwar von ner Batterie versorgt und Brownout nicht
eingeplant aktiviert zu sein, aber ich schätze wenn mal ein sleep
getroffen wird, dann wacht er halt ne Counterrunde später wieder auf.
Danke für diesen Hinweis.
> Könnte ich nicht sinwert sparen, indem ich direkt OCR0A mit> pgm_read_byte(...) überschriebe?
Nein. Da der AVR keine Special Function Register -> Special Function
Register Operationen machen kann, sondern erst alles in ein
Arbeitsregister laden muss, ist sinwert auch bei direktem Beschreiben im
C Code am Ende im Assembler vorhanden, und zwar als eines der Register
r0-r31.
> Und das "&" steht da um die SPeicheraddresse von sinustabelle[..] zu> bekommen richitg?
Ja. Auch das wird vom Compiler passend wegoptimiert, so dass nur noch
ein Berechnen der Absoluten Adresse und ein Laden aus dem Flash übrig
bleibt.
Benedikt K. wrote:
> Nein. Da der AVR keine Special Function Register -> Special Function> Register Operationen machen kann, sondern erst alles in ein> Arbeitsregister laden muss, ist sinwert auch bei direktem Beschreiben im> C Code am Ende im Assembler vorhanden, und zwar als eines der Register> r0-r31.
Steckt da eine Atwort auf diese Frage drin?
>> Einige Variablen werden nur in der ISR verwendet und müssen nicht global>> sein. Folgendes ist zwar nicht optimaler, aber klarer zum Verständnis,>> weil die Gültigkeitsbereiche nicht großer sind als nötig:> stehen sie der Funktion dann auch bei jedem Neuaufruf noch mit dem Alten> wert zur Verfügung? Und würde sie dann nich bei jedem Funktionsaufruf> neu im RAM angelegt werden?,
Wenn ja, dann versthe ich sie nicht sicher richtig.
Hans Wurst wrote:
> Johann L. wrote:>> So wie das Programm angelegt ist liegt die Sinustabelle im RAM, wo sie>> vom Startup-Code aus dem Flash hin kopiert wird. Sie belegt also Platz>> im RAM und im Flash.> In welchem Schritt passiert denn das?
Das passiert im Startup-Code, wie gesagt. Dieser wird vor main()
ausgeführt und initialisiert globale Variablen und ruft statische
Konstruktoren auf (falls vorhanden). Wenn im Progemm ne globale Variable
1
intfoo=1;
definiert ist, dann muss ja irgendwann die 1 in foo reinkommen. Das
macht der Startup-Code.
>>> Ist ANZAHL die Größe der Tabelle? Es ginge sowas:> Richtig. Danke für deinen Definitionstip.>>>
> Könnte ich nicht sinwert sparen, indem ich direkt OCR0A mit> pgm_read_byte(...) überschriebe?
Ja. Der Compiler sollte die doppelte Ausdrücke die dann da stehen wie
wie & sinustabelle[counter] rausoptimieren, so daß nur eine Berechnung
verbleibt (commom sumexpression elimination).
> Und das "&" steht da um die SPeicheraddresse von sinustabelle[..] zu> bekommen richitg?
pgm_read_byte ist in Inline-Assembler Makro, um Werte aus dem Flash zu
lesen. Im Endeffekt tut pgm_read_byte(x) das gleiche wie (*(x)), das
heißt es dereferenziert einen Zeiger. Allerdings nicht im RAM, sondern
im Flash. Alternativ zu & sinustabelle[counter] kann man auch schreiben
sinustabelle+counter. Ich bevorzuge die erste Variabte.
>> Einige Variablen werden nur in der ISR verwendet und müssen nicht global>> sein. Folgendes ist zwar nicht optimaler, aber klarer zum Verständnis,>> weil die Gültigkeitsbereiche nicht großer sind als nötig:> stehen sie der Funktion dann auch bei jedem Neuaufruf noch mit dem Alten> wert zur Verfügung?
Ja.
> Und würde sie dann nich bei jedem Funktionsaufruf> neu im RAM angelegt werden?
Nein. Sie sind static. Diese Variablen leben nicht im Frame der Funktion
(also auf dem Stack bzw. in GPRs) sondern dort, wo auch andere globale
Variablen stehen.
>> Sleepmode braucht nicht deaktiviert zu werden.>>>> Das wäre eine Sicherheitsmaßnahme, wenn keine Brownout-Erkennung>> aktiviert ist und der µC bei niedriger Spannung wild rumhupfpt und ne>> SLEEP trifft.> Das ganze wird zwar von ner Batterie versorgt und Brownout nicht> eingeplant aktiviert zu sein, aber ich schätze wenn mal ein sleep> getroffen wird, dann wacht er halt ne Counterrunde später wieder auf.
Kommt drauf an wie kritisch das ist. Wenn einem die paar µA die der BOD
saugt nicht zu viel sind, ist seine Aktivierung kein Luxus.
Hans Wurst wrote:
> Wenn ja, dann versthe ich sie nicht sicher richtig.
Ok, dann in Kurzform: Du kannst sinwert einsparen (im C Code), der
erzeugte Assemblercode bleibt aber gleich.
Ah ja. 1000 Dank.
Das denke ich hab ich soweit kapiert. Sehr schön Danke euch Jungs.
Jetz bleiben nurnoch ein paar Fragen die oben im C-Coder versteckt
waren:
1.
1
...
2
oc_sel^=0b00000001;
3
...
Stimmt das? wird hier zwischen 0 und 1 hin und her geschalten? Oder
müsste da "0b10000000" stehen? Oder noch etwas anderes?
2.
1
...
2
counter+=summand;
3
...
Kann man ein uin8_t mit einem int8_t addieren? Bzw. im Falle von -1
Subtrahieren?
3.
1
...
2
ISR(TIM0_OVF_vect){
3
...
4
return;// Ist das return hier Nötig?
5
}
6
...
4. Eine Frage wäre dann doch noch:
>> Und würde sie dann nich bei jedem Funktionsaufruf>> neu im RAM angelegt werden?>>Nein. Sie sind static. Diese Variablen leben nicht im Frame der Funktion>(also auf dem Stack bzw. in GPRs) sondern dort, wo auch andere globale>Variablen stehen.
Warum gibt es dann globale Variablen? Oder bleibt eine in einer Funktion
deklarierte Variable zwar bestehen ist aber nicht lesbar für andere
Funktionen. Oder muss ich eine Variable die bestehen bleiben soll als
"static uint8_t ..." einführen und diese ist dann auch für andere
funktionen Verfügbar?
Frage 4 habe ich glaube ich hier
http://home.fhtw-berlin.de/~junghans/cref/CONCEPT/storage_class.html#static
schon gefunden.
Demnach entspricht eine als statik definierte Variable einer globalen
Variable richtig?
Aber wird sie dann nicht bei jedem Funktionsaufruf neu deklariert, oder
schreibt der compiler das dann um?
> Stimmt das? wird hier zwischen 0 und 1 hin und her geschalten? Oder> müsste da "0b10000000" stehen? Oder noch etwas anderes?
Denk nach.
^ bezeichnet die XOR verknüpfung.
0 ^ 1 -> 1
1 ^ 1 -> 0
und das alles auf Bit-Ebene.
Technisch gesehen machst du also aus dem Bit 0 eine 1, wenn das Bit
vorher 0 war und auch wieder zurück. D.h. das Bit 0 toggelt (wechselt)
ständig zwischen 0 und 1.
Du hast also in oc_sel (da diese Variable ja mit 0 vorinitialisiert
wurde) diese beiden Bitmuster
0b00000000
0b00000001
und ja, das sind die Bitmuster für 0 und 1
wenn du mit 0b10000000 xor-en würdest, dann würde Bit 7 ständig zwischen
0 und 1 wechseln. Als uint8_t Zahl ausgedrückt wär das aber
0b00000000 = 0
0b10000000 = 64
Dezimal gesehen, würde oc_sel also ständig zwischen 0 und 64 wechseln.
Eine andere Möglichkeit, bei der ev. klarer wird was passiert und du
nicht auf Biteben umpfriemeln musst, wäre zb
oc_sel = 1 - oc_sel;
ist oc_sel gleich 0, dann bekommt es den Wert 1 ( da: 1 - 0 gleich 1)
ist es 1, dann wird daraus 0 ( da: 1 - 1 gleich 0 )
> 2.>
1
...
2
>counter+=summand;
3
>...
4
>
> Kann man ein uin8_t mit einem int8_t addieren? Bzw. im Falle von -1> Subtrahieren?
Sicher kann man. Die C-Regeln sagen in diesem Fall, dass zuerst der
signed integer in unsigned umgewandelt wird.
> 3.>
1
...
2
>ISR(TIM0_OVF_vect){
3
>...
4
>return;// Ist das return hier Nötig?
5
>}
6
>...
7
>
Nein. Wenn das return die letzte Anweisung in einer Funktion ist und
nicht dazu benutzt wird einen Wert zurückzugeben, dann kann man es sich
auch sparen. Was soll auch sonst passieren, als dass die Funktion zu
ihrem Aufrufer zurückspringt, wenn die Funktion zu Ende ist.
> 4. Eine Frage wäre dann doch noch:>>> Und würde sie dann nich bei jedem Funktionsaufruf>>> neu im RAM angelegt werden?>>>>Nein. Sie sind static. Diese Variablen leben nicht im Frame der Funktion>>(also auf dem Stack bzw. in GPRs) sondern dort, wo auch andere globale>>Variablen stehen.>> Warum gibt es dann globale Variablen?
Du hast das Konzept des Scopes noch nicht verstanden.
Klar könnte man auch globale Variablen machen. Aber dann kann jeder Wald
und Wiesen-Code auf diese Variablen zugreifen und sie mit Werten
bestücken wie er lustig ist.
Als static Variablen hingegen, existieren diese Variablen nur in dieser
Funktion. Andere Code-Stellen sehen diese Variablen nicht und können sie
sich auch nicht zugänglich machen.
Generell ist es immer gut, wenn man die Sichtbarkeit von Variablen so
weit wie möglich einschränkt. Damit vermindert man die Gefahr, dass man
irrtümlich diese Variablen verändert und es vermindert auch das
Kopfzerbrechen, warum und vor allem wo im Code sich schon wieder wer an
dieser Variablen vergangen hat, so dass ihr Wert nicht mehr stimmt.
Aber Achtung: Das Schluesselwort 'static' hat mehrere Verwendungszwecke.
Hier geht es nur darum, dass static auf funktionslokale Variablen dafür
sorgt, dass diese Variablen beim Verlassen einer Funktion nicht zerstört
werden sondern bis zum nächsten Funktionsaufruf überleben.
>> Und das "&" steht da um die SPeicheraddresse von sinustabelle[..] zu>> bekommen richitg?> pgm_read_byte ist in Inline-Assembler Makro, um Werte aus dem Flash zu> lesen. Im Endeffekt tut pgm_read_byte(x) das gleiche wie (*(x)), das> heißt es dereferenziert einen Zeiger. Allerdings nicht im RAM, sondern> im Flash. Alternativ zu & sinustabelle[counter] kann man auch schreiben> sinustabelle+counter. Ich bevorzuge die erste Variabte.>
Heißt das, wenn du nicht
1
pgm_read_byte(x)
sondern
1
(*(x))
schreibst, landet es dann doch im Flash, oder ist das nur wegen der
Übersichtlichkeit/Verständlichkeit?
Ansich entscheidet doch das const für EEPROM oder Flash?
> schreibst, landet es dann doch im Flash,
Nein.
SRAM und Flash sind voneinander völlig getrennte Speicherbereiche. Jeder
Speicherbereich beginnt aber seine Adressierung bei 0. D.h. wenn du nur
den numerischen Wert einer Speicheradresse hast, kannst du nicht
entscheiden, ob das jetzt die Adressierung ins SRAM oder ins Flash sein
soll. Daher muss man nachhelfen.
Ist nichts weiter angegeben, dann geht der COmpiler davon aus, dass die
Adresse eine SRAM Adresse ist. Das kommt dann bei *x zum Zug
Will man aus dem Flash lesen, dann muss man das mitteilen. pgm_read_byte
weiss wie man aus dem Flash an einer bestimmten Speicheradresse lesen
muss. Nur muss man dieser Funktion dann auch diese Adresse übergeben.
Thats all.
> Ansich entscheidet doch das const für EEPROM oder Flash?
Ist compilerabhängig. Beim AVR-gcc muss man mit geeigneten Mitteln
sicherstellen, dass Konstanten im Flash landen. Ansonsten landet alles
letztendlich im SRAM
> schreibst, landet es dann doch im Flash, oder ist das nur wegen der> Übersichtlichkeit/Verständlichkeit?
Landen tut da gar nichts, weil pgm_read_byte etwas aus dem Flash liest
und nichts hineinschreibt.
Und nein, es ist nicht nur wegen der Übersichtlichkeit. Die
Harvard-Architektur der AVRs hat getrennte Busse für Daten- und
Programmspeicher. Der Zugriff auf Daten im Programmspeicher (Flash)
geschieht völlig anders als der auf Daten im SRAM, nämlich über
spezielle Assembler-Befehle.
Ein einfacher Zeiger zeigt immer ins SRAM. Deshalb muss man, um an Daten
im Flash zu kommen, die speziellen Makros verwenden. Beim EEPROM sieht
das noch ganz anders aus, da dieses von der µC-Hardware nicht wie ein
Speicher behandelt wird, sondern wie eine Peripheriekomponente, weshalb
der Zugriff hier über I/O-Register geschieht.
> Ansich entscheidet doch das const für EEPROM oder Flash?const besagt zunächst nichts über den Speicherort, sondern besagt
nur, dass eine so deklarierte Variable eben konstant ist und vom
Programm nicht verändert werden kann/darf.
Karl heinz Buchegger wrote:
>> Ansich entscheidet doch das const für EEPROM oder Flash?>> Ist compilerabhängig. Beim AVR-gcc muss man mit geeigneten Mitteln> sicherstellen, dass Konstanten im Flash landen. Ansonsten landet *alles*> letztendlich im SRAM
Stimmt natürlich. Manche Compiler machen solche Sachen automatisch. Aber
zunächst hat const eben nur o.g. Bedeutung. Manche Compiler benutzen
spezielle Speicherklassenqualifizierer (CVAVR z.B. flash bzw.
eeprom). Die so deklarierten Daten sind dann ohne Makros verarbeitbar,
die korrekte Umsetzung erledigt der Compiler im Hintergrund.
BTW:
Welcome back!
Hey danke euch. Ich glaube ich verstehe sogar so langsam von was ihr
redet.
Aber nebenbei hab ich mal noch so ne Frage. Ich will meinen mC einfach n
paar mikrosekunden blockieren bevor er weiter macht. Nur warum
funktioniert das nicht:
1
for(uint16_ti=0;i<3000;i++);
Da kommt die Fehlermeldung:
../test.c:22: error: 'for' loop initial declaration used outside C99
mode
Variablendeklarationen in For-Schleifenköpfen waren in früheren
C-Standards noch nicht erlaubt, erst in C99. Mit der Option
-std=c99
aktivierst du den C99-Modus des Compilers, und die Fehlermeldung
verschwindet. Der Compiler nimmt es dann mit dem Standard aber sehr
genau und beanstandet das
1
asm("SLEEP");
das du nun durch ein
1
__asm("SLEEP");
ersetzen musst.
Deine For-Schleife ist allerdings nicht geeignet, um Wartezeiten ins
Programm einzufügen, da sie aus Sicht des Compilers keinen Effekt hat
und deswegen wegoptimiert wird. Speziell dafür vorgesehen sind aber die
Funktionen _delay_ms und _delay_us aus der der AVR-Libc:
http://www.nongnu.org/avr-libc/user-manual/group__util__delay.html
yalu wrote:
> Der Compiler nimmt es dann mit dem Standard aber sehr> genau und beanstandet das
[...]
Wenn man es etwas laxer haben möchte, kann man -std=gnu99 benutzen.
Die Voreinstellung entspricht -std=gnu89.
Ah ja super. Die "Delay.h" kenne ich sogar, ich wollte sich rauslassen
um Speicher zu Sparen (und weil ich nicht kapier was die macht), aber
jetzt stelle ich fest, dass sie weniger speicher braucht. Also gekauft^^
Danke.
Aber dank einigen Codeerweiterungen geht mir jetzt der Speicher im SRAM
aus. 64byte is halt wenig. jetz muss ich irgendwie ein struct erstellen.
Das GCC-Tutorial finde ich da ja schon ganz schön aber Speicherklassen (
so nennt man doch static und co oder?) lassen sich da nicht mehr
verwenden oder?
Ich dachte mir das so:
1
struct{
2
unsignedintcounter:4;
3
signedintsummand:2;
4
unsignedintoc_sel:1;
5
}byte0;
2 neue Fragen. Kann ich denen beim definieren schon einen wert
verpassen? also summand = 1 oder sowas?
Und 2. stimmts dass summand 2 Bit baraucht um 1 und -1 zu speichern?
Hans Wurst wrote:
> 2 neue Fragen. Kann ich denen beim definieren schon einen wert> verpassen? also summand = 1 oder sowas?
Ja.
> Und 2. stimmts dass summand 2 Bit baraucht um 1 und -1 zu speichern?
Ja. In GNU-C etwa so:
1
...byte0={.counter=1,...};
Ansonsten auch ohne die Felder zu nennen, dann aber die Reigenfolge
beachten!
Aber wenn es dir um Code geht ist es wohl günstiger, sowas zu machen:
>> 2 neue Fragen. Kann ich denen beim definieren schon einen wert>> verpassen? also summand = 1 oder sowas?>> Ja.>
Wie? etwa so?
1
struct{
2
unsignedintcounter:4=0;
3
signedintsummand:2=1;
4
unsignedintoc_sel:1=0;
5
}byte0;
1
...byte0={.counter=1,...};
So kann ich den Feldern nach dem definieren einen Wert zuweisen oder?
Aber ich wollte es ja beim definieren schon machen.
> Aber wenn es dir um Code geht ist es wohl günstiger, sowas zu machen:
> So kann ich den Feldern nach dem definieren einen Wert zuweisen oder?> Aber ich wollte es ja beim definieren schon machen.
Machst du doch. Komplett ausgeschrieben
1
struct{
2
unsignedintcounter:4;
3
signedintsummand:2;
4
unsignedintoc_sel:1;
5
}byte0={.counter=1,.summand=0,.oc_sel=0};
Das man hier die Strukturkomponenten benennen kann, ist eine GNU
Erweiterung (damit man nicht auf die Reihenfolge achten muss). In reinem
Standard-C ist die Reihenfolge ganz einfach die Deklarationsreihenfolge
Hans Wurst schrob:
>>> 2 neue Fragen. Kann ich denen beim definieren schon einen wert>>> verpassen? also summand = 1 oder sowas?>>>> Ja.>>> Wie? etwa so?
Waren oben wohl zu viele Pünktchen...
Ah eure antworten kombiniert und ich verstehe was gemeint ist. Sehr
cool. Danke!
die Pünktchen habe ich falsch interpretiert. Aber jetzt verstehe ich
das. Danke.
Und dann meintest du mit
> Aber wenn es dir um Code geht ist es wohl günstiger, sowas zu machen:
also, dass es den kürzeren Code gabe wenn ich counter auf diese weise
zählen lasse, anstatt meiner signed int.
Oder dass wenigstens nur 1 bit nicht 2 gespeichert werden müssen.
Das werde ich natürlich anwenden. Danke.
Wieder 2 Fragen sind aber noch offen.
1. Speicherklassen wie static und const lasen sich in structs nicht
verwenden richtig?
2. das struct muss ich (zumindest bei meiner Simulation von Studio 4)
ganz am Anfang global definieren.
schreibe ich
1
intmain(void){
2
...
3
}
4
ISR(TIM0_OVF_vect){
5
struct{
6
unsignedintcounter:4;
7
signedintsummand:2;
8
unsignedintoc_sel:1;
9
}byte0={0,1,0);
10
...
11
}
sind die Variablen irgendwie nicht schreib oder lesbar. Es gibt zwar
keine Fehlermeldung, aber das Programm arbeitet auch nicht.
Kann das stimmen?
PS: Die variablen werden auch NUR in der Interruptroutine gelesen und
geschreiben.
Eine Frage noch:
Hat es einen Grund, warum du deinem Programm die Bürde mit der
Bitpfriemelei innerhalb der Struktur aufhalst?
Du bist dir hoffentlich im klaren, dass die Bitextraktion aus der
Struktur
* mehr Code erfordert
* langsamer ist
Wenn du also die paar Bytes für 'normale' Variablen verschmerzen kannst,
fährst du mit einer nicht-bitgepfriemelten Struktur besser.
Hans Wurst wrote:
> Wieder 2 Fragen sind aber noch offen.> 1. Speicherklassen wie static und const lasen sich in structs nicht> verwenden richtig?
Da scheint ein Misverständnis vorzuliegen.
Mit einer struct Deklaration zeigst du dem Compiler einfach nur, wie ein
bestimmter, von dir gewünschter, Datentyp aussieht.
1
structMeinTyp
2
{
3
inta;
4
intb;
5
};
Das ist einfach nur die Deklaration, was gemeint ist, wenn eine Variable
vom Typ MeinTyp ist. Damit weiß der Compiler was gemeint ist, wenn du
dann tatsächlich eine Varaible davon anlegst
1
structMeinTypVariable1;
und ja. So wie bei jeder anderen Variablen kann die Variable static oder
const gemacht werden.
1
staticstructMeinTypVariable2;
2
conststructMeinTypVar3={2,3};
Was du hast, ist eine Kombination aus mehreren C-Dingen.
Zum einen kann gleichzeitig in der Deklaration einer Struct auch eine
Variablendefinition erfolgen
1
structMeinTyp
2
{
3
inta;
4
intb;
5
}Variable4;
und zum anderen kann dann in diesen Fällen due Struct als anonyme Struct
(also ohne Datentypnamen) ausgeführt werden.
1
struct
2
{
3
inta;
4
intb;
5
}Variable4;
Aber der springende Punkt ist immer noch:
Das eine ist eine Deklaration (also die Beschreibung wie etwas aussieht)
und das andere eine Definition (also das Erzeugen des tatsächlichen
'Objekts' anhand der Beschreibung.
Der Unterschied ist ungefähr so, wie der Unterschied zwischen Bauplan
und dem nach diesem Bauplan gebauten Haus. Es macht dann keinen Sinn,
wenn du fragst, wie du den Bauplan 'mit Farbe streichen kannst', denn in
Wirklichkeit willst du ja das tatsächliche Haus streichen und wenn
mehrere Häuser anhand desselben Plans gebaut werden, dann soll natürlich
jedes Haus seine eigene Farbe bekommen können
> sind die Variablen irgendwie nicht schreib oder lesbar. Es gibt zwar> keine Fehlermeldung, aber das Programm arbeitet auch nicht.> Kann das stimmen?
Nein, das kann nicht stimmen. Da ist dann noch was anderes faul
Karl heinz Buchegger wrote:
> Nein, das kann nicht stimmen. Da ist dann noch was anderes faul
Im Speziellen musst du dir darüber im klaren sein, dass funktionslokale
Variablen beim Betreten einer Funktion erzeugt und beim Verlassen einer
Funktion zerstört werden (es sei denn sie sind static)
Karl heinz Buchegger schrieb:
> Hat es einen Grund, warum du deinem Programm die Bürde mit der> Bitpfriemelei innerhalb der Struktur aufhalst?
In dem Post, wo er nach der Strukturinitialisierung fragte, schrieb er:
> Aber dank einigen Codeerweiterungen geht mir jetzt der Speicher im> SRAM aus. 64byte is halt wenig.
Programmspeicher hat er wohl noch übrig.
@Hans Wurst:
Nur solltest du, um den RAM-Verbrauch zu optimieren, die Elemente der
Struktur nicht als int sondern als char deklarieren, da nur dann die
gesamte Struktur tatsächlich nur 1 Byte belegt.
> 1. Speicherklassen wie static und const lasen sich in structs nicht> verwenden richtig?
Mit static kann nur die gesamte Strukturvariable deklariert werden, da
die Elemente einer Struktur immer als zusammenhängender Block
gespeichert werden.
const ist keine Speicherklasse, sondern ein Qualifier (auf deutsch
Qualifizierer?). Und Qualifier können auch auf einzelne Strukturelemente
angewendet werden.
> 2. das struct muss ich (zumindest bei meiner Simulation von Studio 4)> ganz am Anfang global definieren. schreibe ich> ...> sind die Variablen irgendwie nicht schreib oder lesbar. Es gibt zwar> keine Fehlermeldung, aber das Programm arbeitet auch nicht. Kann das> stimmen?
Ja, weil die Strukturvariable lokal, aber nicht static ist. Dadurch
geht ihr Inhalt zwischen zwei Interrupts möglicherweise verloren.
yalu wrote:
> Programmspeicher hat er wohl noch übrig.
Jo da hab ich noch 66% frei.
> Nur solltest du, um den RAM-Verbrauch zu optimieren, die Elemente der> Struktur nicht als int sondern als char deklarieren, da nur dann die> gesamte Struktur tatsächlich nur 1 Byte belegt.
Ich dachte die Zahl nach dem Doppelpunkt gibt die anzahl der Bytes an,
die die Variable bekommt?
damit wäre ja eigentlich (kommt mir erst jetzt) int oder char völlig
überflüssig, da dies eine widersprüchliche Doppeldefinition der Länge
ist.
>> 2. das struct muss ich (zumindest bei meiner Simulation von Studio 4)>> ganz am Anfang global definieren. schreibe ich>> ...>> sind die Variablen irgendwie nicht schreib oder lesbar. Es gibt zwar>> keine Fehlermeldung, aber das Programm arbeitet auch nicht. Kann das>> stimmen?>> Ja, weil die Strukturvariable lokal, aber nicht static ist. Dadurch> geht ihr Inhalt zwischen zwei Interrupts möglicherweise verloren.
Das könnte der fehler gewesen sein. Ich habs wie folgt gehabt.
1
intmain(void){
2
...
3
}
4
ISR(TIM0_OVF_vect){
5
struct{
6
staticunsignedintcounter:4;
7
staticsignedintsummand:2;
8
staticunsignedintoc_sel:1;
9
}byte0;
10
if(byte0.summand==0)byte0.summand=1;
11
...
12
}
Ziemlich doof. Hat mir auch nicht gefallen und niht funktioniert.
Hans Wurst wrote:
> Ich dachte die Zahl nach dem Doppelpunkt gibt die anzahl der Bytes an,> die die Variable bekommt?
Spätestens an dieser Stelle ist der Hinweis auf Literatur angebracht.
Eine Programmiersprache wie C, mit all ihren Feinheiten kann man nicht
nach dem Prinzip "Versuch und Irrtum" lernen.
Die Zahl gibt die Bits an!
Alles andere wäre ja auch unsinng. Aus dem Datentyp int, char, long weiß
der Compiler ja sowieso wieviele Bytes das haben soll.
>> Ich dachte die Zahl nach dem Doppelpunkt gibt die anzahl der Bytes an,>> die die Variable bekommt?> ...> Die Zahl gibt die Bits an!> ...
Ich meinte ja statt Byte Bit. Habs nur grad verdreht. Sorry.
Aber wo soll denn das char hin, dass alles in einem Byte bleibt?
vor jeder Variable macht ja keinen Sinn, dann sag ich ja ne variable mit
8 bit die in einem bit gespeichert wird... irgendwie widersprüchlich.
Ich sagte schon: LIteratur!
Der Compiler versucht dann alle Bitanforderungen in dem angegebenen
Datentyp unterzubringen
struct Test
{
unsigned char a : 4;
unsigned char b : 4;
};
a und b teilen sich ein Byte (weil: unsigned char)
a bekommt davon 4 Bits und b bekommt 4 Bits
struct Test
{
unsigned char a : 4;
unsigned char b : 4;
unsigned char c : 3;
};
Hier muss der Compiler 2 Bytes benutzen.
a und b passen gemeinsam in ein Byte und für C muss ein weiteres Byte
angefangen werden, aus dem aber nur 3 Bits benutzt werden.