📄 uart.c
字号:
/*! \file uart.c \brief UART driver with buffer support. */
// *****************************************************************************
//
// File Name : 'uart.c'
// Title : UART driver with buffer support
// Author : Pascal Stang - Copyright (C) 2000-2002
// Created : 11/22/2000
// Revised : 11/01/2001
// Version : 1.3
// Target MCU : ATMEL AVR Series
// Editor Tabs : 4
//
// This code is distributed under the GNU Public License
// which can be found at http://www.gnu.org/licenses/gpl.txt
//
// *****************************************************************************
#include <io.h>
#include <interrupt.h>
#include <sig-avr.h>
#include "buffer.h"
#include "uart.h"
// UART global variables
// flag variables
volatile u08 uartReadyTx; //!< uartReadyTx flag
volatile u08 uartBufferedTx; //!< uartBufferedTx flag
// receive and transmit buffers
cBuffer uartRxBuffer; //!< uart receive buffer
cBuffer uartTxBuffer; //!< uart transmit buffer
unsigned short uartRxOverflow; //!< receive overflow counter
#ifndef UART_BUFFERS_EXTERNAL_RAM
// using internal ram,
// automatically allocate space in ram for each buffer
static char uartRxData[UART_RX_BUFFER_SIZE];
static char uartTxData[UART_TX_BUFFER_SIZE];
#endif
//! enable and initialize the uart
void uartInit(void)
{
// initialize the buffers
uartInitBuffers();
// enable RxD/TxD and interrupts
#ifdef UCR
// this line for AT90S8515,8535,ATmega103,etc
outb(UCR, BV(RXCIE)|BV(TXCIE)|BV(RXEN)|BV(TXEN));
#endif
#ifdef UCSRB
// this line for the Mega163
outb(UCSRB, BV(RXCIE)|BV(TXCIE)|BV(RXEN)|BV(TXEN));
#endif
#ifdef UCSR0B
// this line for dual-uart proessors like the Mega161/Mega128
outb(UCSR0B, BV(RXCIE)|BV(TXCIE)|BV(RXEN)|BV(TXEN));
#endif
// set default baud rate
uartSetBaudRate(UART_BAUD_RATE);
// initialize states
uartReadyTx = TRUE;
uartBufferedTx = FALSE;
// clear overflow count
uartRxOverflow = 0;
// enable interrupts
sei();
}
//! create and initialize the uart transmit and receive buffers
void uartInitBuffers(void)
{
#ifndef UART_BUFFERS_EXTERNAL_RAM
// initialize the UART receive buffer
bufferInit(&uartRxBuffer, uartRxData, UART_RX_BUFFER_SIZE);
// initialize the UART transmit buffer
bufferInit(&uartTxBuffer, uartTxData, UART_TX_BUFFER_SIZE);
#else
// initialize the UART receive buffer
bufferInit(&uartRxBuffer, (u08*) UART_RX_BUFFER_ADDR, UART_RX_BUFFER_SIZE);
// initialize the UART transmit buffer
bufferInit(&uartTxBuffer, (u08*) UART_TX_BUFFER_ADDR, UART_TX_BUFFER_SIZE);
#endif
}
//! set the uart baud rate
void uartSetBaudRate(u32 baudrate)
{
// calculate division factor for requested baud rate, and set it
outb(UBRR, (u08)((F_CPU+(baudrate*8L))/(baudrate*16L)-1));
}
//! returns the receive buffer structure
cBuffer* uartGetRxBuffer(void)
{
// return rx buffer pointer
return &uartRxBuffer;
}
//! returns the transmit buffer structure
cBuffer* uartGetTxBuffer(void)
{
// return tx buffer pointer
return &uartTxBuffer;
}
//! transmits a byte over the uart
void uartSendByte(u08 txData)
{
// wait for the transmitter to be ready
while(!uartReadyTx);
// send byte
outp( txData, UDR );
// set ready state to FALSE
uartReadyTx = FALSE;
}
//! gets a byte (if available) from the uart receive buffer
u08 uartReceiveByte(u08* rxData)
{
// make sure we have a receive buffer
if(uartRxBuffer.size)
{
// make sure we have data
if(uartRxBuffer.datalength)
{
// get byte from beginning of buffer
*rxData = bufferGetFromFront(&uartRxBuffer);
return TRUE;
}
else
{
// no data
return FALSE;
}
}
else
{
// no buffer
return FALSE;
}
}
//! flush all data out of the receive buffer
void uartFlushReceiveBuffer(void)
{
// flush all data from receive buffer
bufferFlush(&uartRxBuffer);
// same effect as above
// uartRxBuffer.datalength = 0;
}
//! return true if uart receive buffer is empty
u08 uartReceiveBufferIsEmpty(void)
{
if(uartRxBuffer.datalength == 0)
{
return TRUE;
}
else
{
return FALSE;
}
}
//! start transmission of the current uart Tx buffer contents
void uartSendTxBuffer(void)
{
// turn on buffered transmit
uartBufferedTx = TRUE;
// send the first byte to get things going by interrupts
uartSendByte(bufferGetFromFront(&uartTxBuffer));
}
//! transmit nBytes from buffer out the uart
u08 uartSendBuffer(char *buffer, u16 nBytes)
{
register u08 first;
register u16 i;
// check if there's space (and that we have any bytes to send at all)
if((uartTxBuffer.datalength + nBytes < uartTxBuffer.size) && nBytes)
{
// grab first character
first = *buffer++;
// copy user buffer to uart transmit buffer
for(i = 0; i < nBytes-1; i++)
{
// put data bytes at end of buffer
bufferAddToEnd(&uartTxBuffer, *buffer++);
}
// send the first byte to get things going by interrupts
uartBufferedTx = TRUE;
uartSendByte(first);
// return success
return TRUE;
}
else
{
// return failure
return FALSE;
}
}
//! UART Transmit Complete Interrupt Handler
SIGNAL(SIG_UART_TRANS)
{
// check if buffered tx is enabled
if(uartBufferedTx)
{
// check if there's data left in the buffer
if(uartTxBuffer.datalength)
{
// send byte from top of buffer
outp( bufferGetFromFront(&uartTxBuffer), UDR );
}
else
{
// no data left
uartBufferedTx = FALSE;
// return to ready state
uartReadyTx = TRUE;
}
}
else
{
// we're using single-byte tx mode
// indicate transmit complete, back to ready
uartReadyTx = TRUE;
}
}
//! UART Receive Complete Interrupt Handler
SIGNAL(SIG_UART_RECV)
{
// put received char in buffer
// check if there's space
if( !bufferAddToEnd(&uartRxBuffer, inp(UDR)) )
{
// no space in buffer
// count overflow
uartRxOverflow++;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -