⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 uart.c

📁 基于AVR ATmega32 单片机的DS1820驱动程序 基于winavr 平台编译
💻 C
字号:
/*************************************************************************
Title:     Interrupt UART library with receive/transmit circular buffers
Author:    Peter Fleury <pfleury@gmx.ch>   http://jump.to/fleury
File:      $Id: uart.c,v 1.5.2.2 2004/02/27 22:00:28 peter Exp $
Software:  AVR-GCC 3.3 
Hardware:  any AVR with built-in UART, 
           tested on AT90S8515 at 4 Mhz and ATmega at 1Mhz
Extension: uart_puti, uart_puthex by M.Thomas 9/2004

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
                    
*************************************************************************/
#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.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__)
 /* old AVR classic with one UART */
 #define AT90_UART
 #define UART0_RECEIVE_INTERRUPT   SIG_UART_RECV
 #define UART0_TRANSMIT_INTERRUPT  SIG_UART_DATA
 #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   SIG_UART_RECV
 #define UART0_TRANSMIT_INTERRUPT  SIG_UART_DATA
 #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_ATmega8515__) || defined(__AVR_ATmega8535__) \
  || defined(__AVR_ATmega323__) 
  /* ATMega with one USART */
 #define ATMEGA_USART
 #define UART0_RECEIVE_INTERRUPT   SIG_UART_RECV
 #define UART0_TRANSMIT_INTERRUPT  SIG_UART_DATA
 #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   SIG_UART_RECV
 #define UART0_TRANSMIT_INTERRUPT  SIG_UART_DATA
 #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   SIG_USART0_RECV
 #define UART1_RECEIVE_INTERRUPT   SIG_USART1_RECV
 #define UART0_TRANSMIT_INTERRUPT  SIG_USART0_DATA
 #define UART1_TRANSMIT_INTERRUPT  SIG_USART1_DATA
 #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   SIG_UART0_RECV
 #define UART1_RECEIVE_INTERRUPT   SIG_UART1_RECV
 #define UART0_TRANSMIT_INTERRUPT  SIG_UART0_DATA
 #define UART1_TRANSMIT_INTERRUPT  SIG_UART1_DATA
 #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_ATmega103__)
 /* ATMega with one UART */
 #error "AVR ATmega103 currently not supported by this libaray !"
#elif defined(__AVR_ATmega161__)
 /* ATmega with UART */
 #error "AVR ATmega161 currently not supported by this libaray !"
#elif defined(__AVR_ATmega169__)
 #error "AVR ATmega169 currently not supported by this libaray !"
#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;



SIGNAL(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;   
 }


SIGNAL(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 */
   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 */
   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 */
   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_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_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_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_puti()
Purpose:  transmit integer as ASCII to UART
Input:    integer value
Returns:  none
This functions has been added by Martin Thomas <eversmith@heizung-thomas.de>
Don't blame P. Fleury if it doesn't work ;-)
**************************************************************************/
void uart_puti( const int val )
 { char buffer[sizeof(int)*8+1];
  
   uart_puts( itoa(val, buffer, 10) );
 }/* uart_puti */

/*************************************************************************
Function: uart_puthex_nibble()
Purpose:  transmit lower nibble as ASCII-hex to UART
Input:    byte value
Returns:  none
This functions has been added by Martin Thomas <eversmith@heizung-thomas.de>
Don't blame P. Fleury if it doesn't work ;-)
**************************************************************************/
void uart_puthex_nibble(const unsigned char b)
 { unsigned char  c = b & 0x0f;
   if (c>9) c += 'A'-10;
   else c += '0';
   uart_putc(c);
 } /* uart_puthex_nibble */

/*************************************************************************
Function: uart_puthex_byte()
Purpose:  transmit upper and lower nibble as ASCII-hex to UART
Input:    byte value
Returns:  none
This functions has been added by Martin Thomas <eversmith@heizung-thomas.de>
Don't blame P. Fleury if it doesn't work ;-)
**************************************************************************/
void uart_puthex_byte(const unsigned char  b)
 { uart_puthex_nibble(b>>4);
   uart_puthex_nibble(b);
 } /* uart_puthex_byte */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -