串口是单片机领域最常见的数据传输接口,我们几乎可以在任何单片机上找到一个或者更多的硬件串行接口(Uart)。单片机开发中,会经常使用到串口,而编写相应的开发库将会大大提高开发效率,省去诸多麻烦。
Peter Fleury编写了AVR系列串口程序编程接口库。Tim Sharpe在Fleury的基础上作了更多的改进。详见:http://beaststwo.org/avr-uart/index.shtml
但是该编程库在使用的时候有若干问题,所以我做了一些修改。改动如下:
1。波特率计算:注释部分为Tim Sharpe原来的代码
#define UART_BAUD_SELECT(baudRate,xtalCpu) ((xtalCpu)/(baudRate)/16-1)
//#define UART_BAUD_SELECT(baudRate,xtalCpu) ((xtalCpu)/((baudRate)*16l)-1)
#define UART_BAUD_SELECT_DOUBLE_SPEED(baudRate,xtalCpu) (((xtalCpu)/(baudRate)/8-1)|0x8000)
//#define UART_BAUD_SELECT_DOUBLE_SPEED(baudRate,xtalCpu) (((xtalCpu)/((baudRate)*8l)-1)|0x8000)
2.增加一些阻塞接口:
/**
* @brief block Get received byte from ringbuffer
* Returns in the lower byte the received character and in the
* higher byte the last receive error.
* UART_NO_DATA is returned when no data is available.
*
* @param void
* @return input char
*/
extern unsigned char uart_ngetc(void);
/**
* @brief block Put byte to ringbuffer for transmitting via UART
* @param data byte to be transmitted
* @return none
*/
extern void uart_nputc(unsigned char data);
/**
* @brief block Put string to ringbuffer for transmitting via UART
*
* The string is buffered by the uart library in a circular buffer
* and one character at a time is transmitted to the UART using interrupts.
* Blocks if it can not write the whole string into the circular buffer.
*
* @param s string to be transmitted
* @return none
*/
extern void uart_nputs(const char *s );
根据Tim的网页,该库支持的芯片型号有:
Supported AVR Models (in alphabetical order):
改修后代码:
uart.h:
#ifndef UART_H #define UART_H /************************************************************************ Title: Interrupt UART library with receive/transmit circular buffers Author: Peter Fleury <[email protected]> http://jump.to/fleury File: $Id: uart.h,v 1.8.2.1 2007/07/01 11:14:38 peter Exp $ Software: AVR-GCC 4.1, AVR Libc 1.4 Hardware: any AVR with built-in UART, tested on AT90S8515 & ATmega8 at 4 Mhz License: GNU General Public License Usage: see Doxygen manual LICENSE: Copyright (C) 2006 Peter Fleury This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ************************************************************************/ /************************************************************************ uart_available, uart_flush, uart1_available, and uart1_flush functions were adapted from the Arduino HardwareSerial.h library by Tim Sharpe on 11 Jan 2009. The license info for HardwareSerial.h is as follows: HardwareSerial.h - Hardware serial library for Wiring Copyright (c) 2006 Nicholas Zambetti. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ************************************************************************/ /************************************************************************ Changelog for modifications made by Tim Sharpe, starting with the current library version on his Web site as of 05/01/2009. Date Description ========================================================================= 05/12/2009 Added Arduino-style available() and flush() functions for both supported UARTs. Really wanted to keep them out of the library, so that it would be as close as possible to Peter Fleury's original library, but has scoping issues accessing internal variables from another program. Go C! ************************************************************************/ /** * @defgroup pfleury_uart UART Library * @code #include <uart.h> @endcode * * @brief Interrupt UART library using the built-in UART with transmit and receive circular buffers. * * This library can be used to transmit and receive data through the built in UART. * * An interrupt is generated when the UART has finished transmitting or * receiving a byte. The interrupt handling routines use circular buffers * for buffering received and transmitted data. * * The UART_RX_BUFFER_SIZE and UART_TX_BUFFER_SIZE constants define * the size of the circular buffers in bytes. Note that these constants must be a power of 2. * You may need to adapt this constants to your target and your application by adding * CDEFS += -DUART_RX_BUFFER_SIZE=nn -DUART_RX_BUFFER_SIZE=nn to your Makefile. * * @note Based on Atmel Application Note AVR306 * @author Peter Fleury [email protected] http://jump.to/fleury */ /**@{*/ #if (__GNUC__ * 100 + __GNUC_MINOR__) < 304 #error "This library requires AVR-GCC 3.4 or later, update to newer AVR-GCC compiler !" #endif /* ** constants and macros */ /** @brief UART Baudrate Expression * @param xtalcpu system clock in Mhz, e.g. 4000000L for 4Mhz * @param baudrate baudrate in bps, e.g. 1200, 2400, 9600 */ #define UART_BAUD_SELECT(baudRate,xtalCpu) ((xtalCpu)/(baudRate)/16-1) //#define UART_BAUD_SELECT(baudRate,xtalCpu) ((xtalCpu)/((baudRate)*16l)-1) /** @brief UART Baudrate Expression for ATmega double speed mode * @param xtalcpu system clock in Mhz, e.g. 4000000L for 4Mhz * @param baudrate baudrate in bps, e.g. 1200, 2400, 9600 */ #define UART_BAUD_SELECT_DOUBLE_SPEED(baudRate,xtalCpu) (((xtalCpu)/(baudRate)/8-1)|0x8000) //#define UART_BAUD_SELECT_DOUBLE_SPEED(baudRate,xtalCpu) (((xtalCpu)/((baudRate)*8l)-1)|0x8000) /** Size of the circular receive buffer, must be power of 2 */ #ifndef UART_RX_BUFFER_SIZE #define UART_RX_BUFFER_SIZE 32 #endif /** Size of the circular transmit buffer, must be power of 2 */ #ifndef UART_TX_BUFFER_SIZE #define UART_TX_BUFFER_SIZE 32 #endif /* test if the size of the circular buffers fits into SRAM */ #if ( (UART_RX_BUFFER_SIZE+UART_TX_BUFFER_SIZE) >= (RAMEND-0x60 ) ) #error "size of UART_RX_BUFFER_SIZE + UART_TX_BUFFER_SIZE larger than size of SRAM" #endif /* ** high byte error return code of uart_getc() */ #define UART_FRAME_ERROR 0x0800 /* Framing Error by UART */ #define UART_OVERRUN_ERROR 0x0400 /* Overrun condition by UART */ #define UART_BUFFER_OVERFLOW 0x0200 /* receive ringbuffer overflow */ #define UART_NO_DATA 0x0100 /* no receive data available */ /* ** function prototypes */ /** @brief Initialize UART and set baudrate @param baudrate Specify baudrate using macro UART_BAUD_SELECT() @return none */ extern void uart_init(unsigned int baudrate); /** * @brief Get received byte from ringbuffer * * Returns in the lower byte the received character and in the * higher byte the last receive error. * UART_NO_DATA is returned when no data is available. * * @param void * @return lower byte: received byte from ringbuffer * @return higher byte: last receive status * - \b 0 successfully received data from UART * - \b UART_NO_DATA * <br>no receive data available * - \b UART_BUFFER_OVERFLOW * <br>Receive ringbuffer overflow. * We are not reading the receive buffer fast enough, * one or more received character have been dropped * - \b UART_OVERRUN_ERROR * <br>Overrun condition by UART. * A character already present in the UART UDR register was * not read by the interrupt handler before the next character arrived, * one or more received characters have been dropped. * - \b UART_FRAME_ERROR * <br>Framing Error by UART */ extern unsigned int uart_getc(void); /** * @brief non-block Get received byte from ringbuffer * Returns in the lower byte the received character and in the * higher byte the last receive error. * UART_NO_DATA is returned when no data is available. * * @param void * @return input char */ extern unsigned char uart_ngetc(void); /** * @brief Put byte to ringbuffer for transmitting via UART * @param data byte to be transmitted * @return none */ extern void uart_putc(unsigned char data); /** * @brief non-block Put byte to ringbuffer for transmitting via UART * @param data byte to be transmitted * @return none */ extern void uart_nputc(unsigned char data); /** * @brief Put string to ringbuffer for transmitting via UART * * The string is buffered by the uart library in a circular buffer * and one character at a time is transmitted to the UART using interrupts. * Blocks if it can not write the whole string into the circular buffer. * * @param s string to be transmitted * @return none */ extern void uart_puts(const char *s ); /** * @brief non-block Put string to ringbuffer for transmitting via UART * * The string is buffered by the uart library in a circular buffer * and one character at a time is transmitted to the UART using interrupts. * Blocks if it can not write the whole string into the circular buffer. * * @param s string to be transmitted * @return none */ extern void uart_nputs(const char *s ); /** * @brief Put string from program memory to ringbuffer for transmitting via UART. * * The string is buffered by the uart library in a circular buffer * and one character at a time is transmitted to the UART using interrupts. * Blocks if it can not write the whole string into the circular buffer. * * @param s program memory string to be transmitted * @return none * @see uart_puts_P */ extern void uart_puts_p(const char *s ); /** * @brief Macro to automatically put a string constant into program memory */ #define uart_puts_P(__s) uart_puts_p(PSTR(__s)) /** * @brief Return number of bytes waiting in the receive buffer * @param none * @return bytes waiting in the receive buffer */ extern int uart_available(void); /** * @brief Flush bytes waiting in receive buffer * @param none * @return none */ extern void uart_flush(void); /** @brief Initialize USART1 (only available on selected ATmegas) @see uart_init */ extern void uart1_init(unsigned int baudrate); /** @brief Get received byte of USART1 from ringbuffer. (only available on selected ATmega) @see uart_getc */ extern unsigned int uart1_getc(void); /** @brief Put byte to ringbuffer for transmitting via USART1 (only available on selected ATmega) @see uart_putc */ extern void uart1_putc(unsigned char data); /** @brief Put string to ringbuffer for transmitting via USART1 (only available on selected ATmega) @see uart_puts */ extern void uart1_puts(const char *s ); /** @brief Put string from program memory to ringbuffer for transmitting via USART1 (only available on selected ATmega) @see uart_puts_p */ extern void uart1_puts_p(const char *s ); /** @brief Macro to automatically put a string constant into program memory */ #define uart1_puts_P(__s) uart1_puts_p(PSTR(__s)) /** @brief Return number of bytes waiting in the receive buffer */ extern int uart1_available(void); /** @brief Flush bytes waiting in receive buffer */ extern void uart1_flush(void); /**@}*/ #endif // UART_H
uart.c:
/************************************************************************* Title: Interrupt UART library with receive/transmit circular buffers Author: Peter Fleury <[email protected]> http://jump.to/fleury File: $Id: uart.c,v 1.6.2.1 2007/07/01 11:14:38 peter Exp $ Software: AVR-GCC 4.1, AVR Libc 1.4.6 or higher Hardware: any AVR with built-in UART, License: GNU General Public License DESCRIPTION: An interrupt is generated when the UART has finished transmitting or receiving a byte. The interrupt handling routines use circular buffers for buffering received and transmitted data. The UART_RX_BUFFER_SIZE and UART_TX_BUFFER_SIZE variables define the buffer size in bytes. Note that these variables must be a power of 2. USAGE: Refere to the header file uart.h for a description of the routines. See also example test_uart.c. NOTES: Based on Atmel Application Note AVR306 LICENSE: Copyright (C) 2006 Peter Fleury This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. *************************************************************************/ /************************************************************************ uart_available, uart_flush, uart1_available, and uart1_flush functions were adapted from the Arduino HardwareSerial.h library by Tim Sharpe on 11 Jan 2009. The license info for HardwareSerial.h is as follows: HardwareSerial.cpp - Hardware serial library for Wiring Copyright (c) 2006 Nicholas Zambetti. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Modified 23 November 2006 by David A. Mellis ************************************************************************/ /************************************************************************ Changelog for modifications made by Tim Sharpe, starting with the current library version on his Web site as of 05/01/2009. Date Description ========================================================================= 05/11/2009 Changed all existing UARTx_RECEIVE_INTERRUPT and UARTx_TRANSMIT_INTERRUPT macros to use the "_vect" format introduced in AVR-Libc v1.4.0. Had to split the 3290 and 6490 out of their existing macro due to an inconsistency in the UART0_RECEIVE_INTERRUPT vector name (seems like a typo: USART_RX_vect for the 3290/6490 vice USART0_RX_vect for the others in the macro). Verified all existing macro register names against the device header files in AVR-Libc v1.6.6 to catch any inconsistencies. 05/12/2009 Added support for 48P, 88P, 168P, and 328P by adding them to the existing 48/88/168 macro. Added Arduino-style available() and flush() functions for both supported UARTs. Really wanted to keep them out of the library, so that it would be as close as possible to Peter Fleury's original library, but has scoping issues accessing internal variables from another program. Go C! 05/13/2009 Changed Interrupt Service Routine label from the old "SIGNAL" to the "ISR" format introduced in AVR-Libc v1.4.0. ************************************************************************/ #include <avr/io.h> #include <avr/interrupt.h> #include <avr/pgmspace.h> #include "uart.h" /* * constants and macros */ /* size of RX/TX buffers */ #define UART_RX_BUFFER_MASK ( UART_RX_BUFFER_SIZE - 1) #define UART_TX_BUFFER_MASK ( UART_TX_BUFFER_SIZE - 1) #if ( UART_RX_BUFFER_SIZE & UART_RX_BUFFER_MASK ) #error RX buffer size is not a power of 2 #endif #if ( UART_TX_BUFFER_SIZE & UART_TX_BUFFER_MASK ) #error TX buffer size is not a power of 2 #endif #if defined(__AVR_AT90S2313__) \ || defined(__AVR_AT90S4414__) || defined(__AVR_AT90S4434__) \ || defined(__AVR_AT90S8515__) || defined(__AVR_AT90S8535__) \ || defined(__AVR_ATmega103__) /* old AVR classic or ATmega103 with one UART */ #define AT90_UART #define UART0_RECEIVE_INTERRUPT UART_RX_vect #define UART0_TRANSMIT_INTERRUPT UART_UDRE_vect #define UART0_STATUS USR #define UART0_CONTROL UCR #define UART0_DATA UDR #define UART0_UDRIE UDRIE #elif defined(__AVR_AT90S2333__) || defined(__AVR_AT90S4433__) /* old AVR classic with one UART */ #define AT90_UART #define UART0_RECEIVE_INTERRUPT UART_RX_vect #define UART0_TRANSMIT_INTERRUPT UART_UDRE_vect #define UART0_STATUS UCSRA #define UART0_CONTROL UCSRB #define UART0_DATA UDR #define UART0_UDRIE UDRIE #elif defined(__AVR_ATmega8__) || defined(__AVR_ATmega16__) || defined(__AVR_ATmega32__) \ || defined(__AVR_ATmega323__) /* ATmega with one USART */ #define ATMEGA_USART #define UART0_RECEIVE_INTERRUPT USART_RXC_vect #define UART0_TRANSMIT_INTERRUPT USART_UDRE_vect #define UART0_STATUS UCSRA #define UART0_CONTROL UCSRB #define UART0_DATA UDR #define UART0_UDRIE UDRIE #elif defined(__AVR_ATmega8515__) || defined(__AVR_ATmega8535__) /* ATmega with one USART */ #define ATMEGA_USART #define UART0_RECEIVE_INTERRUPT USART_RX_vect #define UART0_TRANSMIT_INTERRUPT USART_UDRE_vect #define UART0_STATUS UCSRA #define UART0_CONTROL UCSRB #define UART0_DATA UDR #define UART0_UDRIE UDRIE #elif defined(__AVR_ATmega163__) /* ATmega163 with one UART */ #define ATMEGA_UART #define UART0_RECEIVE_INTERRUPT UART_RX_vect #define UART0_TRANSMIT_INTERRUPT UART_UDRE_vect #define UART0_STATUS UCSRA #define UART0_CONTROL UCSRB #define UART0_DATA UDR #define UART0_UDRIE UDRIE #elif defined(__AVR_ATmega162__) /* ATmega with two USART */ #define ATMEGA_USART0 #define ATMEGA_USART1 #define UART0_RECEIVE_INTERRUPT USART0_RXC_vect #define UART1_RECEIVE_INTERRUPT USART1_RXC_vect #define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect #define UART1_TRANSMIT_INTERRUPT USART1_UDRE_vect #define UART0_STATUS UCSR0A #define UART0_CONTROL UCSR0B #define UART0_DATA UDR0 #define UART0_UDRIE UDRIE0 #define UART1_STATUS UCSR1A #define UART1_CONTROL UCSR1B #define UART1_DATA UDR1 #define UART1_UDRIE UDRIE1 #elif defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__) /* ATmega with two USART */ #define ATMEGA_USART0 #define ATMEGA_USART1 #define UART0_RECEIVE_INTERRUPT USART0_RX_vect #define UART1_RECEIVE_INTERRUPT USART1_RX_vect #define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect #define UART1_TRANSMIT_INTERRUPT USART1_UDRE_vect #define UART0_STATUS UCSR0A #define UART0_CONTROL UCSR0B #define UART0_DATA UDR0 #define UART0_UDRIE UDRIE0 #define UART1_STATUS UCSR1A #define UART1_CONTROL UCSR1B #define UART1_DATA UDR1 #define UART1_UDRIE UDRIE1 #elif defined(__AVR_ATmega161__) /* ATmega with UART */ #error "AVR ATmega161 currently not supported by this libaray !" #elif defined(__AVR_ATmega169__) /* ATmega with one USART */ #define ATMEGA_USART #define UART0_RECEIVE_INTERRUPT USART0_RX_vect #define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect #define UART0_STATUS UCSRA #define UART0_CONTROL UCSRB #define UART0_DATA UDR #define UART0_UDRIE UDRIE #elif defined(__AVR_ATmega48__) ||defined(__AVR_ATmega88__) || defined(__AVR_ATmega168__) || \ defined(__AVR_ATmega48P__) ||defined(__AVR_ATmega88P__) || defined(__AVR_ATmega168P__) || \ defined(__AVR_ATmega328P__) /* TLS-Added 48P/88P/168P/328P */ /* ATmega with one USART */ #define ATMEGA_USART0 #define UART0_RECEIVE_INTERRUPT USART_RX_vect #define UART0_TRANSMIT_INTERRUPT USART_UDRE_vect #define UART0_STATUS UCSR0A #define UART0_CONTROL UCSR0B #define UART0_DATA UDR0 #define UART0_UDRIE UDRIE0 #elif defined(__AVR_ATtiny2313__) #define ATMEGA_USART #define UART0_RECEIVE_INTERRUPT USART_RX_vect #define UART0_TRANSMIT_INTERRUPT USART_UDRE_vect #define UART0_STATUS UCSRA #define UART0_CONTROL UCSRB #define UART0_DATA UDR #define UART0_UDRIE UDRIE #elif defined(__AVR_ATmega329__) ||\ defined(__AVR_ATmega649__) ||\ defined(__AVR_ATmega325__) ||defined(__AVR_ATmega3250__) ||\ defined(__AVR_ATmega645__) ||defined(__AVR_ATmega6450__) /* ATmega with one USART */ #define ATMEGA_USART0 #define UART0_RECEIVE_INTERRUPT USART0_RX_vect #define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect #define UART0_STATUS UCSR0A #define UART0_CONTROL UCSR0B #define UART0_DATA UDR0 #define UART0_UDRIE UDRIE0 #elif defined(__AVR_ATmega3290__) ||\ defined(__AVR_ATmega6490__) || /* TLS-Separated these two from the previous group because of inconsistency in the USART_RX */ /* ATmega with one USART */ #define ATMEGA_USART0 #define UART0_RECEIVE_INTERRUPT USART_RX_vect #define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect #define UART0_STATUS UCSR0A #define UART0_CONTROL UCSR0B #define UART0_DATA UDR0 #define UART0_UDRIE UDRIE0 #elif defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega640__) /* ATmega with two USART */ #define ATMEGA_USART0 #define ATMEGA_USART1 #define UART0_RECEIVE_INTERRUPT USART0_RX_vect #define UART1_RECEIVE_INTERRUPT USART0_UDRE_vect #define UART0_TRANSMIT_INTERRUPT USART1_RX_vect #define UART1_TRANSMIT_INTERRUPT USART1_UDRE_vect #define UART0_STATUS UCSR0A #define UART0_CONTROL UCSR0B #define UART0_DATA UDR0 #define UART0_UDRIE UDRIE0 #define UART1_STATUS UCSR1A #define UART1_CONTROL UCSR1B #define UART1_DATA UDR1 #define UART1_UDRIE UDRIE1 #elif defined(__AVR_ATmega644__) /* ATmega with one USART */ #define ATMEGA_USART0 #define UART0_RECEIVE_INTERRUPT USART0_RX_vect #define UART0_TRANSMIT_INTERRUPT USART0_UDRE_vect #define UART0_STATUS UCSR0A #define UART0_CONTROL UCSR0B #define UART0_DATA UDR0 #define UART0_UDRIE UDRIE0 #elif defined(__AVR_ATmega164P__) || defined(__AVR_ATmega324P__) || defined(__AVR_ATmega644P__) /* ATmega with two USART */ #define ATMEGA_USART0 #define ATMEGA_USART1 #define UART0_RECEIVE_INTERRUPT USART0_RX_vect #define UART1_RECEIVE_INTERRUPT USART0_UDRE_vect #define UART0_TRANSMIT_INTERRUPT USART1_RX_vect #define UART1_TRANSMIT_INTERRUPT USART1_UDRE_vect #define UART0_STATUS UCSR0A #define UART0_CONTROL UCSR0B #define UART0_DATA UDR0 #define UART0_UDRIE UDRIE0 #define UART1_STATUS UCSR1A #define UART1_CONTROL UCSR1B #define UART1_DATA UDR1 #define UART1_UDRIE UDRIE1 #else #error "no UART definition for MCU available" #endif /* * module global variables */ static volatile unsigned char UART_TxBuf[UART_TX_BUFFER_SIZE]; static volatile unsigned char UART_RxBuf[UART_RX_BUFFER_SIZE]; static volatile unsigned char UART_TxHead; static volatile unsigned char UART_TxTail; static volatile unsigned char UART_RxHead; static volatile unsigned char UART_RxTail; static volatile unsigned char UART_LastRxError; #if defined( ATMEGA_USART1 ) static volatile unsigned char UART1_TxBuf[UART_TX_BUFFER_SIZE]; static volatile unsigned char UART1_RxBuf[UART_RX_BUFFER_SIZE]; static volatile unsigned char UART1_TxHead; static volatile unsigned char UART1_TxTail; static volatile unsigned char UART1_RxHead; static volatile unsigned char UART1_RxTail; static volatile unsigned char UART1_LastRxError; #endif ISR(UART0_RECEIVE_INTERRUPT) /************************************************************************* Function: UART Receive Complete interrupt Purpose: called when the UART has received a character **************************************************************************/ { unsigned char tmphead; unsigned char data; unsigned char usr; unsigned char lastRxError; /* read UART status register and UART data register */ usr = UART0_STATUS; data = UART0_DATA; /* */ #if defined( AT90_UART ) lastRxError = (usr & (_BV(FE)|_BV(DOR)) ); #elif defined( ATMEGA_USART ) lastRxError = (usr & (_BV(FE)|_BV(DOR)) ); #elif defined( ATMEGA_USART0 ) lastRxError = (usr & (_BV(FE0)|_BV(DOR0)) ); #elif defined ( ATMEGA_UART ) lastRxError = (usr & (_BV(FE)|_BV(DOR)) ); #endif /* calculate buffer index */ tmphead = ( UART_RxHead + 1) & UART_RX_BUFFER_MASK; if ( tmphead == UART_RxTail ) { /* error: receive buffer overflow */ lastRxError = UART_BUFFER_OVERFLOW >> 8; }else{ /* store new index */ UART_RxHead = tmphead; /* store received data in buffer */ UART_RxBuf[tmphead] = data; } UART_LastRxError = lastRxError; } ISR(UART0_TRANSMIT_INTERRUPT) /************************************************************************* Function: UART Data Register Empty interrupt Purpose: called when the UART is ready to transmit the next byte **************************************************************************/ { unsigned char tmptail; if ( UART_TxHead != UART_TxTail) { /* calculate and store new buffer index */ tmptail = (UART_TxTail + 1) & UART_TX_BUFFER_MASK; UART_TxTail = tmptail; /* get one byte from buffer and write it to UART */ UART0_DATA = UART_TxBuf[tmptail]; /* start transmission */ }else{ /* tx buffer empty, disable UDRE interrupt */ UART0_CONTROL &= ~_BV(UART0_UDRIE); } } /************************************************************************* Function: uart_init() Purpose: initialize UART and set baudrate Input: baudrate using macro UART_BAUD_SELECT() Returns: none **************************************************************************/ void uart_init(unsigned int baudrate) { UART_TxHead = 0; UART_TxTail = 0; UART_RxHead = 0; UART_RxTail = 0; #if defined( AT90_UART ) /* set baud rate */ UBRR = (unsigned char)baudrate; /* enable UART receiver and transmmitter and receive complete interrupt */ UART0_CONTROL = _BV(RXCIE)|_BV(RXEN)|_BV(TXEN); #elif defined (ATMEGA_USART) /* Set baud rate */ if ( baudrate & 0x8000 ) { UART0_STATUS = (1<<U2X); //Enable 2x speed baudrate &= ~0x8000; } UBRRH = (unsigned char)(baudrate>>8); UBRRL = (unsigned char) baudrate; /* Enable USART receiver and transmitter and receive complete interrupt */ UART0_CONTROL = _BV(RXCIE)|(1<<RXEN)|(1<<TXEN); /* Set frame format: asynchronous, 8data, no parity, 1stop bit */ #ifdef URSEL UCSRC = (1<<URSEL)|(3<<UCSZ0); #else UCSRC = (3<<UCSZ0); #endif #elif defined (ATMEGA_USART0 ) /* Set baud rate */ if ( baudrate & 0x8000 ) { UART0_STATUS = (1<<U2X0); //Enable 2x speed baudrate &= ~0x8000; } UBRR0H = (unsigned char)(baudrate>>8); UBRR0L = (unsigned char) baudrate; /* Enable USART receiver and transmitter and receive complete interrupt */ UART0_CONTROL = _BV(RXCIE0)|(1<<RXEN0)|(1<<TXEN0); /* Set frame format: asynchronous, 8data, no parity, 1stop bit */ #ifdef URSEL0 UCSR0C = (1<<URSEL0)|(3<<UCSZ00); #else UCSR0C = (3<<UCSZ00); #endif #elif defined ( ATMEGA_UART ) /* set baud rate */ if ( baudrate & 0x8000 ) { UART0_STATUS = (1<<U2X); //Enable 2x speed baudrate &= ~0x8000; } UBRRHI = (unsigned char)(baudrate>>8); UBRR = (unsigned char) baudrate; /* Enable UART receiver and transmitter and receive complete interrupt */ UART0_CONTROL = _BV(RXCIE)|(1<<RXEN)|(1<<TXEN); #endif }/* uart_init */ /************************************************************************* Function: uart_getc() Purpose: return byte from ringbuffer Returns: lower byte: received byte from ringbuffer higher byte: last receive error **************************************************************************/ unsigned int uart_getc(void) { unsigned char tmptail; unsigned char data; if ( UART_RxHead == UART_RxTail ) { return UART_NO_DATA; /* no data available */ } /* calculate /store buffer index */ tmptail = (UART_RxTail + 1) & UART_RX_BUFFER_MASK; UART_RxTail = tmptail; /* get data from receive buffer */ data = UART_RxBuf[tmptail]; return (UART_LastRxError << 8) + data; }/* uart_getc */ /************************************************************************* Function: uart_ngetc() Purpose: non-block return byte from ringbuffer Returns: char input **************************************************************************/ unsigned char uart_ngetc(void) { while ( !(UART0_STATUS & (1<<RXC)) ); return UART0_DATA; }/* uart_ngetc */ /************************************************************************* Function: uart_putc() Purpose: write byte to ringbuffer for transmitting via UART Input: byte to be transmitted Returns: none **************************************************************************/ void uart_putc(unsigned char data) { unsigned char tmphead; tmphead = (UART_TxHead + 1) & UART_TX_BUFFER_MASK; while ( tmphead == UART_TxTail ){ ;/* wait for free space in buffer */ } UART_TxBuf[tmphead] = data; UART_TxHead = tmphead; /* enable UDRE interrupt */ UART0_CONTROL |= _BV(UART0_UDRIE); }/* uart_putc */ /************************************************************************* Function: uart_nputc() Purpose: non-block write byte to ringbuffer for transmitting via UART Input: byte to be transmitted Returns: none **************************************************************************/ void uart_nputc(unsigned char data) { while (!(UART0_STATUS & (1<<UDRE)) ) ; UART0_DATA = data; }/* uart_nputc */ /************************************************************************* Function: uart_puts() Purpose: transmit string to UART Input: string to be transmitted Returns: none **************************************************************************/ void uart_puts(const char *s ) { while (*s) uart_putc(*s++); }/* uart_puts */ /************************************************************************* Function: uart_nputs() Purpose: non-block transmit string to UART Input: string to be transmitted Returns: none **************************************************************************/ void uart_nputs(const char *s ) { while (*s) uart_nputc(*s++); }/* uart_nputs */ /************************************************************************* Function: uart_puts_p() Purpose: transmit string from program memory to UART Input: program memory string to be transmitted Returns: none **************************************************************************/ void uart_puts_p(const char *progmem_s ) { register char c; while ( (c = pgm_read_byte(progmem_s++)) ) uart_putc(c); }/* uart_puts_p */ /************************************************************************* Function: uart_available() Purpose: Determine the number of bytes waiting in the receive buffer Input: None Returns: Integer number of bytes in the receive buffer **************************************************************************/ int uart_available(void) { return (UART_RX_BUFFER_MASK + UART_RxHead - UART_RxTail) % UART_RX_BUFFER_MASK; }/* uart_available */ /************************************************************************* Function: uart_flush() Purpose: Flush bytes waiting the receive buffer. Acutally ignores them. Input: None Returns: None **************************************************************************/ void uart_flush(void) { UART_RxHead = UART_RxTail; }/* uart_flush */ /* * these functions are only for ATmegas with two USART */ #if defined( ATMEGA_USART1 ) SIGNAL(UART1_RECEIVE_INTERRUPT) /************************************************************************* Function: UART1 Receive Complete interrupt Purpose: called when the UART1 has received a character **************************************************************************/ { unsigned char tmphead; unsigned char data; unsigned char usr; unsigned char lastRxError; /* read UART status register and UART data register */ usr = UART1_STATUS; data = UART1_DATA; /* */ lastRxError = (usr & (_BV(FE1)|_BV(DOR1)) ); /* calculate buffer index */ tmphead = ( UART1_RxHead + 1) & UART_RX_BUFFER_MASK; if ( tmphead == UART1_RxTail ) { /* error: receive buffer overflow */ lastRxError = UART_BUFFER_OVERFLOW >> 8; }else{ /* store new index */ UART1_RxHead = tmphead; /* store received data in buffer */ UART1_RxBuf[tmphead] = data; } UART1_LastRxError = lastRxError; } SIGNAL(UART1_TRANSMIT_INTERRUPT) /************************************************************************* Function: UART1 Data Register Empty interrupt Purpose: called when the UART1 is ready to transmit the next byte **************************************************************************/ { unsigned char tmptail; if ( UART1_TxHead != UART1_TxTail) { /* calculate and store new buffer index */ tmptail = (UART1_TxTail + 1) & UART_TX_BUFFER_MASK; UART1_TxTail = tmptail; /* get one byte from buffer and write it to UART */ UART1_DATA = UART1_TxBuf[tmptail]; /* start transmission */ }else{ /* tx buffer empty, disable UDRE interrupt */ UART1_CONTROL &= ~_BV(UART1_UDRIE); } } /************************************************************************* Function: uart1_init() Purpose: initialize UART1 and set baudrate Input: baudrate using macro UART_BAUD_SELECT() Returns: none **************************************************************************/ void uart1_init(unsigned int baudrate) { UART1_TxHead = 0; UART1_TxTail = 0; UART1_RxHead = 0; UART1_RxTail = 0; /* Set baud rate */ if ( baudrate & 0x8000 ) { UART1_STATUS = (1<<U2X1); //Enable 2x speed baudrate &= ~0x8000; } UBRR1H = (unsigned char)(baudrate>>8); UBRR1L = (unsigned char) baudrate; /* Enable USART receiver and transmitter and receive complete interrupt */ UART1_CONTROL = _BV(RXCIE1)|(1<<RXEN1)|(1<<TXEN1); /* Set frame format: asynchronous, 8data, no parity, 1stop bit */ #ifdef URSEL1 UCSR1C = (1<<URSEL1)|(3<<UCSZ10); #else UCSR1C = (3<<UCSZ10); #endif }/* uart_init */ /************************************************************************* Function: uart1_getc() Purpose: return byte from ringbuffer Returns: lower byte: received byte from ringbuffer higher byte: last receive error **************************************************************************/ unsigned int uart1_getc(void) { unsigned char tmptail; unsigned char data; if ( UART1_RxHead == UART1_RxTail ) { return UART_NO_DATA; /* no data available */ } /* calculate /store buffer index */ tmptail = (UART1_RxTail + 1) & UART_RX_BUFFER_MASK; UART1_RxTail = tmptail; /* get data from receive buffer */ data = UART1_RxBuf[tmptail]; return (UART1_LastRxError << 8) + data; }/* uart1_getc */ /************************************************************************* Function: uart1_putc() Purpose: write byte to ringbuffer for transmitting via UART Input: byte to be transmitted Returns: none **************************************************************************/ void uart1_putc(unsigned char data) { unsigned char tmphead; tmphead = (UART1_TxHead + 1) & UART_TX_BUFFER_MASK; while ( tmphead == UART1_TxTail ){ ;/* wait for free space in buffer */ } UART1_TxBuf[tmphead] = data; UART1_TxHead = tmphead; /* enable UDRE interrupt */ UART1_CONTROL |= _BV(UART1_UDRIE); }/* uart1_putc */ /************************************************************************* Function: uart1_puts() Purpose: transmit string to UART1 Input: string to be transmitted Returns: none **************************************************************************/ void uart1_puts(const char *s ) { while (*s) uart1_putc(*s++); }/* uart1_puts */ /************************************************************************* Function: uart1_puts_p() Purpose: transmit string from program memory to UART1 Input: program memory string to be transmitted Returns: none **************************************************************************/ void uart1_puts_p(const char *progmem_s ) { register char c; while ( (c = pgm_read_byte(progmem_s++)) ) uart1_putc(c); }/* uart1_puts_p */ /************************************************************************* Function: uart1_available() Purpose: Determine the number of bytes waiting in the receive buffer Input: None Returns: Integer number of bytes in the receive buffer **************************************************************************/ int uart1_available(void) { return (UART_RX_BUFFER_MASK + UART1_RxHead - UART1_RxTail) % UART_RX_BUFFER_MASK; }/* uart1_available */ /************************************************************************* Function: uart1_flush() Purpose: Flush bytes waiting the receive buffer. Acutally ignores them. Input: None Returns: None **************************************************************************/ void uart1_flush(void) { UART1_RxHead = UART1_RxTail; }/* uart1_flush */ #endif