Hallo MSP430 Gemeinde,
ich bin gerade dabei meine eigne Ofensteuerung zu programmieren.
Platinen habe ich anfertigen lassen, die Hardware ist ok.
Die Beispiel- Codes von TI funktionieren mit ACLK=8MHz und 115200 Baud.
Das Auslesen der 8 ADC- Kanäle für Steuerfunktionen macht mir keine
Sorgen.
Allerdings die Werte dieser 8 ADC- Kanäle über RS232 (usart) an meinen
PC zu senden klappt hinten und vorne nicht.
Im Code ist eine Funktion, die die RS232 bedienen soll. Diese
funktioniert wenigstens etwas, allerdings spuckt sie haufenweise Müll
aus.
Ich habe es auch schon mit einer TX_ISR von TI versucht, damit kommt
erst gar nichts raus.
Ich bekomme es einfach nicht hin, die 8 Arrays gescheit zu senden.
Mir ist auch noch nicht klar wie der TX- Interrupt überhaupt ausgelöst
werden soll.
Es handelt sich um einen MSP430f167 und ich benutze Code Composer Studio
Version: 5.1.1.00031 und den MSP-FET430UIF
(Der zweite Code- Upload (rechts) ist der richtige, weiß nicht wie man
den alten löscht)
Gruß
Stefan
Also einen Quelltext in RichText ist natürlich ungünstig. Hier mal
eingefügt, damit man auch was sehen kann und nicht immer zwischen
Browser und Word wechseln muss:
1
#include<msp430f167.h>
2
#include<intrinsics.h>
3
4
5
voidInit_ADC(void);//ADC init
6
voidRead_ADC(void);//Temp. T1 - T8 lesen
7
voidSendUSART0(void);
8
voidinit_XT(void);//Ext. Quarz 8MHz
9
10
staticcharDigit[8];
11
12
voidmain(void)
13
{
14
init_XT();//Ext. Quarz 8MHz und Stop WDT
15
16
//Definition des Port C für P3.4 bis P3.5 für RS232
17
18
P3SEL|=0x30;//Port C P3.4 bis P3.5 Aux Funktion
19
20
ME1|=UTXE0+URXE0;//USART0 Rx + Tx einschalten
21
UCTL0|=CHAR;//USART0 8N1
22
UTCTL0|=SSEL0;//ACLK
23
UBR00=0x45;// 115200 baud aus 8 MHz erzeugen
24
UBR10=0x00;//
25
UMCTL0=0x00;// keine korrektur der division noetig
Jetzt zu deinem Code:
Das hier:
Dennis schrieb:> while (1)> {> Read_ADC(); //A/D- Wandler starten> }
Und das hier:
Dennis schrieb:> void Read_ADC(void)> {> ADC12CTL0 |= ADC12SC; // Neue Konvertierung starten> }
geht natürlich schonmal garnicht! Du kannst ja nicht immer eine neue
Wandlung starten, ohne zu prüfen, ob die alte überhaupt fertig ist. Die
neue Wandlung startest du wenn am Ende der ISR oder irgendwo anders,
vorausgesetzt du weißt, dass der ADC wenigstens mal die Zeit hatte in
Ruhe zu wandeln.
Das hier:
Dennis schrieb:> static char Digit[8];
Und das hier:
Dennis schrieb:> Digit[0] = ADC12MEM0;
geht natürlich auch überhaupt nicht! Erstens deklariert man Variablen,
die in der ISR manipuliert werden als volatile, aber das ist bei dem
folgenden Patzer noch relativ belanglos...der AD-Wandler ist doch ein
12-Bit-Wandler. Wie willst du das Ergebnis in einen 8-Bit char
quetschen? Der läuft dir doch über.
Dennis schrieb:> Diese Funktion brigt nur Müll raus!!!> void SendUSART0 (void)> {> char i, j;>> for (j=0; j<8; j++)> {> for (i=0; i < sizeof Digit[j]; i++)> U0TXBUF = Digit[j];>> }> }> */
Das kann auch nicht funktionieren, da du deinen eigenen Puffer immer
wieder überschreibst.
Dennis schrieb:> // UART0 TX ISR Diese ISR bringt nichts raus!!!> #pragma vector=USART0TX_VECTOR> __interrupt void usart0_tx (void)> {> char i, j;> for (j=0; j<2; j++)> {> for (i=0; i < sizeof Digit[j]; i++)> TXBUF0 = Digit[j];>> }> }
Das ist genauso falsch - hier passiert dasselbe wie in der main, dass du
das im Interrupt ausführst, macht es nicht besser. Du musst EIN Zeichen
senden und in der ISR, welche nach dem "TX-Buffer-leer"-Interrupt
kommt, das nächste. Und während eines gesendet wird, machste was
anderes, bis der Interrupt wieder eintritt.
Dennis schrieb:> ADC12MCTL0 = SREF_2
Hast du eine externe Referenz angeschlossen?
Dennis schrieb:> ADC12IE = 0x02;
Wieso den Interrupt bei 0x02? Du samplest doch noch bis MEM7.
So, das ist erstmal ein kleiner Ausschnitt deiner Fehler im Quelltext.
Du solltest vielleicht auch mal die Hardware reinstellen.
Gruß, Dennis
Vielen Dank Dennis,
da habe ich erst mal was zum knabbern.
Das mit der externen Referenz ist richtig so.
Die A/D- Wandlung läuft, jedenfalls für A0 und A1. Mehr habe ich bis
jetzt noch nicht benutzt um zwei Relais anzusteuern.
Das mit dem 8-bit Char ist natürlich peinlich, kann ich denn alles über
uart senden? Also auch int, unsigned int usw.?
Aber wie veranlasse ich denn in der Funktion oder in der ISR dass der
Buffer auch mal ein Zeichen los schickt?
Also woher der Buffer weiß dass er senden soll ist mir noch ein Rätsel.
Heißt das ich muss in der Schleife bei jedem Durchgang prüfen ob der
Buffer bereit ist und dann sollte das schon mal gehen?
In den Coder- Beispielen von TI wird meisten im Loop gearbeitet und
daraus einen geeigneten Code für mich abzuleiten ist mit, wie du sehen
kannst, leider noch nicht gelungen.
Ich werde mich gegen Abend mal wieder dran setzten und mir meinen Kopf
zerbrechen.
Gruß
Stefan
Stefan S. schrieb:> Das mit dem 8-bit Char ist natürlich peinlich, kann ich denn alles über> uart senden? Also auch int, unsigned int usw.?
Über UART sendest du nur 1 Zeichen. Bei einer Zahl von beispielsweise
1276 sendest du '1', '2', '7' und '6' hintereinander. Das als ganze Zahl
kannst du nicht versenden. Du musst die Zahl also vorher zerlegen:
1
zahl=1276
2
3
chardigits[4];
4
5
digits[0]=zahl/1000
6
zahl%=1000
7
digits[1]=zahl/100
8
zahl%=100
9
digits[2]=zahl/10
10
digits[3]=zahl%10
Deine digits kannste dann versenden.
Stefan S. schrieb:> Aber wie veranlasse ich denn in der Funktion oder in der ISR dass der> Buffer auch mal ein Zeichen los schickt?
Du kannst das erste Zeichen direkt in den Puffer schreiben, worauf der
USCI anfängt, die Daten zu senden und in der Zeit das Flag löscht,
welches anzeigt, dass eine Transaktion vorliegt. Ist der Puffer
vollständig gesendet, dann wird das Flag gesetzt und die ISR wird
aufgerufen. In der ISR schreibst du das nächste Zeichen in den Puffer
usw.
Du kannst das alles auch in der main oder in irgendeiner anderen
Funktion machen, als Loop also. Aber dann musst du halt immer das Flag
abfragen:
1
sende_puffer
2
{
3
for(i=0;i<PUFFERGROESSE;i++)
4
{
5
UART_TX_BUFFER=puffer[i];
6
while(UART_BUSY){}
7
}
8
}
Aber das ist natürlich die unelegante Lösung, wenn es schon extra IFGs
gibt.
[/c]
Dennis schrieb:> Deine digits kannste dann versenden.
Wenn sie in einem Terminalprogramm o.ä. lesbar sein sollen, sollte
allerdings aus den numerischen Werten 0-9 auch die
ASCII-Zeichendarstellung '0'-'9' gemacht werden, was durch Addieren von
'0' (man beachte die Hochkommata!) geht.
Vielen Dank,
Digit_1 wird schon mal gesendet, der Rest folgt morgen, ist schon spät.
Allerdings alles zusammenhängend gesendet, also: 123412341234.
Wo und wie muss ich denn das Steuerzeichen für CR oder LF unterbringen?
Hab's jetzt mal wie folgt geändert:
while(ADC12CTL1&ADC12BUSY);//ADC noch beschäftigt?
4
ADC12CTL0|=ADC12SC;// Neue Konvertierung starten
5
}
Wie schaffe ich es denn nun in der ISR zuerst ein Zeichen zu senden um
den Iterrupt auszulösen und dann in der ISR die restlichen Zeichen zu
senden?
Wenn ich das so richtig verstanden habe.
Stefan S. schrieb:> Allerdings alles zusammenhängend gesendet, also: 123412341234.> Wo und wie muss ich denn das Steuerzeichen für CR oder LF unterbringen?
Wie wäre es zwischen den einzelnen Werten?
Stefan S. schrieb:> Wie schaffe ich es denn nun in der ISR zuerst ein Zeichen zu senden um> den Iterrupt auszulösen und dann in der ISR die restlichen Zeichen zu> senden?
Das geht natürlich nicht. Das erste Zeichen muss in der main() gesendet
werden.
Gruß Dietrich
@Rufus T.
Dass ich das Zeichen zwischen den Werten unterbringen muss ist mir schon
klar. Aber wo und wie hänge ich rein technisch das /n oder /r dran?
Egal wo ich es versucht habe kommt anschließend nur noch Müll raus, oder
die Zeichen /n und /r werden mit als Text ausgegeben.
@Dietrich
Vielen Dank, das dachte ich mir schon so halber.
Allerdings macht das die ISR für mich wieder etwas unattraktiver da
nicht die gesamte Ausgabe in einem Block steht.
Ansonsten versuche ich jetzt mal meine ADC- Digits etwas zu glätten, die
springen so ca. 50 Digits auf und ab.
Dann suche ich noch nach einer geeigneten Funktion um meine Digits auch
in °C umzurechnen, dafür gibt es aber wohl schon genug Beispiele.
Viele Grüße
Stefan
Stefan S. schrieb:> Aber wo und wie hänge ich rein technisch das /n oder /r dran?
Wenn Du es richtig schreiben würdest, käme auch was anderes heraus. Es
heißt \r \n.
Ansonsten müsstest Du schon den Quelltext zeigen, in dem Du das versucht
hast, sonst kann man Dir nicht mehr sagen, als daß der Fehler in Zeile
42 liegt.
Rufus Τ. Firefly schrieb:> Wenn Du es richtig schreiben würdest, käme auch was anderes heraus. Es> heißt \r \n.
Kaum macht man es richtig und schon geht es.
Danke.
Aber mal noch was anderes, hat vielleicht noch jemand eine bessere Idee
zum Thema ADC- Werte mitteln?
1
for(i_avg=0;i_avg<50;i_avg++)
2
{
3
Read_ADC();
4
avg_1[i_avg]=Digit_1;
5
avg_2[i_avg]=Digit_2;
6
7
8
9
}
10
11
for(i_avg=0;i_avg<50;i_avg++)
12
{
13
Digit_1=Digit_1+avg_1[i_avg];
14
Digit_2=Digit_2+avg_2[i_avg];
15
}
16
17
Digit_1=Digit_1/50;
18
Digit_2=Digit_2/50;
Ich finde das etwas unelegant und es verlangsamt auch alles etwas.
Den Quelltext werde ich bei Gelegenheit mal komplett hier einstellen,
muss nur noch etwas Ordnung machen und die ganzen Fehlversuche wieder
entfernen.
Stefan S. schrieb:> Allerdings macht das die ISR für mich wieder etwas unattraktiver da> nicht die gesamte Ausgabe in einem Block steht.
Das geht aber trotzdem. Du must nur das Interruptflag in der main
ausloesen.
Da mit stöst du die Interruptfunktion an und die macht den Rest.