共2条
1/1 1 跳转至页
LPC214x,USB LPC214x USB虚拟串口改进版
问
我从菲利普的网站下载过虚拟串口的例子,但实际应用中发现并不稳定.
尤其是当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个虚拟串口同时收发的时候,经常丢失数据.
经过分析,发现是因为例子采用查询的方式,所以我对例子改进了下,采用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 跳转至页
回复
有奖活动 | |
---|---|
【有奖活动】分享技术经验,兑换京东卡 | |
话不多说,快进群! | |
请大声喊出:我要开发板! | |
【有奖活动】EEPW网站征稿正在进行时,欢迎踊跃投稿啦 | |
奖!发布技术笔记,技术评测贴换取您心仪的礼品 | |
打赏了!打赏了!打赏了! |
打赏帖 | |
---|---|
与电子爱好者谈读图四被打赏50分 | |
与电子爱好者谈读图二被打赏50分 | |
【FRDM-MCXN947评测】Core1适配运行FreeRtos被打赏50分 | |
【FRDM-MCXN947评测】双核调试被打赏50分 | |
【CPKCORRA8D1B评测】---移植CoreMark被打赏50分 | |
【CPKCORRA8D1B评测】---打开硬件定时器被打赏50分 | |
【FRDM-MCXA156评测】4、CAN loopback模式测试被打赏50分 | |
【CPKcorRA8D1评测】--搭建初始环境被打赏50分 | |
【FRDM-MCXA156评测】3、使用FlexIO模拟UART被打赏50分 | |
【FRDM-MCXA156评测】2、rt-thread MCXA156 BSP制作被打赏50分 |