【转】Atmega32串口驱动(基于ucos)——循环缓冲区
原文地址:http://bbs.ednchina.com/BLOG_ARTICLE_235210.HTM
/* ******************************************************************
* Filename: uart.c
* Author: lstzixing
* Mail: blievethink@gmail.com
* Date: 2009-5-26
* Description: 串口数据收发接口. For Atmega32
* ****************************************************************** */
#include "app.h"
// 对发送缓冲,信号计数为空闲字符数
// 对接收缓冲,计数为缓冲已有计数
typedef struct _FIFO
{
INT8U * buf; // FIFO缓冲区
INT8U * in, * out; // FIFO读写指针
OS_EVENT * sem; // FIFO读写同步信号量
}FIFO;
static INT8U UartTxBuf[ UART_TX_LEN ]; // 发送缓冲
static INT8U UartRxBuf[ UART_RX_LEN ]; // 接收缓冲
static FIFO UartTxFifo, UartRxFifo; // 收发缓冲控制FIFO结构
OS_SEM_DATA SemData;
static INT8U UartPutRxChar( INT8U c );
static INT8U UartGetTxChar( INT8U * err );
#define UartStartTx() { UCSRB |= 1<<UDRIE; }
#define UartStopTx() { UCSRB &= ~(1<<UDRIE); }
#define UartStartRx() { UCSRB |= 1<<RXCIE; }
#define UartStopRx() { UCSRB &= ~( 1<<RXCIE ); }
/* ****************************************************************
* UartFlush()
* 功能:缓冲清空
* 参数: isTxBuf ------ 是否为发送缓冲
* 返回值:None
* 说明:清空收发缓冲
* *************************************************************** */
void UartFlush( INT8U isTxBuf )
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
INT8U cnt;
OS_ENTER_CRITICAL();
if( isTxBuf )
{
UartTxFifo.buf = UartTxBuf; // 复位发送缓冲读写指针
UartTxFifo.in = UartTxBuf;
UartTxFifo.out = UartTxBuf;
OSSemQuery( UartTxFifo.sem, &SemData );
cnt = UART_TX_LEN - SemData.OSCnt; // 在其它地方必须保证SemData.OSCnt < UART_TX_LEN
while( cnt-- )
OSSemPost( UartTxFifo.sem ); // 复位发送信号量值为UART_TX_LEN
}
else
{
UartRxFifo.buf = UartRxBuf; // 复位接收缓冲读写指针
UartRxFifo.in = UartRxBuf;
UartRxFifo.out = UartRxBuf;
while( OSSemAccept( UartRxFifo.sem ) ); // 复位接收信号量值为0
}
OS_EXIT_CRITICAL();
}
void UartPutStr( char * str )
{
char * ptr;
ptr = (char *)str;
while(*ptr != '\0')
UartPutChar( *ptr++, 0 );
}
/* *****************************************************************
* UartPutChar()
* 函数名:UartPutChar()
* 功能: 发送一字节至串口缓冲区
* 参数: c ----------- 要发送的字节
* to ---------- 指定的等待操作完成的超时时间
* 返回值: OS_NO_ERR --- 操作成功
* OS_TIMEOUT --- 操作超时
* 说明:
* ***************************************************************** */
INT8U UartPutChar( INT8U c, INT16U to )
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
INT8U err;
OSSemPend( UartTxFifo.sem, to, &err ); // 等待发送缓冲可用
if( err == OS_NO_ERR )
{
OS_ENTER_CRITICAL();
*(UartTxFifo.in)++ = c;
if( UartTxFifo.in >= UartTxBuf + UART_TX_LEN) // 调整指针
UartTxFifo.in = UartTxBuf;
OS_EXIT_CRITICAL();
// 启动发送
UartStartTx();
}
return err;
}
/* ***************************************************************
* UartGetChar()
* 函数名:UartGetChar()
* 功能:从接收缓冲区中取一字节
* 参数: to --- 指定的超时量
* err --- 指定存储错误变量
* OS_TIMEOUT / OS_NO_ERR
* 返回值: 接收的字节
* 说明:NO
* *************************************************************** */
INT8U UartGetChar( INT16U to, INT8U * err )
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
INT8U c;
c = 0;
OSSemPend( UartRxFifo.sem, to, err );
if( *err != OS_TIMEOUT )
{
OS_ENTER_CRITICAL();
c = *(UartRxFifo.out)++; // 写入字节
if( UartRxFifo.out >= UartRxBuf + UART_RX_LEN ) // 调整指针
UartRxFifo.out = UartRxBuf;
OS_EXIT_CRITICAL();
UartStartRx(); // 接收缓冲非满,使能接收
}
return c;
}
/* ******************************************************************
* UartHdInit()
* 函数名:UartInit()
* 说明:
* 参数:baudrate ----- 波特率
* partity ------ 奇偶校验方式
* stops ------ 停止位数
* len -------- 数据帧长度
* 说明:此函数必须最先被调用
* ****************************************************************** */
void UartInit( void )
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
UartTxFifo.sem = OSSemCreate( UART_TX_LEN ); // 发送结构初始化
UartTxFifo.buf = UartTxBuf;
UartTxFifo.in = UartTxFifo.out = UartTxBuf;
UartRxFifo.sem = OSSemCreate( 0 ); // 接收结构初始化
UartRxFifo.buf = UartRxBuf;
UartRxFifo.in = UartRxFifo.out = UartRxBuf;
// 初始化串口,设置baudrate, len, parity, stops --
OS_ENTER_CRITICAL();
// UCSRA = 0xff;
UCSRB = 1<<RXCIE | 1<<RXEN | 1<<TXEN; // 收发使能,接收中断
UCSRC = 1<<URSEL| 1<<UPM1| 1<<UPM0| 1<<UCSZ1| 1<<UCSZ0; // 异步,8位字节,奇校验
UBRRL = ((INT32U)F_OSC / (16*(INT32U)UART_BAUD ) - 1 ) & 0xff; // 设置波特率
UBRRH = ((INT32U)F_OSC / (16*(INT32U)UART_BAUD ) - 1 ) >> 8;
OS_EXIT_CRITICAL();
}
void UartTxIsr( void ) // 发送寄存器空中断
{
INT8U err, c;
c = UartGetTxChar( &err );
if( err == UART_OK )
UDR = c; // 发送数据
}
void UartRxIsr( void ) // 发送寄存器空中断
{
INT8U err, c;
err = UCSRA;
c = UDR;
if( !(err & ( DOR|PE|FE )) )
UartPutRxChar( c );
}
/* *****************************************************************
* UartPutRxChar()
* 函数名: UartPutRxChar()
* 参数:c ----- 要写入的字符
* 返回值:UART_OK --- 操作成功
* UART_BUF_FULL -- 失败,缓冲满
* 说明:此函数仅供中断系统调用
* ***************************************************************** */
static INT8U UartPutRxChar( INT8U c )
{
OSSemQuery( UartRxFifo.sem, &SemData );
if( SemData.OSCnt < UART_RX_LEN ) // 缓冲不满
{
*(UartRxFifo.in)++ = c;
if( UartRxFifo.in >= UartRxBuf + UART_RX_LEN )
UartRxFifo.in = UartRxBuf;
OSSemPost( UartRxFifo.sem ); // 向任务发送信号量
return UART_OK;
}
else
{
UartStopRx(); // 缓冲满,不再接收数据
return UART_BUF_FULL;
}
}
/* *****************************************************************
* UartGetTxChar()
* 函数名: UartGetTxChar()
* 参数:err ---- 错误参量
* 返回值:UART_OK
* UART_BUF_EMPTY --- 失败,缓冲空
* 说明:
* ***************************************************************** */
static INT8U UartGetTxChar( INT8U * err )
{
INT8U c;
c = 0;
OSSemQuery( UartTxFifo.sem, &SemData );
if( SemData.OSCnt < UART_TX_LEN ) // <TX_LEN, 缓冲有数据可发送
{
c = *(UartTxFifo.out)++;
if( UartTxFifo.out >= UartTxBuf + UART_TX_LEN )
UartTxFifo.out = UartTxBuf;
OSSemPost( UartTxFifo.sem ); // 向任务发送信号量
*err = UART_OK;
}
else
{
UartStopTx(); // 缓冲空,不再使能发送中断
*err = UART_BUF_EMPTY;
}
return c;
}