📄 uart.c
字号:
/****************************************Copyright (c)**************************************************
** TRIG WORKROOM
** http://greatbin.21ic.org
**
**--------------File Info-------------------------------------------------------------------------------
** File name: uart.c
** Last modified Date: 2006-09-17
** Last Version: 1.0
** Descriptions: 基于LPC2200/UCOSII的UART驱动
** 5个串口:
** 0软串口
** 1LPC2214的UART0
** 2LPC2214的UART1
** 3外扩SC16C2550的UARTA
** 4外扩SC16C2550的UARTB
**------------------------------------------------------------------------------------------------------
** Created by: greatbin
** Created date: 2006-03-01
** Version: 0.1
** Descriptions: The original version
**
**------------------------------------------------------------------------------------------------------
** Modified by: greatbin
** Modified date: 2006-09-17
** Version: 1.0
** Descriptions: 修改UART_write接口,增加超时机制。这样,当串口因为某种原因不能发送数据,任务不会
** 被挂起
** 修改中断服务程序的接收部分。原来存在这样的现象:虽然收到的是一个连续的字节流,可
** 能会被分成两次接收
**
**------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
** Version:
** Descriptions:
**
********************************************************************************************************/
#include "config.h"
#define IN_UART
#define RXBUFFERSIZE 256*2
#define FIFONUM 16 //接收FIFO深度
//2.1 数据结构
typedef struct
{
uint32 BaudScale;//pclk/baudrate/16
uint8 DataBit;//数据位数目5~8
uint8 CheckBit;//校验位
uint8 StopBit;//停止位
uint8 RxBuffer[RXBUFFERSIZE];//接收缓冲区
uint16 nRx;//接收数据数目
uint8 *TxBuffer;//发送缓冲区指针
uint32 nTxLeft;//待发送的数据数目
//OS_EVENT* semUsed;//本串口是否被使用
OS_EVENT *semRx;//是否收到一个数据包
OS_EVENT *semTx;//是否发送完毕
} UARTTYPE;
static UARTTYPE UART[UARTNUM];
//static unsigned long UART0_REG[8];
static const unsigned long UART_BASE_ADDR[UARTNUM][8]=
{//UART的基础寄存器地址,UART必须符合550工业标准,以下的地址必须和目标板一致
{0xE000C000,0xE000C004,0xE000C008,0xE000C00c,0xE000C010,0xE000C014,0xE000C018,0xE000C01c},
{0xE0010000,0xE0010004,0xE0010008,0xE001000c,0xE0010010,0xE0010014,0xE0010018,0xE001001c},
};
#define RBR 0
#define THR 0
#define IER 1
#define ISR 2
#define FCR 2
#define LCR 3
#define MCR 4
#define LSR 5
#define MSR 6
#define SCR 7
#define DLL 0
#define DLH 1
#define ReadReg(x) (*((volatile unsigned char *)x))
#define WriteReg(x,b) do {*((volatile unsigned char *)x)=b;} while (0)
typedef void UART_EXCEPTION_TYPE(void);
extern UART_EXCEPTION_TYPE *UART_exception_TAB[UARTNUM];
#define SETTXD0 do {PWMTCR=0x00;PINSEL1&=~0x00000c00;IO0SET=1<<21;} while(0)
#define RESETTXD0 do {IO0CLR=1<<21;PINSEL1|=0x00000400;PWMTCR=0x09;} while(0)
#define GETRXD0 ((IO0PIN&(1<<10))?0:1)
//2.2 初始化串口
//在对硬件初始化时需要对调用此函数。
uint8 UART_Init(uint8 port)
{
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr;
#endif
if (port>=UARTNUM)
return false;
UART[port].nRx=0;
UART[port].nTxLeft=0;
//if ((UART[port].semUsed=OSSemCreate(1))==NULL)//创建信号灯,初值为1
// return false;
if ((UART[port].semRx=OSSemCreate(0))==NULL)//创建接收完成信号灯
return false;
if ((UART[port].semTx=OSSemCreate(0))==NULL)//创建发送完成信号灯
return false;
OS_ENTER_CRITICAL();
//注册中断
WriteReg(UART_BASE_ADDR[port][IER],0x00);//关掉收发中断
switch (port)
{
case 0://第一个LPC213x上的硬件串口
PINSEL0 &= ~0x0000000f;
PINSEL0 |= 0x00000005;
//注册硬件UART0中断
//VICIntSelect &= (~(1<<6));
VICVectAddr6 = (uint32)UART_exception_0;
VICVectCntl6 = (0x20 | 0x06);
VICIntEnable = 1 << 6;
break;
case 1://第二个LPC213x上的硬件串口
PINSEL0 &= ~0x000f0000;
PINSEL0 |= 0x00050000;
//注册硬件UART1中断
//VICIntSelect &= (~(1<<7));
VICVectAddr7 = (uint32)UART_exception_1;
VICVectCntl7 = (0x20 | 0x07);
VICIntEnable = 1 << 7;
break;
default:
OS_EXIT_CRITICAL();
return false;
}
OS_EXIT_CRITICAL();
return true;
}
//2.3 串口中断服务
static void UART_exception(int port)
{
volatile uint8 b,isr;
int i,x;
while (((isr=ReadReg(UART_BASE_ADDR[port][ISR]))&0x01)==0)//有待处理的中断
{
switch (isr&0x0e)
{
case 0x04://接收FIFO满
case 0x0c://接收超时
if (ReadReg(UART_BASE_ADDR[port][LSR])&0x0e)//接收错误
{
while (ReadReg(UART_BASE_ADDR[port][LSR])&0x01)//接收寄存器不空
b=ReadReg(UART_BASE_ADDR[port][RBR]);//从接收寄存器读出接收字符
WriteReg(UART_BASE_ADDR[port][FCR],ReadReg(UART_BASE_ADDR[port][FCR])|0x02);//清除RXFIFO 0x8b????????????
break;
}
if ((isr&0x0e)==0x04)
{
for (i=0;i<FIFONUM-1;i++)
{//从RXFIFO中取出FIFONUM-1个字节,留至少1个字节在RXFIFO中
x = ReadReg(UART_BASE_ADDR[port][LSR]);
if (x&0x01)//接收寄存器不空
{
UART[port].RxBuffer[UART[port].nRx++]=ReadReg(UART_BASE_ADDR[port][RBR]);
if (UART[port].nRx>=sizeof(UART[port].RxBuffer))//防止接收缓冲区溢出,宁缺勿乱
UART[port].nRx--;
}
}
OSSemPost(UART[port].semRx);//信号灯P操作 /**** ADD BY HK *******/
break;
}
if ((isr&0x0e)==0x0c)
{
while (ReadReg(UART_BASE_ADDR[port][LSR])&0x01)//接收寄存器不空
{
UART[port].RxBuffer[UART[port].nRx++]=ReadReg(UART_BASE_ADDR[port][RBR]);
if (UART[port].nRx>=sizeof(UART[port].RxBuffer))//防止接收缓冲区溢出,宁缺勿乱
UART[port].nRx--;
}
OSSemPost(UART[port].semRx);//信号灯P操作
}
break;
case 0x02://发送空
for (i=0;i<FIFONUM;i++)
{
if (UART[port].nTxLeft < 1)//发送完成
{
WriteReg(UART_BASE_ADDR[port][IER],ReadReg(UART_BASE_ADDR[port][IER])&0xfd);//关闭发送中断;
OSSemPost(UART[port].semTx);//信号灯P操作
break;
}
b=*UART[port].TxBuffer;
UART[port].TxBuffer++;
WriteReg(UART_BASE_ADDR[port][THR],b);
UART[port].nTxLeft--;
}
break;
default:
//b=ReadReg(UART_BASE_ADDR[port][MSR]);//读Modem状态寄存器
b=ReadReg(UART_BASE_ADDR[port][LSR]);//读Line状态寄存器
break;
}
}
return;
}
void UART_exception_0(void)
{
UART_exception(0);
VICVectAddr=0x00;
}
void UART_exception_1(void)
{
UART_exception(1);
VICVectAddr=0x00;
}
//3.1 打开串口
uint8 UART_open( uint8 port, uint32 baudrate, uint8 databit, uint8 checkbit, uint8 stopbit)
{
//INT8U err;
volatile unsigned char setting;
if (port>=UARTNUM)
return false;
UART[port].nRx=0;
UART[port].nTxLeft=0;
while (OSSemAccept(UART[port].semRx));//查询接收信号灯保证此信号灯的值为0
while (OSSemAccept(UART[port].semTx));//查询发送信号灯保证此信号灯的值为0
UART[port].BaudScale=Fpclk/baudrate/16;
UART[port].DataBit=databit;
UART[port].CheckBit=checkbit;
UART[port].StopBit=stopbit;
WriteReg(UART_BASE_ADDR[port][IER],0x00);//关掉收发中断
WriteReg(UART_BASE_ADDR[port][LCR],0x80);
if (baudrate==0) baudrate=1200;
WriteReg(UART_BASE_ADDR[port][DLL],(Fpclk/baudrate/16)&0xff);
WriteReg(UART_BASE_ADDR[port][DLH],((Fpclk/baudrate/16)>>8)&0xff);
setting=0;
if (databit==6)
setting |= 1;
else
if (databit==7)
setting |= 2;
else
if (databit==8)
setting |= 3;
if (stopbit==2)
setting |= (1<<2);
if (checkbit=='o')
setting |= (1<<3);
else
if (checkbit=='e')
setting |= (3<<3);
WriteReg(UART_BASE_ADDR[port][LCR],setting);
WriteReg(UART_BASE_ADDR[port][MCR],ReadReg(UART_BASE_ADDR[port][MCR])|0x08);
WriteReg(UART_BASE_ADDR[port][FCR],0x87);//使能FIFO,深度8
setting=ReadReg(UART_BASE_ADDR[port][LSR]);//清除状态
while (OSSemAccept(UART[port].semRx));
WriteReg(UART_BASE_ADDR[port][IER],0x01);//打开接收中断
return true;
}
//3.2 关闭串口
uint8 UART_close(uint8 port)
{
if (port>=UARTNUM)
return false;
WriteReg(UART_BASE_ADDR[port][IER],0x00);//关闭接收发送中断
//OSSemPost(UART[port].semUsed);
return true;
}
//3.3 发送数据
uint8 UART_write(uint8 port, const uint8 *buffer, uint32 wlen, uint16 timeout)
{
INT8U err;
if (port>=UARTNUM)
return false;
if (wlen==0)
return false;
WriteReg(UART_BASE_ADDR[port][THR],*buffer++);//写入第一个字节,以便在这个字节发送完后能进入发送中断
wlen--;
UART[port].TxBuffer=(uint8 *)buffer;
UART[port].nTxLeft=wlen;
WriteReg(UART_BASE_ADDR[port][IER],ReadReg(UART_BASE_ADDR[port][IER])|0x02);//打开发送中断
OSSemPend(UART[port].semTx,timeout,&err);
if (err==OS_NO_ERR)
return true;
return false;
}
//3.4 接收数据
uint16 UART_read(uint8 port, uint8 *buffer, uint32 buffersize, uint16 timeout)
{
uint8 err;
uint16 rxlen;
if (port>=UARTNUM)
return 1;
OSSemPend(UART[port].semRx,timeout,&err);
if (err!=OS_NO_ERR)
{//在超时时间之内没有收到数据
return 0;
}
WriteReg(UART_BASE_ADDR[port][IER],ReadReg(UART_BASE_ADDR[port][IER])&(~0x01));//关闭接收中断
rxlen=(buffersize<UART[port].nRx)?buffersize:UART[port].nRx;
memcpy(buffer,UART[port].RxBuffer,rxlen);
if (rxlen<UART[port].nRx)//一次没有读完收到的数据
{
uint16 i;
for (i=0;i<UART[port].nRx-rxlen;i++)
UART[port].RxBuffer[i]=UART[port].RxBuffer[i+rxlen];
OSSemPost(UART[port].semRx);//模拟接收完成,以便再读
}
UART[port].nRx-=rxlen;//剩下的数据再读还有
WriteReg(UART_BASE_ADDR[port][IER],ReadReg(UART_BASE_ADDR[port][IER])|0x01);//打开接收中断
return rxlen;
}
//3.5 清除接收缓冲区
uint8 UART_flush(uint8 port)
{
if (port>=UARTNUM)
return false;
WriteReg(UART_BASE_ADDR[port][IER],ReadReg(UART_BASE_ADDR[port][IER])&(~0x01));//关闭接收中断
UART[port].nRx=0;
while (OSSemAccept(UART[port].semRx));//查询接收信号灯保证此信号灯的值为0
WriteReg(UART_BASE_ADDR[port][IER],ReadReg(UART_BASE_ADDR[port][IER])|0x01);//打开接收中断
return true;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -