UART-Problem beim Empfangen eines Zeichens

Derzeit arbeite ich mit zwei MSP430G2553-Mikrocontrollern für ein Schulprojekt und muss UART verwenden, damit sie miteinander kommunizieren. Der Sende-MSP430 soll immer dann ein Zeichen senden, wenn ein Benutzer ein Passwort richtig eingibt, um einen Eingang zu öffnen. Die Tür wird durch einen Servomotor auf dem empfangenden MSP430 simuliert. Mein aktueller Code funktionierte sehr gut, aber das Servo öffnete und schloss sich weiter; Die einzige Möglichkeit, dies zu stoppen, bestand darin, den MSP430 zu trennen oder auszuschalten. Als ich das 'UCA0RXBUF'-Register überprüfte, stellten wir fest, dass das Zeichen im Register verblieb und nicht klar war. Wir haben vergeblich versucht, eine Null zu drücken, um das Register zu löschen. Mein Code enthält eine Reihe von .c-Dateien, um die Initialisierung des UART einfacher zu machen. Anbei ist mein aktueller Code und vielleicht können Sie auf einen Fehler oder Syntaxfehler hinweisen,

#include <msp430g2553.h>
#include <string.h>
#include "uartMsp.h"
#include "adcMsp.h"

void door(void);
void delay(void);
void buzzer(void);
void door2(void);
void door3(void);


volatile int i, x;
char received = 0;
unsigned int mode = 1;

void main(void){
//Setup
WDTCTL = WDTPW + WDTHOLD;// Stop Watchdog Timer

//Setup Timer A0.1 and Port 1.6
P1DIR |= BIT6;//Output for SERVO PWM
P2DIR |= BIT7;//Button to shut off buzzer
P1SEL |= BIT1 + BIT6;
P1SEL2 &= ~(BIT6);//??
TA0CTL = TASSEL_2;//Setup Timer
TA0CCTL1 = OUTMOD_6;
TA0CCR0 = 20000;

//Setup DCO
DCOCTL  = CALDCO_1MHZ;    //DCO at 1MHz
BCSCTL1 = CALBC1_1MHZ;    //DCO at 1MHz

//Setup ADC
ADC10CTL0    = ADC10ON + ADC10IE;             //Turn on ADC and Enable interrupts.
ADC10CTL1    = INCH_5;              //Pick an input to sample from (Any Port 1 Pin EXCEPT P1.0 or P1.6; those belong to the LEDs)
ADC10AE0     = BIT5;                //Set your pin to analog. Hint: BITx = P1.x

__delay_cycles(500000);

clock_init();                // Set clock frequency to 1 MHz
serial_init_inter();     // Initialize UART module
_enable_interrupts(); //Enable General Interrupts. Best to do this last.

while(1) {
    received = UCA0RXBUF;
    UCA0RXBUF = 0;
    if(received == 'o'){
        received = 0;
        door();

    }
    else if(received == 'b'){
        received = 0;
        buzzer();
    }
    else if(received == 'u'){
        received = 0;
        door2();

    }
    else if(received == 'e'){
        received = 0;
        door3();

    }
    ADC10CTL0 |= ENC + ADC10SC;
}//create an infinite loop that does nothing (or goes into low power mode)
}//End of main

// ADC10 Interrupt Service Routine
#pragma vector = ADC10_VECTOR
__interrupt void ADC10_ISR( void ) {
x = ADC10MEM;
if((x > 700) || (x < 300)){
    P1OUT |= BIT7;
    while((P1IN & BIT4) != BIT4){}
    delay();
    delay();
    P1OUT &= ~BIT7;
}
}//End of ADC10_ISR

//Door function
void door(void){
TA0CCR1 = 1500;
TA0CTL |= MC_1;//Setup Timer
delay();
TA0CCR1 = 750;
delay();
TA0CTL |= MC_0;//
}//End of door

void delay(void){
volatile unsigned j, k;
for(j=4;j>0;j--){
    for(k=20000;k>0;k--);
}
}

void buzzer(void){
P2OUT |= BIT5;
delay();
P2OUT &= ~BIT5;
}

void door2(void){
TA0CCR1 = 1500;
TA0CTL |= MC_1;//Setup Timer
}

void door3(void){
delay();
TA0CCR1 = 750;
delay();
TA0CTL |= MC_0;//

}
Verwenden Sie immer selbsterklärende Namen für globale Variablen. Und dies ist kein Debugging- oder Review-Service. Siehe Wie man ein [mcve] fragt und bereitstellt.
Es sieht so aus, als ob Sie den UART-Eingangsdatenpuffer lesen, ohne seinen RX-Status zu überprüfen und zu ignorieren, dass Sie eine serielle Interrupt-Routine haben. Das Dateneingangsregister wird nicht gelöscht, indem darauf geschrieben wird: Das Lesen auf einem typischen UART löscht das rx-Daten-Flag. Sie lesen das Datenregister dann nicht erneut, bis das rx-Datenflag Sie dazu auffordert.
Und während ich darüber nachdenke, eine whileSchleife zu haben, die auf den Status wartet, und eine delayFunktion innerhalb einer ISR wie your __interrupt void ADC10_ISRare cardinal sins aufzurufen . Finden Sie besser einen anderen Weg, um den Code zu strukturieren.
@WeatherVane Danke für deinen Beitrag. Der aktuelle Code würde also nicht richtig funktionieren, da der RX nicht extrahiert und gelesen wird. Ich denke, dass die Verwendung des entsprechenden Pragmas ISR das Problem vereinfachen würde. Liege ich mit dieser Annahme richtig? Vielen Dank auch, dass Sie mich über meine aktuelle Verletzung der Struktur informiert haben. Ich werde den Code effizienter strukturieren.
@Olaf Ich entschuldige mich, wenn dies eine Unannehmlichkeit für Sie ist. Ich habe nicht nach jemandem gesucht, der meinen Code für mich debuggt, sondern mir Input gibt, der für das Erlernen des Programmierens relevant ist, damit ich darin effizienter werden kann.
@olaf Wenn dies kein Debugging-Dienst ist, was in aller Welt ist es dann?
@nicomp: Lesen Sie die FAQs, siehe How to Ask . Dies ist eine Q&A-Site.
@Olaf, und er hat ein Q gefragt, das ein A benötigt. QED.
@nicomp: Sie haben vergessen, die Einschränkungen zu überprüfen. Mit Ihrer Argumentation wäre auch die Frage, wie man eine Kleinigkeit macht, vollkommen gültig.
@Olaf Es ist eine Frage zu UART.
@nicomp Ich hatte offensichtlich eine Frage. Danke für die Richtlinien. Es ist nicht so, dass ich sie nicht schon einmal gelesen hätte. Das ist nicht meine erste Frage.
@MarineUTEP Kopiere das. Frage weiter und ignoriere die Negativität.

Antworten (1)

Das Hauptproblem besteht wahrscheinlich darin, dass Sie nicht warten, bis ein neues Zeichen empfangen wird, bevor Sie das UCA0RXBUFRegister lesen. Sofern Sie keinen Interrupt-basierten Ansatz verwenden, sollten Sie eine Busy-Schleife wie folgt ausführen:

while(!(UC0IFG & UCA0RXIFG)); /* wait for UCA0RXIFG to become set */
received = UCA0RXBUF;  /* read the received character */

Sie zeigen hier nicht den sendeseitigen Code, aber die Idee dort ist dieselbe - schreiben Sie in das TXBUFRegister und warten Sie dann, bis das Byte übertragen wird. Oder verwenden Sie Interrupts, um einen wirklich asynchronen Betrieb über den UART zu erhalten (das "A" bedeutet asynchron).

Allgemein denke ich, dass Sie hier einfach den falschen Ansatz haben. Warum nicht einen der synchronen Busse verwenden? Die MCU unterstützt SPI und I2C. Normalerweise wird bei der Zusammenarbeit zwischen zwei MCUs eines dieser Protokolle verwendet, wobei eines für den Master-Modus der MCUs und das andere in den Slave-Modus versetzt wird. Der synchrone Datenaustausch ist im Allgemeinen zuverlässiger und Sie müssen sich nicht um Dinge wie die MCU-Geschwindigkeitskalibrierung kümmern.

Wir haben SPI und I2C noch nicht im Unterricht behandelt, aber ich werde mich definitiv damit befassen und etwas recherchieren. Außerdem habe ich herausgefunden, was ich falsch gemacht habe. Ich habe nicht dieselbe Konfiguration für den Sendecode verwendet. Alles, was ich tun musste, war, die Variable received = UCA0RXBUF;in zu ändern c = UCA0RXBUF;, weil das der Sendecode war. Es hat mein Problem behoben und ich konnte die Interrupt Service Routine verwenden, um meinen Code fertigzustellen. Vielen Dank für Ihr Feedback und ich werde mich auf jeden Fall mit SPI und I2C befassen.