比zlg串口中间件好的UART串口驱动(带超时的同步操作)

比zlg串口中间件好的UART串口驱动(带超时的同步操作)
引言
以下的串口驱动是我在一个产品中实现了的,其特点:
一、支持FIFO,系统开销小,中断少
二、在多任务操作系统里使用串口很简单,对串口操作就4个:打开、关闭、读和写。
三、支持串口的互斥操作,多个任务竞争使用串口,保证正常分配串口资源,有利于写出高效率的与串口通信有关的线程(任务)
四、代码简练,支持N个串口
五、不清楚的地方可以发帖问,或者上我的笔记里咨询


UART的操作是嵌入系统中最常用的通信方式,现在网上有很多朋友提出了许多思路,在一定的应用环境中能够收到良好的效果。本人在下面的介绍中提出一种在RTOS中使用最方便的UART Driver思想,希望大家讨论并批评。


1、接口规范

1.1 设备打开
bool UART_open( int PORT, int baudrate, int databit, CHAR checkbit, int stopbit, int timeout)
输入:
    PORT串口号0~n
    baudrate波特率110,300,600,12002400,...,115200bps
    databit数据位数目5~8
    checkbit校验位'e','o','n'
    stopbit停止位0(1),1(1.5),2(2)
    timeout超时时间
返回:
    true if 成功打开此串口
    false if 打开串口失败
功能描述:
   用指定的属性(串口速率、奇偶校验等)打开串口。
    如果此串口空闲并且属性合理则本函数立即返回true;如果串口属性不合理则返回false;如果属性合理但是串口已经被其他进程(线程)使用,并且在timeout时间以内串口仍然没有被释放则返回false;如果串口已经被使用,但是在timeout时间之内被释放,则返回true
    如果timeout=0,则永久等待,直到串口被释放。

1.2 串口关闭
bool UART_close(int PORT)
输入:
    PORT串口号0~n
返回:
    true if 成功关闭
    false if 关闭失败
功能描述:
   关闭(释放)串口PORT
   如果此串口未被打开,返回false;如果此串口已经打开,则关闭之,返回true

1.3 从串口接收数据
int UART_read(int PORTCHAR *buffer, int buffersize, int timeout)
输入:
    PORT串口号0~n
    buffer接收数据缓冲区
    buffersize接收缓冲区大小
    timneout接收超时时间
返回:
   <0出错
   =0没有收到数据
   >0收到数据的个数
功能描述:
    从串口上接收数据放在缓冲区buffer里,收到的字节数目就是本函数的返回值。
    如果串口没有被打开,或者buffer为空指针,或者buffersize为0,则返回<0;
    如果串口已经有收到数据,将收到的数据填入buffer,并立即返回填入buffer的数据个数(字节计),但是最多填入buffersize个。
    如果串口还没有收到数据,则等待接收数据,但最多等待timeout时间,如果仍然没有收到数据,则返回0;在等待的过程中如果来了数据,则接收他们直到这一包数据结束或者数据个数达到了buffersize,然后返回接收到的数据个数。
    参数buffersize的作用是避免在填入buffer时发生溢出。

1.4 向串口发送数据
bool UART_write(int PORT, const CHAR *buffer, int wlen)
输入:
    PORT串口号0~n
    buffer发送数据缓冲区
    wlen发送的数据个数
返回:
    true if 发送成功
    false if 发送失败
功能描述:
    向串口发送数据。
    如果此串口未打开,或者buffer为空,或者wlen=0,立即返回false;
    否则将buffer[0~wlen-1]发送到串口上,发送完成以后返回true。

1.5 清除接收缓冲区
bool UART_flush(int PORT)
输入:
    PORT串口号0~n
返回:
    true if 成功
    false if 失败
功能描述:
     清除串口此前收到的数据。
     如果PORT未打开,返回false;否则清除此串口已经收到的数据,并返回true。
     <待续>http://blog.21ic.com/blog.asp?NAME=greatbin

                                      

* - 本贴最后修改时间:2006-5-15 10:57:02 修改者:greatbin

2楼: >>参与讨论
greatbin
UART驱动(带超时的同步操作)续
2、底层驱动

2.1 数据结构

#define UARTNUM         4
#define RXBUFFERSIZE    1024
#define FIFONUM         8      //接收FIFO深度

typedef struct
{
    CHAR RxBuffer[RXBUFFERSIZE];//接收缓冲区
    int nRx;//接收数据数目
    CHAR *TxBuffer;//发送缓冲区指针
    int nTxLeft;//待发送的数据数目
    semaphore semUsed;//本串口是否被使用
    semaphore semRx;//是否收到一个数据包
    semaphore semTx;//是否发送完毕
} UARTTYPE;
UARTTYPE UART[UARTNUM];

2.2 初始化串口
    在使用串口之前需要对串口进行初始化。
bool UART_Init(int PORT)
{
    UART[PORT].nRx=0;
    UART[PORT].nTxLeft=0;
    if ((UART[PORT].semUsed=CreateSemaphore(1))<0)//创建信号灯,初值为1
        return false;
    if ((UART[PORT].semRx=CreateSemaphore(0))<0)//创建接收完成信号灯
        return false;
    if ((UART[PORT].semTx=CreateSemaphore(0))<0)//创建发送完成信号灯
        return false;
    registerException(UART_exception_TAB[PORT]);//注册中断
    return true;
}

2.3 串口中断服务
void UART_exception(int PORT)
{
    volatile unsigned CHAR b;
    while (有未处理的中断)
    {
        SWITCH (中断类型)
        {
            case 接收FIFO满:
            case 接收超时:
                if (接收错误)
                {
                    while (接收寄存器不空)
                        b=RBR;//从接收寄存器读出接收字符
                    break;
                }
                for (i=0;i<FIFONUM-1;i++)
                {//从RXFIFO中取出FIFONUM-1个字节,留至少1个字节在RXFIFO中
                    UART[PORT].RxBuffer[UART[PORT].nRx++]=RBR;
                    if (UART[PORT].nRx>=sizeof(UART[PORT].RxBuffer))//防止接收缓冲区溢出,宁缺勿乱
                        UART[PORT].nRx=sizeof(UART[PORT].RxBuffer)-2;
                }
                if (是接收超时)
                    semPost(UART[PORT].semRx);//信号灯P操作
                break;
            case 发送空:
                if (UART[PORT].nTxLeft==0)//发送完成
                {
                    关闭发送中断;
                    semPost(UART[PORT].semTx);//信号灯P操作
                    break;
                }
                while (发送寄存器空)
                {
                    THR=*UART[PORT].TxPointer++;
                    UART[PORT].nTxLeft--;
                    if (UART[PORT].nTxLeft==0)
                        break;
                }
                break;
            default:
                读MODEM状态寄存器;
                读LINE状态寄存器;
                break;
        }
    }
    return;
}

void UART_exception_0(void)
{
    UART_exception(0);
}

void UART_exception_1(void)
{
    UART_exception(1);
}

void UART_exception_2(void)
{
    UART_exception(2);
}

void UART_exception_3(void)
{
    UART_exception(3);
}

typedef void *UART_EXCEPTION_TYPE(void);
UART_EXCEPTION_TYPE UART_exception_TAB[ ]=
{
    UART_exception_0,
    UART_exception_1,
    UART_exception_2,
    UART_exception_3,
};
       <待续>http://blog.21ic.com/blog.asp?NAME=greatbin

* - 本贴最后修改时间:2006-4-19 12:01:11 修改者:greatbin

3楼: >>参与讨论
greatbin
UART驱动(带超时的同步操作)续
3、API实现

3.1 打开串口
bool UART_open( int PORT, int baudrate, int databit, CHAR checkbit, int stopbit, int timeout)
{
    if (PORT>=UARTNUM)
        return false;
    if (semPend(UART[PORT].semUsed,timeout)<0)//得到信号灯
        return false;//超时了,还是无法得到信号灯
    UART[PORT].nRx=0;
    UART[PORT].nTxLeft=0;
    while (semCheck(UART[PORT].semRx));//查询接收信号灯保证此信号灯的值为0
    while (semCheck(UART[PORT].semTx));//查询发送信号灯保证此信号灯的值为0
    设置波特率、校验位等;
    FIFO设置为FIFINUM水平;
    打开接收中断;
    return true;
}

3.2 关闭串口
bool UART_close(int PORT)
{
    if (PORT>=UARTNUM)
        return false;
    semPost(UART[PORT].semUsed);
    return true;
}

3.3 发送数据
bool UART_write(int PORT, const CHAR *buffer, int wlen)
{
    if (PORT>=UARTNUM)
        return false;
    UART[PORT].TxPointer=buffer;
    UART[PORT].nTxLeft=wlen;
    打开发送中断;
    semPend(UART[PORT].semTx);
    return true;
}

3.4 接收数据
int UART_read(int PORTCHAR *buffer, int buffersize, int timeout)
{
    if (PORT>=UARTNUM)
        return -1;
    if (semPend(UART[PORT].semRx,timeout)<0)
    {//在超时时间之内没有收到数据
        return 0;
    }
    关闭接收中断;
    rxlen=(buffersize<UART[PORT].nRx)?buffersize:UART[PORT].nRx;
    memcpy(buffer,UART[PORT].buffer,rxlen);
    if (rxlen<UART[PORT].nRx)//一次没有读完收到的数据
    {
        for (i=0;i<UART[PORT].nRx-rxlen;i++)
            UART[PORT].RxBuffer[i]=UART[PORT].RxBuffer[i+rxlen];
        semPost(UART[PORT].semRx);//模拟接收完成,以便再读
    }
    UART[PORT].nRx-=rxlen;//剩下的数据再读还有
    打开接收中断;
    return rxlen;
}

3.5 清除接收缓冲区
bool UART_flush(int PORT)
{
    if (PORT>=UARTNUM)
        return false;
    关闭接收中断;
    UART[PORT].nRx=0;
    while (semCheck(UART[PORT].semRx));//查询接收信号灯保证此信号灯的值为0
    打开接收中断;
    return true;
}

     <待续>http://blog.21ic.com/blog.asp?NAME=greatbin

* - 本贴最后修改时间:2006-4-17 17:35:59 修改者:greatbin

4楼: >>参与讨论
greatbin
UART驱动(带超时的同步操作)续
4、应用举例

void Task1(void *argv)
{//本任务处理:从上级站来的命令,收到命令,处理,发回应答
//本任务独享串口0
    unsigned CHAR Rx[256];
    unsigned CHAR Tx[256];
    UART_open(0,115200,8,'n',0,0);//打开串口0
    for (;;)
    {
        int rxlen;
        rxlen=UART_read(0,Rx,sizeof(Rx),0);//从串口接收数据
        //如果数据没有来,本任务挂起
        if (rxlen>0)
        {
            txlen=DealPacket(Rx,rxlen,Tx,sizeof(Tx));//解包,组包放在Tx中,返回包长
            UART_write(0,Tx,txlen);
        }
    }
    UART_close(0);//关闭串口
    return;
}

void Task2(void *argv)
{//本任务处理:每分钟发送读IED(智能电子设备)
//本任务与任务3共享竞争串口1
    for (;;)
    {
        unsigned CHAR Tx[256];
        unsigned CHAR Rx[512];
        if (分钟到)
        {
            txlen=MakePacket(Tx);//组包到Tx中,返回包长度
            UART_Open(1,9600,8,'e',0,0);//打开(获得)串口
            UART_write(1,Tx,txlen);//发送
            rxlen=UART_read(1,Rx,sizeof(Rx),500);//接收,在500ms里应该收到第一个字节
            if (rxlen>0)
                DelaPack(Rx,rxlen);//处理收到的数据包
            UART_close(1);//关闭(释放)串口
        }
    }
    return;
}

void Task3(viod *argv)
{//在某事件发生后,立即启动串口与IED设备通信
//本任务与任务3共享竞争串口1    
    for (;;)
    {
        if (事件成立)
        {
            unsigned CHAR Tx[256];
            unsigned CHAR Rx[512];
            txlen=MakePacket(Tx);//组包到Tx中,返回包长度
            UART_Open(1,9600,8,'e',0,0);//打开(获得)串口
            UART_write(1,Tx,txlen);//发送
            rxlen=UART_read(1,Rx,sizeof(Rx),500);//接收,在500ms里应该收到第一个字节
            if (rxlen>0)
                DealPack(Rx,rxlen);//处理收到的数据包
            UART_close(1);//关闭(释放)串口
        }
    }
    return;
}

     <待续>http://blog.21ic.com/blog.asp?NAME=greatbin

* - 本贴最后修改时间:2006-4-17 17:38:07 修改者:greatbin

5楼: >>参与讨论
greatbin
自己顶一下
 
6楼: >>参与讨论
terrence
帮你顶一下!:)
楼主用的什么RTOS哦?
7楼: >>参与讨论
ysh815
好!!!!!!!!!!
希望论坛里多一些这样的好帖
8楼: >>参与讨论
db10
辛苦了
 
9楼: >>参与讨论
lpc2000
要是ZLG有个区域可以存文件就更好了
像yahoo的GROUP一样
10楼: >>参与讨论
greatbin
用的就是usOS,其实用任何RTOS都一样
 
11楼: >>参与讨论
zsdfwnl
学习
细节见真功夫
12楼: >>参与讨论
boy123
顶一下..学习中..
 
13楼: >>参与讨论
hqgboy
好呀。。。。谢谢。
 
14楼: >>参与讨论
yutu2
re
好像没有zlg中间件那样的数据队列功能
15楼: >>参与讨论
greatbin
回楼上
zlg的中间件开销太大,做实验可以,真的拿来做产品,不合适。至少我这么认为。
我的这个代码在串口发送和接收过程中,完全是中断。只有在发送完成和接收完成之后才调用OS的系统调用,开销最小了。用115200bps通信,发送和接收的字节流基本不间断的情况下,程序跑的欢畅。用OSStat统计,CPU的使用率只有2%,如果用Zlg的中间件,你不妨试试看。

* - 本贴最后修改时间:2006-4-25 9:52:52 修改者:greatbin

16楼: >>参与讨论
greatbin
自己顶一下
 
17楼: >>参与讨论
poly_lou
BANG NI DING YI XIA
 
18楼: >>参与讨论
xianfei520
ding
 
19楼: >>参与讨论
btiger2000
好!
 
20楼: >>参与讨论
lhzw2001
有没有工程样例文件,
greatbin有没有工程样例文件,发来试试LHZW2001@163.com
21楼: >>参与讨论
greatbin
我整理一下,放在我的笔记里。请留意
 
22楼: >>参与讨论
greatbin
要求板主加酷
 
23楼: >>参与讨论
fxb0115
非常感谢,学习中...
非常感谢,学习中...
24楼: >>参与讨论
hqgboy
加裤?好象不太可能。人家的自尊心呢?
 
25楼: >>参与讨论
hotpower
实用就好,不一定太完美
 
26楼: >>参与讨论
armuclinux
可否也发给我一个
greatbin能不能发给我一个ssjguan@163.com谢谢!
27楼: >>参与讨论
greatbin
我将在笔记里给出一个完整的工程,请在下周1下载
这个工程将在lpc2214上验证,使用ucosii和zlg的移植模板。
28楼: >>参与讨论
liwenz
期待
 
29楼: >>参与讨论
greatbin
源文件已经整理好,请大家来下载
 

* - 本贴最后修改时间:2006-4-22 12:11:39 修改者:greatbin

http://blog.21ic.com/blog.asp?NAME=greatbin

30楼: >>参与讨论
backupyan
copy下来,学习,学习!
copy下来,学习,学习!
31楼: >>参与讨论
ketp
不必这么麻烦
收到数据强制转为指针直接扔到消息队列就可以了,既有缓冲又有超时.
32楼: >>参与讨论
greatbin
回ketp:
如果这样做,消息队列的深度就必须和接收缓冲区的大小一样例如1024,空间开销大,此其一;
每收到一个字节,都要调用RTOS的系统调用,时间开销大,此其二;
我的UART API接口和WIN32/LINUX的UART API十分相似,如果再做些工作,可以在WIN32/LINUX上提供与此相同的API,这样代码就可以在PC上写好,调试完成后再在目标板上运行,开发效率是不是可以提高呢?此其三。
请批评
33楼: >>参与讨论
天际一灰尘
高人多多,有的学了
 
34楼: >>参与讨论
ketp
-
1,FIFO满或字符超时才调用RTOS的系统调用,或者可以申请块内存,填充FIFO的数据,再把内存地址发到队列

2,"代码就可以在PC上写好,调试完成后再在目标板上运行",这个从来没试过

* - 本贴最后修改时间:2006-4-23 20:55:24 修改者:ketp

35楼: >>参与讨论
greatbin
UART驱动源文件在目标板上测试完成,需要的可以下载了
做了3个任务:
Task1:在lpc2214的UART0上作了一个echo,即收到什么就回送什么,115200,n,8,1
Task2:不断发送字符串到lpc2214的UART1,9600,e,8,1
Task3:不断发送字符串到lpc2214的UART1,1200,e,8,1
同时在串口上发送OSCPUUsage
实测效果:如果每100MS发送250字节到UART0上,OSCPUUsage:02%

请到
http://blog.21ic.org/blog.asp?NAME=greatbin
上下载

* - 本贴最后修改时间:2006-4-24 0:03:44 修改者:greatbin

http://blog.21ic.org/blog.asp?NAME=greatbin

36楼: >>参与讨论
greatbin
顶上
 
37楼: >>参与讨论
cmos2345
一般
lpc2000的UART不就是16C550嘛,公开的驱动满地都是,随便找一个拿来用就行了。
38楼: >>参与讨论
greatbin
re:cmos2345
在哪里可以下载公开的550的驱动。谢谢
39楼: >>参与讨论
armuclinux
有问题如何请教,谢谢了
接收数据中的这段怎么理解?
rxlen=(buffersize<UART[PORT].nRx)?buffersize:UART[PORT].nRx;//问号是什么意思?
    memcpy(buffer,UART[PORT].buffer,rxlen);
40楼: >>参与讨论
greatbin
re:armuclinux
rxlen=(buffersize<UART[PORT].nRx)?buffersize:UART[PORT].nRx
等同于:
if (buffersize<UART[PORT].nRx)
    rxlen=buffersize;
else
    rxlen=UART[PORT].nRx;

41楼: >>参与讨论
greatbin
re:armuclinux
在调用UART_read时,如果buffersize比UART已经收到的字节数少时,只能返回buffersize个字节到buffer中。如果把UART收到的所有字符都返回到buffer中,就是缓冲区溢出了。
UART_read的调用接口如下:
int UART_read(int PORTCHAR *buffer, int buffersize, int timeout)

也可以到http://blog.21ic.com/blog.asp?NAME=greatbin中讨论
42楼: >>参与讨论
lightrainy
发现问题。。。
发现一个问题,PC端发送n个字节的数据,UART_read()总是接收到 (n/7 +1)*7个字节。。为什么?

43楼: >>参与讨论
greatbin
你看看代码,我echo之后,又多发了一些字节。
这是多发的:
sprintf(Tx,"\r\nOSCPUUsage:%02u%%\r\nThis is Task1 Tx..\r\n",OSCPUUsage);
UART_write(0,Tx,strlen(Tx));

44楼: >>参与讨论
lightrainy
LZ你理解错了。。。看看这个代码
改写了你的 Task2 的代码,你可以自己测试一下


void DoTask2(void *argv)
{//本任务处理:不断发送命令
//本任务与任务3共享竞争串口1
    argv=argv;

    UART_open( 1, 9600, 8, 'e', 0, 0 );
    
    for (;;)
    {
        int rxlen,txlen;
        CHAR Tx[256];
        CHAR Rx[512];
        
        rxlen = UART_read( 1, Rx, sizeof( Rx ), 0 );
        if (rxlen>0 )
        { 
               UART_write( 1, Rx, rxlen );
        }
        
    }
    UART_close( 1 );
    return;
}

45楼: >>参与讨论
greatbin
好,我晚上回去测试一下
 
46楼: >>参与讨论
greatbin
re:lightrainy
确实,有一个Bug,多谢!
在接收中断的处理上有一个错误,原来的代码
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],0x83);//清除RXFIFO
    break;
  }
  for (i=0;i<FIFONUM-1;i++)
  {//从RXFIFO中取出FIFONUM-1个字节,留至少1个字节在RXFIFO中
    UART[PORT].RxBuffer[UART[PORT].nRx++]=ReadReg(UART_BASE_ADDR[PORT][RBR]);
    if (UART[PORT].nRx>=sizeof(UART[PORT].RxBuffer))//防止接收缓冲区溢出,宁缺勿乱
      UART[PORT].nRx--;
  }
  if ((b&0x0e)==0x0c)
    OSSemPost(UART[PORT].semRx);//信号灯P操作
  break;

更改后的代码:
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],0x83);//清除RXFIFO
    break;
  }
  for (i=0;i<FIFONUM-1;i++)
  {//从RXFIFO中取出FIFONUM-1个字节,留至少1个字节在RXFIFO中
    if (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--;
    }
    else
      break;
  }
  if ((b&0x0e)==0x0c)
    OSSemPost(UART[PORT].semRx);//信号灯P操作
  break;

新的工程文件见我的笔记


http://blog.21ic.org/blog.asp?NAME=greatbin

47楼: >>参与讨论
2132
有没有工程样例文件?
 
48楼: >>参与讨论
greatbin
re:2132
有完整的工程文件。在
http://blog.21ic.org/blog.asp?NAME=greatbin

49楼: >>参与讨论
greatbin
这个坛子里浮躁的是很多
这个坛子里浮躁的是很多,就象如今在校的很多大学生,对一些真实的知识不愿意研究学习,相反对一些搞恶、贫嘴之类的无聊事情津津乐道。
我想放一些有关LPC221X的更多的实用代码和设计思想上来,希望对一些想做产品和以后想做产品的网友有些帮助,但不知道是不是真的有作用和有必要。
50楼: >>参与讨论
xzYue
很好,你的例子程序能在SmartARM2200上运行吗?
我在SmartARM2200上不能运行。我的应用程序用周工的驱动没有问题,后来换成你的了,不知为什么运行的状态不太正常,有时会死机。
呵呵。
51楼: >>参与讨论
greatbin
re xzYue
我没有SamrtARM2200。但是我的程序在lpc2214上是正常工作的。
如果你遇到这样的问题,可以检查一下分散加载文件。或者单步调试一下,看看问题出在哪里,希望你找出问题并告诉我,以便我能改进程序。
谢谢


52楼: >>参与讨论
taurusq1
支持楼主!
我用的是SmartARM2200,明天去试试行不行,呵呵!
53楼: >>参与讨论
greatbin
re taurusq1
谢谢。
我也希望我的这段代码更有通用性,这样也许大家还真能用得上。
54楼: >>参与讨论
taurusq1
可以使用
经测试,在SmartARM2200上可以使用,目前一切正常
至于稳定性如何,有待进一步测试!
55楼: >>参与讨论
hqgboy
"有作用和有必要"
1,对你自己也有好处,这么多人帮你测试,绝对能提高你的编程技术。
2,对大家也有好处。
支持。。。谢谢。
56楼: >>参与讨论
greatbin
re hqgboy
你说的对。所谓与人方便,与己方便。又云人人为我,我为人人
57楼: >>参与讨论
mohanwei
不管多牛也不可能吸引所有的眼光,有知音足矣
况且看前面的回帖,已经不只一个知音了^_^

支持楼主这种钻研的精神^_^
58楼: >>参与讨论
autoele
各有各的编程风格
 
59楼: >>参与讨论
hotpower
估计是天热zlg不愿给楼主穿裤子~~~
在此玩玩就将就着吧~~~
60楼: >>参与讨论
greatbin
re LS
我开始用LPC arm时有些问题是通过这个论坛解决的,现在呢有点体会所以就放上来,也许让别人受益。我上论坛不是只是玩一玩,不知LS上论坛是不是只是玩一玩。别怪
61楼: >>参与讨论
hotpower
交流为上~~~交友为真.玩肯定是真的~~~这里又不发奖金
口头表扬,支持有什么用???

楼主想通些~~~
62楼: >>参与讨论
rykong
顶·!`
顶·!`
63楼: >>参与讨论
zxsxr
不错,不错
 
64楼: >>参与讨论
zxsxr
不错的驱动
总算看到一个不错的驱动
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值