Hallo, ich habe wieder mal ein kleineres Problem mit meinem MSP430.
Es ist ein MSP430F1612.
Softwareumgebung: IAR Workbench 3.21A
Hochsprache: C
Ich habe eine Uhrzeit eingebaut, mit den Bibliotheken von TI.
Das geht auch soweit ganz gut. Die eine Sekunde Abweichung alle zwei
Tage sind verkraftbar!
Für die Uhrzeit nehme ich Timer_A
Die TA_ISR ist hier zu sehen:
Ich habe nur das "RSEG INTVEC" durch das "COMMON INTVEC" ersetzt, weil
jemand mir vor einer Weile hier im Forum sagte, man müsse das so machen.
Ich habe in meinem Programm noch den Timer_B in Benutzung. Weil ich mich
mit Assambler gar nicht auskenne habe ich mir halt nen anderen Timer
initialisiert und eine eigene ISR geschrieben.
Der Timer_B soll alle 125ms einen "SystemTick" erzeugen.
Dieser dient als Basis für meine Messungen.
Hier erstmal die Initialisierung und dann die ISR des Timer_B:
1
// ZEITBASIS wird woanders als 32768/8 definiert...
2
// er soll also bis 125ms zählen...
3
TBCCTL0=CCIE;// CCR0 interrupt enabled
4
TBCCR0=ZEITBASIS;// wert in owndef, zaehl-zeit bis interrupt
Ich habe dann eine Routine im Programm, die alle 125ms durchlaufen wird.
Dann eine, die alle Sekunde durchlaufen wird. Und darauf aufbauend dann
halt für 5s, 10s...usw.
In diesen Routinen werden Zähler erhöht, damit man nach der jeweiligen
Zeit in die nächste Routine "rutscht".
Das Problem ist jetzt, dass EINE Minute nicht eine Minute ist, sondern
schon 2 Sekunden länger dauert! Das ist schlecht, weil ich Messwerte
über mehrere Stunden brauche. Und der Fehler setzt sich ja fort und wird
immer größer!
Ich protokolliere die Messwerte, und wenn nach einer "realen" halben
Stunde die halbe Stunde vom Timer_B schon lange erreicht ist, dann
bekomme ich keine, oder falsche Messwerte.
Ich denke, es hat irgendwas mit der Initialisierung des Timers zu tun?
Könnte ich die ISR für den Timer_A so abändern, dass ich keinen zweiten
Timer brauche?
Das Dumme ist halt, dass ich einmal den Sekunden-Takt für die Uhr und
den 125ms-Tackt für die Messungen brauche.
Hier aber wieder das Problem, dass ich Assembler so rein gar nicht kann.
Aber theoretisch muss man doch nur alle 125 nen Tick erzeugen. Und wenn
halt 8 Ticks vorbei sind, dann soll die Funktion increment_second()
aufgerufen werden für die Uhrzeit.
Sieht jemand einen offensichtilichen Fehler in meiner Inititialisierung?
Falls ich irgendwas schlecht ausgedrückt habe, dann sagts mal an. Ich
kann auch weitere Ausführungen machen, aber dann müsste man etwas weiter
ausholen.
Es wäre super, wenn mir jemand helfen könnte!
danke
>weil jemand mir vor einer Weile hier im Forum sagte,>man müsse das so machen
Jo, das war ich :-)
Wenn ZEITBASIS als 32768/8 definiert ist, warum rechnest Du dann in der
ISR nochmal 32768/ZEITBASIS? Das ist doch einfach 8 !
Zweitens, warum zählst Du in der TB ISR dieses Tick auf 8 hoch?
8*125ms = 1s, schon klar. Aber die 1s kriegst Du doch schon von TA ???
Also entweder steh' ich auf'm Schlauch... aber erklär mal bitte genauer,
welcher Timer jetzt ein Problem macht und wo und wann diese ominösen 2s
auftauchen.
Warum benutzt du nicht das TBCCR-Register, da kannst du im Upmode bis
32767 zählen lassen und dann springt der Zähler automatisch auf Null. Da
kannst du dann entweder beim CCR = TAR einen Int auslösen lassen,
oder beim Überlauf, beide kommen dann im richtigen Takt. Da musst du
nix selber gucken und auf Null setzen.
Gut, die Berechnung von 32768/ZEITBASIS kann ich mir natürlich
sparen...hast recht!
Ich brauche alle 125ms einen Tick, damit dann eine Messung per ADC12
durchgeführt wird.
Und ich habe halt in der Routine, die alle 125ms aufgerufen wird nen
Zähler drin, der hochzählt, um dann irgendwann in die 1s-routine zu
kommen...
Am besten, ich zeig mal nen Code-Schnipsel:
1
// routine zu jedem tick
2
if(Tick!=tnext)
3
{
4
tnext=Tick;
5
6
//dann adc12 wandlung...
7
//berechnungen...
8
//aufsummieren der werte
9
10
t1next++;
11
teiler_1s=t1next;
12
}
13
14
// routine für 1s
15
if(t1next==8)
16
{
17
//berechnungen...(aufsummierte werte / teiler_1s)
18
19
teiler_5s=teiler_5s+teiler_1s;
20
t5next++;
21
}
22
23
//...dann die routinen für 5s usw...bis 30min
Beim allerersten Durchlauf werden die routinen NICHT durchlaufen,
weil Tick = tnext = 0.
Danach sind sie IMMER unterschiedlich...
Jetzt zum Problem:
Die Uhrzeit mit Timer_A läuft wunderbar!
Ich lasse die Werte für 1s und für 1min auf dem Display anzeigen...
und wenn ich jetzt ne Uhr danebenstelle, dann müsste doch theoretisch
der 1min-Wert alle MINUTE neu aktualisiert werden...
Und genau DAS macht er eben nicht.
Bsp.:
Ich hab nen Wert von 400 für die letzte Minute. Nach einer Minute sollte
sich dieser Wert auf dem Display verändert haben. Er ändert sich aber
erst nach 1min 2s (so ungefähr...) und entsprechende kommen die
30min-Werte auch verzögert an...
@ Christian R. : Ich versteh nicht ganz, was Du meinst. Kannst mir das
mal bitte
etwas genauer erklären...
Also nochmal zusammenfassend:
Ich brauche einen Interrupt alle 125ms, damit dann jeweils eine Messung
per ADC12 durchgeführt wird.
Weiterhin brauche ich einen Sekundentakt für die Uhrzeit.
Ob ich jetzt den Sekundentakt für meine Berechnungsroutinen (halt 8* die
125ms Routine) aus dem Timer_b hole, oder aus dem Timer_a dürfte doch
egal sein, oder?
danke
>Ich brauche alle 125ms einen Tick, damit dann eine Messung per ADC12>durchgeführt wird.
Gut... hast Du mit Timer_B aufgebaut. ISR alle 125ms, in der ISR den ADC
triggern... fertig!
>Und ich habe halt in der Routine, die alle 125ms aufgerufen wird nen>Zähler drin, der hochzählt, um dann irgendwann in die 1s-routine zu>kommen...
Wozu? Ich denke Du hast dafür dem Timer A, der doch anscheinend richtig
funktioniert!
Mathias U. wrote:
> @ Christian R. : Ich versteh nicht ganz, was Du meinst. Kannst mir das> mal bitte> etwas genauer erklären...
Ahso, ich nehm alles zurück. Hab nochma genau durchgelesen, und gesehn,
dass du es ja schon machst. Ich denke der Fehler liegt in der Definition
von ZEITBASIS. Da hast du 1 zuviel. Es kommt ja bei deiner Rechnung 4096
raus, in den CCR muss aber 4095, damit du alle 4096 Takte einen Int
bekommst. Schließlich braucht´s noch einen Takt, um den Timer wieder auf
0 zu setzen, der springt ja nicht von 4096 auf 1.
Also setze mal ZEITBASIS auf 32768/8 -1 also 4095, dann sollte es
klappen.
Gut, ich würde das jetzt also so machen:
Die ISR für Timer_B so lassen...
Die Routine für alle 125ms bleibt auch so, nur dass ich halt nicht
hochzähle für die 1s usw. -Routinen...
Ich würde jetzt gerne meine globale Variable "t1next" in der ISR für
Timer_A auf 1 setzen wollen...
Dann würde jede Sekunde diese Variable auf 1 stehen, und ich könnte sie
dann in meinen Routinen abfragen...
In der Routine für 1s würde dann am Schluss die Variable wieder auf Null
gesetzt, also zurückgesetzt...
Dann käme jetzt der Sekundentakt vom Timer_A und nicht über den Umweg
Timer_B, obwohl das ja auch gehen müsste...
Nur wie mach ich das? Ich kenn mich halt mit Assembler nicht aus? Da
muss doch dann noch meine my_globals.h eingebunden werden, sonst kennt
der die Variable t1next ja nicht...
WAS muss ich WO reinschreiben?
Kannst mir das bitte kurz schreiben?
Danke
*edit: @ Christian R. : das probier ich als erstes gleich mal aus...
Dann müsste ich meine ISR für Timer_b auch so abändern???
@Christian:
Das bezweifle ich. Korrigiere mich bitte, wenn ich falsch liege:
Bei ZEITBASIS = 4095 kommt der IRQ alle 4096 Takte (4095 + 1 Takt zum
Nullsetzen des Timers)
Wenn ZEITBASIS = 4096 ist, dann kommt der IRQ also alle 4097 Takte. Bei
32768kHz wären das 125,0305176ms (anstatt 125,0ms). Hochgerechnet auf
eine Minute ergibt sich also 125,0305176ms x 8 x 60 = 60,015s.
Also gerade mal 15ms zuviel. Fehlen also immer noch 1,985s, die irgendwo
verbraten werden!
@ Stefan (Gast)
>Also gerade mal 15ms zuviel. Fehlen also immer noch 1,985s, die irgendwo>verbraten werden!
Hab dein Programm jetzt nicht angeschaut. Kann es ein, dass
Timer-Interrupts verschluckt werden, weil andere Interrupts (oder der
Interrupt selber!) länger als 125ms dauern?
MFG
Falk
Also ichhabe jetzt mal ((ZEITBASIS/8)-1) geändert --> bringt rein gar
nichts!
Schade!
Jetzt nochmal zu der Sache, wie ich meine t1next in der ISR von Timer_A
setzen kann: Wie macht man das in Assembler?
@Falk Brunner: also ich sag mal, dass die ISR zu lange dauern, kann ich
mir eigentlich nicht vorstellen...da wird ja fast nichst drin gemacht!
In der ISR von Timer_A wird nur die funktion increment_seconds()
aufgerufen, die von der Uhrzeit aus der Ti-Biblio.
Und in meiner eigenen wird auch nur eine Variable gesetzt...
Am allerschicksten wäre es natürlich, wenn ich es irgendwie hinbekäme,
dass ich meine ISR für den Timer_A so umschreibe, dass sie alle 125ms
nen Tick erzeugt und nach 8 Ticks (also 1s) die Funktion zum erhöhen der
Sekunden aufruft. Damit wären zwei Fliegen mit einer Klappe geschlagen!
Dann könnten meine Routinen für die Berechnungen für 1s, und die
weiteren so bleiben... und ich spare mir die verwendung eines zweiten
timers.
Kann mir einer erklären, wie ich das machen könnte? (Das Problem ist die
Assembler-programmierung...)
danke
Probier mal, ob die Geschichte genauer wird, wenn du für den Timer B
auch den Cont-Mode nimmst und in der ISR einfach immer 4096 dann auf das
TBCCR0 drauf addierst.
Ansosten kannste dir doch das stück TI-Asm auch in C schreiben, da is ja
keine Hexerei dabei, die ISR von oben bekommt jeder Compiler genauso
hin.
Für sowas gibts bei TI nen Dokument: Mixing C and Assembler.
Aber die 2 Sek sind schon bissl viel, sehr seltsam.
@ Mathias U. (munter)
>Am allerschicksten wäre es natürlich, wenn ich es irgendwie hinbekäme,>dass ich meine ISR für den Timer_A so umschreibe, dass sie alle 125ms>nen Tick erzeugt und nach 8 Ticks (also 1s) die Funktion zum erhöhen der>Sekunden aufruft. Damit wären zwei Fliegen mit einer Klappe geschlagen!>Dann könnten meine Routinen für die Berechnungen für 1s, und die>weiteren so bleiben... und ich spare mir die verwendung eines zweiten>timers.
???
Sollte man das nicht sowieso so machen? Wo ist das Problem?
>Kann mir einer erklären, wie ich das machen könnte? (Das Problem ist die>Assembler-programmierung...)
Warum nicht C? Du hast doch dort oben C-Fragmente drin?.
Mach einen Timer, der nach 125ms tickt. die brühmten 4096 Takte, mit
4095 als TBCCR0 Wert. Dort wird eine Variable hochgezählt. Ist sie 8,
wird sie auf 0 zurückgesetzt und gleichzeitig die Routine für die 1s
Aktion ausgeführt. Besser ist es allerdings, ein Flag zu setzten,
welches in der Hauptschleife erkannt wird und die entsprechende Routine
aufruft. Dann werden die Interrupts nicht so lange blockiert.
MFG
Falk
Hallo Falk, so wie Du das so schreibst, klingt das total einfach.
Aber es ist leider nicht ganz so einfach für mich, da Assembler ein Buch
mit min. 7 Siegeln für mich ist...
>Wo ist das Problem?
Die RTC_TA.s43 von TI:
incrementSeconds();// die funktion liegt in assembler vor in der RTC_Calendar.s43 von TI
10
// kann man die funktion einfach so aufrufen?
11
}
12
}
Ich kann mir nicht vorstellen, dass DAS reichen soll und kann! In der
ISR oben steht ja noch mehr drin!
*ich glaub ich stell mich grad dämlicher an, als nötig...
>*ich glaub ich stell mich grad dämlicher an, als nötig...
Jepp :-)
>In der ISR oben steht ja noch mehr drin!
TAIV Register auslesen, entfällt, da CCR0-IRQ (und nicht CCR1/2 oder
TMRA). Und das Addieren von 32768 auf CCR1 kannst Du Dir auch sparen,
weil die Timerperiode von CCR0 vorgegeben wird!
"reti" macht Dein Compiler für Dich.
Passt schon!
Nur:
>TACTL= TASSEL_1 + MC_2;
MC_1 ist besser. Du willst ja, dass der Timer nur bis CCR0 zählt und
dann wieder von 0 anfängt!
@ Mathias U. (munter)
>Hallo Falk, so wie Du das so schreibst, klingt das total einfach.>Aber es ist leider nicht ganz so einfach für mich, da Assembler ein Buch>mit min. 7 Siegeln für mich ist...
Warum programmierst du dann in Assembler? C ist hier vollkommen OK und
genauso schnell.
>Wo ist das Problem?>Ich kann mir nicht vorstellen, dass DAS reichen soll und kann! In der
Warum nicht? Es wird alles gemacht, was zu tun ist? Ob man die Funktion
so aufrufen kann weiss ich nicht, dazu kenn ich mich zu wenig mit ASM/C
Mix auf dem Compiler aus.
>ISR oben steht ja noch mehr drin!
Nöö. Lies mal die Kommentare.
> tst.w &TAIV ; read clears flag
Macht AFAIK der C-Compiler für dich
> call #incrementSeconds ; tick one second
Normaler Funktionsaufruf, wie in C
> add.w #32768, &CCR1
Comparewert um 32768 Takte erhöhen = 1 Sekunde.
> reti ;
Feierabend
>*ich glaub ich stell mich grad dämlicher an, als nötig...
Maybe. ;-)
MfG
Falk
Und wieso willst du unbedingt von CCR1 auf CCR0 wechseln? Probier doch
erst mal, den Code für die ISR rein von ASM in C zu portieren. Das TAIV
musst du abfragen, macht der Compiler nicht.
Wenn da geht, sehen wir weiter. Nicht immer 2 Schritte auf einmal
versuchen ;)
Ich das mal so getestet, wie oben angegeben probiert, aber es geht
trotzdem nicht wie gewünscht!
Die Uhrzeit läuft, soweit ich das bis jetzt sagen kann, recht genau,
aber die Messroutinen dauern länger, als sie eigentlich sollten!
D.h. z.b. die Messroutine für 1min wird nach ca. 1min 2s wiederholt.
Das die Uhrzeit geht ist für mich auch logisch, weil in der ISR die
Funktion zu erhöhen der Sekunden drin steht! Die hat also eine ziemlich
hohe Priorität.
@ Christian R. : Ich hatte es auch mal mit CCR1 und CCTL1 probiert, aber
da fängt die Uhrzeit gar nicht an zu laufen...
Wo muss ich den TAIV abfragen? Und was mach ich dann damit?
danke
@ Mathias U. (munter)
>aber die Messroutinen dauern länger, als sie eigentlich sollten!>D.h. z.b. die Messroutine für 1min wird nach ca. 1min 2s wiederholt.
Das ist ein Widerspruch. Das eine ist die Länge der Routine, das
andere die Wiederholzeit. Was macht die Routine denn? Wie lange dauert
das?
Poste mal vollständigen Quelltext. Als Anhang.
>Wo muss ich den TAIV abfragen? Und was mach ich dann damit?
Um das Flag zu löschen. Kommentare und das Datenblatt sollte mans chon
ab und zu mal lesen, egal wie fir man in Assembler ist . . .
MFG
Falk
Oh Mist, jetzt muss ich wohl die Hosen runter lassen...
Ich hab Dir mal das ganze Projekt gepackt drangehangen.
--> VORSICHT! Die main() ist seeehr lang!
--> Ich weiß, dass da so einiges nicht ganz optimal ist und schön ist
der Code schon gar nicht!
--> IAR Workbench 3.21A
In den einzelnen Messroutinen werden berechnungen gemacht, die lange
dauern könnten (log10...). Ich tippe daruaf, dass er da irgendwie aus
dem Tackt kommt.
@Falk: Ich finds großartig, dass Du den Leuten hier so hilfts!
Lese viel mit, und Dein Name taucht oft auf! THUMBS UP!!!
Du musst den TAIV Vektor abfragen, weil sich da mehrere Ereignisse des
Timer A einen Interrupt-Vektor teilen.
Was hindert dich, die Beispiele von TI mal anzugucken?
>VORSICHT! Die main() ist seeehr lang!
wohl war!
Vielleicht hab ich's genau deshalb übersehen...?
Wo ist die Init für die Basic clock settings?
Ohne Änderungen 'dümpelt' der MSP mit ca. 800kHz vor sich hin.
Stell doch mal Deinen DCO auf Maximum (weiß jetzt nicht Auswendig, was
der F1612 kann). Ich denke nämlich auch, dass Du ein Zeitproblem in
Deinen unendlichen Funktionen hast, und gar nicht vor dem nächsten IRQ
damit fertig wirst!
Sooooooo.
Naja, auch wenn du dich schon in Vorfeld entschuldigt hast.
- Schon mal was von Funktionen gehört? Macht den Code WESENTLICH
lesbarer und wartbarer. Also bitte mal die einzelnen Funktionen für die
einzelnen Messungen/Blöcke auslagern.
- Deine wait Funktion sieht komisch aus. Das _NOP()) soll doch
garantiert IN die for Schleife, oder?
- Warum schreibst du die ISR wieder falsch hin?
1
// timer_a interrupt service routine
2
#pragma vector=TIMERA0_VECTOR
3
__interruptvoidTimer_A(void)
4
{
5
if(Tick==8){Tick=0;incrementSeconds();}
6
elseTick=Tick+1;
7
}
Damit wird dein incrementSeconds() alle NEUN Ticks aufgerufen!
0,1,2,3,4,5,6,7,8,0,1, !
Einfach so
1
// timer_a interrupt service routine
2
#pragma vector=TIMERA0_VECTOR
3
__interruptvoidTimer_A(void)
4
5
{
6
if(Tick==7){
7
Tick=0;
8
incrementSeconds();
9
}
10
elseTick++;
11
}
Formatierung ist WICHTIG! Durchblick!
- Wie lange dauert incrementSeconds() ? Wenn es länger als 125ms dauert
verlierst du Interrupts und deine Zeitbasis ist im Eimer.
- Eigene Datentypen definieren ist schlecht bis sinnlos. Nutze stdint
mit uint8_t etc. Ist genormt, getestet und portabel.
Also, um die Sache mal in trockene Tücher zu bringen ohne nur an
Symtomen rumzudoktern, mein Vorschlag.
- Bring sämliche Blöcke, die du schön über if(tnexte) etc. anspringst in
eigene Funktionen, die dann in der main-Endlosschleife aufgerufen
werden. Vor allem den Monster-SWITCH!
- Die Main-Hauptschliefe sollte dann auf 1-2 Seiten locker passen,
bestehend aus wenigen IFs und vielen Funktionsaufrufen.
- loesche_buffer wird sinnloserweise zweimal aufgerufen. Wahrscheinlich
ist sie sowieso überflüssig, weil ja der Buffer immer mit neuen Daten
überschrieben wird.
- Die Funktionen thematisch geordnet in Dateien auslagern. Nicht alles
in eine main.c!
- Deine Zeit-und Ablaufsteuerung scheint mir nicht ganz koscher. Z.B.
auf t1next machst du sieben! Schreibzugriffe in den unterschiedlichen
Blöcken. Ich behaupte mal, dass sich da irgendwas verhaspelt. Es darf
nur EINEN Schreibzugriff zum setzen und EINEN Schreibzugriff zum
Löschen geben, weil das ja über die Interrupts läuft.
Etwa so
1
while(1){// Endlose Main-Schleife
2
3
if(tnext){// hier eine Fehlerausgabe rein, z.B. Port auf HIGH setzen
4
// Wenn tnext schon aktiv ist, dann ist die Main-Schleife zu langsam
5
}
6
7
while(!tnext);// warte auf nächsten 125ms Tick
8
9
tnext=0;
10
// alle 125 ms Funktion hier
11
12
if(t1next){
13
t1next=0;
14
// alle 1s Funktion hier
15
}
16
17
// etc.
18
}
- Dann kannst du wunderbar deine kleine main-Schleife strukturieren, und
jeder (auch DU) sieht sofort, welche Funktionen alle 125ms, alle 1s und
alle 5s etc. aufgerufen werden.
- Deine Zeitsteurung ist wie bereits gesagt ziemlich verquer. Mach es
so.
1
// timer_a interrupt service routine
2
#pragma vector=TIMERA0_VECTOR
3
__interruptvoidTimer_A(void)
4
5
{
6
staticuint8_tcnt_sec=0;
7
staticuint8_tcnt_5sec=0;
8
staticuint8_tcnt_20sec=0;
9
staticuint8_tcnt_30sec=0;
10
staticuint8_tcnt_40sec=0;
11
staticuint8_tcnt_50sec=0;
12
staticuint8_tcnt_1m=0;
13
staticuint8_tcnt_30m=0;
14
15
tnext=1;// 1/8 Sekunde, Timerperiode
16
if(Tick==7){// eine Sekunde
17
Tick=0;
18
t1next=1;
19
incrementSeconds();
20
cnt_sec++;
21
if(cnt_sec==5){// fünf Sekunden
22
cnt_sec=0;
23
t5next=1;
24
cnt_5sec++;
25
if(cnt_5sec==2){// zehn Sekunden
26
cnt_5sec=0;
27
t10next=1;
28
cnt_20sec++;
29
cnt_30sec++;
30
cnt_40sec++;
31
cnt_50sec++;
32
cnt_1m++;
33
cnt_30m++;
34
35
if(cnt_20sec==2){// zwanzig Sekunden
36
cnt_20sec=0;
37
t20next=1;
38
}
39
if(cnt_30sec==3){// dreissig Sekunden
40
cnt_30sec=0;
41
t30next=1;
42
}
43
if(cnt_40sec==4){// vierzig Sekunden
44
cnt_40sec=0;
45
t40next=1;
46
}
47
if(cnt_50sec==5){// fünfzig Sekunden
48
cnt_50sec=0;
49
t50next=1;
50
}
51
if(cnt_1m==6){// 1 Minute
52
cnt_1m=0;
53
t1mnext=1;
54
}
55
if(cnt_30m==180){// Dreissig Minuten
56
cnt_30m=0;
57
t30mnext=1;
58
}
59
}
60
}
61
62
}
63
elseTick++;
64
}
- Da in vielen Funktionen recht viel Mathematik drinsteckt, musst du
prüfen, wie lange die jeweiligen Funktionen dauern. Dazu setzt du vor
dem Funktionsaufruf ein Portpin auf HIGH und direkt danach auf LOW. Das
kann man wunderbar mit dem Oszi messen. Denn deine 125ms Funktionen
dürfen zusammen nicht mehr als 125ms verbrauchen! Das Gleiche gilt für
die 1s und 5s Funktionen, denn sonst werden Ticks verpennt bzw. zu spät
aufgerufen! Sprich, deine Main-Schleife darf worst Case max. 125ms
dauern! Ein kleiner Check ist oben im Beispiel schon eingebaut.
Bring erstmal Ordnung in deinen Code und poste nochmal. Dann sehen wir
weiter.
MFG
Falk
Guten Morgen.
*edit: problem hat sich von selbst gelöst...
@Falk: Deine Kritik ist völlig berechtigt! Aber ich komme nicht von der
Programmierschiene, bin also noch im Lernprozess ;-)
Ich werde aber, sovile wie möglich von Deinen Hinweisen versuchen
einzuarbeiten. Danke
MFG
mathias
Also der Hinweis mit den stdint-Typen ist zwar in Ordnung.
Meines Erachtens ist aber die Definition von BYTE, WORD, ... jetzt auch
nicht sooooo schlimm!
Die stdint.h steht in der DLIB, das bedeutet, dass Du Dein Projekt in
IAR von C auf C++ umstellen musst. Das jetzt aber nur wegen den
Typdefinitionen zu tun, halte ich für übertrieben!
Was ist nun eigentlich mit der Taktrate?
Den DCO mal hochgeschraubt?
Nee, ich ahtte ein riesiges Prob mit der Einbindung der stdint.h...
Das ging nicht so richtig.
Jetzt hab ich die <inttypes.h> eingebunden, und die Datentypen kann ich
jetzt so nehmen, wie Du angegeben hast, Falk. Also uint8_t usw..
@ Stefan: Ich hab echt ne ganze Weile rumprobiert, aber irgendwie hatte
ich immer nen Fehler mit der stdint.h...hatte auch mal DLIB eingestellt,
da hat er mir dann andere Fehler gebracht...
Jetzt werd ich mal schauen, wie ich den DCO hochsetze. Wo kann man das
machen? Ich hab da noch nichst verändert. Evtl. reicht das ja schon.
*hoffe. Ansonsten werde ich dann Falks Vorschlag folgen und meinen Code
erstmal *übersichtlicher machen...
danke
>und meinen Code erstmal *übersichtlicher machen...
Das solltest Du so oder so tun!
>hatte auch mal DLIB eingestellt,>da hat er mir dann andere Fehler gebracht...
Naja, wie ich schon sagte: Nur wegen Datentypen auf C++ zu wechseln
macht keinen Sinn! Ausserdem sind Typdefinitionen wie BYTE, WORD, DWORD
nicht falsch! Wer z.B. aus der Visual Studio Ecke kommt, kennt diese
Typen auch.
>Jetzt werd ich mal schauen, wie ich den DCO hochsetze.
User Guide -> Basic Clock Module (Register: DCOCTL, BCSCTL1, BCDCTL2)
@ Mathias U. (munter)
>Jetzt werd ich mal schauen, wie ich den DCO hochsetze. Wo kann man das>machen?
In mcuinit(). Gibst in den TI-Codebeispielen.
> Ich hab da noch nichst verändert. Evtl. reicht das ja schon.>*hoffe.
Naja, beiss mal lieber ind e "sauren Apfel" und bring dein Code in
Ordnung. Hat viele Vorteile:
- Du lernst was
- Du hast WIRKLICh Überblick über deine Main-Schleife
- Dein Program wird sicherer
und praktisch keine Nachteile:
- dauert halt ein paar Stündchen.
Die Zeit ist sehr gut investiert.
MFG
Falk
Diese ganzen Register sind echt recht tricky...
Da ich ja an XT2 keinen Quarz dran habe, kann ich die Quelle ja auch
ausschalten, oder?
Ich habe nur an XT1 den 32kHz Quarz dran.
Wenn ich jetzt im DCOCTL DCOx auf 111, also 7 setzen, und im BCSCTL1
RSELx auch auf 111 setzen, dann müsste doch der DCO mit der max.
möglichen Frequenz laufen, oder? Laut User-Guide Seite 4-7 müssten das
dann ca. 8MHz sein.
Aber im Datenblatt zum F1612 steht auf Seite 36 für
RSEL = 7, DCO = 7, MOD = 0 und DCOR = 0; bei 3V knapp 5MHz.
Ja, was denn nun?
Meint Ihr, dass könnte SO gehen?
Vcc ist bei mir übrigens 3,3V.
1
DCOCTL=DCO0+DCO1+DCO2;// Max DCO
2
BCSCTL1=XT2OFF+RSEL0+RSEL1+RSEL2;// XT2off, max RSEL
In einem Code-Bsp. haben sie noch
1
BCSCTL2|=SELS;// SMCLK = XT2
gemacht, aber da ich ja XT2 nicht benutze, brauch ich das doch nicht,
oder?
>Wenn ich jetzt im DCOCTL DCOx auf 111, also 7 setzen, und im BCSCTL1>RSELx auch auf 111 setzen, dann müsste doch der DCO mit der max.>möglichen Frequenz laufen, oder? Laut User-Guide Seite 4-7 müssten das>dann ca. 8MHz sein.
max. Frequenz: JA
8MHz: NEIN, es sind max 5,4MHz (s. Datenblatt)
Der F1612 kann mit max. 8MHz betrieben werden, die müssen dann aber von
einem externen Quarz oder Clock kommen. Der DCO kann in dem Fall nur die
5,4MHz
>Meint Ihr, dass könnte SO gehen?>Vcc ist bei mir übrigens 3,3V.
1
>DCOCTL=DCO0+DCO1+DCO2;// Max DCO
2
>BCSCTL1=XT2OFF+RSEL0+RSEL1+RSEL2;// XT2off, max RSEL
Ja, genau so!
>In einem Code-Bsp. haben sie noch
1
>BCSCTL2|=SELS;// SMCLK = XT2
Solltest Du in Deinem Fall auch nicht machen, da sonst SMCLK nicht
getaktet wird, da ja kein XT2-Clock vorhanden ist.
@Christian:
Jetzt immer langsam... ;-)
Er hat (vermutlich) ein Zeitproblem. Deshalb sollte er den max. DCO-Takt
verwenden, um seine Berechnungen schneller durchzuführen. Das hat er
gemacht (einfach, übersichtlich, schnell)
Aber er braucht keine Synchronisation des DCO auf den Uhrenquarz!
Stefan wrote:
> @Christian:> Jetzt immer langsam... ;-)
hehe...überfordert mich mal nicht. Immer langsam mit den Anfängern...
*edit: übrigens läuft jetzt meine "mess-minute" auch in etwa wie meine
"reale" minute...
Werde jetzt mal Tests durchführen, aber der Tipp mit dem DCO hat erstmal
weitergeholfen...
(Den Code werde ich aber trotzdem noch übersichtlicher machen...;
jedenfalls nen bissl)
@ Mathias U. (munter)
>Da ich ja an XT2 keinen Quarz dran habe, kann ich die Quelle ja auch>ausschalten, oder?
Ja.
>möglichen Frequenz laufen, oder? Laut User-Guide Seite 4-7 müssten das>dann ca. 8MHz sein.
Kann sein.
>Ja, was denn nun?
???
>In einem Code-Bsp. haben sie noch>BCSCTL2 |= SELS; // SMCLK = XT2>gemacht, aber da ich ja XT2 nicht benutze, brauch ich das doch nicht,>oder?
Nein. Dann ist ja dein SMCLK tot. Stell den auf DCO. Bzw. Lass es wie es
ist.
"After a PUC, MCLK and SMCLK are sourced from DCOCLK at ~800 kHz (see
device-specific datasheet for parameters) and ACLK is sourced from LFXT1
in LF mode."
Das willst du ja und hast du schon. Du must nur den DCO hochtakten,
fertig.
Ich sag mal, Rsel=7 und DCO=4.
MFG
Falk
@ Mathias U. (munter)
>(Den Code werde ich aber trotzdem noch übersichtlicher machen...;>jedenfalls nen bissl)
Kein halben Sachen! Ein Benzintank der zu 99% dicht ist ist auch
unbrauchbar!
MFG
Falk
Hehe, DCO-Max geht natürlich auch, aber spätestens, wenn man eine UART
bedienen will, ist das ungünstig. Weiß ja nicht, was er mit seinen
Messwerten da anstellt.
Ich würd ma sagen, du misst mal mit dem Oszilloskop nach, wie lange
deine Routinen dauern. Einfach am Anfang einen Pin setzen und am Ende
zurück setzen. Nur so kommst du dem Übeltäter auf die Schliche.
Wie siehts mit der Optimierung aus? Steht die auf höchster Stufe?
>In einem Code-Bsp. haben sie noch>BCSCTL2 |= SELS; // SMCLK = XT2>gemacht, aber da ich ja XT2 nicht benutze, brauch ich das doch nicht, oder?>Nein. Dann ist ja dein SMCLK tot. Stell den auf DCO. Bzw. Lass es wie es >ist.
Du meinst JA, ich brauche diese Zeile nicht?!
Ich hab jetzt nur
1
DCOCTL=DCO0+DCO1+DCO2;// Max DCO
2
BCSCTL1=XT2OFF+RSEL0+RSEL1+RSEL2;// XT2off, max RSEL
@ Mathias U. (munter)
>Du meinst JA, ich brauche diese Zeile nicht?!
Ja, diese Zeile ist für dich Gift.
>DCOCTL = DCO0 + DCO1 + DCO2; // Max DCO>BCSCTL1 = XT2OFF + RSEL0 + RSEL1 + RSEL2; // XT2off, max RSEL
KDF? Würde ich nicht machen. Es gibt Berichte, nachdem für maximalen
Takt der Controller mit 3.6V betrieben werden muss. Mach mal lieber
DCOCTL = DCO2; // DCO=4
BCSCTL1 = XT2OFF + RSEL0 + RSEL1 + RSEL2; // XT2off, RSEL=7
Das reicht locker.
MfG
Falk
Falk Brunner wrote:
> @ Mathias U. (munter)> KDF? Würde ich nicht machen. Es gibt Berichte, nachdem für maximalen> Takt der Controller mit 3.6V betrieben werden muss. Mach mal lieber
Der maximale DCO-Takt (mit internem R) ist nicht der maximale
CPU-Takt. Die CPU kann maximal 8MHz, da muss aber dann 3,6V sein,
externer Quarz oder der DCO mit dem externen R. Der DCO mit internem
Widerstand macht bei maximal-Einstellung etwa 5,4MHz. Bis 7,3MHz geht
mit 3,3V laut Diagramm im Datenblatt.
P.S. Leider funktioniert der MSP430F1611 nicht zuverlässig mit 7,3728MHz
Baudratenquarz und 3,3V.
P.P.S.: Wieso bindest du eigentlich die msp430x14x.h ein, und nicht die
msp430x16x.h?
>P.S. Leider funktioniert der MSP430F1611 nicht zuverlässig mit 7,3728MHz>Baudratenquarz und 3,3V.
Nicht jedes Projekt benötigt einen UART ;-)
>P.P.S.: Wieso bindest du eigentlich die msp430x14x.h ein, und nicht die>msp430x16x.h?
Hä? Er nimmt doch msp430x16x.h
So, jetzt geht auch die Uhrzeit wieder richtig...hatte in meiner ISR für
den Timer_A noch die 8 drin, statt der 7, die richtig ist.
1
#pragma vector=TIMERA0_VECTOR
2
__interruptvoidTimer_A(void)
3
{
4
if(Tick==7)
5
{
6
Tick=0;
7
incrementSeconds();
8
}
9
else
10
Tick++;
11
}
Ich benutze aber nen UART im SPI mode...
Ich habe einen PGA am MSP, der scheint aber mit meinen Einstellungen zu
gehen. Ich kann per Taster die Verstärkung des PGA wie gewünscht in
0,5dB schritten verändern...
Desweiteren habe ich eine SD-Card dran auf der ich die gemessenen
Minutenwerte protokolliere.
Auch das scheint auf den ersten Blick zu funktionieren! Jedenfalls
schreibt er mir die gewünschten Daten drauf...
Könnte das trotzdem noch zu Problemen führen? Weil die Taktfrequenzen
für den SPI sind ja jetzt sicher auch höher, als sie vorher waren...
Die init für den UART0 (da hängt der PGA dran):
Bei beiden Initialisierungen wird ja der SMCLK genommen. Dieser wird
aber durch den DCO beeinflusst, der ja jetzt höher ist.
Sollte da jetzt noch was geändert werden,oder kann ich es so lassen?
Da es ja zu gehen scheint...
Stefan wrote:
>>P.P.S.: Wieso bindest du eigentlich die msp430x14x.h ein, und nicht die>>msp430x16x.h?> Hä? Er nimmt doch msp430x16x.h
In seinem allerersten Post steht in dem TI-Code noch 14x.h, aber
vielleicht hat er´s jetzt rausgenommen, weil er das auf C umgeschrieben
hat. Hab auch langsam den Überblick verloren...sorry, wenn´s falsch war.
Aber nun scheint ja alles zu passen. Was ne schwere Geburt ;)
>Bei beiden Initialisierungen wird ja der SMCLK genommen. Dieser wird>aber durch den DCO beeinflusst, der ja jetzt höher ist.>Sollte da jetzt noch was geändert werden,oder kann ich es so lassen?
Da Du beide USART's im SPI-Master Mode betreibst, ist die Taktfrequenz
(relativ) egal, denn der Master (also Dein MSP) gibt den Takt vor und
der Slave muss sich danach richten. Es könnte nur Probleme geben, wenn
Dein Master-Takt zu hoch für Deine Slaves ist.
Aber da es anscheinend funktioniert... :-)
Ich bin NOCH am testen...aber BIS JETZT gehts wie gewünscht...
Die Geburt war wirklich schwer...
Aber das gute ist, ich hab wieder nen bissl was gelernt!
danke
Hab ich jetzt noch nicht gemacht, aber ich werde morgen mal messen, wie
lange die Routinen für 125ms, 1s usw so brauchen...
Und dann werd ich auf jeden Fall nochmal die ganzen Funktionen
auslagern.
Die beiden riesigen Switch-Case-Routinen kann man auch in eine Funktion
auslagern?
Werd ich mal probieren...
Quasi so?
@ Mathias U. (munter)
>Die beiden riesigen Switch-Case-Routinen kann man auch in eine Funktion>auslagern?>Werd ich mal probieren...>Quasi so?
Ja, du machst ja alles über globale Variablen (naja), da geht das. Aber
auch Parameter für Funktionen sind nicht erst gestern erfunden worden .
. .
MFG
Falk
Lokale Variablen sind mir schon ein Begriff, aber warum auch immer kann
ich mir den Wert von Lokalen Variablen NICHT im Debugger anschauen...
Als ich die Variablen global deklariert hatte, ging es. Keine ahnung
warum...
Als ich z.B. gemacht habe:
1
voidmain(void)
2
{
3
4
inta=3;
5
// hier dann nen breakpoint
6
intb=27;
7
}
Dann hab ich den Debugger bis zum Breakpoint laufen lassen...
Und als ich mir dann a anschauen wollte, dann war das "undefined".
Mathias U. wrote:
> Lokale Variablen sind mir schon ein Begriff, aber warum auch immer kann> ich mir den Wert von Lokalen Variablen NICHT im Debugger anschauen...> Als ich die Variablen global deklariert hatte, ging es. Keine ahnung> warum...
Weil lokale Variablen (normalerweise) in den Arbeitsregistern angelegt
werden und nicht im RAM.
>Dann hab ich den Debugger bis zum Breakpoint laufen lassen...>Und als ich mir dann a anschauen wollte, dann war das "undefined".
Ich hab Dein Besipiel mal in IAR 3.42A (Kickstart) ausprobiert. Beim
Breakpoint angekommen, kann ich 'a' im Watchfenster sehen, 'b' ist noch
'undefined' (klar, weil noch nicht angelegt).
Es gibt allerdings auch ein Window 'Locals', da werden die zur Zeit
aktiven lokalen Variablen automatisch angezeigt. Probier mal das.
Allerdings glaube ich eher, dass Dein Compiler (zumindest in dem
Beispiel oben) die Variablen einfach wegoptimiert, da sie nicht wirklich
benutzt werden!
@Christian.
>Weil lokale Variablen (normalerweise) in den Arbeitsregistern angelegt>werden und nicht im RAM.
Das kann sein, weiß ich nicht genau.
Aber das sollte dem Benutzer eigentlich egal sein, ob Variablen in
Registern oder auf'm Stack liegen. Egal wo, ich sollte die Variablen
sehen können, ansonsten ist das Debuggen (fast) sinnlos.
Stefan wrote:
>> @Christian.>>Weil lokale Variablen (normalerweise) in den Arbeitsregistern angelegt>>werden und nicht im RAM.> Das kann sein, weiß ich nicht genau.> Aber das sollte dem Benutzer eigentlich egal sein, ob Variablen in> Registern oder auf'm Stack liegen. Egal wo, ich sollte die Variablen> sehen können, ansonsten ist das Debuggen (fast) sinnlos.
Theoretisch ja, aber je nach Optimierungsgrad und "Intelligenz" des
Debuggers öfters mal nicht.....
Guten Morgen,
das Beispiel oben ist völlig frei erfunden...mir ging es nur darum diese
komische Sache zu beschreiben...
Mit dem Fenster für lokale Variablen könnte ich mal probieren...ist aber
auch eigentlich nicht so wichtig!
Ich bin gerade dabei, meine main() aufzuräumen...
Ich komme mit den ganzen #includes nicht klar.
bsp.:
Ich habe eine my_globals.h in der stehen haufenweise globale Variablen
drin. (ob das jetzt gut oder schlecht ist, sei mal dahingestellt)
Diese füge ich per #include am Anfang in meine main.c ein.
Dann habe ich eine init_mcu.h in der der Prototyp der Funktion
init_mcu() drin steht.
Ich dachte eigentlich, dass wenn ich in meiner main.c NACH dem #include
von my_globals.h die init_mcu.h einbinde, dann kennt meine init_mcu.c,
in der die Funktion init_mcu() definiert ist, meine globalen
Variablen...
Dies ist aber nicht der Fall. Ich muss in meiner init_mcu.c sowohl die
init_mcu.h (DAS ist klar!!), aber auch noch die my_globals.h einbinden.
Ist das nicht doppelt gemoppelt?
Ich dachte ein #include schreibt einfach den inhalt der eingebundenen
Header-Datei an die Stelle des #includes. oder hab ich da was falsch
verstanden?
Wäre schön, wenn Ihr Euch dem Thema noch ein wenig annehmen würdet.
mfg
mathias
@ Mathias U. (munter)
>Ist das nicht doppelt gemoppelt?
Nein. Jede .c Datei wird VOLLKOMMEN unabhängig kompiliert. D.h. sie muss
aber per #include alles wissen, was sie anwendet (gloable Variablen,
Funktionsaufrufe). Danach wird alles vom Linker zusammengepackt.
>Ich dachte ein #include schreibt einfach den inhalt der eingebundenen>Header-Datei an die Stelle des #includes. oder hab ich da was falsch>verstanden?
Macht es auch.
MFG
Falk
Gut, danke. Dann werde ich das so machen...
Schon taucht das nächste Problem auf:
Ich mache mir eine my_functions.c in der ich dann halt einige Funktionen
auslagern tue...
Die Funktionen brauchen meine globalen Variablen...also binde ich die
my_globals.h dort mit ein.
Da ich aber nicht alle Funktionen gleichzeitig auslagern möchte, weil
ich will ja schrittweis testen, obs geht, hab ich in meiner main.c auch
noch Funktion drin, die auch globale variablen brauchen. Also hab ich
die globals in der main.c auch noch "includiert" (blödes wort!)
Beim Compilieren der my_functions.c allein und auch der main.c geht
alles glatt.
Will ich aber ein "make" machen, erscheit der Fehler:
Error[e27]: Entry "Gain_aktuell" in module main ( C:\...\main.r43 )
redefined in module my_functions ( C:\...\my_functions.r43 )
Die besagte Variable ist ein Integer, global definiert und mit 0
initialisiert, und taucht in der main() in meiner for(;;)-Schleife nur
an der folgenden Stelle auf.
Die wird doch gar nicht redefined, sonder einfach nur gesetzt.
1
if(Mode==1)// im line-mode aus dem elektrischen signal den
2
{// schallpegel bestimmen
3
Gain_aktuell=LUT_GAIN_01[PGA_WERT];// bestimmung der aktuellen verstaerkung
4
if(Wichtung==1)
5
{
6
delta_1=Lequ/10-Kalib_LequA_el_5s_neu;// bestimmung der elektr. pegeldifferenz
7
delta_2=Gain_aktuell-Gain_eff_A;// bestimmung der verstaerkungsdifferenz
8
}
9
elseif(Wichtung==2)
10
{
11
delta_1=Lequ/10-Kalib_LequB_el_5s_neu;// bestimmung der elektr. pegeldifferenz
12
delta_2=Gain_aktuell-Gain_eff_B;// bestimmung der verstaerkungsdifferenz
13
}
14
elseif(Wichtung==3)
15
{
16
delta_1=Lequ/10-Kalib_LequC_el_5s_neu;// bestimmung der elektr. pegeldifferenz
17
delta_2=Gain_aktuell-Gain_eff_C;// bestimmung der verstaerkungsdifferenz
18
}
19
...
Das ist auch die einzige Stelle im Programm (bis jetzt), an der die
Variable benutz wird.
Was ist das jetzt wieder für ein Fehler?
*edit: witzig find ich ja, dass wenn ich die Variable aus meiner
my_globals.h rausnehme, und dierekt in der main.c als global definiere,
dann gehts, aber er hat bei einer anderen Variable den Fehler...
Naja, das kommt daher, dass der Linker dann mehrere Funktionen hat, die
den gleichen Namen haben.
Du musst die Header-Dateien folgendermaßen gestalten:
Beispiel:
@ Mathias U. (munter)
>die globals in der main.c auch noch "includiert" (blödes wort!)
Eingebunden. Es geht aus problemlos auf Deutsch. ;-)
>Will ich aber ein "make" machen, erscheit der Fehler:>Error[e27]: Entry "Gain_aktuell" in module main ( C:\...\main.r43 )>redefined in module my_functions ( C:\...\my_functions.r43 )
Du musst unterscheiden zwischen Deklaration (in .h Headerfiles) und
Definition (in .c Sourcefiles). Dann passt das auch. Die Deklaration
kanst du hundertmal einbinden, die Definition wird nur einmal
compiliert.
>*edit: witzig find ich ja, dass wenn ich die Variable aus meiner>my_globals.h rausnehme, und dierekt in der main.c als global definiere,>dann gehts, aber er hat bei einer anderen Variable den Fehler...
In .h kommen KEINE VariablenDEFINITIONEN rein, nur DEKLARATION. Die
deklarieren, dass es diese variable gibt! WO, ist was anderes. Und zwar
nur einmal in my_globals.c.
MfG
Falk
...jetzt bin ich verwirrt.
Was eine VariablenDEKLARATION ist, ist mir klar.
Mit z.B. :
int a = 8;
wird eine Variable deklariert und gleich mit initialisiert.
Aber was bitte ist eine VariablenDEFINITION? Da gibts doch keinen
Unterschied, oder?
Bei Funktionen ist mir die Sache klar: Deklarieren heißt, die Funktion
ist da und in der Definition steht drin, was die Fkt. machen soll...
Wo schreib ich jetzt meine globalen Variablen rein? In eine
my_globals.c? und die wird über den Projektmanager eingebunden?
@ Mathias U. (munter)
>Was eine VariablenDEKLARATION ist, ist mir klar.>Mit z.B. :>int a = 8;>wird eine Variable deklariert und gleich mit initialisiert.
OK.
>Aber was bitte ist eine VariablenDEFINITION? Da gibts doch keinen>Unterschied, oder?
Doch. Die Definition einer Variable ist genauso wie die Definition einer
Funktion in Headerdateien. Sie zeigt nur wie sie heisst und wie gross
sie ist. Sie wird aber NICHT angelegt (definiert). Das ist der
Springende Punkt.
>Bei Funktionen ist mir die Sache klar: Deklarieren heißt, die Funktion>ist da und in der Definition steht drin, was die Fkt. machen soll...>Wo schreib ich jetzt meine globalen Variablen rein?
1
// my_globals.c
2
uint8_tmy_tmp;
1
// my_globals.h
2
externuint8_tmy_tmp;
my_globals.h wird dann überall per #include eingebunden. Sieht aus wie
doppelt gemoppelt, ist aber schon sinnvoll.
MFG
Falk
@ Christian R. (supachris)
>Naja, in die h-Datei kommt einfach nur:>unsigned int test; (Deklaration)>und in irgendeiner C-Datei dann:>test = 0; (Definition)
Nein, so eben nicht. Karl Heinz oder Jörg können das sicher besser
erklären als ich mit meinem C-Halbwissen.
MFG
Falk
@ Mathias U. (munter)
>Und initialisiert werden die variablen in der my_globals.c?
Ja. Wobei alle ohne explizite Initialisierung automatisch und garantiert
auf Null gesetzt werden.
MFG
Falk
GOTT...schwere Kaiserschnittgeburt!...es ist ein Junge!
Wieder was gelernt!
@Falk: das mit der Nullinitialisierung kenn ich auch, aber ich mach es
trotzdem immer nochmal. Ich finds übersichtlicher! (wie man an meiner
alten main() sehen kann ;-) )
danke Euch!
@ Mathias U. (munter)
>GOTT...schwere Kaiserschnittgeburt!...es ist ein Junge!
Gratulation an den stozen Papa ;-)
>trotzdem immer nochmal. Ich finds übersichtlicher! (wie man an meiner
Du hast ein komische "Logik".
MFG
Falk
Falk Brunner wrote:
> @ Christian R. (supachris)> Nein, so eben nicht. Karl Heinz oder Jörg können das sicher besser> erklären als ich mit meinem C-Halbwissen.
Hmm...war also wieder mal ein Schnellschuss.
Also ich deklariere grundsätzlich keine Variablen in den Headern. Da
werden bei mir nur Funktiosdeklarationen und Deklarationen von
Strukturen angelegt.
Variablen deklariere ich da, wo sie (für mich gesehen) logisch
hingehören, in den C-Dateien über den Funktionen.
Überall da, wo ich auf die Variable einer anderen Funktionseinheit
(einer anderen C-Datei) zugreifen will, hole ich mit diese Variable mit
extern rein.
Weiß jetzt nicht, ob das die Standard-Vorgehensweise ist, aber ich
find´s sehr übersichtlich. Weil jede Variable da deklariert und
definiert wird, wo sie hingehört. Und extern zeigt mir an, dass sie zu
einem anderen Funktionsblock gehört.
@ Christian R. (supachris)
>Also ich deklariere grundsätzlich keine Variablen in den Headern. Da>werden bei mir nur Funktiosdeklarationen und Deklarationen von>Strukturen angelegt.>Variablen deklariere ich da, wo sie (für mich gesehen) logisch>hingehören, in den C-Dateien über den Funktionen.
Du machst dann aber eine DEFINITION mit impliziter DEKLARATION. Das ist
ein kleiner Unterschied. Damitkannst du auf sie nur innerhalb des Files
zugreifen. Was bei globalen Varibalen bissel schlecht ist.
>Überall da, wo ich auf die Variable einer anderen Funktionseinheit>(einer anderen C-Datei) zugreifen will, hole ich mit diese Variable mit>extern rein.
Super, und wenn du das in drei, vier Files machst, hast du erstens
mehrfachen Schreibaufwand und zwetens holst du dir schnell
Inkonsistenzen an den Hals.
>Weiß jetzt nicht, ob das die Standard-Vorgehensweise ist, aber ich>find´s sehr übersichtlich. Weil jede Variable da deklariert und>definiert wird, wo sie hingehört. Und extern zeigt mir an, dass sie zu>einem anderen Funktionsblock gehört.
Nööö. Allgemein gibt es nur lokale und globale Variablen. Die lokalen
brauchen keine expliziten Deklaration, logisch. Und die globalen sind
wie der Name schon sagt GLOBAL. Die in verschiedenen Dateien zu
versteuen ist Murks. Deshalb globals.h und globals.c .
MfG
Falk
Na gut, dann ist das halt nicht ganz die korrekte Art und Weise, aber da
hat wohl jeder seinen eigenen Stil.
Der Schreibaufwand ist minimal, da die "Vorhersage" von Eclipse ja
praktisch alles macht.
@ Christian R. (supachris)
>Na gut, dann ist das halt nicht ganz die korrekte Art und Weise, aber da>hat wohl jeder seinen eigenen Stil.
Als Hobbyprogrammierer kannst du das machen wie du willst, als Profi
wäre es schlicht unprofessionell.
MFG
Falk
Falk Brunner wrote:
> @ Christian R. (supachris)> Als Hobbyprogrammierer kannst du das machen wie du willst, als Profi> wäre es schlicht unprofessionell.
Na wie gut dass ich E-Techniker und kein Informatiker bin, und nur
"nebebei" mal die Sofware für die Elektronik schreibe. Bisher hat sich
noch keiner beschwert. Viel wichtiger sind da Kommentare und eine klare
Gliederung in Funktionseinheiten.
Ich kann´s ja demnächst "richtig" machen....sowas haben wir im Studium
halt nicht gelernt.
So hab mal nen bissl aufgeräumt...
Ist zwar noch lange nicht optimal, aber man kann jetzt leichter
durchsteigen...
Die main.c hat sich doch tatsächlich von knapp 2900 zeilen auf 85
reduziert...
Sieht doch schon wesentlich schicker aus, oder Falk? :-)
Und durch die Erhöhung des DCO-Taktes hat sich mein Zeitproblem auch
erledigt.
Am Montag werde ich evtl. noch mal messen, wie lange die einzelnen
Routinen so brauchen...würde mich auch so mal interessieren.
Danke
mathias
Guten Morgen.
Ich habe noch eine Frage zum DCO:
Wenn ich RSEL = 7 und DCO = 4 mache, mit welcher Frequenz arbeitet dann
die CPU eigentlich?
Im Datenblatt gibt es ja auf Seite 4-7 diese tolle Tabelle, da steht
aber meine Kombination leider nicht drin...
Für f(DCO73) sind es bei 3V nominell 3,2MHz. Das MEIN Takt geringfügig
höher ist, ist klar, aber es muss doch auch irgendwo auszurechnen gehen,
oder?
Mal abgesehen davon, dass ich 3,3Vcc hab.
Komisch finde ich auch, dass bei f(DCO47) Werte drin stehen, die mit
f(DCO40) berechnet werden sollen. Nur steht auch f(DCO40) nicht drin.
Wie soll man das dann ausrechnen??
Hab ich da im Datenblatt was übersehen? Auch im Family Guide hab ich
nichts gefunden...
danke
mathias
Steht in derselben Tabelle mit drin:
SDCO = fDCO+1/fDC0 = 1,12 (typ.)
D.h. wenn man DCO um eins erhöht, dann erhöht sich die Frequenz
typischerweise um den Faktor 1,12
Dasselbe gilt für RSEL: SRSEL = fRSEL+1/fRSEL = 1,65 (typ.)
Aber Ausrechnen macht beim DCO nicht all zuviel Sinn, da die Werte doch
sehr streuen und von der Vcc, von der Temperatur und auch vom Exemplar
abhängen.
Argg, Ja danke...man kann natürlich auch messen...an P5.4 liegt ja der
MCLK an...
Und wenn ich das tue, dann kommt 3,44MHz raus. Passt schon...
mathias