最新日志

发表于:2008-5-6 22:48:07
标签:无标签

0

D12的USB C51驱动程序开发

浅入深开展应用D12的USB C51驱动程序开发

USB设备启动流程:

1.USB设备接入USB口,发出连接USB命令
2.
主机发出读设备描述符两次。

3.
主机根据设备描述符——厂商ID、产品ID,启动相应设备驱动程序。

4.
设备驱动程序初始化USB设备:

  a.读设备描述符

  b.读配置描述符

  c.选择接口、端点(管道),确定传输方式

D12固件驱动:

//指向外部D12访问地址
#define D12_COMMAND (*(unsigned char xdata *)0x8000)
#define D12_DATA (*(unsigned char xdata *)0x0000)

D12_COMMAND = 0xf3;D12_DATA = 0x0e;D12_DATA = 0x03;//初始化频率 12MHz
D12_COMMAND = 0xd0;D12_DATA = 0x80;//
设置地址 0 使能

D12_COMMAND = 0xf3;D12_DATA = 0x1e;//
连接主机

D12_COMMAND = 0xf4;//
读中断寄存器

if(D12_DATA & 0x01)//
收到 SETUP

{
D12_COMMAND = 0x40;//
OUT 最后状态

if(D12_DATA & 0x20)
{
SETUP_read();
HandleSetup();
}
}
D12缓冲区

unsigned char SetupBuf[8];

void SETUP_read(void)
{
    unsigned char i;
    unsigned char * j;
    j = SetupBuf;
    D12_COMMAND = 0xf0;//
读标准控制码

    *j = D12_DATA;
    *(j+1) = D12_DATA;
    for(i=0;i<8;i++)
    {
       *(j + i) = D12_DATA;
    }
    D12_COMMAND = 0xf1;//
应答SETUP,使能( OUT 缓冲区、使能 IN 缓冲区)命令

    D12_COMMAND = 0xf2;//
OUT 缓冲区

}

D12缓冲区

void USB_submit(void)
{
    unsigned char i;
    D12_COMMAND = 0xf0;//
写缓冲区

    D12_DATA = 0x00;
    D12_DATA = XmtBuff.bLength;

    for(i=0;i<16;i++)
    {
        D12_DATA = *(XmtBuff.p++);
        if (!--XmtBuff.bLength)
        {
            break;
        }
    }
    D12_COMMAND = 0xfa;//
设置 IN 缓冲区有效

}


 
先介绍一下D12个管脚功能

1. D12的命令/数据切换有两种方式
 a. ALE 接地,由A0进行命令/数据切换,A0 1 时可以向D12写命令,A0 0 时可以向D12写数据。这时可以将A0P2口一个管脚(这里是A0P27),通过读写外部数据时,发出的地址来将A0 1/ 0

 b. A0 接高电平,由ALE进行命令/数据切换,将D12ALE51ALE(D12CS_N进行片选),当读写外部数据时,P0口发出奇数地址时,可向D12写入一个命令;P0口发出偶数地址时,可向D12读写数据。

2. D12SUSPEND
  当不能对D12操作时,不要忘了检查SUSPEND状态。如果SUSPEND为高表示D12已挂起,可将其置低,并发出恢复命令,唤醒主机。

3. D12INT_N
  可以说INT_N总是有效(由中断模式设置有关),一般D12挂起和忙时无效。

4. D12DMA传输有关管脚
  DMREQ 51发出DMA请求,51可以DMA要求读写数据

  DMACK_N 51D12确认DMA操作,D12完成DMA操作

  EOT_N 51D12发出结束DMA操作,同时要求DMACK_N置低,并发出读或写的动作。

引脚参数定义:

sbit D12_suspend=P1^0;
sbit D12_int_n=P1^1;
sbit D12_eot_n=P1^2;
sbit D12_DMAck_n=P1^3;
sbit D12_DMAreq=P1^4;


面对主机USB设备首先要处理的是主机标准控制请求。

下面代码可作为开发USB设备面对主机的模板。

[1] 处理主机标准控制请求:

unsigned char ENDPOINT_A0_FIFO[8]
//
判断输入的是SETUP请求,并将其读入缓冲区ENDPOINT_A0_FIFO

...
if((ENDPOINT_A0_FIFO[0] & 0b01100000)==0x00)
{
if (ENDPOINT_A0_FIFO[1] <= 0x0C)
{
(*StandardFunctionTable[ENDPOINT_A0_FIFO[1]])();
return;
}
}
...

const void (* StandardFunctionTable[])(void)=
{
GetStatus,ClearFeature,USB_Reserved,SetFeature,
USB_Reserved,SetAddress,GetDescriptor,SetDescriptor,
GetConfiguration,SetConfiguration,GetInterface,
SetInterface,SynchFrame
};

void GetStatus(void)
{
switch (ENDPOINT_A0_FIFO[0])
   {
case (0b10000000)://
返回设备状态

         //
发送两个字节数据:第一字节D1 1支持远程唤醒、为0不支持远程唤醒,D0 1设备自己供电、为0 USB总线供电,其它位为0;第二字节为0

break;
   case (0b100000001)://
返回接口状态

//
发送两个字节数据:第一字节为0;第二字节为0

break;
   case (0b10000010)://
返回端点状态

//
发送两个字节数据:第一字节D01端点处于暂停,否则D00,其它位为0;第二字节为0

break;
   }
}

void ClearFeature(void)
{
    if ((ENDPOINT_A0_FIFO[0] ==0b00000000)
        && (ENDPOINT_A0_FIFO[2] == 1) &&
           ( !ENDPOINT_A0_FIFO[3]))
        {
            //
清除设备远程唤醒功能

            return;
        }
    if ((ENDPOINT_A0_FIFO[0] ==0b00000001)
        && (ENDPOINT_A0_FIFO[2] == 0) &&
           ( !ENDPOINT_A0_FIFO[3]))
        {
            //
清除设备接口特殊功能 ENDPOINT_A0_FIFO[4] 为接口号

            return;
        }
    if ((ENDPOINT_A0_FIFO[0] == 0b00000010)
&& (ENDPOINT_A0_FIFO[2] == 0) &&
           (!ENDPOINT_A0_FIFO[3])) 
        {
            //
清除设备端点暂停功能 ENDPOINT_A0_FIFO[4] D7为端点方向,D3~D0为端点号

      return;
       }
}

void USB_Reserved(void)
{
//
只发确认信息。

}

void SetFeature(void)
{
if ((ENDPOINT_A0_FIFO[0] ==0b00000000)
&& (ENDPOINT_A0_FIFO[2] == 1) &&
( !ENDPOINT_A0_FIFO[3]))
{
//
设置设备远程唤醒功能

return;
}
if ((ENDPOINT_A0_FIFO[0] ==0b00000001)
&& (ENDPOINT_A0_FIFO[2] == 0) &&
( !ENDPOINT_A0_FIFO[3]))
{
//
设置设备接口特殊功能 ENDPOINT_A0_FIFO[4] 为接口号

return;
}
if ((ENDPOINT_A0_FIFO[0] == 0b00000010)
&& (ENDPOINT_A0_FIFO[2] == 0) &&
(!ENDPOINT_A0_FIFO[3]))
{
//
设置设备端点暂停 ENDPOINT_A0_FIFO[4] D7为端点方向,D3~D0为端点号

return;
}
}void SetAddress(void)
{
    if (ENDPOINT_A0_FIFO[0] == 0b00000000)
    {
        //
保存USB地址
0x80 | ENDPOINT_A0_FIFO[2];
    }
}
/*
注:

    SetAddress
请求实际可分成三个阶段。第一阶段,Setup包被送至设备,第二个可有无的阶段,数据在设备与主机之间传送,第三阶段,状态信息在主机与设备之间传送。

   
数据与状态传送的方向要看是主机发数据给设备还是设备发数据给主机。状态的传送方向总是与数据传送方向是相反的,如果没有数据传输阶段则状态由设备传向主机的。

    Setup
包传送以后的两个阶段的地址保持与Setup包传送阶段一致。USB设备只有在Status阶段过后才能改变设备地址。

*/

void GetDescriptor(void)
{
     if ( (ENDPOINT_A0_FIFO[0] != 0b10000000 DEVICE)) && 
         (ENDPOINT_A0_FIFO[0] != 0b10000001  INTERFACE)) &&
         (ENDPOINT_A0_FIFO[0] != 0b10000010  ENDPOINT)))        
    {
            return;
    }
    switch (ENDPOINT_A0_FIFO[3]) 
    {
        case 1 :
            //
发送设备描述表。 发送数据
<= ENDPOINT_A0_FIFO[6,7]
            break;
        case 2 :
            //
发送配置 [,接口(1),端点(1),接口(2),端点(2),...,,厂商等] 描述表

            break;
        case 3 :
            switch(ENDPOINT_A0_FIFO[2])
            {
            case 0x00 :
                //
发送字符串0描述表

                break;
            case 0x01 :
                //
发送字符串1描述表

               break;
            default   :
                return;
            }
            break;
        case 4 :
            //
发送接口描述表

            break;
        case 5 :
            //
发送端点描述表

            break;
    }
}

//设备描述表
const char USB_DEVICE_DEscriptOR[]=

  UCHAR bLength 
  UCHAR bDescriptorType 
  USHORT bcdUSB 
  UCHAR bDeviceClass 
  UCHAR bDeviceSubClass 
  UCHAR bDeviceProtocol 
  UCHAR bMaxPacketSize0 
  USHORT idVendor 
  USHORT idProduct 
  USHORT bcdDevice 
  UCHAR iManufacturer 
  UCHAR iProduct 
  UCHAR iSerialNumber 
  UCHAR bNumConfigurations 
};

//配置描述表
const char USB_CONFIGURATION_DEscriptOR[]=

  UCHAR bLength 
  UCHAR bDescriptorType 
  USHORT wTotalLength 
  UCHAR bNumInterfaces 
  .
  .
  UCHAR iConfiguration 
  UCHAR bmAttributes 
  UCHAR MaxPower 
};
//
接口描述表

const char USB_INTERFACE_DEscriptOR[]=

  UCHAR bLength 
  UCHAR bDescriptorType 
  UCHAR bInterfaceNumber 
  UCHAR bAlternateSetting 
  UCHAR bNumEndpoints 
  UCHAR bInterfaceClass 
  UCHAR bInterfaceSubClass 
  UCHAR bInterfaceProtocol 
  UCHAR iInterface 
};

//端点描述表
const char USB_ENDPOINT_DEscriptOR[]=

  UCHAR bLength 
  UCHAR bDescriptorType 
  UCHAR bEndpointAddress 
  UCHAR bmAttributes 
  USHORT wMaxPacketSize 
  UCHAR bInterval 
};

//字符串0描述表
const char USB_STRING_DEscriptOR[]=
{
  UCHAR bLength 
  UCHAR bDescriptorType 
  WCHAR bLangID[1] 
..
}

//字符串1描述表
const char USB_STRING_DEscriptOR[]=
{
  UCHAR bLength 
  UCHAR bDescriptorType 
  WCHAR bString[1] 
}


在发送配置 [,接口(1),端点(1),接口(2),端点(2),...,,厂商等] 联合描述表时,各描述表的先后顺序可随意,主机USBD根据描述表类型标识区分各种分描述表。

描述表类型:

USB_DEVICE_DEscriptOR_TYPE                0x01
USB_CONFIGURATION_DEscriptOR_TYPE        0x02
USB_STRING_DEscriptOR_TYPE                0x03
USB_INTERFACE_DEscriptOR_TYPE            0x04
USB_ENDPOINT_DEscriptOR_TYPE              0x05


//
标准设备描述表
const char USB_DEVICE_DEscriptOR[]=

  0x12, //
描述表长18字节

  0x01, //
设备描述表类型

  0x10,0x01, //
此设备与描述表兼容的USB设备说明版本号(BCD
)
  0x00, //
设备类码

  0x00, //
子类码

  0x00, //
协议码

  0x08, //
端点0的最大包大小(8,16,32,64为合法值
)
  0xb4,0x04,//
厂商ID(USB标准付值
)
  0x70,0x63,//
产品ID(由厂商付值
)
  0x01,0x00,//
设备发行号(BCD
)
  0x01,//
描述厂商信息的字串描述表索引

  0x02,//
描述产品信息的字串描述表索引

  0x00,//
描述设备序列号信息的字串描述表索引(不支持设为
0)
  0x01,//
可能的设置描述表数

};

USB设备类码(UNKNOWN设为0):

USB_DEVICE_CLASS_RESERVED           0x00
USB_DEVICE_CLASS_AUDIO              0x01
USB_DEVICE_CLASS_COMMUNICATIONS     0x02
USB_DEVICE_CLASS_HUMAN_INTERFACE    0x03
USB_DEVICE_CLASS_MONITOR            0x04
USB_DEVICE_CLASS_PHYSICAL_INTERFACE 0x05
USB_DEVICE_CLASS_POWER              0x06
USB_DEVICE_CLASS_PRINTER            0x07
USB_DEVICE_CLASS_STORAGE            0x08
USB_DEVICE_CLASS_HUB                0x09
USB_DEVICE_CLASS_VENDOR_SPECIFIC    0xFF

点击此处查看原文 >>

系统分类: 接口电路   |    用户分类: 无分类    |    来源: 转贴

评论(0) | 阅读(89)
发表于:2008-5-6 15:04:01
标签:无标签

0

volatile关键字

volatile关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。

使用该关键字的例子如下:

int volatile nVint;

  当要求使用volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存。

例如:

volatile int i="10";
int a = i;
...
//其他代码,并未明确告诉编译器,对i进行过操作

int b = i;
  volatile 指出 i是随时可能发生变化的,每次使用它的时候必须从i的地址中读取,因而编译器生成的汇编代码会重新从i的地址读取数据放在b中。而优化做法是,由于编译器发现两次从i读数据的代码之间的代码没有对i进行过操作,它会自动把上次读的数据放在b中。而不是重新从i里面读。这样以来,如果i是一个寄存器变量或者表示一个端口数据就容易出错,所以说volatile可以保证对特殊地址的稳定访问。

点击此处查看原文 >>

系统分类: 嵌入式   |    用户分类:    |    来源: 转贴

评论(0) | 阅读(60)
发表于:2008-5-6 10:17:48
标签:无标签

0

[转]Unicode编码规范

[转]Unicode编码规范
 
 

先从ASCII说起。ASCII是用来表示英文字符的一种编码规范,每个ASCII

字符占用1个字节(8bits)

因此,ASCII编码可以表示的最大字符数是256,其实英文字符并没有那么多,一般只用前128个(最高位为0),其中包括了控制字符、数字、大小写字母和其他一些符号 。

而最高位为1的另128个字符被成为“扩展ASCII”,一般用来存放英文的制表符、部分音标字符等等的一些其他符号

这种字符编码规范显然用来处理英文没有什么问题 。(实际上也可以用来处理法文、德文等一些其他的西欧字符,但是不能和英文通用),但是面对中文、阿拉伯文之类复杂的文字,255个字符显然不够用

于是,各个国家纷纷制定了自己的文字编码规范,其中中文的文字编码规范叫做“GB2312-80”,它是和ASCII兼容的一种编码规范,其实就是利用扩展ASCII没有真正标准化这一点,把一个中文字符用两个扩展ASCII字符来表示。

但是这个方法有问题,最大的问题就是,中文文字没有真正属于自己的编码,因为扩展ASCII码虽然没有真正的标准化,但是PC里的ASCII码还是有一个事实标准的(存放着英文制表符),所以很多软件利用这些符号来画表格。这样的软件用到中文系统中,这些表格符就会被误认作中文字,破坏版面。而且,统计中英文混合字符串中的字数,也是比较复杂的,我们必须判断一个ASCII码是否扩展,以及它的下一个ASCII是否扩展,然后才“猜”那可能是一个中文字 。

总之当时处理中文是很痛苦的。而更痛苦的是GB2312是国家标准,台湾当时有一个Big5编码标准,很多编码和GB是相同的,所以……,嘿嘿。

这时候,我们就知道,要真正解决中文问题,不能从扩展ASCII的角度入手,也不能仅靠中国一家来解决。而必须有一个全新的编码系统,这个系统要可以将中文、英文、法文、德文……等等所有的文字统一起来考虑,为每个文字都分配一个单独的编码,这样才不会有上面那种现象出现。

于是,Unicode诞生了。

Unicode有两套标准,一套叫UCS-2(Unicode-16),用2个字节为字符编码,另一套叫UCS-4(Unicode-32),用4个字节为字符编码。

以目前常用的UCS-2为例,它可以表示的字符数为2^16=65535,基本上可以容纳所有的欧美字符和绝大部分的亚洲字符 。

UTF-8的问题后面会提到 。

在Unicode里,所有的字符被一视同仁。汉字不再使用“两个扩展ASCII”,而是使用“1个Unicode”,注意,现在的汉字是“一个字符”了,于是,拆字、统计字数这些问题也就自然而然的解决了 。

但是,这个世界不是理想的,不可能在一夜之间所有的系统都使用Unicode来处理字符,所以Unicode在诞生之日,就必须考虑一个严峻的问题:和ASCII字符集之间的不兼容问题。

我们知道,ASCII字符是单个字节的,比如“A”的ASCII是65。而Unicode是双字节的,比如“A”的Unicode是0065,这就造成了一个非常大的问题:以前处理ASCII的那套机制不能被用来处理Unicode了 。

另一个更加严重的问题是,C语言使用'\0'作为字符串结尾,而Unicode里恰恰有很多字符都有一个字节为0,这样一来,C语言的字符串函数将无法正常处理Unicode,除非把世界上所有用C写的程序以及他们所用的函数库全部换掉 。

于是,比Unicode更伟大的东东诞生了,之所以说它更伟大是因为它让Unicode不再存在于纸上,而是真实的存在于我们大家的电脑中。那就是:UTF 。

UTF= UCS Transformation Format UCS转换格式

它是将Unicode编码规则和计算机的实际编码对应起来的一个规则。现在流行的UTF有2种:UTF-8和UTF-16 。

其中UTF-16和上面提到的Unicode本身的编码规范是一致的,这里不多说了。而UTF-8不同,它定义了一种“区间规则”,这种规则可以和ASCII编码保持最大程度的兼容 。

UTF-8有点类似于Haffman编码,它将Unicode编码为00000000-0000007F的字符,用单个字节来表示;

00000080-000007FF的字符用两个字节表示

00000800-0000FFFF的字符用3字节表示

因为目前为止Unicode-16规范没有指定FFFF以上的字符,所以UTF-8最多是使用3个字节来表示一个字符。但理论上来说,UTF-8最多需要用6字节表示一个字符。

在UTF-8里,英文字符仍然跟ASCII编码一样,因此原先的函数库可以继续使用。而中文的编码范围是在0080-07FF之间,因此是2个字节表示(但这两个字节和GB编码的两个字节是不同的),用专门的Unicode处理类可以对UTF编码进行处理。

下面说说中文的问题。

由于历史的原因,在Unicode之前,一共存在过3套中文编码标准。

GB2312-80,是中国大陆使用的国家标准,其中一共编码了6763个常用简体汉字。Big5,是台湾使用的编码标准,编码了台湾使用的繁体汉字,大概有8千多个。HKSCS,是中国香港使用的编码标准,字体也是繁体,但跟Big5有所不同。

这3套编码标准都采用了两个扩展ASCII的方法,因此,几套编码互不兼容,而且编码区间也各有不同

因为其不兼容性,在同一个系统中同时显示GB和Big5基本上是不可能的。当时的南极星、RichWin等等软件,在自动识别中文编码、自动显示正确编码方面都做了很多努力 。

他们用了怎样的技术我就不得而知了,我知道好像南极星曾经以同屏显示繁简中文为卖点。

后来,由于各方面的原因,国际上又制定了针对中文的统一字符集GBK和GB18030,其中GBK已经在Windows、Linux等多种操作系统中被实现。

GBK兼容GB2312,并增加了大量不常用汉字,还加入了几乎所有的Big5中的繁体汉字。但是GBK中的繁体汉字和Big5中的几乎不兼容。

GB18030相当于是GBK的超集,比GBK包含的字符更多。据我所知目前还没有操作系统直接支持GB18030。


谈谈Unicode编码,简要解释UCS、UTF、BMP、BOM等名词
这是一篇程序员写给程序员的趣味读物。所谓趣味是指可以比较轻松地了解一些原来不清楚的概念,增进知识,类似于打RPG游戏的升级。整理这篇文章的动机是两个问题:

问题一:
使用Windows记事本的“另存为”,可以在GBK、Unicode、Unicode big endian和UTF-8这几种编码方式间相互转换。同样是txt文件,Windows是怎样识别编码方式的呢?

我很早前就发现Unicode、Unicode big endian和UTF-8编码的txt文件的开头会多出几个字节,分别是FF、FE(Unicode),FE、FF(Unicode big endian),EF、BB、BF(UTF-8)。但这些标记是基于什么标准呢?

问题二:
最近在网上看到一个ConvertUTF.c,实现了UTF-32、UTF-16和UTF-8这三种编码方式的相互转换。对于Unicode(UCS2)、GBK、UTF-8这些编码方式,我原来就了解。但这个程序让我有些糊涂,想不起来UTF-16和UCS2有什么关系。
查了查相关资料,总算将这些问题弄清楚了,顺带也了解了一些Unicode的细节。写成一篇文章,送给有过类似疑问的朋友。本文在写作时尽量做到通俗易懂,但要求读者知道什么是字节,什么是十六进制。

0、big endian和little endian
big endian和little endian是CPU处理多字节数的不同方式。例如“汉”字的Unicode编码是6C49。那么写到文件里时,究竟是将6C写在前面,还是将49写在前面?如果将6C写在前面,就是big endian。还是将49写在前面,就是little endian。

“endian”这个词出自《格列佛游记》。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开,由此曾发生过六次叛乱,其中一个皇帝送了命,另一个丢了王位。

我们一般将endian翻译成“字节序”,将big endian和little endian称作“大尾”和“小尾”。

1、字符编码、内码,顺带介绍汉字编码
字符必须编码后才能被计算机处理。计算机使用的缺省编码方式就是计算机的内码。早期的计算机使用7位的ASCII编码,为了处理汉字,程序员设计了用于简体中文的GB2312和用于繁体中文的big5。

GB2312(1980年)一共收录了7445个字符,包括6763个汉字和682个其它符号。汉字区的内码范围高字节从B0-F7,低字节从A1-FE,占用的码位是72*94=6768。其中有5个空位是D7FA-D7FE。

GB2312支持的汉字太少。1995年的汉字扩展规范GBK1.0收录了21886个符号,它分为汉字区和图形符号区。汉字区包括21003个字符。2000年的GB18030是取代GBK1.0的正式国家标准。该标准收录了27484个汉字,同时还收录了藏文、蒙文、维吾尔文等主要的少数民族文字。现在的PC平台必须支持GB18030,对嵌入式产品暂不作要求。所以手机、MP3一般只支持GB2312。

从ASCII、GB2312、GBK到GB18030,这些编码方法是向下兼容的,即同一个字符在这些方案中总是有相同的编码,后面的标准支持更多的字符。在这些编码中,英文和中文可以统一地处理。区分中文编码的方法是高字节的最高位不为0。按照程序员的称呼,GB2312、GBK到GB18030都属于双字节字符集 (DBCS)。

有的中文Windows的缺省内码还是GBK,可以通过GB18030升级包升级到GB18030。不过GB18030相对GBK增加的字符,普通人是很难用到的,通常我们还是用GBK指代中文Windows内码。

这里还有一些细节:

GB2312的原文还是区位码,从区位码到内码,需要在高字节和低字节上分别加上A0。

在DBCS中,GB内码的存储格式始终是big endian,即高位在前。

GB2312的两个字节的最高位都是1。但符合这个条件的码位只有128*128=16384个。所以GBK和GB18030的低字节最高位都可能不是1。不过这不影响DBCS字符流的解析:在读取DBCS字符流时,只要遇到高位为1的字节,就可以将下两个字节作为一个双字节编码,而不用管低字节的高位是什么。

2、Unicode、UCS和UTF
前面提到从ASCII、GB2312、GBK到GB18030的编码方法是向下兼容的。而Unicode只与ASCII兼容(更准确地说,是与ISO-8859-1兼容),与GB码不兼容。例如“汉”字的Unicode编码是6C49,而GB码是BABA。

Unicode也是一种字符编码方法,不过它是由国际组织设计,可以容纳全世界所有语言文字的编码方案。Unicode的学名是"Universal Multiple-Octet Coded Character Set",简称为UCS。UCS可以看作是"Unicode Character Set"的缩写。

根据维基百科全书(http://zh.wikipedia.org/wiki/)的记载:历史上存在两个试图独立设计Unicode的组织,即国际标准化组织(ISO)和一个软件制造商的协会(unicode.org)。ISO开发了ISO 10646项目,Unicode协会开发了Unicode项目。

在1991年前后,双方都认识到世界不需要两个不兼容的字符集。于是它们开始合并双方的工作成果,并为创立一个单一编码表而协同工作。从Unicode2.0开始,Unicode项目采用了与ISO 10646-1相同的字库和字码。

目前两个项目仍都存在,并独立地公布各自的标准。Unicode协会现在的最新版本是2005年的Unicode 4.1.0。ISO的最新标准是10646-3:2003。

UCS规定了怎么用多个字节表示各种文字。怎样传输这些编码,是由UTF(UCS Transformation Format)规范规定的,常见的UTF规范包括UTF-8、UTF-7、UTF-16。

IETF的RFC2781和RFC3629以RFC的一贯风格,清晰、明快又不失严谨地描述了UTF-16和UTF-8的编码方法。我总是记不得IETF是Internet Engineering Task Force的缩写。但IETF负责维护的RFC是Internet上一切规范的基础。

3、UCS-2、UCS-4、BMP

UCS有两种格式:UCS-2和UCS-4。顾名思义,UCS-2就是用两个字节编码,UCS-4就是用4个字节(实际上只用了31位,最高位必须为0)编码。下面让我们做一些简单的数学游戏:

UCS-2有2^16=65536个码位,UCS-4有2^31=2147483648个码位。

UCS-4根据最高位为0的最高字节分成2^7=128个group。每个group再根据次高字节分为256个plane。每个plane根据第3个字节分为256行 (rows),每行包含256个cells。当然同一行的cells只是最后一个字节不同,其余都相同。

group 0的plane 0被称作Basic Multilingual Plane, 即BMP。或者说UCS-4中,高两个字节为0的码位被称作BMP。

将UCS-4的BMP去掉前面的两个零字节就得到了UCS-2。在UCS-2的两个字节前加上两个零字节,就得到了UCS-4的BMP。而目前的UCS-4规范中还没有任何字符被分配在BMP之外。

4、UTF编码

UTF-8就是以8位为单元对UCS进行编码。从UCS-2到UTF-8的编码方式如下:

UCS-2编码(16进制) UTF-8 字节流(二进制)
0000 - 007F 0xxxxxxx
0080 - 07FF 110xxxxx 10xxxxxx
0800 - FFFF 1110xxxx 10xxxxxx 10xxxxxx

例如“汉”字的Unicode编码是6C49。6C49在0800-FFFF之间,所以肯定要用3字节模板了:1110xxxx 10xxxxxx 10xxxxxx。将6C49写成二进制是:0110 110001 001001, 用这个比特流依次代替模板中的x,得到:11100110 10110001 10001001,即E6 B1 89。

读者可以用记事本测试一下我们的编码是否正确。

UTF-16以16位为单元对UCS进行编码。对于小于0x10000的UCS码,UTF-16编码就等于UCS码对应的16位无符号整数。对于不小于0x10000的UCS码,定义了一个算法。不过由于实际使用的UCS2,或者UCS4的BMP必然小于0x10000,所以就目前而言,可以认为UTF-16和UCS-2基本相同。但UCS-2只是一个编码方案,UTF-16却要用于实际的传输,所以就不得不考虑字节序的问题。

5、UTF的字节序和BOM
UTF-8以字节为编码单元,没有字节序的问题。UTF-16以两个字节为编码单元,在解释一个UTF-16文本前,首先要弄清楚每个编码单元的字节序。例如收到一个“奎”的Unicode编码是594E,“乙”的Unicode编码是4E59。如果我们收到UTF-16字节流“594E”,那么这是“奎”还是“乙”?

Unicode规范中推荐的标记字节顺序的方法是BOM。BOM不是“Bill Of Material”的BOM表,而是Byte Order Mark。BOM是一个有点小聪明的想法:

在UCS编码中有一个叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的编码是FEFF。而FFFE在UCS中是不存在的字符,所以不应该出现在实际传输中。UCS规范建议我们在传输字节流前,先传输字符"ZERO WIDTH NO-BREAK SPACE"。

这样如果接收者收到FEFF,就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little-Endian的。因此字符"ZERO WIDTH NO-BREAK SPACE"又被称作BOM。

UTF-8不需要BOM来表明字节顺序,但可以用BOM来表明编码方式。字符"ZERO WIDTH NO-BREAK SPACE"的UTF-8编码是EF BB BF(读者可以用我们前面介绍的编码方法验证一下)。所以如果接收者收到以EF BB BF开头的字节流,就知道这是UTF-8编码了。

Windows就是使用BOM来标记文本文件的编码方式的。

6、进一步的参考资料
本文主要参考的资料是 "Short overview of ISO-IEC 10646 and Unicode" (http://www.nada.kth.se/i18n/ucs/unicode-iso10646-oview.html)。

点击此处查看原文 >>

系统分类: 自由话题   |    用户分类:    |    来源: 转贴

评论(0) | 阅读(63)
发表于:2008-5-6 9:29:12
标签:无标签

1

USB接口的基础理论知识(转帖)

 USB接口的基础理论知识



 USB的重要关键字:

1、端点:位于USB设备或主机上的一个数据缓冲区,用来存放和发送USB的各种数据,每一个端点都有惟一的确定地址,有不同的传输特性(如输入端点、输出端点、配置端点、批量传输端点)

2、帧:时间概念,在USB中,一帧就是1MS,它是一个独立的单元,包含了一系列总线动作,USB将1帧分为好几份,每一份中是一个USB的传输动作。

3、上行、下行:设备到主机为上行,主机到设备为下行

下面以一问一答的形式开始学习吧:

问题一:USB的传输线结构是如何的呢?

答案一:一条USB的传输线分别由地线、电源线、D+、D-四条线构成,D+和D-是差分输入线,它使用的是3.3V的电压(注意哦,与CMOS的5V电平不同),而电源线和地线可向设备提供5V电压,最大电流为500MA(可以在编程中设置的,至于硬件的实现机制,就不要管它了)。

问题二:数据是如何在USB传输线里面传送的

答案二:数据在USB线里传送是由低位到高位发送的。

问题三:USB的编码方案?

答案三:USB采用不归零取反来传输数据,当传输线上的差分数据输入0时就取反,输入1时就保持原值,为了确保信号发送的准确性,当在USB总线上发送一个包时,传输设备就要进行位插入***作(即在数据流中每连续6个1后就插入一个0),从而强迫NRZI码发生变化。这个了解就行了,这些是由专门硬件处理的。

问题四:USB的数据格式是怎么样的呢?

答案四:和其他的一样,USB数据是由二进制数字串构成的,首先数字串构成域(有七种),域再构成包,包再构成事务(IN、OUT、SETUP),事务最后构成传输(中断传输、并行传输、批量传输和控制传输)。下面简单介绍一下域、包、事务、传输,请注意他们之间的关系。

(一)域:是USB数据最小的单位,由若干位组成(至于是多少位由具体的域决定),域可分为七个类型:

1、同步域(SYNC),八位,值固定为0000 0001,用于本地时钟与输入同步

2、标识域(PID),由四位标识符+四位标识符反码构成,表明包的类型和格式,这是一个很重要的部分,这里可以计算出,USB的标识码有16种,具体分类请看问题五。

3、地址域(ADDR):七位地址,代表了设备在主机上的地址,地址000 0000被命名为零地址,是任何一个设备第一次连接到主机时,在被主机配置、枚举前的默认地址,由此可以知道为什么一个USB主机只能接127个设备的原因。

4、端点域(ENDP),四位,由此可知一个USB设备有的端点数量最大为16个。

5、帧号域(FRAM),11位,每一个帧都有一个特定的帧号,帧号域最大容量0x800,对于同步传输有重要意义(同步传输为四种传输类型之一,请看下面)。

6、数据域(DATA):长度为0~1023字节,在不同的传输类型中,数据域的长度各不相同,但必须为整数个字节的长度

7、校验域(CRC):对令牌包和数据包(对于包的分类请看下面)中非PID域进行校验的一种方法,CRC校验在通讯中应用很泛,是一种很好的校验方法,至于具体的校验方法这里就不多说,请查阅相关资料,只须注意CRC码的除法是模2运算,不同于10进制中的除法。

(二)包:由域构成的包有四种类型,分别是令牌包、数据包、握手包和特殊包,前面三种是重要的包,不同的包的域结构不同,介绍如下

1、令牌包:可分为输入包、输出包、设置包和帧起始包(注意这里的输入包是用于设置输入命令的,输出包是用来设置输出命令的,而不是放据数的)

其中输入包、输出包和设置包的格式都是一样的:

SYNC+PID+ADDR+ENDP+CRC5(五位的校验码)

(上面的缩写解释请看上面域的介绍,PID码的具体定义请看问题五)

帧起始包的格式:

SYNC+PID+11位FRAM+CRC5(五位的校验码)

2、数据包:分为DATA0包和DATA1包,当USB发送数据的时候,当一次发送的数据长度大于相应端点的容量时,就需要把数据包分为好几个包,分批发送,DATA0包和DATA1包交替发送,即如果第一个数据包是 DATA0,那第二个数据包就是DATA1。但也有例外情况,在同步传输中(四类传输类型中之一),所有的数据包都是为DATA0,格式如下:

SYNC+PID+0~1023字节+CRC16

3、握手包:结构最为简单的包,格式如下

SYNC+PID

(注上面每种包都有不同类型的,USB1.1共定义了十种包,具体请见问题五)

(三)事务:分别有IN事务、OUT事务和SETUP事务三大事务,每一种事务都由令牌包、数据包、握手包三个阶段构成,这里用阶段的意思是因为这些包的发送是有一定的时间先后顺序的,事务的三个阶段如下:

1、令牌包阶段:启动一个输入、输出或设置的事务

2、数据包阶段:按输入、输出发送相应的数据

3、握手包阶段:返回数据接收情况,在同步传输的IN和OUT事务中没有这个阶段,这是比较特殊的。

事务的三种类型如下(以下按三个阶段来说明一个事务):

1、 IN事务:

令牌包阶段——主机发送一个PID为IN的输入包给设备,通知设备要往主机发送数据;

数据包阶段——设备根据情况会作出三种反应(要注意:数据包阶段也不总是传送数据的,根据传输情况还会提前进入握手包阶段)

1) 设备端点正常,设备往入主机里面发出数据包(DATA0与DATA1交替);

2) 设备正在忙,无法往主机发出数据包就发送NAK无效包,IN事务提前结束,到了下一个IN事务才继续;

3) 相应设备端点被禁止,发送错误包STALL包,事务也就提前结束了,总线进入空闲状态。

握手包阶段——主机正确接收到数据之后就会向设备发送ACK包。



2、 OUT事务:

令牌包阶段——主机发送一个PID为OUT的输出包给设备,通知设备要接收数据;

数据包阶段——比较简单,就是主机会设备送数据,DATA0与DATA1交替

握手包阶段——设备根据情况会作出三种反应

1)设备端点接收正确,设备往入主机返回ACK,通知主机可以发送新的数据,如果数据包发生了CRC校验错误,将不返回任何握手信息;

2) 设备正在忙,无法往主机发出数据包就发送NAK无效包,通知主机再次发送数据;

3) 相应设备端点被禁止,发送错误包STALL包,事务提前结束,总线直接进入空闲状态。



3、SETUT事务:

令牌包阶段——主机发送一个PID为SETUP的输出包给设备,通知设备要接收数据;

数据包阶段——比较简单,就是主机会设备送数据,注意,这里只有一个固定为8个字节的DATA0包,这8个字节的内容就是标准的USB设备请求命令(共有11条,具体请看问题七)

握手包阶段——设备接收到主机的命令信息后,返回ACK,此后总线进入空闲状态,并准备下一个传输(在SETUP事务后通常是一个IN或OUT事务构成的传输)

(四)传输:传输由OUT、IN、SETUP事务其中的事务构成,传输有四种类型,中断传输、批量传输、同步传输、控制传输,其中中断传输和批量转输的结构一样,同步传输有最简单的结构,而控制传输是最重要的也是最复杂的传输。

1、中断传输:由OUT事务和IN事务构成,用于键盘、鼠标等HID设备的数据传输中

2、批量传输:由OUT事务和IN事务构成,用于大容量数据传输,没有固定的传输速率,也不占用带宽,当总线忙时,USB会优先进行其他类型的数据传输,而暂时停止批量转输。

3、同步传输:由OUT事务和IN事务构成,有两个特殊地方,第一,在同步传输的IN和OUT事务中是没有返回包阶段的;第二,在数据包阶段所有的数据包都为DATA0

4、控制传输:最重要的也是最复杂的传输,控制传输由三个阶段构成(初始设置阶段、可选数据阶段、状态信息步骤),每一个阶段可以看成一个的传输,也就是说控制传输其实是由三个传输构成的,用来于USB设备初次加接到主机之后,主机通过控制传输来交换信息,设备地址和读取设备的描述符,使得主机识别设备,并安装相应的驱动程序,这是每一个USB开发者都要关心的问题。

1、初始设置步骤:就是一个由SET事务构成的传输

2、可选数据步骤:就是一个由IN或OUT事务构成的传输,这个步骤是可选的,要看初始设置步骤有没有要求读/写数据(由SET事务的数据包阶段发送的标准请求命令决定)

3、 状态信息步骤:顾名思义,这个步骤就是要获取状态信息,由IN或OUT事务构成构成的传输,但是要注意这里的IN和OUT事务和之前的INT和OUT事务有两点不同:

1) 传输方向相反,通常IN表示设备往主机送数据,OUT表示主机往设备送数据;在这里,IN表示主机往设备送数据,而OUT表示设备往主机送数据,这是为了和可选数据步骤相结合;

2) 在这个步骤里,数据包阶段的数据包都是0长度的,即SYNC+PID+CRC16

除了以上两点有区别外,其他的一样,这里就不多说

(思考:这些传输模式在实际***作中应如何通过什么方式去设置?)

问题五:标识码有哪些?

答案五:如同前面所说的标识码由四位数据组成,因此可以表示十六种标识码,在USB1.1规范里面,只用了十种标识码,USB2.0使用了十六种标识码,标识码的作用是用来说明包的属性的,标识码是和包联系在一起的,首先简单介绍一下数据包的类型,数据包分为令牌包、数据、握手包和特殊包四种(具体分类请看问题七),标识码分别有以下十六种:

令牌包 :

0x01 输出(OUT)启动一个方向为主机到设备的传输,并包含了设备地址和标号

0x09 输入 (IN) 启动一个方向为设备到主机的传输,并包含了设备地址和标号

0x05 帧起始(SOF)表示一个帧的开始,并且包含了相应的帧号

0x0d 设置(SETUP)启动一个控制传输,用于主机对设备的初始化

数据包 :

0x03 偶数据包(DATA0),

0x0b 奇数据包(DATA1)

握手包:

0x02 确认接收到无误的数据包(ACK)

0x0a 无效,接收(发送)端正在忙而无法接收(发送)信息

0x0e 错误,端点被禁止或不支持控制管道请求

特殊包 0x0C 前导,用于启动下行端口的低速设备的数据传输

问题六:USB主机是如何识别USB设备的?

答案六:当USB设备插上主机时,主机就通过一系列的动作来对设备进行枚举配置(配置是属于枚举的一个态,态表示暂时的状态),这这些态如下:

1、接入态(Attached):设备接入主机后,主机通过检测信号线上的电平变化来发现设备的接入;

2、供电态(Powered):就是给设备供电,分为设备接入时的默认供电值,配置阶段后的供电值(按数据中要求的最大值,可通过编程设置)

3、缺省态(Default):USB在被配置之前,通过缺省地址0与主机进行通信;

4、地址态(Address):经过了配置,USB设备被复位后,就可以按主机分配给它的唯一地址来与主机通信,这种状态就是地址态;

5、配置态(Configured):通过各种标准的USB请求命令来获取设备的各种信息,并对设备的某此信息进行改变或设置。

6、挂起态(Suspended):总线供电设备在3ms内没有总线***作,即USB总线处于空闲状态的话,该设备就要自动进入挂起状态,在进入挂起状态后,总的电流功耗不超过280UA。

问题七:刚才在答案四提到的标准的USB设备请求命令究竟是什么?

答案七:标准的USB设备请求命令是用在控制传输中的“初始设置步骤”里的数据包阶段(即DATA0,由八个字节构成),请看回问答四的内容。标准USB设备请求命令共有11个,大小都是8个字节,具有相同的结构,由5 个字段构成(字段是标准请求命令的数据部分),结构如下(括号中的数字表示字节数,首字母bm,b,w分别表示位图、字节,双字节):

bmRequestType(1)+bRequest(1)+wvalue(2)+wIndex(2)+wLength(2)

各字段的意义如下:

1、bmRequestType:D7D6D5D4D3D2D1D0

D7=0主机到设备

=1设备到主机;

D6D5=00标准请求命令

=01 类请求命令

=10用户定义的命令

=11保留值

D4D3D2D1D0=00000 接收者为设备

=00001 接收者为设备

=00010 接收者为端点

=00011 接收者为其他接收者

=其他 其他值保留

2、bRequest:请求命令代码,在标准的USB命令中,每一个命令都定义了编号,编号的值就为字段的值,编号与命令名称如下(要注意这里的命令代码要与其他字段结合使用,可以说命令代码是标准请求命令代码的核心,正是因为这些命令代码而决定了11个USB标准请求命令):

0) 0 GET_STATUS:用来返回特定接收者的状态

1) 1 CLEAR_FEATURE:用来清除或禁止接收者的某些特性

2) 3 SET_FEATURE:用来启用或激活命令接收者的某些特性

3) 5 SET_ADDRESS:用来给设备分配地址

4) 6 GET_DEscriptOR:用于主机获取设备的特定描述符

5) 7 SET_DEscriptOR:修改设备中有关的描述符,或者增加新的描述符

6) 8 GET_CONFIGURATION:用于主机获取设备当前设备的配置值(注同上面的不同)

7) 9 SET_CONFIGURATION:用于主机指示设备采用的要求的配置

8) 10 GET_INTERFACE:用于获取当前某个接口描述符编号

9) 11 SET_INTERFACE:用于主机要求设备用某个描述符来描述接口

10) 12 SYNCH_FRAME:用于设备设置和报告一个端点的同步帧

以上的11个命令要说得明白真的有一匹布那么长,请各位去看书吧,这里就不多说了,控制传输是USB的重心,而这11个命令是控制传输的重心,所以这11个命令是重中之重,这个搞明白了,USB就算是入门了。

问题八:在标准的USB请求命令中,经常会看到Descriptor,这是什么来的呢?

回答八:Descriptor即描述符,是一个完整的数据结构,可以通过C语言等编程实现,并存储在USB设备中,用于描述一个USB设备的所有属性,USB主机是通过一系列命令来要求设备发送这些信息的。它的作用就是通过如问答节中的命令***作来给主机传递信息,从而让主机知道设备具有什么功能、属于哪一类设备、要占用多少带宽、使用哪类传输方式及数据量的大小,只有主机确定了这些信息之后,设备才能真正开始工作,所以描述符也是十分重要的部分,要好好掌握。标准的描述符有5种,USB为这些描述符定义了编号:

1——设备描述符

2——配置描述符

3——字符描述符

4——接口描述符

5——端点描述符

上面的描述符之间有一定的关系,一个设备只有一个设备描述符,而一个设备描述符可以包含多个配置描述符,而一个配置描述符可以包含多个接口描述符,一个接口使用了几个端点,就有几个端点描述符。这间描述符是用一定的字段构成的,分别如下说明:

1、设备描述符

struct _DEVICE_DEscriptOR_STRUCT

{

BYTE bLength; //设备描述符的字节数大小,为0x12

BYTE bDescriptorType; //描述符类型编号,为0x01

WORD bcdUSB; //USB版本号

BYTE bDeviceClass; //USB分配的设备类代码,0x01~0xfe为标准设备类,0xff为厂商自定义类型

//0x00不是在设备描述符中定义的,如HID

BYTE bDeviceSubClass; //usb分配的子类代码,同上,值由USB规定和分配的

BYTE bDeviceProtocl; //USB分配的设备协议代码,同上

BYTE bMaxPacketSize0; //端点0的最大包的大小

WORD idVendor; //厂商编号

WORD idProduct; //产品编号

WORD bcdDevice; //设备出厂编号

BYTE iManufacturer; //描述厂商字符串的索引

BYTE iProduct; //描述产品字符串的索引

BYTE iSerialNumber; //描述设备序列号字符串的索引

BYTE bNumConfiguration; //可能的配置数量

}

2、配置描述符

struct _CONFIGURATION_DEscriptOR_STRUCT

{

BYTE bLength; //设备描述符的字节数大小,为0x12

BYTE bDescriptorType; //描述符类型编号,为0x01

WORD wTotalLength; //配置所返回的所有数量的大小

BYTE bNumInterface; //此配置所支持的接口数量

BYTE bConfigurationVale; //Set_Configuration命令需要的参数值

BYTE iConfiguration; //描述该配置的字符串的索引值

BYTE bmAttribute; //供电模式的选择

BYTE MaxPower; //设备从总线提取的最大电流

}



3、字符描述符

struct _STRING_DEscriptOR_STRUCT

{

BYTE bLength; //设备描述符的字节数大小,为0x12

BYTE bDescriptorType; //描述符类型编号,为0x01

BYTE SomeDescriptor[36]; //UNICODE编码的字符串

}

4、接口描述符

struct _INTERFACE_DEscriptOR_STRUCT

{

BYTE bLength; //设备描述符的字节数大小,为0x12

BYTE bDescriptorType; //描述符类型编号,为0x01

BYTE bInterfaceNunber; //接口的编号

BYTE bAlternateSetting;//备用的接口描述符编号

BYTE bNumEndpoints; //该接口使用端点数,不包括端点0

BYTE bInterfaceClass; //接口类型

BYTE bInterfaceSubClass;//接口子类型

BYTE bInterfaceProtocol;//接口所遵循的协议

BYTE iInterface; //描述该接口的字符串索引值

}

5、端点描述符

struct _ENDPOIN_DEscriptOR_STRUCT

{

BYTE bLength; //设备描述符的字节数大小,为0x12

BYTE bDescriptorType; //描述符类型编号,为0x01

BYTE bEndpointAddress; //端点地址及输入输出属性

BYTE bmAttribute; //端点的传输类型属性

WORD wMaxPacketSize; //端点收、发的最大包的大小

BYTE bInterval; //主机查询端点的时间间隔

}

点击此处查看原文 >>

系统分类: 接口电路   |    用户分类:    |    来源: 转贴

评论(0) | 阅读(193)
发表于:2008-5-6 9:26:35
标签:无标签

0

USB传输的基本单元---包(转帖)

USB传输的基本单元---包
 
 
包(Packet)是USB系统中信息传输的基本单元,所有的数据都是经过打包后在总线上传输的。USB系统采用反向不归零(NRZI)编码方式,采用位填充方式(Bit-Stuff)避免同步漂移。

1 包的组成

      USB包由5部分组成,即同步字段(Synchronization Sequence,简称SYNC)、包标识符(PID,Packet Identification)字段、数据字段、CRC校验字段和包结尾(End Of Packet,EOP)。任何类型的USB包都必须以同步字段作为起始,其编码为00000001,字段最后两位是同步字段结束的记号,标志着包标识符的开始;在USB协议中,根据包标识PID的不同,包类型也不同,是USB包的必须组成部分。PID包的长度为8位,其中低四位为包标识类型编码,高4位是对类型字段的每一位求反码产生的自校验码。数据字段用来携带主机与设备之间要传递的信息,其内容和长度根据包标识、传输类型的不同而各不相同,可以包含设备地址、端点号、帧序列号以及数据等内容。USB主机通过唯一的设备地址与总线上的USB设备进行数据传输,地址由bit0~bit6共7位组成,最多可以连接127个设备。USB设备的每个功能部件最多可以支持16个端点号,其中端点0必须被用作控制传输端点。当PID为SOF时,其数据字段必须为11位的帧序列号,帧序列号由USB主机产生,自动加一,最大数值为0x7FF。当PID为DATA0或者DATA1时,可发送0~1023之间任意长度数据。CRC校验字段对数据采用CRC16校验,对USB令牌包采用CRC5校验。

2 包的类型

    这里详细介绍四种类型的包:令牌包、数据包、握手包和专用包。

    令牌包:在USB系统中,所有的事务处理都起始于令牌包,它是由USB主机惟一的发送到总线上的。在数据传输的过程中,由USB主机发出令牌包,指明本次事务处理过程的含义,包括数据的传输方向、数据传输的设备地址和端点号。根据PID的不同,令牌包又分为起始令牌包(SOF)、输入令牌包(IN)、输出令牌包(OUT)和用于控制传输的设置令牌包(Setup)。对于SOF包,数据字段为11位序列号,对于IN/OUT/SETUP令牌包,数据字段由7位设备地址和4位端点号组成。

    数据包:这种包有两种类型,即DATA0和DATA1,其中DATA0标示奇数包,DATA1标示偶数包,这是为了避免因出错而带来的数据重传问题。

    握手包:握手包主要用来报告事务处理过程中接收方的状态,它没有数据字段和CRC字段,只有同步字段和标示符字段来表示传输状态。握手包分为ACK、NAK和STALL。其中ACK表示数据的接收方正确地接收到了数据包,对于输入事务处理,ACK由USB设备返回,而对于输出或者控制传输的设置阶段等事务处理过程,ACK由USB设备返回。NAK表示USB设备不能从USB主机接收数据,主要用于流量控制。这和网络中的NAK是不同的。这里的NAK不是表示出错。NAK智能由下游设备传向上游主机,主机只接收NAK。STALL表示由于USB设备内部问题不能发送或者接收数据,或者不支持某个控制命令。

    前导包:是为了使系统区分全速传输和低速传输而产生的,它的目的是为了提醒USB集线器系统要传输的下一个包是一个低速包。USB1.1支持两种传输速率:12Mb/s和1.5Mb/s。

 

点击此处查看原文 >>

系统分类: 接口电路   |    用户分类:    |    来源: 转贴

评论(0) | 阅读(72)
发表于:2008-3-31 8:55:45
标签:无标签

0

步进电机小知识(转帖)

步进电机小知识

 

1.什么是步进电机?
步进电机是一种将电脉冲转化为角位移的执行机构。通俗一点讲:当步进驱动器接收到一个脉冲信号,它就驱动步进电机按设定的方向转动一个固定的角度(及步进角)。您可以通过控制脉冲个数来控制角位移量,从而达到准确定位的目的;同时您可以通过控制脉冲频率来控制电机转动的速度和加速度,从而达到调速的目的。


2.步进电机分哪几种?
步进电机分三种:永磁式(PM) ,反应式(VR)和混合式(HB)永磁式步进一般为两相,转矩和体积较小,步进角一般为7.5度 或15度;反应式步进一般为三相,可实现大转矩输出,步进角一般为1.5度,但噪声和振动都很大。在欧美等发达国家80年代已被淘汰;混合式步进是指混合了永磁式和反应式的优点。它又分为两相和五相:两相步进角一般为1.8度而五相步进角一般为 0.72度。这种步进电机的
应用最为广泛。


3.什么是保持转矩(HOLDING TORQUE)?
保持转矩(HOLDING TORQUE)是指步进电机通电但没有转动时,定子锁住转子的力矩。它是步进电机最重要的参数之一,通常步进电机在低速时的力矩接近保持转矩。由于步进电机的输出力矩随速度的增大而不断衰减,输出功率也随速度的增大而变化,所以保持转矩就成为了衡量步进电机最重要的参数之一。比如,当人们说2N.m的步进电机,在没有特殊说明的情况下是指保持转矩为2N.m的步进电机。


4.什么是DETENT TORQUE?
DETENT TORQUE 是指步进电机没有通电的情况下,定子锁住转子的力矩。DETENT TORQUE 在国内没有统一的翻译方式,容易使大家产生误解;由于反应式步进电机的转子不是永磁材料,所以它没有DETENT TORQUE。

5.步进电机精度为多少?是否累积?
一般步进电机的精度为步进角的3-5%,且不累积。

6.步进电机的外表温度允许达到多少?
步进电机温度过高首先会使电机的磁性材料退磁,从而导致力矩下降乃至于失步,因此电机外表允许的最高温度应取决于不同电机磁性材料的退磁点;一般来讲,磁性材料的退磁点都在摄氏130度以上,有的甚至高达摄氏200度以上,所以步进电机外表温度在摄氏80-90度完全正常。


7.为什么步进电机的力矩会随转速的升高而下降?
当步进电机转动时,电机各相绕组的电感将形成一个反向电动势;频率越高,反向电动势越大。在它的作用下,电机随频率(或速度)的增大而相电流减小,从而导致力矩下降。


8.为什么步进电机低速时可以正常运转,但若高于一定速度就无法启动,并伴有啸叫声?
步进电机有一个技术参数:空载启动频率,即步进电机在空载情况下能够正常启动的脉冲频率,如果脉冲频率高于该值,电机不能正常启动,可能发生丢步或堵转。在有负载的情况下,启动频率应更低。如果要使电机达到高速转动,脉冲频率应该有加速过程,即启动频率较低,然后按一定加速度升到所希望的高频(电机转速从低速升到高速)。


9.如何克服两相混合式步进电机在低速运转时的振动和噪声?
步进电机低速转动时振动和噪声大是其固有的缺点,一般可采用以下方案来克服:
A.如步进电机正好工作在共振区,可通过改变减速比等机械传动避开共振区;
B.采用带有细分功能的驱动器,这是最常用的、最简便的方法;
C.换成步距角更小的步进电机,如三相或五相步进电机;
D.换成交流伺服电机,几乎可以完全克服震动和噪声,但成本较高;
E.在电机轴上加磁性阻尼器,市场上已有这种产品,但机械结构改变较大。


10.细分驱动器的细分数是否能代表精度?
步进电机的细分技术实质上是一种电子阻尼技术(请参考有关文献),其主要目的是减弱或消除步进电机的低频振动,提高电机的运转精度只是细分技术的一个附带功能。比如对于步进角为1.8° 的两相混合式步进电机,如果细分驱动器的细分数设置为4,那么电机的运转分辨率为每个脉冲0.45°,电机的精度能否达到或接近0.45°,还取决于细分驱动器的细分电流控制精度等其它因素。不同厂家的细分驱动器精度可能差别很大;细分数越大精度越难控制。


11.四相混合式步进电机与驱动器的串联接法和并联接法有什么区别?
四相混合式步进电机一般由两相驱动器来驱动,因此,连接时可以采用串联接法或并联接法将四相电机接成两相使用。串联接法一般在电机转速较的场合使用,此时需要的驱动器输出电流为电机相电流的0.7倍,因而电机发热小;并联接法一般在电机转速较高的场合使用(又称高速接法),所需要的驱动器输出电流为电机相电流的1.4倍,因而电机发热较大。


12.如何确定步进电机驱动器的直流供电电源?
A.电压的确定
混合式步进电机驱动器的供电电源电压一般是一个较宽的范围(比如IM483的供电电压为12~48VDC),电源电压通常根据电机的工作转速和响应要求来选择。如果电机工作转速较高或响应要求较快,那么电压取值也高,但注意电源电压的纹波不能超过驱动器的最大输入电压,否则可能损坏驱动器。
B.电流的确定
供电电源电流一般根据驱动器的输出相电流I来确定。如果采用线性电源,电源电流一般可取I 的1.1~1.3倍;如果采用开关电源,电源电流一般可取I 的1.5~2.0倍。


13.混合式步进电机驱动器的脱机信号FREE一般在什么情况下使用?
当脱机信号FREE为低电平时,驱动器输出到电机的电流被切断,电机转子处于自由状态(脱机状态)。在有些自动化设备中,如果在驱动器不断电的情况下要求直接转动电机轴(手动方式),就可以将FREE信号置低,使电机脱机,进行手动操作或调节。手动完成后,再将FREE信号置高,以继续自动控制。

14.如果用简单的方法调整两相步进电机通电后的转动方向?
只需将电机与驱动器接线的A+和A-(或者B+和B-)对调即可。


关于驱动器的细分原理及一些相关说明
在国外,对于步进系统,主要采用二相混合式步进电机及相应的细分驱动器。 但在国内,广大用户对“细分”还不是特别了解,有的只是认为,细分是为了提高精度,其实不然,细分主要是改善电机的运行性能,现说明如下:步进电机的细分控制是由驱动器精确控制步进电机的相电流来实现的,以二相电机为例,假如电机的额定相电流为3A,如果使用常规驱动器(如常用的恒流斩波方式)驱动该电机,电机每运行一步,其绕组内的电流将从0突变为3A或从3A突变到0,相电流的巨大变化,必然会引起电机运行的振动和噪音。如果使用细分驱动器,在10细分的状态下驱动该电机,电机每运行一微步,其绕组内的电流变化只有0.3A而不是3A,且电流是以正弦曲线规律变化,这样就大大的改善了电机的振动和噪音,因此,在性能上的优点才是细分的真正优点。由于细分驱动器要精确控制电机的相电流,所以对驱动器要有相当高的技术要求和工艺要求,成本亦会较高。注意,国内有一些驱动器采用“平滑”来取代细分,有的亦称为细分,但这不是真正的细分,望广大用户一定要分清两者的本质不同:


15.“平滑”并不精确控制电机的相电流,只是把电流的变化率变缓一些,所以“平滑”并不产生微步,而细分的微步是可以用来精确定位的。


16.电机的相电流被平滑后,会引起电机力矩的下降,而细分控制不但不会引起电机力矩的下降,相反,力矩会有所增加。

17.两相和五相的混合式步进电机的应用场合有何不同?
问题解答:
一般来说,两相电机步距角大,高速特性好,但是存在低速振动区。而五相电机步距角小,低速运行平稳。所以,在对电机的 运转精度要求较高&nbsp;,且主要在中低速段(一般低于600转/分) 的场合应选用五相电机;反之,若追求电机的高速性能,对精度及平稳性无太多要求的场合应选用成本较低的两相电机。另外,五相电机的力矩通常在2NM以上,对小力矩的应用,一般采用两相电机,而低速平稳性的问题可以通过采用细分驱动器的 方式解决。

和步进电机相比,伺服电机有以下几点优势:
1、实现了位置,速度和力矩的闭环控制;克服了步进电机失步
的问题;
2、高速性能好,一般额定转速能达到2000~3000转;
3、抗过载能力强,能承受三倍于额定转矩的负载,对有瞬间负载波动和要求快速起动的场合特别适用;
4、低速运行平稳,低速运行时不会产生类似于步进电机的步进运行现象。适用于有高速响应要求的场合;
5、电机加减速的动态相应时间短,一般在几十毫秒之内;6、发热和噪音明显降低。

点击此处查看原文 >>

系统分类: 工业控制   |    用户分类:    |    来源: 转贴

评论(0) | 阅读(168)
发表于:2008-3-31 8:43:36
标签:无标签

0

步进电机原理说明(转帖)

步进电机原理说明

步进电机原理说明

一、前言

1.步进电机是将电脉冲信号转变为角位移或线位移的开环控制元件。在非超载的情况下,电机的转速、停止的位置只取决于脉冲信号的频率和脉冲数,而不受负载变化的影响,即给电机加一个脉冲信号,电机则转过一个步距角。这一线性关系的存在,加上步进电机只有周期性的误差而无累积误差等特点。使得在速度、位置等控制领域用步进电机来控制变的非常的简单。 虽然步进电机已被广泛地应用,但步进电机并不能象普通的直流电机,交流电机在常规下使用。它必须由双环形脉冲信号、功率驱动电路等组成控制系统方可使用。因此用好步进电机却非易事,它涉及到机械、电机、电子及计算机等许多专业知识。 目前,生产步进电机的厂家的确不少,但具有专业技术人员,能够自行开发,研制的厂家却非常少,大部分的厂家只一、二十人,连最基本的设备都没有。仅仅处于一种盲目的仿制阶段。这就给户在产品选型、使用中造成许多麻烦。签于上述情况,我们决定以广泛的感应子式步进电机为例。叙述其基本工作原理。望能对广大用户在选型、使用、及整机改进时有所帮助。

二、感应子式步进电机工作原理(一)反应式步进电机原理由于反应式步进电机工作原理比较简单。下面先叙述三相反应式步进电机原理。

1、结构: 电机转子均匀分布着很多小齿,定子齿有三个励磁绕阻,其几何轴线依次分别与转子齿轴线错开。0、1/3て、2/3て,(相邻两转子齿轴线间的距离为齿距以て表示),即A与齿1相对齐,B与齿2向右错开1/3て,C与齿3向右错开2/3て,A'与齿5相对齐,(A'就是A,齿5就是齿1)下面是定转子的展开图:

2、旋转: 如A相通电,B,C相不通电时,由于磁场作用,齿1与A对齐,(转子不受任何力以下均同)。 如B相通电,A,C相不通电时,齿2应与B对齐,此时转子向右移过1/3て,此时齿3与C偏移为1/3て,齿4与A偏移(て-1/3て)=2/3て。如C相通电,A,B相不通电,齿3应与C对齐,此时转子又向右移过1/3て,此时齿4与A偏移为1/3て对齐。  如A相通电,B,C相不通电,齿4与A对齐,转子又向右移过1/3て 这样经过A、B、C、A分别通电状态,齿4(即齿1前一齿)移到A相,电机转子向右转过一个齿距,如果不断地按A,B,C,A……通电,电机就每步(每脉冲)1/3て,向右旋转。如按A,C,B,A……通电,电机就反转。 由此可见:电机的位置和速度由导电次数(脉冲数)和频率成一一对应关系。而方向由导电顺序决定。 不过,出于对力矩、平稳、噪音及减少角度等方面考虑。往往采用A-AB-B-BC-C-CA-A这种导电状态,这样将原来每步1/3て改变为1/6て。甚至于通过二相电流不同的组合,使其1/3て变为1/12て,1/24て,这就是电机细分驱动的基本理论依据。 不难推出:电机定子上有m相励磁绕阻,其轴线分别与转子齿轴线偏移1/m,2/m……(m-1)/m,1。并且导电按一定的相序电机就能正反转被控制——这是步进电机旋转的物理条件。只要符合这一条件我们理论上可以制造任何相的步进电机,出于成本等多方面考虑,市场上一般以二、三、四、五相为多。
3、力矩: 电机一旦通电,在定转子间将产生磁场(磁通量Ф)当转子与定子错开一定角度产生力F与(dФ/dθ)成正比

其磁通量Ф=Br*S Br为磁密,S为导磁面积 F与L*D*Br成正比 L为铁芯有效长度,D为转子直径 Br="N"·I/RN·I为励磁绕阻安匝数(电流乘匝数)R为磁阻。力矩=力*半径力矩与电机有效体积*安匝数*磁密 成正比(只考虑线性状态)因此,电机有效体积越大,励磁安匝数越大,定转子间气隙越小,电机力矩越大,反之亦然。

(二)感应子式步进电机

1、特点: 感应子式步进电机与传统的反应式步进电机相比,结构上转子加有永磁体,以提供软磁材料的工作点,而定子激磁只需提供变化的磁场而不必提供磁材料工作点的耗能,因此该电机效率高,电流小,发热低。因永磁体的存在,该电机具有较强的反电势,其自身阻尼作用比较好,使其在运转过程中比较平稳、噪音低、低频振动小。 感应子式步进电机某种程度上可以看作是低速同步电机。一个四相电机可以作四相运行,也可以作二相运行。(必须采用双极电压驱动),而反应式电机则不能如此。例如:四相,八相运行(A-AB-B-BC-C-CD-D-DA-A)完全可以采用二相八拍运行方式.不难发现其条件为C= ,D= . 一个二相电机的内部绕组与四相电机完全一致,小功率电机一般直接接为二相,而功率大一点的电机,为了方便使用,灵活改变电机的动态特点,往往将其外部接线为八根引线(四相),这样使用时,既可以作四相电机使用,可以作二相电机绕组串联或并联使用。

2、分类 感应子式步进电机以相数可分为 :二相电机、三相电机、四相电机、五相电机等。以机座号(电机外径)可分为:42BYG(BYG为感应子式步进电机代号)、57BYG、86BYG、110BYG、(国际标准),而像70BYG、90BYG、130BYG等均为国内标准。

3、步进电机的静态指标术语相数:产生不同对极N、S