Hallo zusammen
Ich bin gerade dabei einen UART mit dem MSP430F147 zu programmieren. Da
ich später einen kleineren MSP430 ohne USART-Einheit verwenden werde,
versuche ich das Problem mit dem Timer_A zu lösen.
Die Beispielprogramme von TI habe ich mir angeschaut und angepasst,
funktioniert hat das ganze nicht. Nun habe ich das ganze noch ein wenig
umgebaut, so dass es in den meisten Fällen funktioniert. Leider stimmt
aber oftmals die Bitdauer einzelner Bits nicht, was dann beim Empfang
auf dem PC zu falschen Werten führt. Um das Problem zu isolieren habe
ich die Software mal auf das essentielle beschränkt und habe da das
selbe Problem feststellen können.
Den Code könnt ihr unten sehen. Ich Toggle dabei den Out0 Ausgang des
Timer_A jeweils nach 1 ms, indem ich in der Interrupt-Routine zwischen
Set- und Reset-Mode wechsle. Der Wechsel des Out Mode erfolgt über den
Out Mode 7, wie es im Family Guide empfohlen wird. Dass ich nicht den
Toggle-Mode verwende ist Absicht, das Problem tritt dann nicht. Um das
Ausganssignal mit den Zeitpunkten der Aufrufe der Interrupt-Routine
vergleichen zu können invertiere ich jeweils noch den Zustand einer LED.
Im Ahang seht ihr ein Bild. Auf dem Kanal 1 unten ist der Ausgang Out0
des Timer_A zu sehen. Oben auf Kanal 2 seht ihr das Signal der LED. Das
sechste und das achte High-Bit weisen einen Fehler auf. Ersteres ist zu
kurz, letzteres zu lang.
Wisst ihr, wieso dieser Fehler auftritt? Für eure Hilfe bin ich schon
jetzt dankbar.
Grüsse
Thaller
1
#include"io430.h"
2
#include"intrinsics.h"
3
4
#define TXD 0x02 // P1.1 für TX
5
#define LED 0x80 // P1.7 für LED
6
#define Time 8000 // 1 ms
7
8
unsignedcharcounter=0;
9
10
voidmain(void)
11
{
12
WDTCTL=WDTPW+WDTHOLD;
13
14
// 8 MHz für MCLK, SMCLK
15
BCSCTL2=SELM_2+SELS;
16
BCSCTL1&=~XT2OFF;
17
18
TACTL=TASSEL_2+MC_2;// SMCL für TA, Cont. Mode
19
TACTL&=~TAIE;
20
TACCTL0=OUT;// Mark auf TX
21
22
P1SEL=TXD;// TA OUT0 für TX
23
P1DIR=TXD+LED;
24
P1OUT|=LED;// LED ein
25
26
__bis_SR_register(GIE);//Gener Interrupt Enable
27
28
29
TACCR0=TAR+Time;// Zeitpunkt des nächsten Interrupts
30
TACCTL0|=OUTMOD_1+CCIE;// Set Mode, Compare Interrupt Enable
31
32
while(1);
33
}
34
35
36
// Timer A0 interrupt service routine
37
#pragma vector = TIMERA0_VECTOR
38
__interruptvoidTimer_A(void)
39
{
40
TACCR0+=Time;// Nächstn Interrupt festlegen
41
42
if(counter%2)// Toggle
43
{
44
TACCTL0|=OUTMOD_7;// Über Out Mode 7
45
TACCTL0&=(0xFF1F|OUTMOD_5);// in Out Mode Reset wechseln
46
47
}
48
else
49
{
50
TACCTL0|=OUTMOD_7;// Über Out Mode 7
51
TACCTL0&=(0xFF1F|OUTMOD_1);// in Out Mode Set wechseln
Thaller wrote:
> Hallo zusammen>> Ich bin gerade dabei einen UART mit dem MSP430F147 zu programmieren. Da> ich später einen kleineren MSP430 ohne USART-Einheit verwenden werde,> versuche ich das Problem mit dem Timer_A zu lösen.>> Die Beispielprogramme von TI habe ich mir angeschaut und angepasst,> funktioniert hat das ganze nicht.
Hmm...was hat denn nicht funktioniert? Bei mir klappt das bestens, mit
einem 6MHz Quarz sogar bis 57600 Baud. Wenn man einen Baudratenquarz
nimmt, müsste noch viel höher gehn. Man muss nur die Bitzeiten genau
ausrechnen. Über 57600 kamen bei meinem 6MHz Quarz dann krumme Werte
raus, und das geht bei der Software-UART nicht.
Versucht habe ich es mit einem angepassten Beispiel gemäss
untenstehendem Code. Dabei habe ich alles für den Empfang entfernt, da
ich dies momentan nicht brauche.
TACTL=TASSEL_2+MC_2+TACLR;// SMCL für TA, Cont. Mode
25
TACCTL0=OUT;// Mark auf TX
26
27
P1SEL=TXD;// TA OUT0 für TX
28
P1DIR=TXD;
29
30
__bis_SR_register(GIE);
31
32
while(1)
33
{
34
RXTXData=64;
35
TX_Byte();// TX Back RXed Byte Received
36
}
37
}
38
39
// Function Transmits Character from RXTXData Buffer
40
voidTX_Byte(void)
41
{
42
BitCnt=0xA;// Load Bit counter, 8data + ST/SP
43
TACCR0=TAR;// Current state of TA counter
44
TACCR0+=Bitime;// Some time till first bit
45
RXTXData|=0x100;// Add mark stop bit to RXTXData
46
RXTXData=RXTXData<<1;// Add space start bit
47
TACCTL0=OUTMOD_0+CCIE;// TXD = mark = idle
48
while(TACCTL0&CCIE);// Wait for TX completion
49
}
50
51
// Timer A0 interrupt service routine
52
#pragma vector=TIMERA0_VECTOR
53
__interruptvoidTimer_A(void)
54
{
55
TACCR0+=Bitime;// Add Offset to CCR0
56
57
if(BitCnt==0)
58
TACCTL0&=~CCIE;// All bits TXed, disable interrupt
59
else
60
{
61
TACCTL0|=OUTMOD_2;// TX Space
62
if(RXTXData&0x01)
63
TACCTL0&=~OUTMOD_2;// TX Mark
64
RXTXData=RXTXData>>1;
65
BitCnt--;
66
}
67
}
Dabei sind die Bitfolgen falsch, das Signal geht am Schluss nicht wieder
auf den High-Pegel zurück und es gibt daber auch kein Stoppbit.
Da es mir ehrlich gesagt auch schleierhaft ist, wieso im Beispiel der
Out Mode 2 verwendet wird, habe ich es so umprogrammiert, dass ich es
für mich schlüssig ist. Und wie gesagt funktioniert es auch in den
meisten Fällen, nur stimmen manchmal die Bitzeiten nicht.
Die ausgerechneten Werte für die Bitzeiten stimmen schon, ich hab das
mehrmals überprüft.
Aber auch wenn ich es nun mit dem TI-Beispiel doch noch hinbekäme, würde
es mich brennend interessieren, wieso mein Programm diese Macken hat.
Das Auftreten der Interrupts in meinem Programm stimmt jedenfalls, das
kann ich mit dem Referenzsignal, welches ich auf die LED ausgebe,
überprüfen.
// Function Transmits Character from RXTXData Buffer
void TX_Byte (void)
{
BitCnt = 0xA; // Load Bit counter, 8data +
ST/SP
TACCR0 = TAR; // Current state of TA
//counter
TACCR0 += Bitime; // Some time till first
bit
RXTXData |= 0x100; // Add mark stop bit to
// RXTXData
RXTXData = RXTXData << 1; // Add space start bit
TACCTL0 = OUTMOD0 + CCIE; // TXD = mark = idle
while ( TACCTL0 & CCIE ); // Wait for TX completion
}
Benutz die Funktion hier. Du musst den Unterstrich bei OUTMOD0
weglassen.
Sollte hoffentlich gehen
Danke für eure Hilfe, aber ob nun OUTMOD_0 oder OUTMOD0 kommt auf den
Compiler an. Ich benutze die aktuelle IAR Kickstart Edition und da ist
es als OUTMOD_0 definiert, das andere kennt er, wenn ich mich recht
besinne, gar nicht.
Nun, ich begreif trotzdem nicht, wieso weder das TI-Beispiel noch mein
Programm funktionieren.
Doch doch, er kennt beides.
Beim IAR isses IMHO so, dass mit Underscore immer die einzelnen Modi
(OUTMOD_0...OUTMOD_7) und ohne Underscore die einzelnen Bits
(OUTMOD0...OUTMOD2) in den Registern bezeichnet werden. Is ein bissl
tricky und fehlerträchtig, aber man gewöhnt sich an alles :-)
Achso. Dabei könnte ich schwören, dass der beim kompilieren reklamiert
hat und ich es deshalb geändert habe. Nun, ich werde das montags
ausprobieren und hier reinschreiben, ob es funktioniert hat oder nicht.
Vielen dank auf jeden Fall.
Nachtrag:
Ich habe den IAR kurz zu Hause installiert und verstehe nun auch, wieso
er bei mir OUTMOD0 nicht gekannt hat. Ich habe das standardmässige
Headerfile "io430.h" eingebunden, welches dann wiederum das Headerfile
"io430x14x.h" einbindet. Und in diesem ist OUTMOD0 gegenüber dem
Headerfile "msp430x14x.h" im Beispiel von TI nicht definiert. Da frage
ich mich schon, wieso zwei Headerfiles existieren, welche nicht gleich
sind. Die unterscheiden sich noch diversen weiteren Punkten.
Und nun ist mir auch endlich klar, wieso im Beispiel von TI in der
Interruptroutine das Bit OUTMOD2 beinflusst wird. Das führt wie in
meinem ersten Beispiel zu einem Umschalten zwischen OUTMOD_1 und
OUTMOD_5, da das erste Bit OUTMOD0 ja bereits in TX_Byte() gesetzt
wurde.
Vielen Dank für die Hilfe, nun ist mir schon einiges klarer.
Aber es würde mich nun doch noch interessieren, wieso mein Programm aus
dem ersten Eintrag nicht sauber funktioniert. Dort schalte ich ja auch
einfach zwischen OUTMOD_1 und OUTMOD_5 um.
Ich habe das selbe Programm, angepasst für den internen Clock, nun mal
auf dem eZ430-F2013 von TI laufengelassen, und da funktioniert es
einwandfrei. Scheint wohl ein Hardware- oder Prozessorproblem zu sein.
Nochmals Danke für eure Hilfe.