7
\$\begingroup\$

I am receiving bytes from my UART as uint8. How do I convert these bytes into ASCII? I am using Atmel 6.0 and my microcontroller is ATMega16L.

EDIT

I am using an android phone to send and receive information to a Wifi module (RN-131) from Roving networks. The wifi module connects to the microcontroller (atmega16L) through UART. Whatever the wifi module receives from the phone is transmitted out its UART. Similarly, whatever is written to its UART is transmitted out through wifi.

Now, what I'm trying to do is send a string from the phone which gets converted into bytes. The code is shown below:

PrintWriter out = new PrintWriter(new BufferedWriter(new outputStreamWriter(socket.getOutputStream())), true);
out.println("Eclipse");

here, the 'BufferedWriter' - Constructs a new BufferedWriter, providing out with a buffer of 8192 bytes. and 'PrintWriter' - Constructs a new PrintWriter with out as its target writer. The parameter autoFlush determines if the print writer automatically flushes its contents to the target writer when a newline is encountered.

now to program the microcontroller, I'm using AVR studio 6.0

uint8_t data;
char arr[32];
data = UDR;
length = strlen(data);
itoa(data, arr, 10);

But what I receive is "50, 53, 52" even when I'm sending "Eclipse".

EDIT 20th June 2012

Here is my code till now. Note: the code is written in AVR Studio 6.0 so it looks a bit different to other codes written in AVR Studio 4.18.

/**************************************************
 *  Includes
 */
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
#include "../../../../../../Program Files (x86)/Atmel/Atmel Studio 6.0/extensions/Atmel/AVRGCC/3.4.0.65/AVRToolchain/avr/include/avr/iom16.h"

/**************************************************
 *  Global Variables
 */
int trigger=0, length=0;
int i=0, n=0;
uint8_t data;
char arr[8];

/**************************************************
 *  Defines
 */
#define LED_PORT PORTA
#define RED_ON (PORTA | 0x01)
#define RED_OFF (PORTA & ~0x01)
#define YELLOW_ON (PORTA | 0x02)
#define YELLOW_OFF (PORTA & ~0x02)
#define GREEN_ON (PORTA | 0x04)
#define GREEN_OFF (PORTA & ~0x04)

/**************************************************
 *  Function Prototypes
 */
void initialize(void);                      
void time_display(void);

int main(void){
    initialize();

    while(1){
        //TODO:: Please write your application code

    }
}

void initialize(void){

    DDRA = 0x07; //PORTA pins 0,1,2 set as outputs
//  DDRD = 0x02; //PORTD pin 1 is output (TX) and pin 0 is input (RX)

    //Timer SETUP
    TCCR1A = 0x80; //OCR1A enable in CTC mode
    TCCR1B = 0x0C; //CTC mode, 256 prescale 
    TIMSK = 0x10; //CTC on OCR1A enabled, overflow disabled
    OCR1A = 2000; //OCR value set to get an interrupt every 1 second (15624)

    //USART SETUP
    UCSRA = 0x00; //no Frame Error, no parity error, no Data OverRun
    UCSRB = 0xE0; //receiver enable, transmitter enable (0x18)
    UCSRC = 0x8E; //Asynchronous USART mode, no parity, 1 stop bit, 8-bit character size, Data transmitted on rising edge and received on falling edge of the clock
    UBRRL = 51; //Baud rate of 9600bps
    UBRRH = 0;

    sei(); //Global interrupt enable
}

//timer capture interrupt
ISR(TIMER1_COMPA_vect){

}

ISR(USART_RXC_vect){
    LED_PORT = RED_ON;
    _delay_ms(100);

    for(int x=0; x<5; x++){
        arr[x] = UDR;
    }

    LED_PORT = RED_OFF;
    _delay_ms(100);

    trigger = 1;
}

ISR(USART_UDRE_vect){
    if(trigger >= 1){
        LED_PORT = GREEN_ON;
        _delay_ms(200);
        LED_PORT = GREEN_OFF;
        _delay_ms(200);

        UDR = data; //transmit the data
        trigger = 0;
    }
}
\$\endgroup\$
20
  • 1
    \$\begingroup\$ Um, uint8 is a 0 to 255 integer already, which by definition = char ... how much more ASCII could it be? \$\endgroup\$ Jun 19, 2012 at 1:28
  • \$\begingroup\$ i know that too, but im receiving rubbish from my UART using uint8 \$\endgroup\$ Jun 19, 2012 at 1:54
  • \$\begingroup\$ Try casting each byte as a char. \$\endgroup\$ Jun 19, 2012 at 1:58
  • 1
    \$\begingroup\$ Print your received data as hex or an integer, and look it up on an ASCII table. That usually produces some clues as to what is going on. The "little diamonds" could mean a lot of things, the most likely that whatever is displaying the characters simply does not know how to interpret them, and the diamond character is simply a place-holder. \$\endgroup\$ Jun 19, 2012 at 3:51
  • 1
    \$\begingroup\$ Also, you are using strlen() on a 16 bit integer. the strlen() function is expecting a string, so it is counting locations in memory into it finds the termination ascii character '\0'. I think you are still confused on what your data is represented as still. Can you maybe expand your main post and add more detail> (your code, set up, etc) \$\endgroup\$
    – justing
    Jun 19, 2012 at 5:08

2 Answers 2

6
\$\begingroup\$

**EDIT 6/19/2012***********************************************************

Ok, so after you added your code I have made a few changes for you to try (and to understand!)

First of all, we have declared our character array volatile so that the compiler knows it may change unexpectedly from an interrupt. Likewise, we have created a variable to keep track of our index position in the array:

/**************************************************
 *  Global Variables
 */
int trigger=0, length=0;
int i=0, n=0;
uint8_t data;
volatile char arr[8];
volatile char arr_idx = 0;

Next, i have edited your UART initialization code based on the ATMega16L Datasheet and your comments:

//USART SETUP
UCSRA = 0x00; //no Frame Error, no parity error, no Data OverRun
UCSRB = 0xD8; //receiver enable, transmitter enable (0x18)
UCSRC = 0x86; //Asynchronous USART mode, no parity, 1 stop bit, 8-bit character size, Data transmitted on rising edge and received on falling edge of the clock
UBRRL = 51; //Baud rate of 9600bps (8MHz clock?)
UBRRH = 0;

Look closely at the datasheet (page ~166). I believe I have correctly configures the UART now based on your comments. I will not go over each bit, but you should. Please ask questions if you think I made a mistake or you don't get something.

Finally, I have edited your ISR routine:

ISR(USART_RXC_vect){
    arr[arr_idx] = UDR;
    arr_idx++;
    arr_idx %= 7; //make sure index stays within array

    trigger = 1;
}

Note that, the ISR is executed every time a single byte (or character) is received. This means we want to process the single character (add it to our array), increment our index location, and get out of it quickly so that we are ready for the next character to come in.

You now need to look at the arr[] through whatever method you have been using and see if it is now receiving your characters correctly.

**END OF EDIT****************************************

One option is to just use one of the available libraries included in AVR Studio:

#include <stdlib.h>

and then somewhere in your code...

char num2[5]; //create a buffer for the ascii string
itoa(num1,num2,10); //convert the integer (num1) to an ascii string (num2) in base 10

If you are then displaying this on a character LCD, you can send the num2 array to the lcd print function that you are using.

If you are concerned about code space you can fairly easily write your own simple itoa (integer to ascii) function. You will need to grab each "tens" position from your integer using the "/" and "%" operators and convert it to ascii:

enter image description here
(source: asciitable.com)

From the table above, you can see that once you grab each digits value (0-9), just add 48 to it to convert it into the ascii character representation.

EDIT

Ok, so after you adding your information and assuming:

  • You have correctly initialized the UART baud rate etc on your ATMEGA
  • The android code is successfully sending the ascii bytes across the WiFly and out of its UART

Then the microcontroller should already be receive these characters as Ascii, and the ITOA function is not what is needed here and in fact would mess up your string data coming in.

It could still be a lot of different things though...How are you viewing the uart data that is being received by your microcontroller?

\$\endgroup\$
10
  • \$\begingroup\$ well I look at the watch window for incoming characters, I have seen that when I send a string to the microcontroller's UART which is "Eclipse" what I receive is this: {171, 70, 254, 70, 70, 70, 70} in my character array. What does this mean? I dont think this is the data I'm suppose to receive \$\endgroup\$ Jun 19, 2012 at 20:59
  • \$\begingroup\$ @DavidNorman The problem is complicated enough that it is still guess work on what could be wrong. If you are still having troubles after more attempts, you should post your actual C file code (whole code, not just snippets) so that we can properly debug it. Once we know you are reading the UART correctly we can better isolate the problem. \$\endgroup\$
    – justing
    Jun 19, 2012 at 21:19
  • \$\begingroup\$ you're right ill upload my code now \$\endgroup\$ Jun 19, 2012 at 21:27
  • \$\begingroup\$ @DavidNorman, justin says something important here: Note that, the ISR is executed every time a single byte (or character) is received. Every time that happens, UDR will have a new value. You don't need to have the loop within the ISR. Hopefully that will give you enough insight to solve the problem. \$\endgroup\$
    – Jon L
    Jun 19, 2012 at 22:50
  • 1
    \$\begingroup\$ @justin - i got my code working, the problem was the delays in the interrupt function, and the changes from your code above helped. so yeah, thanks a lot \$\endgroup\$ Jun 20, 2012 at 9:50
4
\$\begingroup\$

An ASCII character is simply an 8-bit number that is displayed as a character when you call functions like "printf" that are meant to display characters.

In C, a string is an array of these characters (or 8-bit numbers) that is terminated with the value 0 or "null-terminated".

So when you send a string like "Eclipse", you're actually sending numbers already. In fact, this is what it looks like when you send it:

[69, 99, 108, 105, 112, 115, 101, 0]

Passing this to printf, for example, will print "Eclipse". Note the null-terminator. Also note that you don't need any function to convert this.

itoa is a function used to convert numbers to their string representation. For example:

 char str[32];
 itoa(223, str, 10);
 printf("%s", str);

This would print out "223". The actual number values that reside in str[] that we know of for sure: [50, 50, 51, 0]. From your description, I'm pretty sure that this is not what you want.

Don't always assume ASCII encoding. Here's an extremely widely-used character encoding in use at the application level and web development: UTF-8 - These characters are not always 8-bits, some of them are 16-bits to represent characters in other languages for example.

EDIT:

There is something that you need to know about a typical UART peripheral on an AVR (not meant to be a blanket statement for all UART's on all uC's, just the family that you are using). They work like this: when a byte comes in, it gets put into a single-byte memory location: UDR - When you do a read from this register, it will be cleared. If new data is coming in on the UART and you haven't read from this register yet? It's going to get overwritten with the new value. Entire strings will not be placed here. Just single characters. All of this is described in the datasheet for your uC, I highly recommend getting familiar with it.

Hopefully, that will give you enough information to understand why strlen(data) won't work. If you're still not sure why, read over the datasheet, read up on what happens when you make this assignment in C data = UDR; and also read what strlen's parameters are, and note that one of them is a pointer to a string. If you don't have a good grasp on pointers, I highly suggest this: http://www.cplusplus.com/doc/tutorial/pointers/

If this all sounds like too much work to you, then I suggest picking up an Arduino instead. Don't get me wrong, it would be awesome if you could grasp all of this and be using plain C on your AVR, but if there are too many gaps in your knowledge at the moment, then it may be a bit overwhelming.

Now, on to what you want to accomplish. You mentioned in your comment that you wanted to loop until you get a full string out of the UART, storing it into a buffer, where you will then process it as a command. Ok. Totally do-able, in fact, a somewhat common technique.

Here's some psuedo code for you:

i = 0;
char str[32];

while(forever) {
   if (data_byte_is_available) {
        if (i == 31)
             i = 0;
        str[i] = UDR;
        i++;
   }
   print(str);
}

Try to figure out what you need to do for a data_byte_is_available function. The datasheet is your friend. Also, how are you displaying what is coming in on the uC's UART? Whatever that is, substitute the print I have up there with that. I hope there's no issues with whatever you're using there...

\$\endgroup\$
2
  • \$\begingroup\$ @DavidNorman, if you'd like to add some more information, please edit your original post. I see you were trying to show me an ISR - great. You can post it in your original question. \$\endgroup\$
    – Jon L
    Jun 19, 2012 at 7:15
  • 1
    \$\begingroup\$ ASCII is only 7-bit. The character sets used by modern computers tend to be based on ASCII, such as ISO 8859-1 (Latin-1). More details at en.wikipedia.org/wiki/ISO/IEC_8859-1 and en.wikipedia.org/wiki/Extended_ASCII \$\endgroup\$ Jun 19, 2012 at 7:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.