This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CCS/MSP430G2553: How to check String Command Sent over UART RX / Echoed back over UART TX in an If-Statement, and Convert last three Characters into an Integer??

Part Number: MSP430G2553

Tool/software: Code Composer Studio

I posted a very similar question to this one a while ago, and I made several adjustments since then. The project I am working on involves a temperature sensor fan controller and the MSP430G2553. ADC values are measured from the sensor, and an error difference between a preset desired temperature and the current temperature are both printed over UART TX to the PC. The fan increases in speed via PWM, dependent on three if-statements that check the ADC10MEM value (i removed many other if-statements for cleaning). I used CoolTerm, by the way, to see the printed values. 

The last thing I want to do is send multiple-character commands over UART RX, to set any desired temperature value. Right now, single character commands such as if(UCA0RXBUF == 'a') can set a SetDesiredTemp = 100. Also, I can type any random string of characters over UART RX, and the exact same string will be echoed over UART RX back to PC. This means I can confirm that my MSP430 is able to read a full string of characters and send it back to PC.

Here's where my issue arises. I know UART RX is doing what I want it to do, but using this code below, how can I check the string I sent to RX (or check the string echoed over TX) to see if a string command such as "Set Desired Temperature = " has been entered? And more importantly, how can I then convert the last three characters "100" into an integer that can be plugged into a SetDesiredTemp = 100 line?

I'll post my full code here for all to see. It compiles. I'm mainly hoping where in this code I can do the things described above, debugging for hours has gotten me nowhere.

#include <msp430g2553.h>
#include <stdio.h>
#include <string.h>

//Closed Loop: Temperature Sensor Fan Controller

/*** Initialize UART-Related Code ***/
volatile unsigned int current = 0; // store the currently read ADC10MEM at the beginning of the loop.
volatile unsigned int timer_count = 0;
static char data;
char buffer[32];
char buffer2[32];
void init_uart();
void init_timer();
void start_conversion();
void UARTSendArray(unsigned char *TxArray, unsigned char ArrayLength);

/*** Initialize Temperature Variables ***/
int error = 0; // subtract current from current to determine fan speed.
int SETtemperror = 370; //the default room temperature for making the error temperature values.

void (*uart_rx_isr_ptr)(unsigned char c);

void uart_set_rx_isr_ptr(void (*isr_ptr)(unsigned char c)) 
{
	uart_rx_isr_ptr = isr_ptr;
}

void uart_putc(unsigned char c)             // print to PC over TX one character at a time.
{
	while (!(IFG2&UCA0TXIFG));              // USCI_A0 TX buffer ready?
  	UCA0TXBUF = c;                    		// TX
}

void uart_puts(const char *str)             // print any string message to PC with this function.
{
     while(*str) uart_putc(*str++);
}

void uart_rx_isr(unsigned char c) { // UART RX Commands go here?
	uart_putc(c);
	P1OUT ^= BIT0;		// toggle P1.0 (red led)
	
	switch(c) {
        case 'a': {
            SETtemperror = 460;
            uart_puts((char *)"\n\rDesired Temperature is now: 460\n\r");
        }
    }
}

void init_uart() 
{
	P1SEL  = BIT1 + BIT2;	// P1.1 = RXD, P1.2 = TXD
	P1SEL2 = BIT1 + BIT2;	// P1.1 = RXD, P1.2 = TXD
	UCA0CTL1 |= UCSSEL_2;	// SMCLK
	UCA0BR0 = 104;			// see baud rate divider above
	UCA0BR1 = 0;
	UCA0MCTL = UCBRS0;		// modulation UCBRSx = 1
	UCA0CTL1 &= ~UCSWRST;	// ** initialize USCI state machine **
	IE2 |= UCA0RXIE;		// Enable USCI_A0 TX interrupt
}

void UARTSendArray(unsigned char *TxArray, unsigned char ArrayLength) 
{
    while(ArrayLength--) { // Loop until StringLength == 0 and post decrement
        while(!(IFG2 & UCA0TXIFG)); // Wait for TX buffer to be ready for new data
        
        UCA0TXBUF = *TxArray; //Write the character at the location specified py the pointer
        TxArray++; //Increment the TxString pointer to point to the next character
    }
}

void init_timer() 
{
	TA1CTL |= TACLR;		// reset timer
	TA1CTL  = TASSEL_2		// SMCLK
			+ ID_0			// input divider = 1
			+ MC_2;			// continuous mode, interrupt disabled
	TA1CCTL0 = OUTMOD_2		// compare mode
			+ CCIE			// interrupt enabled
			+ CCIFG;
			
	/*** Timer0_A Set-Up ***/
    DCOCTL = 0;							// Select lowest DCO settings
	BCSCTL1 = CALBC1_1MHZ;				// Set DCO to 1 MHz
	DCOCTL = CALDCO_1MHZ;
    TA0CTL |= TASSEL_2 | MC_1 | ID_3;
    TA0CCR0 |= 800;
    TA0CCTL1 |= OUTMOD_7;
    TA0CCR1 |= 0;
}

void start_conversion() 
{
	if ((ADC10CTL1 & ADC10BUSY) == 0) {	// if not already converting
		//P1OUT ^= 0x40; //green led
		ADC10CTL0 |= ADC10SC;
		ADC10SA = (unsigned) &current; // store latest ADC value into address
	}
}

int main(void)
{
    WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
    init_uart();
    init_timer();

    /*** GPIO Set-Up ***/
    P1DIR |= BIT6; // PWM output
    P1SEL |= BIT6;
    P2DIR |= BIT0 + BIT1 + BIT3 + BIT4;

    /*** ADC10 Set-Up ***/
    ADC10CTL0 = SREF_0 + ADC10SHT_3 + ADC10ON + ADC10IE + REFON + ENC; // ADC10ON, interrupt enabled. enable (but not yet start) conversions
    ADC10DTC1 = 1;			// one block per transfer
    ADC10CTL1 = INCH_3 + SHS_0 + ADC10DIV_3 + ADC10SSEL_3 + CONSEQ_0;	// clock source = SMCLK
    //ADC10AE0 |= BIT0;                         // PA.1 ADC option select
    
    // register ISR called when data was received
    uart_set_rx_isr_ptr(uart_rx_isr);

    // enable interrupts and put the CPU to sleep
	_bis_SR_register(GIE+LPM0_bits);

	unsigned char c = UCA0RXBUF;
	uart_putc(c);       // initialize retrieving of characters, initialize printing of characters.
	
	uart_puts((char *)"\n\rTemperature Controller: ON and READY\n\r");  // signal that the main block has been initialized

    unsigned int a = 0, delay = 50000, sec = 0;
    for (;;)
    {
        current = ADC10MEM;
        error = current - SETtemperror;   // Calculate error difference from preset temperature. abs() removed.
        
        //a = 0; sec = 0;                         // Delays to remove LED flickering
        //while (a < delay) { a++; }
        //while ((a >= delay) && (sec < 10)) { a = 0; sec++; }
        
        if (error < 10) {
            P2OUT &= ~BIT4; P2OUT &= ~BIT3; P2OUT &= ~BIT1; P2OUT &= ~BIT0; // 0000
            TA0CCR1 = 0; // TA0CCR1 = ADC10MEM
        }
        if ((error >= 10) && (error < 100)) {
            P2OUT &= ~BIT4; P2OUT |= BIT3; P2OUT |= BIT1; P2OUT &= ~BIT0; // 0000
            TA0CCR1 = 400; // TA0CCR1 = ADC10MEM
        }
        if(error >= 100) {
            P2OUT |= BIT4; P2OUT |= BIT3; P2OUT |= BIT1; P2OUT |= BIT0; // 1111
            TA0CCR1 = 800; // TA0CCR1 = ADC10MEM
        }
    }
}

#pragma vector=ADC10_VECTOR // ADC10 interrupt service routine
__interrupt void ADC10_ISR(void)
{
    __bic_SR_register_on_exit(CPUOFF);        // Clear CPUOFF bit from 0(SR)
}

// INTERRUPT HANDLERS
#pragma vector = TIMER1_A0_VECTOR
__interrupt void Timer1_A0(void) 
{
	timer_count++;
	if (timer_count > 16) { //default is 16 for 1 second refresh rate. set to 16 for slower data transfer
		timer_count = 0;
		start_conversion();

		IE2 |= UCA0TXIE; // activate TX interrupt
        IE2 |= UCA0RXIE; // Enable USCI_A0 RX interrupt
	}
}

#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCI0TX_ISR(void) 
{
    //P1DIR = 0x01;
	//P1OUT ^= 0x01; //red led
	
	unsigned int i = 0;					// iterator pointers
	sprintf(buffer, "temp measured: %d \n\r", (int)(current)); //output text to PC
	//uart_puts((char *)"MSP430 harduart\n\r");
	while (buffer[i] != '\0') {
		while (!(IFG2 & UCA0TXIFG));	// USCI_A0 TX buffer ready?
		UCA0TXBUF = buffer[i++];
	}
	
	unsigned int j = 0;					// iterator pointers
	sprintf(buffer2, "Error diff: %d \n\r", (int)(error)); //output text to PC
	while (buffer2[j] != '\0') {
		while (!(IFG2 & UCA0TXIFG));	// USCI_A0 TX buffer ready?
		UCA0TXBUF = buffer2[j++];
	}
	IE2 &= ~UCA0TXIFG; // reset interrupt flag
}

#pragma vector=USCIAB0RX_VECTOR
__interrupt void USCI0RX_ISR(void)
{
	if(uart_rx_isr_ptr != 0L) {         // if there are more characters to send to RX buffer, keep sending characters.
		(uart_rx_isr_ptr)(UCA0RXBUF);
	}
	
	switch(UCA0RXBUF) { // unsure where exactly the commands would go
        case 'd': {
            SETtemperror = 460;
            uart_puts((char *)"\n\rDesired Temperature is now: 460\n\r");
        }
    }
}

  • This is my re-attempt at getting the program to save the inputting RX string in a global buffer, outside of the RX interrupt. It seems to work already, looking at the image of printed strings. There are portions of code, mainly lines 22-42 and 120-129 and 202-204, that I grabbed from a GitHub page a bit ago, so I am unsure how exactly this code is saving into a global buffer. But I can confirm that a string command i send over RX, say "slkjdflksjdfklsjdklfjsd", the same command "slkjdflksjdfklsjdklfjsd" is echoed over TX back to PC, thus I believe a global buffer is already in this code. 

    I guess what I am looking to do is, somehow extract / check / read whatever string command I just entered and analyze it with an if-statement or something similar. This string is echoed back over TX, so maybe there is a way to read whatever string command was just echoed back? I'm just too unsure on how to proceed.

    I have tried running the code line-by-line in the debugger, and simply nothing is telling me where exactly the code saves the incoming RX data into a string / array, to be fed one character at a time back to TX. This process seems to be happening out of nowhere, and I was hoping to grab that string / array variable name to call it within an if-statement, assuming if-statements can check for something like "if (RXstring[0:25] == 'Set Desired Temperature = ') { SETdesiredtemp = strtoul( RXstring[26:28] ) }; //set desired temp to whatever 3-digit number is after the equals sign". I know the syntax in that if-statement is horrible, but that is precisely what I am looking to do, it seems impossible.

  • I would approach it as follows:
    1- Send a "start receiving a value" command. This should set your RX state machine to add the incoming bytes to a buffer.
    2- Read the bytes one digit at a time and increment buffer index (i.e. '1' at buffer index 0, '0' at buffer index 1...etc.)
    3- Send a "evaluate and use sent value" command. This command would then just be a "atoi()" function on the digits buffer to reset your RX state machine.
  • Hi,

    Have you had success getting UART communication to work as you intend or do you still have any outstanding questions?

    Best regards,
    Caleb Overbay

**Attention** This is a public forum