how do you transmit more than one character using UART?

Hi there,

The following function transmit(), transmits only a charater.

void transmit(unsigned char data);

void main(void)
{

	InitUART();
	transmit('A');
	
}

void transmit(unsigned char data)
{
	
	while ( !( UCSRA & (1<<UDRE)) );   // Wait for empty transmit buffer
	UDR = data;  // Put data into buffer, sends the data 

}

But if you want to transmit more than one character, how do you do that?

I tried the following for loop but it does not work and displays only the last character.

for(int i=1;i<=13;i++) // this does not work displays only the last character d 13 times
{
	transmit('Wrong command');	
}

Try using a string:

char buffer[] = "Wrong command";

for (i = 0; i < 13; i++)
  transmit(buffer[i]);

Leon

first off:

transmit(‘Wrong command’);

The ’ character is used to indicate a character constant. So you’re likely getting a compiler warning here, since you’re trying to cram several characters into a single character constant. Look at your compiler warnings; they’re usually trying to tell you something.

Second - why would a for loop calling the same function with the same parameter print something different every time?

Here’s an example of how to do it:

1: char * mystring = "Hello World\n";
2: char * txptr = mystring;

3: while (*txptr)
4:     transmit(*txptr++);

1: mystring is a pointer, which is the address, of a set of bytes; ‘H’,‘e’,‘l’,‘l’,‘o’,…‘d’,‘\n’,0

2: copy the pointer to mystring, so that we have the original pointer around if we need it later

3: While the byte that txptr points to is not 0 [there’s a trailing 0 at the end of the string]

4: tranmit the byte that txptr points to, and increment txptr [aka, move it to the next byte.

Now, this is non-optimal, because you end up using the .data section for storing your string, when it is constant. [.data is in ram, so you use up a chunk of flash to store the string, then copy it to ram on function entry]. However, putting strings in flash is a bit out of the scope of this post.

Cheers,

–David Carne

EDIT

leon_heller beat me to it. His way will work fine too; but sometimes compilers generate a bit tighter code using the pointer arithmetic method.

busonerd:
first off:

transmit(‘Wrong command’);

The ’ character is used to indicate a character constant. So you’re likely getting a compiler warning here, since you’re trying to cram several characters into a single character constant. Look at your compiler warnings; they’re usually trying to tell you something.

Second - why would a for loop calling the same function with the same parameter print something different every time?

Here’s an example of how to do it:

1: char * mystring = "Hello World\n";

2: char * txptr = mystring;

3: while (*txptr)
4: transmit(*txptr++);






1: mystring is a pointer, which is the address, of a set of bytes; 'H','e','l','l','o',......'d','\n',0



2: copy the pointer to mystring, so that we have the original pointer around if we need it later



3: While the byte that txptr points to is not 0 [there's a trailing 0 at the end of the string]



4: tranmit the byte that txptr points to, and increment txptr [aka, move it to the next byte.



Now, this is non-optimal, because you end up using the .data section for storing your string, when it is constant. [.data is in ram, so you use up a chunk of flash to store the string, then copy it to ram on function entry]. However, putting strings in flash is a bit out of the scope of this post.



Cheers,



--David Carne



*EDIT*

leon_heller beat me to it. His way will work fine too; but sometimes compilers generate a bit tighter code using the pointer arithmetic method.

Thanks Leon and David. I think these methods will work. I will try them and let you know. I am more leaning towards Leon’s solution because it is simpler. I do not mess with pointers. I leave that for experts now.Thanks David. I will use your solution when I am a little more experienced. Now the next question:

The above question was related to char and string. But how do you transmit an integer value?

My immediate goal is to measure pH level of water and put the measured value into a variable. and then transmit this value of the variable upon request.

I am not sure if the measured value of the sensor will be one byte.

Here is another question:

How should I proceed if I want to measure pH, say every 5 minutes? Should I put the value into an array? Thanks

Regards

Since the OP is using C, can’t he redirect the standard IO to the UART and just use printf or something similar? I haven’t done much coding in C for micros, so I don’t know if this is possible.

falingtrea:
Since the OP is using C, can’t he redirect the standard IO to the UART and just use printf or something similar? I haven’t done much coding in C for micros, so I don’t know if this is possible.

Hi there,

I tried that but it did not work for some reason. Also while downloading the .hex files to uContorller, it takes a little longer.

falingtrea:
Since the OP is using C, can’t he redirect the standard IO to the UART and just use printf or something similar? I haven’t done much coding in C for micros, so I don’t know if this is possible.

That depends on the compiler. It is implemented in some compilers, but one has to write a low-level character output function (something like _putchar(c) as a rule, so that the compiler can find it. It probably won’t be there by default.

Leon

leon_heller:

falingtrea:
Since the OP is using C, can’t he redirect the standard IO to the UART and just use printf or something similar? I haven’t done much coding in C for micros, so I don’t know if this is possible.

That depends on the compiler. It is implemented in some compilers, but one has to write a low-level character output function (something like _putchar(c) as a rule, so that the compiler can find it. It probably won’t be there by default.

Leon

Every compiler’s C runtime docs explain how to hook an I/O driver to stdio. In GCC it’s fdevopen() as I recall.

stevech:
Every compiler’s C runtime docs explain how to hook an I/O driver to stdio. In GCC it’s fdevopen() as I recall.

Thats a function of the C library in use. fdevopen() happens to be the way to do it using the avr-libc. It has nothing to do with GCC.

Newlib for instance requires implementing _putchar/_putchar_r stubs instead.

I strongly suggest NOT including printf/sprintf and kin. Lots of code bloat for things you will likely never use.

leon_heller:
Try using a string:

char buffer[] = "Wrong command";

for (i = 0; i < 13; i++)
transmit(buffer[i]);






Leon

Hi there,

I test the above with Bray++ terminal and it works fine. However at the end the following appears <0>. I am not sure why.

.

C strings are null terminated and end with a 0. Leon’s example looks right. Did you change your message and not the length of your for loop?

riden:
C strings are null terminated and end with a 0. Leon’s example looks right. Did you change your message and not the length of your for loop?

The lenght of the message is the same exactly. I did not change anything.

To clarify, you are receiving the following characters on the terminal (in other words, the message is displayed, but with an extra zero at the end)?

W r o n g c o m m a n d <0>

If so, the offset value has to be wrong. However, the code that was posted is correct, so this is a bit of mystery. Perhaps another part of your code is writing the extra <0>.

If you are getting nothing but <0> characters, it may be that your compiler is not pointing to the actual string. On C18 for the PIC, I need to use a ROM char* instead of char* to access string constants in my code.

riden:
To clarify, you are receiving the following characters on the terminal (in other words, the message is displayed, but with an extra zero at the end)?

W r o n g c o m m a n d <0>

If so, the offset value has to be wrong. However, the code that was posted is correct, so this is a bit of mystery. Perhaps another part of your code is writing the extra <0>.

If you are getting nothing but <0> characters, it may be that your compiler is not pointing to the actual string. On C18 for the PIC, I need to use a ROM char* instead of char* to access string constants in my code.

Yes. I get the following written on PC: Wrong coammand<0>

If you want to be more generic with your output, you can use a while like this:

i = 0;

while (buffer[i] != 0) 
{
    transmit(buffer[i]);
    i++;
}

or

i = 0;

while (buffer[i] != 0) 
    transmit(buffer[i++]);

to take advantage of C tricks by post incrementing.

That way you would transmit any size string and end transmission on the null character.

edit: fixed inequality.

falingtrea:
If you want to be more generic with your output, you can use a while like this:

i = 0;

while (buffer[i] <> 0)
{
transmit(buffer[i]);
i++;
}

or

i = 0;

while (buffer[i] <> 0)
transmit(buffer[i++]);

to take advantage of C tricks by post incrementing.




That way you would transmit any size string and end transmission on the null character.

Wow! nice and neat code. I wonder if there is a book that just teaches these kind of nice tricks and different ways of doing the same thing. Thanks

The C Programming Language by Kernighan and Ritchie.

Leon

while (buffer <> 0)
{
transmit(buffer);
i++;
}
[/quote]
shouldn’t it be "while (buffer != 0)" ?
The inequality sign in C is != ( ! means not, so != means not equal), not <>

Yeah, BASIC on the brain. I do that all the time. :oops:

smdFan:
The above question was related to char and string. But how do you transmit an integer value?

My immediate goal is to measure pH level of water and put the measured value into a variable. and then transmit this value of the variable upon request.

I am not sure if the measured value of the sensor will be one byte.

Here is another question:

How should I proceed if I want to measure pH, say every 5 minutes? Should I put the value into an array? Thanks

Regards

i think this would work:

    void print_integer(int val) {

        int i;
    
        for(i=100;i>0;i/=10) {
            transmit((val/i)+48);
            val-=(val/i)*i;
        }
    
    }

Maybe there’s a better way, but this works for me… Just in case you don’t have figured out how to do it. Note that it only prints integers with less than 4 digits. If you need to use bigger numbers you can increment the initial value of i of 100 to 1000 for 4 digits or less and so on.