这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 综合技术 » 基础知识 » LPC214x,USB LPC214x USB虚拟串口改进版

共2条 1/1 1 跳转至

LPC214x,USB LPC214x USB虚拟串口改进版

院士
2006-09-17 18:14:16     打赏
LPC214x,USB LPC214x USB虚拟串口改进版



关键词: LPC214x     虚拟     串口     改进    

院士
2006-12-22 22:43:00     打赏
2楼
问 我从菲利普的网站下载过虚拟串口的例子,但实际应用中发现并不稳定.
尤其是当2个虚拟串口同时收发的时候,经常丢失数据.
经过分析,发现是因为例子采用查询的方式,所以我对例子改进了下,采用UART中断的方式.


/*
    发送/接收 缓冲区是1个循环缓冲,如下图.

  图 1)
       |       |first                    |next                     |
       |  not  |                         |                         |
       +-used--+--------valid data-------+---------not used--------+
       |       v                         v                         |
       .-----------------------------------------------------------.
       |                  recive or send buffer                    |
       '-----------------------------------------------------------'


   图 2)
       |       |next                     |first                    |
       | valid |                         |                         |
       +-data--+--------not used---------+-------valid data--------+
       |       v                         v                         |
       .-----------------------------------------------------------.
       |                  recive or send buffer                    |
       '-----------------------------------------------------------'


    位于first和next之间的区域是已经接收的数据或者将要发送的数据.
    其它区域是空的区域.
    此缓冲区是1个循环缓冲区,当指针达到缓冲区的末尾,将循环到缓冲区头重新开始.
    当first==next,表示是整个缓冲区无任何数据.
    当next=first-1,表示缓冲区已满.
*/

在例子代码中,增加了个uart.c文件,处理UART的收发.
以下改进过后是keil的工程代码.
http://bbs.21ic.com/upfiles/img/2006719153732873.rar

对于使用XP的朋友或者没有没有从菲利普下载例子程序的朋友,
以下是虚拟串口的驱动程序(含源码),我重新编译过,产生了xp的驱动.
http://bbs.21ic.com/upfiles/img/2006719153250303.rar 1: uart.c的源代码
/*******************************************************************
* 文 件 名:     uart.c
*版本/时间:     v1.10  2006/06/29
* 描    述:     UART0/1的通讯例程,假设Fosc=12M,Fcclk=Fpclk=60M
* 作    者:     lenglx
*-------------------------------------------------------------------
* 修改记录:
* 修改时间:
* 描    述:
* 修 改 人:
*******************************************************************/

#include <LPC214X.H>
#include "type.h"
#include "USB.h"
#include "USBcfg.h"
#include "USBhw.h"
#include "uart.h"


// 4个缓冲区,uart0接收/发送,uart1接收/发送
// 接收缓冲区的数据要等待USB读取,如果USB读取不及时,有可能丢失数据,所以缓冲区可设置稍微大点.

#define    RCV_BUF_LEN        1024
#define    SEND_BUF_LEN    512

BYTE    SendBuf0[SEND_BUF_LEN];
BYTE    RcvBuf0[RCV_BUF_LEN];
BYTE    SendBuf1[SEND_BUF_LEN];
BYTE    RcvBuf1[RCV_BUF_LEN];
DWORD    r_first0, r_first1, r_next0, r_next1;
DWORD     s_first0, s_first1, s_next0, s_next1;


/*
    发送/接收 缓冲区是1个循环缓冲,如下图.

  图 1)
       |       |first                    |next                     |
       |  not  |                         |                         |
       +-used--+--------valid data-------+---------not used--------+
       |       v                         v                         |
       .-----------------------------------------------------------.
       |                  recive or send buffer                    |
       '-----------------------------------------------------------'


   图 2)
       |       |next                     |first                    |
       | valid |                         |                         |
       +-data--+--------not used---------+-------valid data--------+
       |       v                         v                         |
       .-----------------------------------------------------------.
       |                  recive or send buffer                    |
       '-----------------------------------------------------------'


    位于first和next之间的区域是已经接收的数据或者将要发送的数据.
    其它区域是空的区域.
    此缓冲区是1个循环缓冲区,当指针达到缓冲区的末尾,将循环到缓冲区头重新开始.
    当first==next,表示是整个缓冲区无任何数据.
    当next=first-1,表示缓冲区已满.
*/

/*******************************************************************
* 功能描述: 重置缓冲区指针    
* 参    数:
* 返    回:
* 备    注:    
*******************************************************************/

void    ResetBufferPointer(DWORD dwPortNum)
{
    if(dwPortNum==0)
    {
        s_first0 = s_next0 = 0;
        r_first0 = r_next0 = 0;
    }
    else
    {
        s_first1 = s_next1 = 0;
        r_first1 = r_next1 = 0;
    }
}

/*******************************************************************
* 功能描述:     
* 参    数:
* 返    回:
* 备    注:    
*******************************************************************/
void    UartDataToHost(DWORD dwPort)
{
    BYTE tmpbuf[USB_MAX_PACKET];
    DWORD dwEp;
    DWORD next;
    DWORD first;
    BYTE * pBuf;
    DWORD i;
    DWORD dwCnt;

    // 因为此函数调用比较频繁,在没数据的时候尽量快点返回
    if( (dwPort==0 && r_next0==r_first0) || (dwPort==1 && r_next1==r_first1))
        return;
        

     dwEp     = dwPort==0 ? 2 : 5;
    next     = dwPort==0 ? r_next0 : r_next1;
    first = dwPort==0 ? r_first0 : r_first1;
    pBuf = dwPort==0 ? RcvBuf0 : RcvBuf1;
     dwCnt = USB_MAX_PACKET;
     i=0;

    // 将接收缓冲区的数据移动到tmpbuf
    while(dwCnt--)
    {
        if(next == first)
            break;
        tmpbuf[i] = pBuf[first];
        if(++first >= RCV_BUF_LEN)
            first = 0;
        i++;
    }
    USB_WriteEP(dwEp | 0x80, tmpbuf, i);

    if(dwPort == 0)
        r_first0 = first;
    else
        r_first1 = first;
}
/*******************************************************************
* 功能描述: 将从USB来的数据发送到UART端口    
* 参    数:
* 返    回:
* 备    注:    
*******************************************************************/
void    HostDataToUart(DWORD dwPort)
{
    BYTE tmpbuf[USB_MAX_PACKET];
    DWORD dwEp     = dwPort==0 ? 2 : 5;
    DWORD next     = dwPort==0 ? s_next0 : s_next1;
    DWORD first = dwPort==0 ? s_first0 : s_first1;
    BYTE * pBuf = dwPort==0 ? SendBuf0 : SendBuf1;
    DWORD dwCnt    = USB_ReadEP(dwEp, tmpbuf);
    DWORD i=0;
    // 将数据移到发送缓冲区
    while(dwCnt--)
    {
        if(next == first-1)
            break;
        pBuf[next] = tmpbuf[i];
        if(++next >= SEND_BUF_LEN)    
            next = 0;
        i++;
    }

    if(dwPort == 0)
    {
        s_next0 = next;
        if(U0LSR & 0x40 && s_first0 != s_next0)    // 发送器为空,需要重新启动发送
        {
            U0THR = pBuf[s_first0];
            if(++s_first0 >= SEND_BUF_LEN)
                s_first0 = 0;
        }
    }
    else
    {
        s_next1 = next;
        if(U1LSR & 0x40 && s_first1 != s_next1)
        {
            U1THR = pBuf[s_first1];
            if(++s_first1 >= SEND_BUF_LEN)
                s_first1 = 0;
        }
    }
}

/*******************************************************************
* 功能描述:    irq中断函数,处理UART0的字节接收/发送
* 参    数:
* 返    回:
* 备    注:    
*******************************************************************/
void    Uart0_irq(void) __irq
{
    uchar     iir,ch;
    while(1)  // 循环处理,直到UART0中无任何挂起的中断
    {
        if((iir = U0IIR) & 1)
            break;
        switch(iir & 0x0e)
        {
        case 0x04:    // RDA.
        case 0x0c:    // CTI.
            while(U0LSR & 1)  //将fifo中的所有数据读完
            {
                ch = U0RBR;
                if(r_next0 != r_first0-1)
                {
                    RcvBuf0[r_next0] = ch;
                    if (++r_next0 >= RCV_BUF_LEN)
                        r_next0 = 0;
                }
            }
            break;

        case 0x02:    // THR Empty.
            {
                DWORD nCnt = 16; //fifo counter
                while( s_next0 != s_first0 && nCnt--)
                {
                    U0THR = SendBuf0[s_first0];
                    if(++s_first0 >= SEND_BUF_LEN)
                        s_first0 = 0;
                }
            }
               break;
        default:
            ;
        }  
    }

       VICVectAddr=0;
}

void    Uart1_irq(void) __irq
{
    uchar     iir,ch;
    while(1)  // 循环处理,直到UART1中无任何挂起的中断
    {
        if((iir = U1IIR) & 1)
            break;
        switch(iir & 0x0e)
        {
        case 0x04:    // RDA.
        case 0x0c:    // CTI.
            while(U1LSR & 1)  //将fifo中的所有数据读完
            {
                ch = U1RBR;
                if(r_next1 != r_first1-1)
                {
                    RcvBuf1[r_next1] = ch;
                    if (++r_next1 >= RCV_BUF_LEN)
                        r_next1 = 0;
                }
            }
            break;

        case 0x02:    // THR Empty.
            {
                DWORD nCnt = 16; //fifo counter
                while( s_next1 != s_first1 && nCnt--)
                {
                    U1THR = SendBuf1[s_first0];
                    if(++s_first1 >= SEND_BUF_LEN)
                        s_first1 = 0;
                }
            }
               break;
        default:
            ;
        }  
    }

       VICVectAddr=0;
}


/*******************************************************************
* 功能描述:      初始化UART0
* 参    数:
* 返    回:
* 备    注:    
*******************************************************************/
void     InitUart (void)
{
    // 配置UART管脚
    PINSEL0 = (PINSEL0 & (~0x0f000f)) | 0x050005;    // set p0[1..0] for uart0

    ResetBufferPointer(0);
    ResetBufferPointer(1);

    U0LCR = 0x83;                   //  默认"9600,n,8,1"
    SET_UART0_BAUD(9600)                
    U0LCR = 0x03;
    U0IER = 0x03;                // enable rx/tx interrupt.
    U0FCR = 1 | (2<<6);            // enable fifo,8 byte

    U1LCR = 0x83;                   //  默认"9600,n,8,1"
    SET_UART1_BAUD(9600)                
    U1LCR = 0x03;
    U1IER = 0x03;                // enable rx/tx interrupt.
    U1FCR = 1 | (2<<6);            // enable fifo,8 byte

    //设置向量中断
    VICVectAddr3 = (unsigned long)Uart0_irq;
    VICVectCntl3 = 0x20 | 6;                    
    VICIntEnable = 1 << 6 ;

    VICVectAddr4 = (unsigned long)Uart1_irq;
    VICVectCntl4 = 0x20 | 7;                    
    VICIntEnable = 1 << 7 ;
}
2: 对原例子程序的几处改动void USB_EndPoint2 (DWORD event) {
    switch (event) {
    case USB_EVT_IN:
        Data2Host0 = 1;
        break;
    case USB_EVT_OUT:
        HostDataToUart(0);//这个是uart.c中增加的函数

    //    DeviceData2UART( 0 );//这个是原来菲利普的函数.
        break;
    }
    event;
}
端点5做过同样的修改.
main函数中:
if ( Data2Host0 || Data2Host1 ) {
    UartDataToHost(0); // 也使用uart.c的函数代替原来的DeviceData2Host()函数.
    UartDataToHost(1);
}
3: 大侠,有将这个工程转到ADS下编译调试?我将工程转到ADS下编译可通过,就是始终和驱动连不上。不能转出两个虚拟的串口!大侠能否指教一二。 4: 不错... 5: 好东西!作个标记 6: 使劲顶啊!!! 7: 好好的LPC2148就这样被你们当USBTOUART,太可惜了.嘿嘿. 8: 就是,现在一个USB转UART的专用IC,也才20元,且很稳定   9: 把操作UART的代码KILL掉,直接做为LPC2148还可以考虑这样上位机的程序和驱动就不费心了,也可以省掉串口转换芯片.

共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]