Leider komme ich mit meinem Problem, welches schon im Beitrag "MSP430F1610 und TIMER-B" beschrieben wurde, nicht weiter. Ich will die Impulslänge, welche ein Ultraschallabstandsmesser als Echo sendet, messen. Mit dem Eingang TB0 (1.Gerät) funktioniert die Messung einwandfrei, während die Messung mit z.B. TB3 (2.Gerät) nicht läuft. Offensichtlich reicht es nicht, nur die Register von TBCCTL0 auf z.B. TBCCTL3 umzustellen und TBCCR3 auszulesen. In dem Datenblatt zum MSP430F16xx steht unter „interrupt vector addresses“ Timer_B7 (see Note 5) TBCCR0 CCIFG (see Note 2) Maskable 0FFFAh 13 Timer_B7 (see Note 5) TBCCR1 to TBCCR6 CCIFGs, TBIFG (see Notes 1 & 2) Maskable 0FFF8h 12 was ich leider nicht deuten kann. Ich entnehme nur, dass es einen Unterschied zwischen TBCCR0 und TBCCR1 bis TBCCR6 gibt. Kennt sich jemand genauer damit aus und könnte mir helfen?
Das User's Guide sagt in Abschnitt 12.2.6: > Two interrupt vectors are associated with the 16-bit Timer_B module: > ☐ TBCCR0 interrupt vector for TBCCR0 CCIFG > ☐ TBIV interrupt vector for all other CCIFG flags and TBIFG oder <msp430f1610.h>: > #define TIMERB1_VECTOR (13) /* 0xFFF8 Timer B CC1-6, TB */ > #define TIMERB0_VECTOR (14) /* 0xFFFA Timer B CC0 */ Für CCR3 darfst du also nicht TIMERB0_VECTOR nehmen. Und außer für CCR0 werden die CCIFG-Bits nicht automatisch gelöscht. Das muss dein Code tun; siehe das User's Guide.
Clemens L. schrieb: > Für CCR3 darfst du also nicht TIMERB0_VECTOR nehmen. > > Und außer für CCR0 werden die CCIFG-Bits nicht automatisch gelöscht. Das > muss dein Code tun; siehe das User's Guide. Danke für die Hinweise. Die Umstellung auf TIMERB1 sollte ja nicht das Problem sein. Aber wie die CCIFG-Bits zu löschen sind, da hab ich wieder so meine Probleme. Im Anhang mein "überarbeiteter" Programmschipsel mit der Fehlermeldung für die letzte Zeile: >Error[Pe137]: expression must be a modifiable lvalue Wie wäre es richtig?
Was soll TBIV_TBCCR3 sein? Im "Family User's Guide" (slau049f) gibt es das nicht.
Rufus Τ. F. schrieb: > Was soll TBIV_TBCCR3 sein? steht bei mir in msp430x16x.h >/* TB7IV Definitions */ >#define TBIV_NONE (0x0000) /* No Interrupt pending */ >#define TBIV_TBCCR1 (0x0002) /* TBCCR1_CCIFG */ >#define TBIV_TBCCR2 (0x0004) /* TBCCR2_CCIFG */ >#define TBIV_TBCCR3 (0x0006) /* TBCCR3_CCIFG */ wahrscheinlich bin ich da auf dem Holzweg
Ah. Das ist ein Bitwert, kein Register. Du willst im Register TBIV etwas löschen:
1 | TBIV &= ~TBIV_CCR3; |
Sieh Dir im Family User's Guide die Seite 12-25 an, da wird das Register TBIV beschrieben.
Rufus Τ. F. schrieb: > TBIV &= ~TBIV_CCR3; Leider erzeugt diese Zeile bei mir die gleiche Fehlermeldung. >Error[Pe137]: expression must be a modifiable lvalue
Das würde bedeuten, daß es das Register TBIV nicht gibt. Da stimmt was nicht. Sieh Dir dir Tabelle der Register in slau049f auf Seite 12-20 (244) an. Wie ist das Register mit der Adresse 0x11E in Deiner Headerdatei definiert?
Rufus Τ. F. schrieb: > Das ist ein Bitwert Nein, das ist die Nummer des Interrupts (mal zwei, damit man das direkt als Offset verwenden kann). Das IFG-Bit kann man auf die übliche Art löschen:
1 | TBCCTL3 &= ~CCIFG; |
Aber wenn man mehrere Interrupts behandeln muss, nimmt man lieber das IV-Register:
1 | switch (TBIV) { |
2 | case TBIV_TBCCR1: |
3 | ...
|
4 | break; |
5 | case TBIV_TBCCR2: |
6 | ...
|
7 | break; |
8 | case TBIV_TBCCR3: |
9 | ...
|
10 | break; |
11 | ...
|
12 | }
|
Beim Lesen des TBIV-Registers wird das entsprechende IFG-Bit autmatisch gelöscht.
Du hast natürlich recht. Habe wohl nicht aufmerksam genug in die Dokumentation gesehen; das Register TBIV ist obendrein nur les-, aber nicht beschreibbar.
Rufus Τ. F. schrieb: > Wie ist das Register mit der Adresse 0x11E in Deiner Headerdatei > definiert? meinst Du damit diese Definitionen? >* Timer B7 >************************************************************/ >#define _MSP430_HAS_TB7_ /* Definition to show that Module is available */ >#define TBIV_ (0x011E) /* Timer B Interrupt Vector Word */ >READ_ONLY DEFW( TBIV , TBIV_) >#define TBCTL_ (0x0180) /* Timer B Control */ >DEFW( TBCTL , TBCTL_) >#define TBCCTL0_ (0x0182) /* Timer B Capture/Compare Control 0 */ >DEFW( TBCCTL0 , TBCCTL0_) Ich habe es zusätzlich mal mit mspgcc probiert. Hier kommt zwar keine Fehlermeldung, aber das Programm hängt sich auf. Da war ich zu langsam. Die weiteren Tips werde ich mal testen.
:
Bearbeitet durch User
Ich bin mit meinen Kenntnissen des 'F1611 wohl etwas arg rostig; ich kann Dir nur raten, Dir mal die verschiedenen Sourcecodebeispiele von TI höchstselbst zu Gemüte zu führen - und ansonsten den Beitrag von Clemens zu lesen. http://www.ti.com/lit/zip/slac015
So richtig verstanden habe ich zwar noch nicht alles, aber mein Programm läuft jetzt erst einmal wunschgemäß. Verwendet habe ich: >Das IFG-Bit kann man auf die übliche Art löschen: >TBCCTL3 &= ~CCIFG; Der 2. Teil wurde für einen evtl. späteren Gebrauch abgespeichert. Für die Hilfe recht vielen Dank.
wolle g. schrieb: > aber mein Programm läuft jetzt erst einmal wunschgemäß. Mit dieser Einschätzung war ich wohl etwas zu voreilig. Das Programm läuft bei mir nur, wenn man jeweils nur einen HC SR04 betreibe. Ziel ist es aber, 2x HC SR04 an einem µC zu betreiben. Wenn ich, wie im Anhang unter TimerA0, beide HC SR04 betreibe, dann ist das Messergenis des HC SR01-1 nur Müll. HC SR04-2 behält aber seine brauchbaren Werte. Wird nur HC SR01-1 getaktet, dann liefert auch dieser brauchbare Werte. Kann mir noch einmal jemand helfen?
:
Bearbeitet durch User
Das kommt davon, wenn du TBCLR verwendest – das setzt den gesamten Timer auf Null, beeinflusst also auch alle CCRs. Um eine Zeitdauer zu messen, solltest du den Timer-Zähler vorher und nachher speichern (1. per Hand, 2. mit Capture-Event), und dann subtrahieren.
Clemens L. schrieb: > Das kommt davon, wenn du TBCLR verwendest – das setzt den gesamten Timer > auf Null, beeinflusst also auch alle CCRs. Das war eigentlich auch so gedacht. Zuerst die Impulslänge von HC SR04-1 erfassen (TB0) --> TBCCR0 lesen --> Timer auf Null setzen --> Pause und dann das Gleiche mit HC SR04-2 an TB3 wiederholen. Da bin ich offensichtlich auf dem Holzweg. >Um eine Zeitdauer zu messen, solltest du den Timer-Zähler vorher und >nachher speichern (1. per Hand, 2. mit Capture-Event), und dann >subtrahieren. Das erscheint für mich zu hoch zu sein. z.B. Was soll per Hand gemacht werden? Könntest Du vielleicht mein Programm versuchsweise korrigieren?
Innerhalb eines Interrupthandlers sind alle Interrupts erst einmal gesperrt. Der Code in Timer_A() sollte in die Hauptschleife verschoben werden. Um die Schleife in regelmäßigen Abständen auszuführen, kann sich der Code dort schlafen legen und durch den TimerA-Interrupt-Handler aufwecken lassen.
Nach einer „kleinen“ Pause melde ich jetzt wieder. Clemens L. schrieb: > Innerhalb eines Interrupthandlers sind alle Interrupts erst einmal > gesperrt. Der Code in Timer_A() sollte in die Hauptschleife verschoben > werden. Ich habe mal mein Programm (leider immer noch erfolglos) umgebaut. Den Start und die Antwort habe ich in die while-Schleife der Hauptschleife verlegt. War es so gemeint? Wird jeweils nur 1 Ultraschallmesser gestartet, dann erscheint die Antwort plausibel. Sind beide, wie im umgebauten Programm, in Betrieb, dann gibt es unbrauchbare Messergebnisse. MfG
Die beiden CCRs kommen sich immer noch in die Quere; TBCLR und das Start-Signal für den Sensor sind nicht synchonisiert. Also konkret: beim Start und beim Ende wird der Zeitstempel gelesen:
1 | start1 = TBR; |
2 | P4OUT &= ~BIT1; |
3 | ...
|
Im Interrupt:
1 | ende1 = TBCCR0; |
2 | ech1 = ende1 - start1; |
Der Timer wird dabei nie auf 0 zurückgesetzt! (Und dann könnte man auch beide Messungen gleichzeitig machen.) Und "volatile" fehlt bei den gemeinsam vom Hauptprogramm und Interrupt-Handlern benutzen Variablen. Und Warteschleifen macht man besser mit __delay_cycles().
Clemens L. schrieb: > Der Timer wird dabei nie auf 0 zurückgesetzt! (Und dann könnte man > auch beide Messungen gleichzeitig machen.) > > Und "volatile" fehlt bei den gemeinsam vom Hauptprogramm und > Interrupt-Handlern benutzen Variablen. > Und Warteschleifen macht man besser mit __delay_cycles(). Das sehe ich zum Teil etwas anders. Im Prinzip habe ich nur meine Warteschleifen (pause) durch __delay_cycles() ersetzt und das überarbeitete Programm funzt. Könnte man diesen Effekt erklären? Noch zwei Fragen: Warum sollte man "volatile" verwenden? Wie hängen __delay_cycles() und die Quarzfrequenz zusammen? Im Anhang jetzt das in meinen Augen funktionstüchtige Programm. (Falls es jemanden interessiert)
wolle g. schrieb: > Im Prinzip habe ich nur meine Warteschleifen (pause) durch > __delay_cycles() ersetzt und das überarbeitete Programm funzt. Könnte > man diesen Effekt erklären? Offensichtlich waren die Warteschleifen zu kurz, oder wurden vom Compiler wegoptimiert. > Warum sollte man "volatile" verwenden? http://stackoverflow.com/q/246127/11654 > Wie hängen __delay_cycles() und die Quarzfrequenz zusammen? Du hast MCLK auf 8 MHz konfiguriert, also 1 Takt = 125 ns.
Clemens L. schrieb: >> Warum sollte man "volatile" verwenden? > http://stackoverflow.com/q/246127/11654 >> Wie hängen __delay_cycles() und die Quarzfrequenz zusammen? > Du hast MCLK auf 8 MHz konfiguriert, also 1 Takt = 125 ns. Danke. Gibt es auch etwas ohne Frage- Antwortspiel und in deutsch? und wann wird der Compiler ohne "volatile" etwas wegoptimieren? Kann man das auch in wenigen Sätzen beschreiben?
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.