Serial data transmission to PC

Hello,

I am trying to serially transmit data to PC from my baby-o. I am using my programmer’s TX and RX pins (switching the jumper to serial transmission). To test the link I am using the following code:

#define F_CPU 20000000//CPU clock
#define BAUD 9600//baud rate for UART
#define MYUBRR (F_CPU/16/BAUD-1)//baud rate variable for UART hardware

#include <avr/io.h>
#include <avr/interrupt.h>

volatile unsigned char newSerCmd=0;
volatile unsigned char serCmd;

void USART_Init(unsigned int ubrr){//Initialize USART hardware & settings for Serial Radio
   UBRR0H=(unsigned char)(ubrr>>8);//set buad rate
   UBRR0L=(unsigned char) ubrr;
   UCSR0B=(1<<RXEN0)|(1<<TXEN0);//enable reciever & transmitter, recieve interrupt
   UCSR0B|=(1<<RXCIE0);
   UCSR0C=(3<<UCSZ00);//Set frame format for 8bit with 1 stop
}

void USART_Trans (unsigned char data){//Transmit a byte of data over USART
   while(!(UCSR0A&(1<<UDRE0)));//wait for transmition to complete
   UDR0=data;
}

ISR(USART_RX_vect){//USART Byte reieved
   serCmd=UDR0;
   newSerCmd=1;
}

int main(){
   USART_Init(MYUBRR);

   USART_Trans('H');
   USART_Trans('i');
   USART_Trans(0X0D);//Carriage Return

   sei();//enable global interrupts

   while(1){
      if(newSerCmd){
         USART_Trans('T');
         USART_Trans('e');
         USART_Trans('s');
         USART_Trans('t');
         USART_Trans(0X0D);//Carriage Return
         newSerCmd=0;
      }
   }

   return 0;
}

from nexisnet post in:


And it works fine!

Now, if I want to serially transmit an 8-bit character variable (e.g. char b=128;) and I want its content (128) to appear on my terminal screen and not the ASCII character that the value represents. How could I do that?

I am sure it is something very simple.

Thank you,
Akis

Hello, Akis,

Essentially, what you are trying to do is to convert a number into a string, and the easiest way to do that is by using sprintf:

char b = 128;
char buf[10];
sprintf(buf, "%d", b);
// buf now contains "128", composed of the chars '1', '2', and '8', and you can send these as serial bytes

However, be aware that sprintf can be relatively slow and take up a lot of program space, so you might want to try writing your own simpler function for doing this kind of conversion if that is important to you.

By the way, nexisnet provided a very good code example for doing serial communication, but we have since released an AVR C/C++ Library that makes it much easier to write programs for the Orangutans. For example, you could rewrite that program like this:

#include <pololu/orangutan.h>

int main()
{
	char buf[1];
	
	serial_set_baud_rate(9600);
	serial_send("Hi\r\n", 4);
	
	while (1)
	{
		serial_receive(buf, 1);
		while (serial_get_received_bytes() < 1);
		serial_send("Test\r\n", 6);
	}
}

(I think these code examples should work, but I have not tested them so there may be a bug or two.)

- Kevin

Dear Kevin and all,

First of all sorry for my very late response, but it is the first time after a year that I can dedicate some time in my project.

Based on your previous response, I have created the following program:

#include <pololu/orangutan.h>

char da=120;
char send_buffer[100];

int main()
{
char buf[1];

serial_set_baud_rate(9600);
serial_send(“Hi\r\n”, 4);

while (1)
{
serial_receive(buf, 1);
while (serial_get_received_bytes() < 1);
sprintf(send_buffer,"%d",da);
serial_send(send_buffer, 100);
serial_send("\r\n", 2);
}
}

As I mentioned earlier, my goal here is to appear the full contents of register “da” to my hyper terminal screen via the serial port.

Unfortunately, the above code displays only the first two digits of “da” (in our case 12) and does not display the third digit (0).

What do I do wrong? Is there any alternative method of writing the above program without the usage of “sprintf” command but only with pololu’s serial command library?

Thank you in advance,

Akis

Hello, Akis.

Please use the [ code] and [ /code] tags (without the spaces) to make your code more readable.

I can see two things wrong in your code:

sprintf(send_buffer,"%d",da); serial_send(send_buffer, 100); serial_send("\r\n", 2);

On the second line, you are telling our library to send 100 characters (the entire the send_buffer) but you’ve only initialized the first couple characters of send_buffer so this will probably result in the microcontroller sending junk to the terminal. To fix this problem you would change the first two lines to:

int length = sprintf(send_buffer, "%d", da); serial_send(send_buffer, length);

The second problem, and the reason you didn’t actually see any junk appear on your serial terminal, is that you are calling serial_send a second time without waiting for the first transmission to finish. I recommend reading the documentation of any library function you are calling. The documentation of serial_send says:

So you have two choices: wait for the first transmission to finish before starting the second, or just combine the first and second transmissions. I prefer the latter because it makes your code simpler:

int length = sprintf(send_buffer, "%d\r\n", da); serial_send(send_buffer, length);

You could even combine the lines together:

serial_send(send_buffer, sprintf(send_buffer, "%d\r\n", da));

–David

If sprintf() takes up too much program memory, keep in mind that there is a nice little routine in the avrlibc library called itoa(), which converts an integer to ascii characters in decimal or hex.

itoa(da,send_buffer,10); //will convert to decimal itoa(da,send_buffer,16); //will convert to hex

you need to #include <stdlib.h>

Hello David and Jim,

Thank you very much and I do appreciate your help!

Akis

Hello again,

One more question. Let’s say that I need to print out in the screen each component of an integer array e.g.:

int N[3]= {12, 24, 6};

How will I do that? I have tried the following code but obviousely it is not right:

for (ii=0;ii<3;ii++)
serial_send(N, sprintf(N, "%d\r\n", N[ii]));

Any ideas on how to do that? In case I want to use the “itoa” command as Jim indicated, how do I write this code?

Thank you in advance,

Akis

Ok I have made it! My mistake was that I had to declare a separate send_buffer as follows:

char send_buffer[10]; int N[3]= {12, 24, 6};

and then use the previous command as follows:

for (ii=0;ii<3;ii++) serial_send(send_buffer, sprintf(send_buffer, "%d\r\n", N[ii]));

However, I am still very interested to find out how to use the “itoa” command instead of the “sprint”. Any ideas?

Thank you,

Akis

konda wrote:

for (ii=0;ii<3;ii++)
serial_send(send_buffer, sprintf(send_buffer, "%d\r\n", N[ii]));

I don’t expect this to work because again you are calling serial_send a second and third time without waiting for the first transmission to finish. You could do something easy like this:

serial_send(send_buffer, sprintf(send_buffer, "%d %d %d\r\n", N[0], N[1], N[2]));

If you search for “itoa” on Google there is some documentation and example code that should give you an idea of how to use it:
cplusplus.com/reference/clib … dlib/itoa/

–David

Thank you David,

Actually it worked but with some delay after the serial_send command as follows:

for (ii=0;ii<3;ii++){
serial_send(send_buffer, sprintf(send_buffer, "%d\r\n", N[ii]));
delay_ms(100);
}

Now what about if I want to print a “double” nuber instead of integer? Let’s say:

double G=33.4;

If I write the following code:

serial_send(send_buffer, sprintf(send_buffer, "%f\r\n", G));

All I get is question marks on the screen ("?"). I left the send_buffer as:

char send_buffer[10];

Thank you again,

Akis

The default sprintf in AVR libc does not support floating point numbers because it takes a lot of your processor’s resources to do so. If you want it, you can enable it by linking in the right libraries. I’m pretty sure you need to add these options to your linker:

-lprintf_flt -lm

If you are using AVR Studio there is a place to add that in your project configuration options. If you are using a Makefile you can add it onto the command that generates the hex file.

–David

Ok I have made it! Actually you can find a detailed explanation on how to enable floating point operations on the following link:

winavr.scienceprog.com/comment/28

Thank you again,

Akis