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

📄 uart.c

📁 基于ARM的UART串口驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/*******************************************************************************
**
**  File Name:      uart.c
**  Last Modified:  2006-08-28
**  Last Version:   0.9
**  Environment:    LPC2136/ADSv1.2
**  Descriptions:   
**
**------------------------------------------------------------------------------
**  Modified by:    
**  Modified Date:  
**  Version:        
**  Descriptions:   
**
*******************************************************************************/


#include "config.h"
#include "sysinit.h"
#include "timer.h"

#define UART_FIFO_LEN           16
#define	UART_RX_TIMEOUT_TIME	100
#define	AUTO_FAILED_TIME		500  //500ms

//串口寄存器基址
#define USR_BASE  (&U0RBR)   //用户口(UART0)
#define NET_BASE  (&U1RBR)   //网络口(UART1)

//BAUD自适应相关
//#define	CAP0     (1<<2)
//#define	CAP0_status     (IO0PIN & CAP0)

static u8 auto_baud_ok = 0;

//串口寄存器相对于UxRBR的偏移               偏移量
#define RBR             0x00
#define THR             0x00
#define DLL             0x00
#define DLM             0x04
#define IER             0x04
#define IIR             0x08
#define FCR             0x08
#define LCR             0x0C
#define MCR				0x10
#define LSR				0x14
#define MSR				0x18
#define SCR             0x1C
#define TER				0x30

//所有对串口寄存器的读写操作均应通过这两个宏
#define WR_UREG(base, offset, x)    do{*((base) + (offset)) = (x);} while(0)
#define RD_UREG(base, offset)   (*((base) + (offset)))

struct drv_info
{
	volatile unsigned char *base;   //串口寄存器基地址
	                                //只能在USR_BASE和NET_BASE取值
   	u8 *tx_buf_ptr;     //发送数据缓冲区
	uf16 tx_buf_len;    //发送缓冲区长度
	OS_EVENT *tx_sem;   //用于同步发送中断和发送函数的信号量
	
	u8 *rx_buf_ptr;     //接收数据缓冲区,在接收函数中设置
	uf16 rx_buf_len;    //接收缓冲区长度,在接收函数中设置
	                    //为0时表示没有任务在调用接收函数
	
    u8 rx_ring_buf[256];
    u16 wr_buf_ptr;
    u16 rd_buf_ptr;
    u8 rx_buf_cnt;
    
	OS_EVENT *rx_sem;   //用于同步接收中断和接收函数的信号量
};

typedef struct drv_info *handle_t;     //定义串口驱动信息句柄类型

static struct drv_info usr_drv_info__;  //存放用户口串口驱动信息
static struct drv_info net_drv_info__;  //存放网络口串口驱动信息

#define USR_HANDLE  (&usr_drv_info__)   //定义用户口句柄
#define NET_HANDLE  (&net_drv_info__)   //定义网络口句柄

static OS_EVENT * auto_baud_sem__;  //用于同步uart_usr_auto_baud和定时器捕捉中断
                                    //用于串行化多个任务的并发发送请求
static uf8 auto_baud_state__; //自动波特率状态机的状态变量

/*** ARM模拟UART口控制信号,所有信号均为低电平有效 ***/


/*** 自动波特率检测状态机 ***/
#define	FIRST_HIGH					0
#define	FIRST_LOW					1
#define	SEC_HIGH					2
#define	SEC_LOW						3
#define	STOP_HIGH					4

/*******************************************************************************
* 名称:set_baud__()
* 功能:设置串口速率
* 参数:hnd         串口句柄
        baud_rate   串口速率值
* 返回:无
*******************************************************************************/
static void set_baud__(handle_t hnd, u32 baud_rate)
{
	uf8 t0;
	u32 t1;
	
	//assert(baud_rate > 0 && baud_rate <= 115200);
	
	t0 = RD_UREG(hnd->base, LCR);
    WR_UREG(hnd->base, LCR, LCR_EN_DIV);
   	t1 = (Fpclk >> 4) / baud_rate;
  	WR_UREG(hnd->base, DLM, t1 >> 8);
    WR_UREG(hnd->base, DLL, t1 & 0xff);
 	WR_UREG(hnd->base, LCR, t0);
}

/*******************************************************************************
* 名称:uart_usr_set_baud()
* 功能:设置用户口波特率(UART0)
* 参数:baud_rate   串口速率值
* 返回:无
*******************************************************************************/
void uart_usr_set_baud(u32 baud_rate)
{
    set_baud__(USR_HANDLE, baud_rate);
}

/*******************************************************************************
* 名称:uart_net_set_baud()
* 功能:设置网络口波特率(UART1)
* 参数:baud_rate   串口速率值
* 返回:无
*******************************************************************************/
void uart_net_set_baud(u32 baud_rate)
{
    set_baud__(NET_HANDLE, baud_rate);
}

/*******************************************************************************
* 名称:tx__()
* 功能:串口发送
* 参数:hnd     串口句柄
        buf     要发送的数据缓冲区
        len     数据缓冲区的长度
* 返回:无
*******************************************************************************/
static sf16 tx__(handle_t hnd, u8 * buf, u16 len)
{
    u8 err,i;

    //assert(buf != NULL && len > 0);   
    OSSemPend(hnd->tx_sem, 0, &err);
  
   //发送数据触发发送中断
   OS_ENTER_CRITICAL();
   for(i = 0; i < UART_FIFO_LEN && i < len; i++)
   {
       WR_UREG(hnd->base, THR, buf[i]);
   }
    hnd->tx_buf_ptr = buf + i;
    hnd->tx_buf_len = len - i;
    OS_EXIT_CRITICAL();
    
    return len;
}

/*******************************************************************************
* 名称:uart_usr_tx()
* 功能:用户口发送(UART0)
* 参数:buf     要发送的数据缓冲区
        len     数据缓冲区的长度
* 返回:若发送成功,则返回大于0的值,表示成功发送的字节数,一定等于len
		若发送失败,则返回-1
*******************************************************************************/
sf16 uart_usr_tx(u8 buf[], u16 len)
{
    return tx__(USR_HANDLE, buf, len);
}

/*******************************************************************************
* 名称:uart_net_tx()
* 功能:网络口发送(UART1)
* 参数:buf     要发送的数据缓冲区
        len     数据缓冲区的长度
* 返回:若发送成功,则返回大于0的值,表示成功发送的字节数,一定等于len
		若发送失败,则返回-1
*******************************************************************************/
sf16 uart_net_tx(u8 buf[], u16 len)
{
    return tx__(NET_HANDLE, buf, len);
}

/*******************************************************************************
* 名称:tx_isr__()
* 功能:发送中断处理
* 参数:hnd     串口句柄
* 返回:无
*******************************************************************************/
static void tx_isr__(handle_t hnd)
{
    uf8 i;	
    if (hnd->tx_buf_len == 0)
    {
	    OSSemPost(hnd->tx_sem);
	    return;
    }
    
    for (i = 0; i < UART_FIFO_LEN && i < hnd->tx_buf_len; i++)
    {
        WR_UREG(hnd->base, THR, hnd->tx_buf_ptr[i]);
        while(RD_UREG(hnd->base, LSR) & LSR_TEMT == 0);
    }
    
    hnd->tx_buf_ptr += i;
    hnd->tx_buf_len -= i;
}

/*******************************************************************************
* 名称:rx__()
* 功能:串口接收
* 参数:hnd     串口句柄,表示操作哪个串口
        buf     接收缓冲区
        len     接收缓冲区长度
* 返回:若接收成功,则返回大于0的值,表示成功接收到的字节数,一定小于等于len
		若接收超时,则返回-1
*******************************************************************************/
static sf16 rx__(handle_t hnd, u8 *buf, u16 len)
{
    u8 *buf_bak, err;
    
    buf_bak = buf;
    
    //assert(len >= 256);
re:    
    
    while(hnd->rx_buf_cnt > 0)
    {
        if(hnd->rd_buf_ptr == 256) hnd->rd_buf_ptr = 0;
        OS_ENTER_CRITICAL();
        *buf++ = hnd->rx_ring_buf[hnd->rd_buf_ptr++];
        hnd->rx_buf_cnt--;
        OS_EXIT_CRITICAL();
        if(buf - buf_bak > 240) return buf - buf_bak;
    }

    if (hnd == USR_HANDLE) CTS0_LOW();
    if (hnd == NET_HANDLE) RTS1_LOW();
    
    
    if(buf - buf_bak > 0) return buf - buf_bak;
        
    OSSemPend(hnd->rx_sem, UART_RX_TIMEOUT_TIME, &err);
    
    if(err != OS_NO_ERR) return -1;
    else goto re;
}

/*******************************************************************************
* 名称:uart_usr_rx()
* 功能:用户口接收(UART0)
* 参数:buf     接收缓冲区
        len     接收缓冲区长度
* 返回:若接收成功,则返回大于0的值,表示成功接收到的字节数,一定小于等于len
		若接收超时,则返回-1
*******************************************************************************/
sf16 uart_usr_rx(u8 buf[], u16 len)
{
    return rx__(USR_HANDLE, buf, len);
}

/*******************************************************************************
* 名称:uart_net_rx()
* 功能:网络口接收(UART1)
* 参数:buf     接收缓冲区
        len     接收缓冲区长度
* 返回:若接收成功,则返回大于0的值,表示成功接收到的字节数,一定小于等于len
		若接收超时,则返回-1
*******************************************************************************/
sf16 uart_net_rx(u8 buf[], u16 len)
{
    return rx__(NET_HANDLE, buf, len);
}

/*******************************************************************************
* 名称:rx_isr__()
* 功能:接收中断处理
* 参数:hnd     串口句柄,表示操作哪个串口
* 返回:无
*******************************************************************************/
static void rx_isr__(handle_t hnd)
{
    while((RD_UREG(hnd->base, LSR) & LSR_RDR) && (hnd->rx_buf_cnt < 256))
    {
        if(hnd->wr_buf_ptr == 256) hnd->wr_buf_ptr = 0;
        hnd->rx_ring_buf[hnd->wr_buf_ptr++] = RD_UREG(hnd->base, RBR);
        
        OS_ENTER_CRITICAL();
        hnd->rx_buf_cnt++;
        if(hnd->rx_buf_cnt > 128)
        {
            if (USR_HANDLE == hnd) CTS0_HIGH(); //禁止PC向ARM发数据
		    else RTS1_HIGH();                   //让MODEM不要向ARM发数据
        }
        OS_EXIT_CRITICAL();
    }
    
    if((hnd->rx_buf_cnt > 0) && (hnd->rx_sem->OSEventCnt==0)) 
    	OSSemPost(hnd->rx_sem);
}

/*******************************************************************************
* 名称:usr_isr()
* 功能:用户口中断服务程序
* 参数:无
* 返回:无
*******************************************************************************/
void uart_usr_isr(void)
{
	switch(RD_UREG(USR_HANDLE->base, IIR) & 0x0F)
	{
	    case IIR_RX:
	    case IIR_TIMEOUT:
            rx_isr__(USR_HANDLE);
            break;
            
        case IIR_THRE:
            tx_isr__(USR_HANDLE);
            break;
            
        default:
            break;
    }
    
    VICVectAddr = 0x00;
}

/*******************************************************************************
* 名称:net_isr()
* 功能:网络口中断服务程序
* 参数:无
* 返回:无
*******************************************************************************/
void uart_net_isr(void)
{
	switch(RD_UREG(NET_HANDLE->base, IIR) & 0x0F)
	{
    	case IIR_RX:
    	case IIR_TIMEOUT:
            rx_isr__(NET_HANDLE);
            break;
            
        case IIR_THRE:
            tx_isr__(NET_HANDLE);
            break;
            
        case IIR_MODEM:
            switch(RD_UREG(NET_HANDLE->base, MSR) & 0x0F)
            {

⌨️ 快捷键说明

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