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

📄 uart.c

📁 ucos II操作系统的源代码。程序完整
💻 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 + -