Go Down

Topic: small serial tx function (Read 628 times) previous topic - next topic

dcb

Sep 26, 2008, 07:27 pm Last Edit: Sep 26, 2008, 07:29 pm by dcb Reason: 1
I wanted to add serial output to my project, but don't have much space to spare.  Bringing in Serial costs over 1400 bytes just to transmit debug/logging data over the wire.  So I came up with this function which adds only 66 bytes.  

It only sends strings so that's part of why it's smaller    and it only transmits/cant use it in conjunction with Serial (why would you?)/and would need tweaking to work on a atmega8 or a non 16mhz chip.  But maybe someone has a need for it.

Code: [Select]

#define myubbr (16000000/16/9600-1)
void simpletx( char * string ){
 if (UCSR0B != (1<<TXEN0)){ //do we need to init the uart?
    UBRR0H = (unsigned char)(myubbr>>8);
    UBRR0L = (unsigned char)myubbr;
    UCSR0B = (1<<TXEN0);//Enable transmitter
    UCSR0C = (3<<UCSZ00);//N81
 }
 byte x = 0;      
 char c = string[x];      
 while(c != 0){  
   while ( !( UCSR0A & (1<<UDRE0)) );
   UDR0 = c; //send the data
   x++;      
   c = string[x];      
 }      
}

void setup(){}

void loop(){
 simpletx("Hello\n");
 delay(500);
}

mikalhart

Hey, dcb, that is indeed cool and potentially quite useful.  Thanks for sharing!  I gather it's hardcoded for 9600 baud, but that could easily be adjusted by changing the definition of myubbr?

Here's the same function trimmed down to 56 bytes: :)

Quote
#define myubbr (16000000/16/9600-1)
void simpletx( char * string ){
 if (UCSR0B != (1<<TXEN0)){ //do we need to init the uart?
    UBRR0H = (unsigned char)(myubbr>>8);
    UBRR0L = (unsigned char)myubbr;
    UCSR0B = (1<<TXEN0);//Enable transmitter
    UCSR0C = (3<<UCSZ00);//N81
 }
 while (*string)
 {
   while ( !( UCSR0A & (1<<UDRE0)) );
   UDR0 = *string++; //send the data
 }
}


Mikal

mem

#2
Sep 26, 2008, 09:42 pm Last Edit: Sep 26, 2008, 10:02 pm by mem Reason: 1
Quote
#define myubbr (16000000/16/9600-1)
void simpletx( char * string ){
if (UCSR0B != (1<<TXEN0)){ //do we need to init the uart?
   UBRR0H = (unsigned char)(myubbr>>8);
   UBRR0L = (unsigned char)myubbr;
   UCSR0B = (1<<TXEN0);//Enable transmitter
   UCSR0C = (3<<UCSZ00);//N81
}
while (*string)
{
  while ( !( UCSR0A & (1<<UDRE0)) );
  UDR0 = *string++; //send the data
}
}

Hi Mikal, it doesn't look like the while loop will terminate,  I think *string is always true for any non null string

mikalhart

#3
Sep 26, 2008, 10:39 pm Last Edit: Sep 26, 2008, 10:42 pm by mikalhart Reason: 1
Hi mem,

Quote
Hi Mikal, it doesn't look like the while loop will terminate.

Hmm... I think it will.  At least it worked for the one 5-second test I did. :D

No seriously, the (outer) loop will always terminate because string is being incremented at every iteration, and so eventually *string, the while loop test condition, will attain a value of 0 when it gets to the end of the string.

Try dcb's test program:

Code: [Select]
void setup(){}
void loop()
{
 simpletx("Hello\n");
 delay(500);
}


It works great with both revisions of simpletx().  I like that tiny function!  Thanks.

Mikal

PS: You often see this kind of technique in old C strcpy code, like:

Code: [Select]
void strcpy(char *to, char *from)
{
 while (*to++ = *from++); // !
}


M

dcb

Cute,   That seems to work too :)  Except I count 56 bytes ;)

mikalhart

#5
Sep 26, 2008, 10:44 pm Last Edit: Sep 26, 2008, 10:46 pm by mikalhart Reason: 1
Quote
56 bytes

Yup, that's right!  Same here!

M

Go Up