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.

UART displaying characters or number



Hi 

I have a ez430 RF2500, I managed to write a code for UART communication, learned from the wireless sensor monitor program. However, I can only get letters displayed correctly, while the number displayed as some symbol characters. I have tried to keep things the same, e.g long temp, int degC, char msg, but because I don't need to send those amount of data in that example, so I wrote my own.

__interrupt void Port1_ISR (void)

{

 

  int degC;

  long temp;

  int results; 

  char txBuffer[6];

    // when switch is pressed

  if(P1IFG & BIT2)

  {

    ADC10CTL0 |= ENC + ADC10SC;             // Sampling and conversion start

    results = ADC10MEM;

    temp = results;

    degC = ((temp - 673) * 423) / 1024;

    txBuffer[0]= degC &0xFF; ;

    txBuffer[1]= (degC>>8)&0xFF;

    txBuffer[2]= 'L';

    txBuffer[3]= 'O';

    txBuffer[4]= '.';

    //uartTxString(txBuffer);

    TXString(txBuffer, sizeof txBuffer);

    P1IFG &= ~0x04;

    P1OUT ^= BIT1;

  }

}

void TXString( char* string, int length )

{

  int pointer;

  for( pointer = 0; pointer < length; pointer++)

  {

    volatile int i;

    UCA0TXBUF = string[pointer];

    while (!(IFG2&UCA0TXIFG));              // USCI_A0 TX buffer ready?

  }

}

 

  • I think you are confused between numbers and digits.

    Try:

    txBuffer[0] = "1"; txBuffer[1] = "2"; txBuffer[2] = "3"; TXString (txBuffer, 3);

    You will see the three digits 1, 2, 3 as expected.

    But if you try:

    txBuffer[0] = 1; txBuffer[1] = 2; txBuffer[2] = 3; TXString (txBuffer, 3);

    You will not see the three numbers 1, 2, 3 you expect.

    "letters" and "digits" can be displayed. "numbers" cannot. You need to convert "numbers" into one or more "digits" before you can see them.

  • Weng,

    As OYC mentioned, you need to adjust your integer values into something that will be legable.

    Lets say that your degC is 500 degrees which is 0x01F4 in hex. After your first statment  you will have the value 244(0xF4) in txBuffer[0]. If you look at www.asciitable.com , you will see that this is not a valid number.

    You need to do a bit of formating of the data before you can send it.

    I usually do a quick hex conversion If I dont want to use printf. Something along the lines of:

    char hexvalues[] = "0123456789ABCDEF";

    Then you can do something like: 

    txBuffer[0] = hexValues[degC &0x0F];

    txBuffer[1] = hexValues[(degC &0xF0) >>4];

    txBuffer[2] = hexValues[ (degC>>12)&0x0F];

    txBuffer[3] = hexValues[ ((degC>>8)&0xF0) >> 4];

    However a quick note is that you will be displaying your degree C backwards. You are transmitting the LSB first followed by the MSB.  So you would see "F401"  instead of "01F4", these values are also in hex, so I use windows calculator to help convert back and forth.

    This was just some quick psuedo code to help explain the details, but should get you on your way.

    Hope this helps,

    Jason

     

  • Thank you for your reply, I think I know the reason behind, is rather I am transmitting a digital value or a ASCII representation of number. However, this piece of code is copied from the Wireless Sensor Monitor example, in Main_AP.c, so why there is no conversion in here please?

    I had tried putting the if statement of tempOffset, however my UART transmission became weird, the sent characters would replace the previous one, e.g when I transmit the first letter, it is in position 1, the second letter, in position 1 ALSO, replace it, the third one now is in position 2, the forth one, position 1, fifth, position 2, sixth, position 3, seventh, position 1 and so on...

    volatile int * tempOffset = (int *)0x10F4;

    if(sSelfMeasureSem)

        {

          char msg [6];

          char addr[] = {"HUB0"};

          char rssi[] = {"000"};

          int degC, volt;

          volatile long temp;

          int results[2];

     

          /* Get temperature */

          ADC10CTL1 = INCH_10 + ADC10DIV_4;       // Temp Sensor ADC10CLK/5

          ADC10CTL0 = SREF_1 + ADC10SHT_3 + REFON + ADC10ON + ADC10IE + ADC10SR;

          /* Allow ref voltage to settle for at least 30us (30us * 8MHz = 240 cycles)

           * See SLAS504D for settling time spec

           */

          __delay_cycles(240);

          ADC10CTL0 |= ENC + ADC10SC;             // Sampling and conversion start

          __bis_SR_register(CPUOFF + GIE);        // LPM0 with interrupts enabled

          results[0] = ADC10MEM;                  // Retrieve result

          ADC10CTL0 &= ~ENC;

     

          /* Get voltage */

          ADC10CTL1 = INCH_11;                     // AVcc/2

          ADC10CTL0 = SREF_1 + ADC10SHT_2 + REFON + ADC10ON + ADC10IE + REF2_5V;

          __delay_cycles(240);

          ADC10CTL0 |= ENC + ADC10SC;             // Sampling and conversion start

          __bis_SR_register(CPUOFF + GIE);        // LPM0 with interrupts enabled

          results[1] = ADC10MEM;                  // Retrieve result

     

          /* Stop and turn off ADC */

          ADC10CTL0 &= ~ENC;

          ADC10CTL0 &= ~(REFON + ADC10ON);

     

          /* oC = ((A10/1024)*1500mV)-986mV)*1/3.55mV = A10*423/1024 - 278

           * the temperature is transmitted as an integer where 32.1 = 321

           * hence 4230 instead of 423

           */

          temp = results[0];

          degC = ((temp - 673) * 4230) / 1024;

          if( (*tempOffset) != 0xFFFF )

          {

            degC += (*tempOffset);

          }

     

          temp = results[1];

          volt = (temp*25)/512;

     

          /* Package up the data */

          msg[0] = degC&0xFF;

          msg[1] = (degC>>8)&0xFF;

          msg[2] = volt;

     

          /* Send it over serial port */

          transmitDataString(1, addr, rssi, msg );

     

          BSP_TOGGLE_LED1();

     

          /* Done with measurement, disable measure flag */

          sSelfMeasureSem = 0;

        }

    void transmitDataString(char data_mode, char addr[4],char rssi[3], char msg[MESSAGE_LENGTH] )

    {

      char temp_string[] = {" XX.XC"};

      int temp = msg[0] + (msg[1]<<8);

     

      if(!(data_mode & degCMode))

      {

        temp = (int)(((float)temp)*1.8)+320;

        temp_string[5] = 'F';

      }

      if( temp < 0 )

      {

        temp_string[0] = '-';

        temp = temp * -1;

      }

      else if( ((temp/1000)%10) != 0 )

      {

        temp_string[0] = '0'+((temp/1000)%10);

      }

      temp_string[4] = '0'+(temp%10);

      temp_string[2] = '0'+((temp/10)%10);

      temp_string[1] = '0'+((temp/100)%10);

     

      if(data_mode & verboseMode)

      {

        char output_verbose[] = {"\r\nNode:XXXX,Temp:-XX.XC,Battery:X.XV,Strength:XXX%,RE:no "};

     

        output_verbose[46] = rssi[2];

        output_verbose[47] = rssi[1];

        output_verbose[48] = rssi[0];

     

        output_verbose[17] = temp_string[0];

        output_verbose[18] = temp_string[1];

        output_verbose[19] = temp_string[2];

        output_verbose[20] = temp_string[3];

        output_verbose[21] = temp_string[4];

        output_verbose[22] = temp_string[5];

     

        output_verbose[32] = '0'+(msg[2]/10)%10;

        output_verbose[34] = '0'+(msg[2]%10);

        output_verbose[7] = addr[0];

        output_verbose[8] = addr[1];

        output_verbose[9] = addr[2];

        output_verbose[10] = addr[3];

        TXString(output_verbose, sizeof output_verbose );

      }

  • Weng Kou Chan said:
    However, this piece of code is copied from the Wireless Sensor Monitor example, in Main_AP.c, so why there is no conversion in here please?

    Maybe the conversion is done at the receiver side of the transfer? The monitor program gets binary values and prints them to screen using printf() - a library function tat converts binary values to readable text.

    I know, JavaScript and its brethren does automatically convert a number into a string, but at the cost of code size and performance. And it needs to know that one object is a nubmer ant the destination is a string. If you feed something into a bytestream such as RF or RS232, there is no information abotu what something migh tmean. If you receive a byte with the value 32, does it mean the number 32 or does it mean a space character? The recipient doesn't know. So the values are interpreted as ASCI characters - unless the recipient knows to handle them differently (by programming it to do so).

    Weng Kou Chan said:
    the sent characters would replace the previous one, e.g when I transmit the first letter, it is in position 1, the second letter, in position 1 ALSO, replace it, the third one now is in position 2, the forth one, position 1, fifth, position 2, sixth, position 3, seventh, position 1 and so on...

    Because certain binary values have a certain meaning when interpreted as ASCII characters.
    so 0x08 means backspace, 0x32 is a space, 0x0d resets the cursor to the beginning of a line, while 0x0a move the cursor one line down. 0x07 rings a bell and does not cause any screen action. There are others which have special meaning that is not related to screen output at all (and depending on the target software, they will show up as graphical characters).

    You send binary values and the recipient expects ASCII characters. That's like you're sending morse code and the recipient expects spoken words. All he will understand is 'de-deee-de-de-deee....'

  • Thank you so much for your detail explanation, honestly, I don't really understand how this works, especially the increment a counter and subtract, can you provide a little example to illustrate the process please?

    The basic way is to check whether the value is >10000. If it is, increment a counter and subtract 10000 until it isn't. Then you have the value of the 10k digit. 


  •  

    void send(unsigned int x){
    unsigned char count = 0;
    while(x>10000){ // x may be 0..65535 here
     count++;
      x-=10000;
    }
    putchar (0x30+count);
    count=0;
    while(x>1000){ // at this point, x is 9999 at max
     count++;
      x-=1000;
    }
    putchar (0x30+count);
    count=0;
    while(x>100){  // x is no more than 999 now
     count++;
      x-=100;
    }
    putchar (0x30+count);
    count=0;
    while(x>10){ // and here, x cannot be more than 99
     count++;
      x-=10;
    }
    putchar (0x30+count);
    putchar (0x30+x); // x is 0..9 at this point, everything above has been already subtracted.
    }

    This outputs a 5-digit string (with leading zeroes) for every int that might come.

    You can extend it to signed int by sending a '-' first if the value is negative, then subtracting it from 0 so it becomes positive. (be aware of a problem with -32768 then as there is no +32768 in a signed int)

    You can also extend it to suppress the leadign zeroes by setting an initially false boolean to true inside the while loops and only print the resulting value if the boolean is true (except for the last digit, which will always be printed)

    I don't say this is the most elegant solution, but the simplest and maybe the fastest one. And it took me no more time to write it than it took to type it into the keyboard.

  • In the Wireless Sensor Monitor example, the conversion from number to string occurs in the function transmitDataString(). Part of the temperature conversion to ASCII code:

      temp_string[1] = '0'+((temp/100)%10);
      temp_string[2] = '0'+((temp/10)%10);
      temp_string[4] = '0'+(temp%10);

    the voltage conversion to ASCII code:

     output_verbose[32] = '0'+(msg[2]/10)%10;
     output_verbose[34] = '0'+(msg[2]%10);

    Note that '0' is equal to 0x30. All that division and modulo math is equivalent to Jens-Michael Gross's code of repeated subtraction. The repeated subtraction code is probaby much faster.

    Implementations of the library function printf() usually use a more generic form of division/modulo method to handle different base or radix (binary, octo, decimal, hex) and to handle different data sizes (8 ,16,32,64 bits). It more complicated to use as the resulting string is in reverse order. A little heavy in code size and execution time.

     

  • Norman Wong said:
    temp_string[1] = '0'+((temp/100)%10);

    Yes. That's a simple version of my code. On a PC, I'd do it this way too. A millisecond mro eor less doesn't matter here, and the x86 processor has a built-in integer division command.
    On a MC, however, such 'simple' code will often have a large negtive impact on performance.

    During my own developments, I once tried to do a calculation on sampled values every millisecond. I had to learn that the 8 divisions I mad every millisecond were eating 100% of the CPU power on 8MHz system clock. I replaced teh formula by using multiplications and shift operations and the same result was aquired with only 5-10% CPU load. Quite a difference.

**Attention** This is a public forum