📄 uart.c
字号:
/*******************************************************************************
**
** 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 + -