Forum: Mikrocontroller und Digitale Elektronik MSP430x169 und serielle Schnitstelle


von Stephan P. (steph0815)


Lesenswert?

Hallo,

Ich versuche die Serielle Schnittstelle von meinen MSP430x169 zum laufen 
zu bekommen. Leider bisher ohne Erfolg. Ich habe schon viele 
Beispielprogramme  ausprobiert nur bis jetzt hat nichts geklappt. Ich 
benutze das MSP430169STK Board von Olimex. Die Serielle Schnittstelle am 
PC habe ich auch schon getestet und die macht es noch. Auch habe ich 
mein Programm schon auf einen anderen Board laufen lassen und dies 
ebenfalls ohne Erfolg.
1
//------------------------------------------------------------------------------
2
// Init USART0  
3
void init_USART0 (unsigned char IR0)  
4
//------------------------------------------------------------------------------
5
{
6
  P3SEL |= 0x30;    // enable special funktion on PIN3.4, 3.5
7
  P3DIR |= 0x10;     // set direction
8
    
9
  UTCTL0 = CHAR;    // set 8bit
10
  UTCTL0 = SSEL0;    // set ACLK as USART0_CLK
11
  
12
  UBR00 = 0x03;
13
  UBR10 = 0x00;
14
  UMCTL0 = 0x4A;
15
  
16
  ME2 |= UTXE0+URXE0;       // enable UART0 RX&TX
17
  if (IR0 == 1) IE2 |= URXIE0;   // enable UART0 RX ISR
18
  if (IR0 == 2) IE2 |= UTXIE0;   // enable UART0 TX ISR
19
  if (IR0 == 3) IE2 |= UTXIE0+URXIE0;   // enable UART0 TX&RX ISR
20
  
21
  UCTL0 &= ~SWRST;
22
  _EINT();                      // interrupt enable
23
}
24
25
//------------------------------------------------------------------------------
26
// send character  
27
void send_USART0 (unsigned char out_char)  
28
//------------------------------------------------------------------------------
29
{
30
  while((IFG2 & UTXIFG0) != UTXIFG0);
31
  TXBUF0 = out_char;
32
}
Vielleicht kann ja mal jemand ueber meinen Code schauen. Auf jeden Fall 
freue ich mich ueber jede Hilfe! Und einen Dank schon mal von mir


mfg
Stephan

von Ampfing (Gast)


Lesenswert?

Hi Stephan,

als erstes fällt mir mal auf, dass Du zu Beginn der Routine die 
Schnittstelle nicht zurücksetzt (also das SWRST Bit nicht setzt). Dies 
wird explizit im Datenblatt empfohlen.
Außerdem wählst Du den ACLK als Quelle für die Schnittstelle. Der Takt 
ist da, oder??

Viele Grüße

von Wolfgang-G (Gast)


Lesenswert?

welche Baudrate wurde gewählt?

von Richard (Gast)


Lesenswert?

Das geht bei mir:

#define USART0_ENABLE       1
#define RX_INT_ENABLE       0
#define TX_INT_ENABLE       1
#define RXTX_INT_ENABLE     2
#define INIT_INT_REMOVE     1   // Init. interr.-flag loesch. (UTXIFG0)
#define INIT_INT_NOT_REMOVE 0   // Init. interr.-flag nicht loesch. // 
(UTXIFG0)

--> bei  BCSCTL1 = 0x00;              // ACLK = NO CLK !!!
--> BCSCTL2 = SELM_2 | SELS;        // MCLK = LFXT1 (safe)

Init_USART (USART0_ENABLE, 9600, RX_INT_ENABLE, INIT_INT_NOT_REMOVE);

void Init_USART(unsigned char USART0, unsigned int baudrate1, unsigned 
char IR0, unsigned char IR1)
{

  //================ USART 0 =====================//
  if (USART0)
  {
    UCTL0 |= CHAR;        // 8 Data Bits, 1 Stop Bit, no parity (8N1)
    UTCTL0 |= SSEL1;      // SMCLK als UCLK festlegen
  }

  if (baudrate1 == 19200)       Bei 7372800Hz --> Quarz !!
  {                 // - Baud rate control register 0
    // 19200 baud aus 7,3728 Mhz/19200 (0x180) MHz erzeugen
    UBR00 = 0x80;
    UBR10 = 0x01;    // Baud rate control register 0
    UMCTL0 = 0x00;   // keine korrektur der division noetig
  }
  else if (baudrate1 == 9600)
  {
    UBR00 = 0x00; UBR10 = 0x03; UMCTL0 = 0x00;
  }
  else if (baudrate1 == 57600)
  {
    UBR00 = 0x80; UBR10 = 0x00; UMCTL0 = 0x00;
  }
  else // 19200 baud
  {
    UBR00 = 0x80; UBR10 = 0x01; UMCTL0 = 0x00;
  }

  if (USART0)
  {
    ME1 |= UTXE0 + URXE0;       // USART0 einschalten (TX- und RX-teil)
    P3SEL |= 0x30;              // P3.4,5 = USART0 TXD/RXD
    P3DIR |= 0x10;              // P3.4 = output direction
    UCTL0 &= ~SWRST;            // USART freigeben
  }

  if (IR0==0)  IE1 |= URXIE0;   // IR0: 0 -> nur RX-interrupt an
  if (IR0==1)  IE1 |= UTXIE0;   // 1 -> nur TX-interrupt an
  if (IR0==2)  IE1 |= URXIE0 + UTXIE0;  // 2 -> TX- und RX-interr. an
  if (IR1==1 || IR1==2) IFG1 &= ~UTXIFG0;  // init. interr.-flag loesch.

  //================ USART 0 ======================//
}

Gruß

Ricardo

von Stephan P. (steph0815)


Lesenswert?

@ Ampfing
Bit habe ich jetzt vor der Initialisierung gesetzt. Der Takt ist da. Er 
wird ohne Vorteiler vom 32768kHz Quarz abgegriffen.

@ Wolfgang-G
Nach meiner Berechnung wurde eine Baudrate von 9600 gewählt. Errechnet 
sich aus der Quarzfrequenz(32768kHz)/9600Baud = 3.413. UBRx0 = 0x0003 
und das Modulationsregister mit 0x4A. Werte und Berechnung im Datenblatt 
zu finden.

Das ganze funktioniert jetzt ohne Probleme. Das Problem lag einzig darin 
das ich die P3SEL und P3DIR Register beschrieben habe bevor ich das 
SWRST Bit gelöscht habe. Um es euch zu zeigen hier mein Code der nun 
ohne Probs funzt.
1
// Init USART0  
2
void init_USART0 (unsigned int baudrate, unsigned char IR0)  
3
//------------------------------------------------------------------------------
4
{  
5
  UCTL0 = SWRST + CHAR;  // set 8bit, none parity and 1 stoppbit    
6
  UTCTL0 |= SSEL0;    // set ACLK as USART0_CLK
7
  
8
  UBR00 = 0x03;
9
  UBR10 = 0x00;
10
  UMCTL0 = 0x4A;
11
  
12
  ME1 |= UTXE0 + URXE0;   // enable UART0 RX&TX
13
  UCTL0 &= ~SWRST;
14
  
15
  P3SEL |= 0x38;      // enable special funktion on PIN3.3, 3.4, 3.5
16
  P3DIR |= 0x18;       // set direction, PIN3.3, 3.4 OUTPUT
17
  
18
  if (IR0 == 1) IE1 |= URXIE0;   // enable UART0 RX ISR
19
  if (IR0 == 2) IE1 |= UTXIE0;   // enable UART0 TX ISR
20
  if (IR0 == 3) IE1 |= UTXIE0+URXIE0;   // enable UART0 TX&RX ISR  
21
}
22
23
//------------------------------------------------------------------------------
24
// send character  
25
void send_USART0 (unsigned char out_char)  
26
//------------------------------------------------------------------------------
27
{
28
  while((IFG1 & UTXIFG0) != UTXIFG0);
29
  TXBUF0 = out_char;
30
}
Mein einziges Problem ist jetzt nur noch das ich den Clock der UART0 
nicht ausgegeben bekomme. Es ist der PIN3.3 welcher auch mit 
initialisiert wurde (P3SEL |= 0x38;  P3DIR |= 0x18;) Aber das spielt 
jetzt kaum noch eine Rolle.

mfg
Stephan

von Christian R. (supachris)


Lesenswert?

UART Clock gints ja auch nicht. Höchstens USART Clock, im SPI Modus. Im 
UART MOdus gibts nur TXD und RXD.

von Stephan P. (steph0815)


Lesenswert?

Ach so ok, ich hatte das so verstanden das man den Clock mit dem die 
Schnittstelle arbeitet, sprich den eingestellten ACLK, ausgeben kann. 
Aber jetzt versteh ich das!

THX
Stephan

von Jens B. (meddle)


Lesenswert?

Hallo,
hab jetzt auch ein bißchen mit der seriellen Schnittstelle rumprobiert. 
Habe folgende Funktionen für Initialisierung und Aufruf: (MSP430F1611 - 
TXD0 auf PIN 3.4 RXD0 auf Pin 3.5)
1
void InitUSART0()
2
{
3
  UCTL0 = SWRST + CHAR + PENA;
4
  UTCTL0 |= SSEL_2;                     // SMCLK als UCLK festlegen
5
6
  //http://mspgcc.sourceforge.net/baudrate.html
7
  UBR00=0xA0; UBR10=0x01; UMCTL0=0x00; /* uart0 8000000Hz 19198bps */
8
9
10
  ME1 |= UTXE0 + URXE0;   // enable UART0 RX&TX
11
12
  UCTL0 &= ~SWRST;
13
14
  P3DIR |= 0x10;
15
  P3SEL |= 0x30;
16
17
  IE1 |= UTXIE0+URXIE0;  //      2 -> TX- und RX-interrupt anschalten
18
19
20
}
21
22
void SendUSART0c(char c)             // ein einzelnes zeichen über die serielle schnittstelle (USART0) senden
23
                                     // FJG: Obacht: x12xx : IFG1 => IFG2 !
24
{
25
  while (!(IFG1 & UTXIFG0));           // warten, bis USART0 TX-buffer sendebereit
26
  TXBUF0 = c;
27
}

Die Interrupts wurden nach der Initialisierung mit _EINT(); aktiviert. 
Problem ist nun, dass der in der Send-Funktion in der While-Schleife 
hängenbleibt. Wenn ich die while-Schleife testweise weglasse, 
funktioniert es, das gesendete Zeichen kommt im Terminal an. Aber das 
klappt vielleicht bei einzelnen zeichen, aber wenn ich strings senden 
will, sollte man ja schon schauen, ob die Schnittstelle sendebereit ist. 
SMCLK ist 8Mhz, Baudrate 19200. Warum wird das TX-Flag nicht gesetzt und 
das Programm hängt damit in der While-Schleife?

von Christian R. (supachris)


Lesenswert?

UTXIE Bit setzen und dann keine ISR für USART0_TX...das kann nicht 
klappen. Je nach Compiler wird dann wenigstens ein RETI in die Interrupt 
Vector Tabelle eingetragen, allerdings wird eben dann das TF-Flag eben 
sofort gelöscht.

von Jens B. (meddle)


Lesenswert?

wenn ich diese Zeile weglasse, funktioniert es immernoch nicht.
1
IE1 |= UTXIE0+URXIE0;  //      2 -> TX- und RX-interrupt anschalten

von Jörg S. (joerg-s)


Lesenswert?

1
while (!(IFG1 & UTXIFG0));   // warten, bis USART0 TX-buffer sendebereit
UTXIFG0 ist 1 wenn der Buffer FREI ist. D.h. das "!" muss weg.

von Jens B. (meddle)


Lesenswert?

while(1) bleibt ja in der Schleife, aber der soll ja raus, wenn 
sendebereit. also while(!1). das müsste doch richtig sein

von Jörg S. (joerg-s)


Lesenswert?

Öhh, ja, ist richtig, war wohl zu früh am morgen :)

Was steht denn im IFG1 Register wenn du bei der while Schleife stehen 
bleibst?

von Jens B. (meddle)


Lesenswert?

da steht ne glatte "0"

von Jens B. (meddle)


Lesenswert?

ach mist, da war vom vielen ausprobieren eine zeile, die da nicht 
hingehörte. jetzt scheint das was supachris sagte zu stimmen. IE1 raus 
und es funktioniert.

besten Dank.

Ist es eigentlich richtig so, dass ich meine Probleme an die schon 
bestehenden Threads zu bestimmten Themen hänge oder lieber einen neuen 
aufmachen? Denke, so ist es übersichtlicher

von Christian R. (supachris)


Lesenswert?

Ist auch logisch. Wenn es der GCC ist, wird in die Stelle für den USART 
0 TX in die Vektor Tabelle ein RETI eingetragen (bzw. die Adresse des 
unexpected ISR handlers). Tritt nun der Interrupt ein (also Senden 
beendet), dann wird vor dem Einsprung in die ISR das Flag schon wieder 
gelöscht, weil es ein Single-Source Interrupt ist. Da die ISR nur den 
Rücksprungbefehl enthält, landest du gleich wieder im richtigen 
Programm, aber das Flag ist nie gesetzt.

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
Noch kein Account? Hier anmelden.