一、USB接口特点、组成及结构
https://www.wendangku.net/doc/8014553302.html,B接口的优点
⑴ 通信速度快:USB1.1规范,全速最高传输速率可达12Mb/s,比串口快100倍;USB2.0规范,可提供480Mb/s 的数据传输速率。
⑵ 支持多个不同设备,可与主机通信,理论上可达127个设备。
⑶ 提供5V/100mA 的电源,使得低功率USB 设备不再需要另接电源。
⑷ 支持热插拔。即PC 在开机状态下,可实现即插即用功能。当插入USB 设备时,主机检测该外设,并通过加载相关驱动程序,对该设备进行配置。
⑸ USB 为所有USB 外设提供单一的、易于操作的连接形式,简化了设备连接方式。
总之,USB 是一种快速、双向、同步传输、廉价、方便使用的可热插拔的串行接口。其快速通信能力可提升各种外设、仪器、自控设备的功能,并使之进入大容量实时图像传输的新时期。正因为如此,USB 接口已成为各种外设、仪器、自控设备发展的一个新方向,并在逐渐取代传统外设。
2.C8051F32×单片机USB接口特点
⑴ 单片机的USB 接口不需外接任何电子元件,就可进行USB 通信。
⑵ 单片机的USB 接口;全速通信速率可达12Mb/s,慢速可达1.5Mb/s.
⑶ 单片机内嵌USB 核,能处理绝大多数USB 事件,大大简化了程序。
⑷ 单片机USB 接口内有一个串行接口引擎(sie),Sie 与USB 的数据线D+、D-相连,在USB 设备与PC 间传送数据。
⑸ 单片机USB 接口带有1KB fifo(先进先出)专用XRAM 区,方便了USB 数据交换。
⑹ C8051F32×单片机有32只引脚,具有8051内核,指令和8051兼容,在同类带USB 接口的单片机产品中,是功能较强、硬件制作和连接最简单,价格较便宜,最便于推广和应用开发的。
3.C8051F32×单片机USB接口和结构
⑴ 组成和结构
单片机内的USB 接口符合USB 2.0规范,在USB1.1全速工作状态下可达12Mb/s,低速状态下为1.5Mb/s。
USB 内部集成了收发器和端点,以及fifo—XRAM,共有8个端点。
一个双向端点(端点0)和3对输入输出端点(端点1~3)。
XRAM 中有1kb 存储空间专用于USB 的fifo,该空间被分配给端点0~3(说明:每个端点所对应的XRAM 地址空间请查看C8051F32×技术说明的相关内容)。
USB 接口内有4倍时钟乘法器和时钟恢复电路,并允许使用内部高精度振荡器作为USB 时钟源,全速时为48MHz。
CPU 内部时钟源和USB 时钟相互独立。USB 接口的收发器符合USB2.0规范,内部
具有上拉电阻和匹配电路,其内部上拉电阻可被软
编者按:目前,带USB 总线的产品越来越多,其优越性也更加显现,USB 的应用必将向着更深和更广的方向发展。为了使读者进一步了解和掌握USB 设计技术,本刊特推出《使用C8051F32X 带USB 接口的单片机进行数据采集和USB 接口通信》系列讲座,以帮助大家掌握利用片内带USB 接口的单片机进行数据采集和用USB 接口进行数据通信的相关技术。使用C8051F32X 带USB 接口的单片机进行数据采集和USB 接口通信(三)
——C8051F32X 单片机USB 数据通信开发
2010 VOL.03
46
件使能/禁止,可根据用户的需求速度设置出现在D+、D-引脚上。
⑵ USB接口连线定义如下:①脚Vbus(电源正),红线;②脚D-(负差分信号),白线;③脚D+(正差分信号),绿线;④脚GND(电源地),黑线。
二、C8051F32×单片机USB接口数据
通信开发过程和实例
https://www.wendangku.net/doc/8014553302.html,B主机和USB设备(指下位机中带USB 接口的单片机)通信过程简述
用户在PC机应用软件上发出的一条通信指令,经应用软件传送到USB的设备驱动程序,在总线上转换成USB的数据流,通过USB电缆传送给USB 下位机设备;下位机中带USB接口的单片机接收并处理指令后,再将处理后的状态和数据结果传回USB主机。
需注意的是,所有的数据传送都是由主机开始的,任何USB外设(即带USB接口的单片机)都无权开始一次传输,也就是说,USB外设是从机。
https://www.wendangku.net/doc/8014553302.html,B驱动软件和专用开发软件包在USB 开发中的作用
为了使数据能在USB总线进行传输,为了便于使用USB接口,USB接口芯片开发商开发了USB接口专用驱动开发软件包。
本实例所用的USB接口专用驱动开发软件包为USB—Xpress的3.11版,其组成和作用如下:
⑴ 上位机USB接口驱动软件
作用:在windows-xp操作系统支持下,对从PC主机到PC的USB接口间的许多层面之间的物理的/信号的/数据包的/进行顺利连接;能够简捷地将有关软件指令转换成USB数据流。该驱动软件需在PC上安装。
⑵ 在上位机应用软件程序的开发编程中,为了高效地开发USB接口程序,将引用专用USB_api 函数库,用若干功能模块来有效开发USB接口部分。USB_api函数库是以一个windows动态链接库的形式出现的。重要的USB动作,将通过调用对应的功能模块来完成。
如:si_open,是打开设备模块;Si_read,是将要从下位设备中读取数据;Si_write,要对下位机设备写入数据。具体的USB_api函数说明,请看有关说明(见附录)。
⑶ 在下位机USB外设(即带USB接口的单片机)的`USB通信软件程序开发中,对于USB接口的重要功能、动作,同样是通过调用USB_api的下位机(下层)函数库中的重要功能函数模块,来高效地开发USB接口部分的程序的。
下面是几个重要的USB_api功能函数模块:
USB_clock_start(); USB接口时钟初始化。
USB_init(); USB接口使能。
USB_int_enable( ); USB中断使能。
USB_api_test_isr( );中断16,判断中断源。
Block_write; 单片机通过USB口写数据到主机。
Block_read; 通过USB口从主机读数据到单片机。
由于C8051F32×单片机在USB口通信软件开发中使用了USBxpress软件包,大大缩短了软件开发时间,简化了开发过程。所以,了解和掌握该软件包的使用,是开发USB接口的关键。
3.单片机端USB-API函数库说明
⑴ USB_Clock_Start
功能:初始化USB总线时钟。包括使能内部振荡器、初始化时钟倍频器,以及设置USB时钟为48MHz,以便USB全速工作。此功能必须在调用USB_Init函数或访问任何可变的XRAM高1024字节(USB时钟范围)之前调用。
说明:在调用USB_Clock_Start或USB_Init函数之后不应该修改的特殊功能寄存器
1)不应该修改的USB特殊功能寄存器有:USB0XCN、USB0ADR和USB0DAT。
2)不应该修改的其他特殊功能寄存器有:CLKMUL、OSCICN的5~7位、CLKSEL的4~6位,即用于使能内部振荡器、建立4倍频时钟为48MHz,以及将该时钟作为USB模块的时钟的特殊功能寄存器。为确保API的正常运行,它们不得被修改。
47电子制作
API用户共享特殊功能寄存器:特殊功能寄存器CLKSEL用于系统时钟源和USB时钟源的选择。需要注意的是:在为获得所需系统时钟而对其位1~0置位时,要使用或(OR)指令,以免改变其6~4位(即USB时钟选择位)的值。特殊功能寄存器OSCICN用来控制内部振荡器。其IFCN位不会影响12MHz时钟倍频输入或USB时钟,用户可以根据对系统时钟频率的需要对IFCN [1:0]位进行修改。只是在修改IFCN [1:0]位时,应注意保护其5~7位不被改变。
⑵ Block_Write
功能:块写入。即通过USB将单片机缓冲区中的数据传给主机。其最大可传数据块为4096字节。返回的数字是实际写入的字节数。除非错误条件发生,否则应与参数NumBytes完全相符。NumBytes的有效数值为1~4096。如果调用Block_Write,而NumBytes大于4096字节,返回值为零。如果NumBytes大于64字节,所传输得数据将被分成多个数据包,每个数据包64字节(除最后一个数据包外)。在将最后一个数据包复制到设备的USB发送缓冲区后,Block_Write函数返回。
⑶ Block_Read
功能:块读出,即通过USB将主机发来的数据读到单片机的缓冲区中。其最大可接收的数据块为64字节。返回时,无论全部缓冲区是否被Block_Read函数读取过,器件的USB接收缓冲区都将清空。从器件的USB接收缓冲区读取的最大字节数由NumBytes指定。实际读取的字节数(即复制到缓冲区的字节数)由函数返回。如果没有要读取的字节,返回零。通常,Block_Read 函数是在接收一个数据包后被调用,由RX_COMPLETE USB API中断指示。
当发送到SI_Write的缓冲区大于64字节,则通过一次SI_Write函数调用传送的数据,将需要多次调用Block_Read函数来读取。
⑷ Get_Interrupt_Source
功能:获取中断源,即返回一个表示USB-API中断源的8位数,同时清除USB-API待处理中断标志。Get_Interrupt_Source函数应在用户中断服务程序开始时调用,以判定发生了哪些事件。
返回值编码如下:
0x00 没有USB API中断
0x01 USB_RESET USB复位中断
0x02 TX_COMPLETE 发送完成中断
0x04 RX_COMPLETE 接收完成中断
0x08 FIFO_PURGE 命令接收(从主机服务)清除的USB缓冲区
0x10 DEVICE_OPEN 器件打开在主机端
0x20 DEVICE_CLOSE 器件关闭在主机
0x40 DEV_CONFIGURED 器件已进入配置状态
0x80 DEV_SUSPEND 在暂停的USB总线上信号
⑸ USB_Int_Enable
功能:允许USB API中断。调用USB_Int_ Enable函数后,下述API事件均可产生USB API 中断。
1)发生USB复位。
2)一个调用Block_Write(块写入)函数的传送完成。
3)收发缓冲区已准备好为调用Block_Read(块读出)服务。
4)来自主机的命令使USB缓冲区被刷新。
5)设备实例已被主机打开或关闭。
USB API的中断源,可以通过调用Get_ Interrupt_Source 函数得到。如果USB API中断被允许,用户必须提供一个中断服务程序,其程序入口为中断向量16(地址=0x0083)。当此函数被调用时,如果已有任何USB API中断申请,则在1毫秒内程序会响应该中断,进入中断16处理程序。
4. 单片机通过USB口将数据块上传给PC 机的实例
(1)实例介绍
本实例所用的上位机软件界面,如图1所示。
1)最上面的对话框:在将单片机USB接口和PC机的USB接口连接好,并运行上位机软件,且与单片机USB口握手成功后,框内将显示:1 2 3 4;
2)软件的最下面的对话框(RECEIVE FILE)是:PC机接收来自单片机的数据块(存成.hex文件),
2010 VOL.03 48
操作时,先点击BROWSE,选好存储介质,写入.hex 文件名;再点击左边(RECEIVE FILE)框,便把来自单片机的数据存到PC 机的对应.hex 文件中了。
图1
⑵ 用单片机的USB 口将数据传送到PC 的程序流程图
图2是单片机端的USB 数据通信程序流程图。程序是用C51编的。程序中大量调用了USB_API 函数库中的重要功能函数模块,使用的编译器是keil—8.08。
(3)单片机端USB 接口数据上传程序说明这个例程:能实现,将c8051f320单片机内的flash 程序区内的,从2000h 起存放的数据块;通过usb 接口上传到pc 端。通过pc 端的应用接收软件,将数据块存成hex 数据文件。并存放到pc 的硬盘中。一次最大的数据块存储量;是4kb.具体的例程演示和操做,可查看320usb 单片机开发板使用说明。
1)运行上位机软件、上下位机USB 接口连接好,USB 初始化后。上位机软件得到下位机的状态回应(设备已准备好),此时,上位机软件对话框(SELECT)中显示1 2 3 4,表示上下位机USB 接口初始化完成,握手成功。
此时,单片机端的程序为:
调用USB-API 函数:USB_clock_start();USB 时钟初始化,内部时钟12MHz,USBq 全速时钟48MHz ;port1_init();i/o 接口初始化;
调用USB-API 函数:USB_init();USB 接口使能;调用USB-API 函数:
USB_int_enable();USB
图2
usb_cloch_start();USB 时钟初始化usb_init();USB 接口使能
Port1_init();I/O 口初始化Usb_int_enable();USB 中断使能
While(i)等待
Usb_api_test_isp(),interrupt16;中断16为指示中断原因函数;运行usb_api 中断,进入中断服务程序
判中断类型,置当前状态m_stara=;进入state_machine()函数
如USB 设备已打开,接收主机设置信息RECEIRE_SETUP();
block_read 函数读主机所发设置信息(buffer3)
buffer(0)=read_msg ?是执行下一步,否转PC 发数据
设置上传数据块指针、字节长度、地址及数据变量
设置状态m_state=st_tx_file Led2=1灯亮;
进入state_machine()函数,转St_tx_file 模块(数据块发主机)
设传送长度,调block_write 函数确认数据指针,写入指针,确认变量
写数据块到PC,LED2闪
数据块写完?写完led2=0灯灭,传送结束
49
电子制作
中断使能。
2)在上位机软件进行数据块上传操作时,点击左下角对话框(RECEIVE FILE),上位机发出将单片机内数据上传的命令,通过USB口将命令设置信息下载到单片机的buffer中。此时,单片机端程序运行状态为:进入中断16的中断服务程序。
USB_api_test_isr();指示中断原因,设置当时状态。之后,进入state_machine()函数,由于USB上下位机设备都已打开,程序进入接收主机设置信息函数RECEIVE_SETUP(),并用block_ read;USB-api函数,读PC发送的命令设置,---(buffer 3),并判断buffer(0)是否=read_msg.
如成立,则进入单片机数据发送到PC的准备程序。
这段程序的功能是:a)将变量(数据块) numblock,确认;发送的数据块起始地址。数据块在在单片机flash的2000h~21ffh中; b)确定变量(数据块)的最大个发送字节。 c)调用block_ write,USB_api函数,把上述设置信息发送到主机,即Byteswrote=block_write(byte*)&buffer;
同时,将此时的状态设置为:m_state_=st_tx_ file;并点亮led2=1,发光管。
3)程序再次进入state_machine()函数,此时状态设置为:
到tx_file单片机数据发送至PC模块,程序完成下面动作,a) 设要写的数据长度和数据块的起始地址。 b)调用USB_api功能函数block_write进行数据发送。C)检查数据是否发送完毕?发送时,led2在闪动;发送完毕,led2熄灭。
(4)单片机端USB接口数据上传源程序
该源程序采用C语言编制,用C51的keil—8.08编译器编译,文件名:USBsvg.c。程序中大量使用了USB_api单片机端的函数库。所以在编译中,必须连接库文件,即USBx_f320_1.lib库文件。
源文件如下:
//包含文件
#include
// C8051F320头文件
#include
// NULL指针定义
#include "USB_API.h"
// USB_API.lib头文件
//位定义
Sbit Led1=P2^2;
// P2.2置1,点亮LED1
Sbit Led2=P2^3;
// P2.3置1,点亮LED2,指示数据传送
//常量定义
#define NUM_STG_PAGES 20
//定义文件存储的flash 总页数为20
#define MAX_BLOCK_SIZE_READ 64
//读数据块的最大字节数为64
#define MAX_BLOCK_SIZE_WRITE 4096
//写数据块的最大字节数为4096
#define FLASH_PAGE_SIZE 512
//每个flash页为512
#define BLOCKS_PR_PAGE FLASH_PAGE_ SIZE/MAX_BLOCK_SIZE_READ
// 512/64 = 8
#define MAX_NUM_BYTES FLASH_PAGE_ SIZE*NUM_STG_PAGES
#define MAX_NUM_BLOCKS BLOCKS_PR_ PAGE*NUM_STG_PAGES
//信息类型
#define READ_MSG 0x00
//主机通信信息类型
#define WRITE_MSG 0x01
#define SIZE_MSG 0x02
#define DELAYED_READ_MSG 0x05
//机器状态
#define ST_WAIT_DEV 0x01
//等待应用程序打开设备
#define ST_IDLE_DEV 0x02
//设备打开,等待主机发设置信息
#define ST_RX_SETUP 0x04
//收到设置信息,解码并等待接收数据
#define ST_RX_FILE 0x08
//接收主机所发数据文件
#define ST_TX_FILE 0x10
//发送数据文件给主机
2010 VOL.03 50
#define ST_TX_ACK 0x20
//处理8个数据包,发一次应答ACK 0xFF给主机
#define ST_ERROR 0x80
//出错状态
// No such thing as a block of data anymore since it is variable between 1 and 1024
// So comment this out
typedef struct { //数据块结构定义
BYTE Piece[MAX_BLOCK_SIZE_READ];
} BLOCK;
typedef struct { // flash存储器页结构定义
BYTE FlashPage[FLASH_PAGE_SIZE];
} PAGE;
Xdata BLOCK TempStorage[BLOCKS_PR_ PAGE];
// Temporary storage of between flash writes
//data B Y T E c o d e* PageIndices[20] = {0x1400,0x1600,0x1800,0x 1A00,0x1C00,0x1E00,0x2000,0x2200,0x2400,0 x2600
// ,0x2800,0x2A00,0x2C00,0x2E00,0x3000,0x 3200,0x3400,0x3600,0x3800,0x3A00};
Data BYTE code * PageIndices[20] = {0x 2000,0x2200,0x2400,0x2600,0x2800,0x2A00,0x2 C00,0x2E00,0x3000,0x3200,0x3400};
data UINT BytesToRead;
//从主机读入的总字节数
data UINT WriteStageLength;
//当前写传送状态长度
data UINT ReadStageLength;
//当前读传送状态长度
data BYTE Buffer[3];
// 设置信息缓冲区
data UINT NumBytes;
// 传送块数
data BYTE NumBlocks;
data UINT BytesRead;
//读字节数
data BYTE M_State;
//机器当前状态
data UINT BytesWrote;
//接字节数
data BYTE BlockIndex;
//当前块在页内的指针
data BYTE PageIndex;
//当前页在文件中的指针
data BYTE BlocksWrote;
//被写块的总数
data BYTE* ReadIndex;
data UINT BytesToWrite;
/ [开始] USB信息描述 [开始] /
code const UINT USB_VID = 0x10C4;
code const UINT USB_PID = 0xEA61;
code const BYTE USB_MfrStr[] = {0x 1A,0x03,'S',0,'i',0,'l',0,'i',0,'c',0,'o',0,'n',0,' ',0,'L',0,'a',0,'b',0,'s',0}; //生产厂
code const BYTE USB_ProductStr[] = {0x10,0x03,'U',0,'S',0,'B',0,' ',0,'A',0,'P',0,'I',0};
//产品描述
code const BYTE USB_SerialStr[] = {0x0A,0x 03,'1',0,'2',0,'3',0,'4',0};
code const BYTE USB_MaxPower = 15;
// 最大电流30mA(15 * 2)
code const BYTE USB_PwAttributes = 0x80;
// 总线电源,不支持远程唤醒
code const UINT USB_bcdDevice = 0x0100;
// 设备版本号1.00
/ [结束] USB信息描述 [结束] /
Code BYTE LengthFile[3] _at_ 0x2000;
// {Length(Low Byte), Length(High Byte), Number of Blocks}
Void Port_Init(void);
// 口初始化并允许交叉
Void State_Machine(void);
// 确定新状态及执行当前状态
Void Receive_Setup(void);
// 接收并解码主机所发设置包
//主程序
void main(void)
51电子制作
{
PCA0MD &= ~0x40;
//看门狗禁止
USB_Clock_Start();
//使能USB口前,先初始化USB时钟
U S B_I n i t(U S B_V I D,U S B_P I D,U S B_ MfrStr,USB_ProductStr,USB_SerialStr,USB_ MaxPower,USB_PwAttributes,USB_bcdDevice);
CLKSEL|=0x02;
RSTSRC|=0x02;
Port_Init();
//I/O口初始化
USB_Int_Enable();
//开USB_API中断
while (1);
}
void Port_Init(void)
{
P2MDOUT |= 0x0C;
//P2.0、P2.1置为高阻态
XBR0=0x00;
XBR1=0x40;//允许交叉
}
Void State_Machine(void)
{
switch (M_State)
{
Case ST_RX_SETUP:
Receive_Setup();
//接收并解码主机所发设置信息
break;
case ST_RX_FILE:
Receive_File(); //接收主机数据文件
break;
case ST_TX_ACK:
M_State=ST_RX_FILE;
//Ack发送完成,继续接收数据
break;
case ST_TX_FILE:
// 发送数据文件到主机
W r i t e S t a g e L e n g t h=((B y t e s T o W r i t e-BytesWrote)>MAX_BLOCK_SIZE_WRITE)? MAX_BLOCK_SIZE_WRITE:(BytesToWrite - BytesWrote);
BytesWrote += Block_Write((BYTE*) (ReadIndex), WriteStageLength);
ReadIndex += WriteStageLength;
If ((BlocksWrote%8)==0)Led2=~Led2;
If (BytesWrote == NumBytes) Led2=0;
break;
default:
break;
}
}
//当API中断允许且收到一个中断申请时,执行USB_API中断
void USB_API_TEST_ISR(void) interrupt 16
{
BYTE INTVAL=Get_Interrupt_Source();
// 确定API中断类型
If (INTVAL&USB_RESET)
// 是总线复位,转等待状态
{
M_State=ST_WAIT_DEV;
}
If (INTVAL&DEVICE_OPEN)
//主机端设备打开,转Idle
{
M_State=ST_IDLE_DEV;
}
if (INTVAL&TX_COMPLETE)
{
If (M_State==ST_RX_FILE)
//应答Ack传完,转RX状态
{
M_State=(ST_TX_ACK);
}
If (M_State == ST_TX_FILE)
//文件块传完,转TX状态
{
2010 VOL.03 52
M_State=(BytesWrote == BytesToWrite) ? ST_IDLE_DEV :ST_TX_FILE;//执行完,转Idle }
}
if (INTVAL & RX_COMPLETE)
// RX完,转RX设置或RX文件状态
{
M_State=(M_State==ST_IDLE_DEV)?ST_RX_ SETUP:ST_RX_FILE;
}
If (INTVAL&DEVICE_CLOSE)
//关设备,等待再次打开
{
M_State=ST_WAIT_DEV;
}
if (INTVAL&FIFO_PURGE)
//清Fifo,转Idle状态
{
M_State=ST_IDLE_DEV;
}
State_Machine(); //调用状态机程序
}
void Receive_Setup(void)
{
BytesRead=Block_Read(&Buffer,3);
//读设置信息
if (Buffer[0]==READ_MSG)
//读文件已设置,选See
{
PageIndex=0; // 指针复位
NumBlocks=LengthFile[2];
//从flash stg读NumBlocks
NumBlocks=(NumBlocks > MAX_NUM_ BLOCKS)? MAX_NUM_BLOCKS: NumBlocks;
//多字节写
// as we have space available
Buffer[0]=SIZE_MSG;
// 发送主机传送信息长度
Buffer[1]=LengthFile[1];
Buffer[2]=LengthFile[0];
BytesToWrite=Buffer[1] + 256*Buffer[2];
BytesWrote=Block_Write((BYTE*)&Buffer, 3);
M_State=ST_TX_FILE;
//转发送数据状态
BytesWrote=0;
ReadIndex=PageIndices[0];
Led2=1;
}
else //否则为写入设置包
{
BytesToRead=Buffer[1]+256*Buffer[2];
NumBlocks=(BYTE)(BytesToRead/MAX_ BLOCK_SIZE_READ);
//Find NumBlocks
if (BytesToRead > MAX_NUM_BYTES)
//传输数据太大,出错
{
M_State = ST_ERROR;
}
else
{
If (BytesToRead%MAX_BLOCK_SIZE_READ) NumBlocks++;
// NumBlocks加1
TempStorage->Piece[0]=Buffer[2];
TempStorage->Piece[1]=Buffer[1];
TempStorage->Piece[2]=NumBlocks;
//Write Values to Flash
//Store file data to flash
PageIndex= 0;
// Reset Index
BlockIndex= 0;
BytesRead= 0;
Led1=1;
M_State=ST_RX_FILE;//转接收数据状态
}
}
}
程序结束;
53电子制作