4008-04-07 Release
[avr_bc100.git] / BaseMegaFirmware / GCC / uart.c
1 /*************************************************************************\r
2 Title:    Interrupt UART library with receive/transmit circular buffers\r
3 Author:   Peter Fleury <pfleury@gmx.ch>   http://jump.to/fleury\r
4 File:     $Id: uart.c,v 1.5.2.10 2005/11/15 19:49:12 peter Exp $\r
5 Software: AVR-GCC 3.3 \r
6 Hardware: any AVR with built-in UART, \r
7           tested on AT90S8515 at 4 Mhz and ATmega at 1Mhz\r
8 \r
9 DESCRIPTION:\r
10     An interrupt is generated when the UART has finished transmitting or\r
11     receiving a byte. The interrupt handling routines use circular buffers\r
12     for buffering received and transmitted data.\r
13     \r
14     The UART_RX_BUFFER_SIZE and UART_TX_BUFFER_SIZE variables define\r
15     the buffer size in bytes. Note that these variables must be a \r
16     power of 2.\r
17     \r
18 USAGE:\r
19     Refere to the header file uart.h for a description of the routines. \r
20     See also example test_uart.c.\r
21 \r
22 NOTES:\r
23     Based on Atmel Application Note AVR306\r
24                     \r
25 *************************************************************************/\r
26 #include <avr/io.h>\r
27 #include <avr/interrupt.h>\r
28 // #include <avr/signal.h>\r
29 #include <avr/pgmspace.h>\r
30 #include "uart.h"\r
31 \r
32 \r
33 /*\r
34  *  constants and macros\r
35  */\r
36 \r
37 /* size of RX/TX buffers */\r
38 #define UART_RX_BUFFER_MASK ( UART_RX_BUFFER_SIZE - 1)\r
39 #define UART_TX_BUFFER_MASK ( UART_TX_BUFFER_SIZE - 1)\r
40 \r
41 #if ( UART_RX_BUFFER_SIZE & UART_RX_BUFFER_MASK )\r
42 #error RX buffer size is not a power of 2\r
43 #endif\r
44 #if ( UART_TX_BUFFER_SIZE & UART_TX_BUFFER_MASK )\r
45 #error TX buffer size is not a power of 2\r
46 #endif\r
47 \r
48 #if defined(__AVR_AT90S2313__) \\r
49  || defined(__AVR_AT90S4414__) || defined(__AVR_AT90S4434__) \\r
50  || defined(__AVR_AT90S8515__) || defined(__AVR_AT90S8535__) \\r
51  || defined(__AVR_ATmega103__)\r
52  /* old AVR classic or ATmega103 with one UART */\r
53  #define AT90_UART\r
54  #define UART0_RECEIVE_INTERRUPT   SIG_UART_RECV\r
55  #define UART0_TRANSMIT_INTERRUPT  SIG_UART_DATA\r
56  #define UART0_STATUS   USR\r
57  #define UART0_CONTROL  UCR\r
58  #define UART0_DATA     UDR  \r
59  #define UART0_UDRIE    UDRIE\r
60 #elif defined(__AVR_AT90S2333__) || defined(__AVR_AT90S4433__)\r
61  /* old AVR classic with one UART */\r
62  #define AT90_UART\r
63  #define UART0_RECEIVE_INTERRUPT   SIG_UART_RECV\r
64  #define UART0_TRANSMIT_INTERRUPT  SIG_UART_DATA\r
65  #define UART0_STATUS   UCSRA\r
66  #define UART0_CONTROL  UCSRB\r
67  #define UART0_DATA     UDR \r
68  #define UART0_UDRIE    UDRIE\r
69 #elif  defined(__AVR_ATmega8__)  || defined(__AVR_ATmega16__) || defined(__AVR_ATmega32__) \\r
70   || defined(__AVR_ATmega8515__) || defined(__AVR_ATmega8535__) \\r
71   || defined(__AVR_ATmega323__)\r
72   /* ATmega with one USART */\r
73  #define ATMEGA_USART\r
74  #define UART0_RECEIVE_INTERRUPT   SIG_UART_RECV\r
75  #define UART0_TRANSMIT_INTERRUPT  SIG_UART_DATA\r
76  #define UART0_STATUS   UCSRA\r
77  #define UART0_CONTROL  UCSRB\r
78  #define UART0_DATA     UDR\r
79  #define UART0_UDRIE    UDRIE\r
80 #elif defined(__AVR_ATmega163__) \r
81   /* ATmega163 with one UART */\r
82  #define ATMEGA_UART\r
83  #define UART0_RECEIVE_INTERRUPT   SIG_UART_RECV\r
84  #define UART0_TRANSMIT_INTERRUPT  SIG_UART_DATA\r
85  #define UART0_STATUS   UCSRA\r
86  #define UART0_CONTROL  UCSRB\r
87  #define UART0_DATA     UDR\r
88  #define UART0_UDRIE    UDRIE\r
89 #elif defined(__AVR_ATmega162__)\r
90  /* ATmega with two USART */\r
91  #define ATMEGA_USART0\r
92  #define ATMEGA_USART1\r
93  #define UART0_RECEIVE_INTERRUPT   SIG_USART0_RECV\r
94  #define UART1_RECEIVE_INTERRUPT   SIG_USART1_RECV\r
95  #define UART0_TRANSMIT_INTERRUPT  SIG_USART0_DATA\r
96  #define UART1_TRANSMIT_INTERRUPT  SIG_USART1_DATA\r
97  #define UART0_STATUS   UCSR0A\r
98  #define UART0_CONTROL  UCSR0B\r
99  #define UART0_DATA     UDR0\r
100  #define UART0_UDRIE    UDRIE0\r
101  #define UART1_STATUS   UCSR1A\r
102  #define UART1_CONTROL  UCSR1B\r
103  #define UART1_DATA     UDR1\r
104  #define UART1_UDRIE    UDRIE1\r
105 #elif defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__) \r
106  /* ATmega with two USART */\r
107  #define ATMEGA_USART0\r
108  #define ATMEGA_USART1\r
109  #define UART0_RECEIVE_INTERRUPT   SIG_UART0_RECV\r
110  #define UART1_RECEIVE_INTERRUPT   SIG_UART1_RECV\r
111  #define UART0_TRANSMIT_INTERRUPT  SIG_UART0_DATA\r
112  #define UART1_TRANSMIT_INTERRUPT  SIG_UART1_DATA\r
113  #define UART0_STATUS   UCSR0A\r
114  #define UART0_CONTROL  UCSR0B\r
115  #define UART0_DATA     UDR0\r
116  #define UART0_UDRIE    UDRIE0\r
117  #define UART1_STATUS   UCSR1A\r
118  #define UART1_CONTROL  UCSR1B\r
119  #define UART1_DATA     UDR1\r
120  #define UART1_UDRIE    UDRIE1\r
121 #elif defined(__AVR_ATmega161__)\r
122  /* ATmega with UART */\r
123  #error "AVR ATmega161 currently not supported by this libaray !"\r
124 #elif defined(__AVR_ATmega169__) \r
125  /* ATmega with one USART */\r
126  #define ATMEGA_USART\r
127  #define UART0_RECEIVE_INTERRUPT   SIG_USART_RECV\r
128  #define UART0_TRANSMIT_INTERRUPT  SIG_USART_DATA\r
129  #define UART0_STATUS   UCSRA\r
130  #define UART0_CONTROL  UCSRB\r
131  #define UART0_DATA     UDR\r
132  #define UART0_UDRIE    UDRIE\r
133 #elif defined(__AVR_ATmega48__) ||defined(__AVR_ATmega88__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega644__)\r
134  #define ATMEGA_USART0\r
135  #define UART0_RECEIVE_INTERRUPT   SIG_USART_RECV\r
136  #define UART0_TRANSMIT_INTERRUPT  SIG_USART_DATA\r
137  #define UART0_STATUS   UCSR0A\r
138  #define UART0_CONTROL  UCSR0B\r
139  #define UART0_DATA     UDR0\r
140  #define UART0_UDRIE    UDRIE0\r
141 #elif defined(__AVR_ATtiny2313__)\r
142  #define ATMEGA_USART\r
143  #define UART0_RECEIVE_INTERRUPT   SIG_USART0_RX \r
144  #define UART0_TRANSMIT_INTERRUPT  SIG_USART0_UDRE\r
145  #define UART0_STATUS   UCSRA\r
146  #define UART0_CONTROL  UCSRB\r
147  #define UART0_DATA     UDR\r
148  #define UART0_UDRIE    UDRIE\r
149 #else\r
150  #error "no UART definition for MCU available"\r
151 #endif\r
152 \r
153 \r
154 /*\r
155  *  module global variables\r
156  */\r
157 static volatile unsigned char UART_TxBuf[UART_TX_BUFFER_SIZE];\r
158 static volatile unsigned char UART_RxBuf[UART_RX_BUFFER_SIZE];\r
159 static volatile unsigned char UART_TxHead;\r
160 static volatile unsigned char UART_TxTail;\r
161 static volatile unsigned char UART_RxHead;\r
162 static volatile unsigned char UART_RxTail;\r
163 static volatile unsigned char UART_LastRxError;\r
164 \r
165 #if defined( ATMEGA_USART1 )\r
166 static volatile unsigned char UART1_TxBuf[UART_TX_BUFFER_SIZE];\r
167 static volatile unsigned char UART1_RxBuf[UART_RX_BUFFER_SIZE];\r
168 static volatile unsigned char UART1_TxHead;\r
169 static volatile unsigned char UART1_TxTail;\r
170 static volatile unsigned char UART1_RxHead;\r
171 static volatile unsigned char UART1_RxTail;\r
172 static volatile unsigned char UART1_LastRxError;\r
173 #endif\r
174 \r
175 \r
176 \r
177 SIGNAL(UART0_RECEIVE_INTERRUPT)\r
178 /*************************************************************************\r
179 Function: UART Receive Complete interrupt\r
180 Purpose:  called when the UART has received a character\r
181 **************************************************************************/\r
182 {\r
183     unsigned char tmphead;\r
184     unsigned char data;\r
185     unsigned char usr;\r
186     unsigned char lastRxError;\r
187  \r
188  \r
189     /* read UART status register and UART data register */ \r
190     usr  = UART0_STATUS;\r
191     data = UART0_DATA;\r
192     \r
193     /* */\r
194 #if defined( AT90_UART )\r
195     lastRxError = (usr & (_BV(FE)|_BV(DOR)) );\r
196 #elif defined( ATMEGA_USART )\r
197     lastRxError = (usr & (_BV(FE)|_BV(DOR)) );\r
198 #elif defined( ATMEGA_USART0 )\r
199     lastRxError = (usr & (_BV(FE0)|_BV(DOR0)) );\r
200 #elif defined ( ATMEGA_UART )\r
201     lastRxError = (usr & (_BV(FE)|_BV(DOR)) );\r
202 #endif\r
203         \r
204     /* calculate buffer index */ \r
205     tmphead = ( UART_RxHead + 1) & UART_RX_BUFFER_MASK;\r
206     \r
207     if ( tmphead == UART_RxTail ) {\r
208         /* error: receive buffer overflow */\r
209         lastRxError = UART_BUFFER_OVERFLOW >> 8;\r
210     }else{\r
211         /* store new index */\r
212         UART_RxHead = tmphead;\r
213         /* store received data in buffer */\r
214         UART_RxBuf[tmphead] = data;\r
215     }\r
216     UART_LastRxError = lastRxError;   \r
217 }\r
218 \r
219 \r
220 SIGNAL(UART0_TRANSMIT_INTERRUPT)\r
221 /*************************************************************************\r
222 Function: UART Data Register Empty interrupt\r
223 Purpose:  called when the UART is ready to transmit the next byte\r
224 **************************************************************************/\r
225 {\r
226     unsigned char tmptail;\r
227 \r
228     \r
229     if ( UART_TxHead != UART_TxTail) {\r
230         /* calculate and store new buffer index */\r
231         tmptail = (UART_TxTail + 1) & UART_TX_BUFFER_MASK;\r
232         UART_TxTail = tmptail;\r
233         /* get one byte from buffer and write it to UART */\r
234         UART0_DATA = UART_TxBuf[tmptail];  /* start transmission */\r
235     }else{\r
236         /* tx buffer empty, disable UDRE interrupt */\r
237         UART0_CONTROL &= ~_BV(UART0_UDRIE);\r
238     }\r
239 }\r
240 \r
241 \r
242 /*************************************************************************\r
243 Function: uart_init()\r
244 Purpose:  initialize UART and set baudrate\r
245 Input:    baudrate using macro UART_BAUD_SELECT()\r
246 Returns:  none\r
247 **************************************************************************/\r
248 void uart_init(unsigned int baudrate)\r
249 {\r
250     UART_TxHead = 0;\r
251     UART_TxTail = 0;\r
252     UART_RxHead = 0;\r
253     UART_RxTail = 0;\r
254     \r
255 #if defined( AT90_UART )\r
256     /* set baud rate */\r
257     UBRR = (unsigned char)baudrate; \r
258 \r
259     /* enable UART receiver and transmmitter and receive complete interrupt */\r
260     UART0_CONTROL = _BV(RXCIE)|_BV(RXEN)|_BV(TXEN);\r
261 \r
262 #elif defined (ATMEGA_USART)\r
263     /* Set baud rate */\r
264     if ( baudrate & 0x8000 )\r
265     {\r
266          UART0_STATUS = (1<<U2X);  //Enable 2x speed \r
267          baudrate &= ~0x8000;\r
268     }\r
269     UBRRH = (unsigned char)(baudrate>>8);\r
270     UBRRL = (unsigned char) baudrate;\r
271    \r
272     /* Enable USART receiver and transmitter and receive complete interrupt */\r
273     UART0_CONTROL = _BV(RXCIE)|(1<<RXEN)|(1<<TXEN);\r
274     \r
275     /* Set frame format: asynchronous, 8data, no parity, 1stop bit */\r
276     #ifdef URSEL\r
277     UCSRC = (1<<URSEL)|(3<<UCSZ0);\r
278     #else\r
279     UCSRC = (3<<UCSZ0);\r
280     #endif \r
281     \r
282 #elif defined (ATMEGA_USART0 )\r
283     /* Set baud rate */\r
284     if ( baudrate & 0x8000 ) \r
285     {\r
286                 UART0_STATUS = (1<<U2X0);  //Enable 2x speed \r
287                 baudrate &= ~0x8000;\r
288         }\r
289     UBRR0H = (unsigned char)(baudrate>>8);\r
290     UBRR0L = (unsigned char) baudrate;\r
291 \r
292     /* Enable USART receiver and transmitter and receive complete interrupt */\r
293     UART0_CONTROL = _BV(RXCIE0)|(1<<RXEN0)|(1<<TXEN0);\r
294     \r
295     /* Set frame format: asynchronous, 8data, no parity, 1stop bit */\r
296     #ifdef URSEL0\r
297     UCSR0C = (1<<URSEL0)|(3<<UCSZ00);\r
298     #else\r
299     UCSR0C = (3<<UCSZ00);\r
300     #endif \r
301 \r
302 #elif defined ( ATMEGA_UART )\r
303     /* set baud rate */\r
304     if ( baudrate & 0x8000 ) \r
305     {\r
306         UART0_STATUS = (1<<U2X);  //Enable 2x speed \r
307         baudrate &= ~0x8000;\r
308     }\r
309     UBRRHI = (unsigned char)(baudrate>>8);\r
310     UBRR   = (unsigned char) baudrate;\r
311 \r
312     /* Enable UART receiver and transmitter and receive complete interrupt */\r
313     UART0_CONTROL = _BV(RXCIE)|(1<<RXEN)|(1<<TXEN);\r
314 \r
315 #endif\r
316 \r
317 }/* uart_init */\r
318 \r
319 \r
320 /*************************************************************************\r
321 Function: uart_getc()\r
322 Purpose:  return byte from ringbuffer  \r
323 Returns:  lower byte:  received byte from ringbuffer\r
324           higher byte: last receive error\r
325 **************************************************************************/\r
326 unsigned int uart_getc(void)\r
327 {    \r
328     unsigned char tmptail;\r
329     unsigned char data;\r
330 \r
331 \r
332     if ( UART_RxHead == UART_RxTail ) {\r
333         return UART_NO_DATA;   /* no data available */\r
334     }\r
335     \r
336     /* calculate /store buffer index */\r
337     tmptail = (UART_RxTail + 1) & UART_RX_BUFFER_MASK;\r
338     UART_RxTail = tmptail; \r
339     \r
340     /* get data from receive buffer */\r
341     data = UART_RxBuf[tmptail];\r
342     \r
343     return (UART_LastRxError << 8) + data;\r
344 \r
345 }/* uart_getc */\r
346 \r
347 \r
348 /*************************************************************************\r
349 Function: uart_putc()\r
350 Purpose:  write byte to ringbuffer for transmitting via UART\r
351 Input:    byte to be transmitted\r
352 Returns:  none          \r
353 **************************************************************************/\r
354 void uart_putc(unsigned char data)\r
355 {\r
356     unsigned char tmphead;\r
357 \r
358     \r
359     tmphead  = (UART_TxHead + 1) & UART_TX_BUFFER_MASK;\r
360     \r
361     while ( tmphead == UART_TxTail ){\r
362         ;/* wait for free space in buffer */\r
363     }\r
364     \r
365     UART_TxBuf[tmphead] = data;\r
366     UART_TxHead = tmphead;\r
367 \r
368     /* enable UDRE interrupt */\r
369     UART0_CONTROL    |= _BV(UART0_UDRIE);\r
370 \r
371 }/* uart_putc */\r
372 \r
373 \r
374 /*************************************************************************\r
375 Function: uart_puts()\r
376 Purpose:  transmit string to UART\r
377 Input:    string to be transmitted\r
378 Returns:  none          \r
379 **************************************************************************/\r
380 void uart_puts(const char *s )\r
381 {\r
382     while (*s) \r
383       uart_putc(*s++);\r
384 \r
385 }/* uart_puts */\r
386 \r
387 \r
388 /*************************************************************************\r
389 Function: uart_puts_p()\r
390 Purpose:  transmit string from program memory to UART\r
391 Input:    program memory string to be transmitted\r
392 Returns:  none\r
393 **************************************************************************/\r
394 void uart_puts_p(const char *progmem_s )\r
395 {\r
396     register char c;\r
397     \r
398     while ( (c = pgm_read_byte(progmem_s++)) ) \r
399       uart_putc(c);\r
400 \r
401 }/* uart_puts_p */\r
402 \r
403 \r
404 /*\r
405  * these functions are only for ATmegas with two USART\r
406  */\r
407 #if defined( ATMEGA_USART1 )\r
408 \r
409 SIGNAL(UART1_RECEIVE_INTERRUPT)\r
410 /*************************************************************************\r
411 Function: UART1 Receive Complete interrupt\r
412 Purpose:  called when the UART1 has received a character\r
413 **************************************************************************/\r
414 {\r
415     unsigned char tmphead;\r
416     unsigned char data;\r
417     unsigned char usr;\r
418     unsigned char lastRxError;\r
419  \r
420  \r
421     /* read UART status register and UART data register */ \r
422     usr  = UART1_STATUS;\r
423     data = UART1_DATA;\r
424     \r
425     /* */\r
426     lastRxError = (usr & (_BV(FE1)|_BV(DOR1)) );\r
427         \r
428     /* calculate buffer index */ \r
429     tmphead = ( UART1_RxHead + 1) & UART_RX_BUFFER_MASK;\r
430     \r
431     if ( tmphead == UART1_RxTail ) {\r
432         /* error: receive buffer overflow */\r
433         lastRxError = UART_BUFFER_OVERFLOW >> 8;\r
434     }else{\r
435         /* store new index */\r
436         UART1_RxHead = tmphead;\r
437         /* store received data in buffer */\r
438         UART1_RxBuf[tmphead] = data;\r
439     }\r
440     UART1_LastRxError = lastRxError;   \r
441 }\r
442 \r
443 \r
444 SIGNAL(UART1_TRANSMIT_INTERRUPT)\r
445 /*************************************************************************\r
446 Function: UART1 Data Register Empty interrupt\r
447 Purpose:  called when the UART1 is ready to transmit the next byte\r
448 **************************************************************************/\r
449 {\r
450     unsigned char tmptail;\r
451 \r
452     \r
453     if ( UART1_TxHead != UART1_TxTail) {\r
454         /* calculate and store new buffer index */\r
455         tmptail = (UART1_TxTail + 1) & UART_TX_BUFFER_MASK;\r
456         UART1_TxTail = tmptail;\r
457         /* get one byte from buffer and write it to UART */\r
458         UART1_DATA = UART1_TxBuf[tmptail];  /* start transmission */\r
459     }else{\r
460         /* tx buffer empty, disable UDRE interrupt */\r
461         UART1_CONTROL &= ~_BV(UART1_UDRIE);\r
462     }\r
463 }\r
464 \r
465 \r
466 /*************************************************************************\r
467 Function: uart1_init()\r
468 Purpose:  initialize UART1 and set baudrate\r
469 Input:    baudrate using macro UART_BAUD_SELECT()\r
470 Returns:  none\r
471 **************************************************************************/\r
472 void uart1_init(unsigned int baudrate)\r
473 {\r
474     UART1_TxHead = 0;\r
475     UART1_TxTail = 0;\r
476     UART1_RxHead = 0;\r
477     UART1_RxTail = 0;\r
478     \r
479 \r
480     /* Set baud rate */\r
481     if ( baudrate & 0x8000 ) \r
482     {\r
483         UART1_STATUS = (1<<U2X1);  //Enable 2x speed \r
484       baudrate &= ~0x8000;\r
485     }\r
486     UBRR1H = (unsigned char)(baudrate>>8);\r
487     UBRR1L = (unsigned char) baudrate;\r
488 \r
489     /* Enable USART receiver and transmitter and receive complete interrupt */\r
490     UART1_CONTROL = _BV(RXCIE1)|(1<<RXEN1)|(1<<TXEN1);\r
491     \r
492     /* Set frame format: asynchronous, 8data, no parity, 1stop bit */   \r
493     #ifdef URSEL1\r
494     UCSR1C = (1<<URSEL1)|(3<<UCSZ10);\r
495     #else\r
496     UCSR1C = (3<<UCSZ10);\r
497     #endif \r
498 }/* uart_init */\r
499 \r
500 \r
501 /*************************************************************************\r
502 Function: uart1_getc()\r
503 Purpose:  return byte from ringbuffer  \r
504 Returns:  lower byte:  received byte from ringbuffer\r
505           higher byte: last receive error\r
506 **************************************************************************/\r
507 unsigned int uart1_getc(void)\r
508 {    \r
509     unsigned char tmptail;\r
510     unsigned char data;\r
511 \r
512 \r
513     if ( UART1_RxHead == UART1_RxTail ) {\r
514         return UART_NO_DATA;   /* no data available */\r
515     }\r
516     \r
517     /* calculate /store buffer index */\r
518     tmptail = (UART1_RxTail + 1) & UART_RX_BUFFER_MASK;\r
519     UART1_RxTail = tmptail; \r
520     \r
521     /* get data from receive buffer */\r
522     data = UART1_RxBuf[tmptail];\r
523     \r
524     return (UART1_LastRxError << 8) + data;\r
525 \r
526 }/* uart1_getc */\r
527 \r
528 \r
529 /*************************************************************************\r
530 Function: uart1_putc()\r
531 Purpose:  write byte to ringbuffer for transmitting via UART\r
532 Input:    byte to be transmitted\r
533 Returns:  none          \r
534 **************************************************************************/\r
535 void uart1_putc(unsigned char data)\r
536 {\r
537     unsigned char tmphead;\r
538 \r
539     \r
540     tmphead  = (UART1_TxHead + 1) & UART_TX_BUFFER_MASK;\r
541     \r
542     while ( tmphead == UART1_TxTail ){\r
543         ;/* wait for free space in buffer */\r
544     }\r
545     \r
546     UART1_TxBuf[tmphead] = data;\r
547     UART1_TxHead = tmphead;\r
548 \r
549     /* enable UDRE interrupt */\r
550     UART1_CONTROL    |= _BV(UART1_UDRIE);\r
551 \r
552 }/* uart1_putc */\r
553 \r
554 \r
555 /*************************************************************************\r
556 Function: uart1_puts()\r
557 Purpose:  transmit string to UART1\r
558 Input:    string to be transmitted\r
559 Returns:  none          \r
560 **************************************************************************/\r
561 void uart1_puts(const char *s )\r
562 {\r
563     while (*s) \r
564       uart1_putc(*s++);\r
565 \r
566 }/* uart1_puts */\r
567 \r
568 \r
569 /*************************************************************************\r
570 Function: uart1_puts_p()\r
571 Purpose:  transmit string from program memory to UART1\r
572 Input:    program memory string to be transmitted\r
573 Returns:  none\r
574 **************************************************************************/\r
575 void uart1_puts_p(const char *progmem_s )\r
576 {\r
577     register char c;\r
578     \r
579     while ( (c = pgm_read_byte(progmem_s++)) ) \r
580       uart1_putc(c);\r
581 \r
582 }/* uart1_puts_p */\r
583 \r
584 \r
585 #endif\r