📄 usbfunctions.c
字号:
#include <msp430x14x.h>
#include "USBvariables.h"
#include "USBfunctions.h"
typedef unsigned char uchar;
typedef unsigned int uint;
void (*StandardDeviceRequest[])(void)=
{
Get_status,
Clr_feature,
Reserved,
Set_feature,
Reserved,
Set_addr,
Get_descriptor,
Reserved,
Get_config,
Set_config,
Get_interface,
Set_interface,
Reserved,
Reserved,
Reserved,
Reserved
};
/*******************************************
函数名称: Delayus
功 能: 延时指定微秒(8M晶振)
参 数: US--延时的微秒数(大约,不是很精确)
返回值 : 无
********************************************/
void Delayus(uint US)
{
uint i;
US=US*5/4; // 5/4是在8MHz晶振下,通过软件仿真反复实验得到的数值
for( i=0;i<US;i++);
}
/*******************************************
函数名称: Delayms
功 能: 延时指定毫秒(8M晶振)
参 数: MS--延时的毫秒数
返回值 : 无
********************************************/
void Delayms(uint MS)
{
uint i,j;
for(i=0;i<MS;i++)
for(j=0;j<1141;j++); // 1141是在8MHz晶振下,通过软件仿真反复实验得到的数值
}
/*******************************************
函数名称: D12_init
功 能: 初始化D12接口(包括数据接口和控制接口)
参 数: 无
返回值 : 无
********************************************/
void D12_init(void)
{
USBDAT_DDR|=0xFF; //数据端口设置为输出
USBCTL_DDR|=BIT(WR_N)|BIT(RD_N)|BIT(C_D)|BIT(D12_CS);//控制引脚设置为输出
USBINT_DDR&=~BIT(D12_INT); //中断引脚设置为输入 //中断引脚设置为输入
USBINT_IES|=BIT(D12_INT); //选择下降沿中断
USBINT_SEL&=~BIT(D12_INT); //选择IO端口
USBINT_IE|=BIT(D12_INT); //使能端口中断
USBCTL_PORT|=BIT(WR_N)|BIT(RD_N)|BIT(D12_CS); //控制引脚无效
EN_GINT(); //使能全局中断
USBCTL_PORT&=~BIT(D12_CS); //给出片选信号
}
/*******************************************
函数名称: OutB
功 能: 向D12写入一个字节数据或者命令
参 数: cmd--命令标识(为CMD是命令,为DAT是数据)
dat--要写入的字节数据
返回值 : 无
********************************************/
void OutB(uchar cmd,uchar dat)
{
if(cmd==CMD)
{
USBCTL_PORT|=BIT(C_D);
Delayus(5);
USBCTL_PORT&=~BIT(WR_N);
Delayus(5);
USBDAT_PORT=dat;
Delayus(5);
USBCTL_PORT|=BIT(WR_N);
}
else
{
USBCTL_PORT&=~BIT(C_D);
Delayus(1);
USBCTL_PORT&=~BIT(WR_N);
Delayus(1);
USBDAT_PORT=dat;
Delayus(1);
USBCTL_PORT|=BIT(WR_N);
}
}
/*******************************************
函数名称: InB
功 能: 从D12读出一个字节数据
参 数: 无
返回值 : dat--读出的字节数据
********************************************/
uchar InB(void)
{
uchar dat;
USBDAT_DDR=0x00;
USBDAT_PORT=0xFF;
USBCTL_PORT&=~BIT(C_D);
Delayus(1);
USBCTL_PORT&=~BIT(RD_N);
Delayus(1);
dat=USBDAT_PIN;
Delayus(1);
USBCTL_PORT|=BIT(RD_N);
USBDAT_DDR=0xFF;
return dat;
}
/*******************************************
函数名称: Set_addren
功 能: 设置地址/使能
参 数: addr--设置的地址
enable--使能标志(为1使能,为0禁止)
返回值 : 无
********************************************/
void Set_addren(uchar addr, uchar enable)
{
if(USB_FLAG.in_isr == 0)
UEN_GINT();
OutB(CMD, 0xD0); //输出设置地址/使能指令
Delayus(1);
if(enable)
{
addr|=0x80; //bit7置1,使能
}
Delayus(1);
OutB(DAT,addr); //输出设置值
if(USB_FLAG.in_isr == 0)
EN_GINT();
}
/*******************************************
函数名称: Set_EPen
功 能: 设置端点使能
参 数: enable--使能标志(为1使能,为0禁止)
返回值 : 无
********************************************/
void Set_EPen(uchar enable)
{
if(USB_FLAG.in_isr == 0)
UEN_GINT();
OutB(CMD,0xD8); //输出设置端点使能指令
Delayus(1);
if(enable)
OutB(DAT,1); //设置端点允许
else
OutB(DAT,0); //设置端点禁止
if(USB_FLAG.in_isr == 0)
EN_GINT();
}
/*******************************************
函数名称: Set_mode
功 能: 设置模式
参 数: config--配置字节信息
clkdiv--分频因子
返回值 : 无
********************************************/
void Set_mode(uchar config,uchar clkdiv)
{
if(USB_FLAG.in_isr == 0)
UEN_GINT();
OutB(CMD,0xF3); //输出设置模式指令
Delayus(1);
OutB(DAT,config); //输出配置字节信息
OutB(DAT,clkdiv); //输出时钟分频因数字节
if(USB_FLAG.in_isr == 0)
EN_GINT();
}
/*******************************************
函数名称: Set_DMA
功 能: 设置DMA工作方式设置
参 数: bMode--设置值
返回值 : 无
********************************************/
void Set_DMA(uchar bMode)
{
if(USB_FLAG.in_isr == 0)
UEN_GINT();
OutB(CMD, 0xFB); //设置DMA工作方命令
Delayus(1);
OutB(DAT, bMode); //输出设置值
if(USB_FLAG.in_isr == 0)
EN_GINT();
}
/*******************************************
函数名称: Read_IntR
功 能: 读取中断寄存器值
参 数: 无
返回值 : intreg--16位中断寄存器值
********************************************/
uint Read_IntR(void)
{
uchar regl;
uint intreg;
OutB(CMD,0xF4); //读取中断寄存器命令
Delayus(5);
regl=InB( ); //读取低8位字节
intreg=InB( ); //读取高8位字节
intreg<<=8;
intreg+=regl; //组合为16位
return intreg;
}
/*******************************************
函数名称: Sel_EP
功 能: 端点选择,将内部指针初始化到选择的缓冲区起始位置
参 数: endp--端点索引号,取值0 ~ 5
返回值 : byte--一个字节的返回数据
********************************************/
uchar Sel_EP(uchar endp)
{
uchar byte;
if(USB_FLAG.in_isr == 0)
UEN_GINT();
OutB(CMD,endp); //端点选择
Delayus(1);
byte=InB( ); //读出一个字节
if(USB_FLAG.in_isr == 0)
EN_GINT();
return byte;
}
/*******************************************
函数名称: Sel_EP
功 能: 读取端点状态
参 数: endp--端点索引号,取值0 ~ 5
返回值 : status--端点状态
********************************************/
uchar Read_EPsta(uchar endp)//-----------------
{
uchar status;
if(USB_FLAG.in_isr == 0)
UEN_GINT();
OutB(CMD,0x80+endp); //读取端点状态命令
status=InB( ); //读取端点状态
if(USB_FLAG.in_isr == 0)
EN_GINT();
return status;
}
/*******************************************
函数名称: Read_LttransSta
功 能: 读取最后处理状态寄存器
参 数: endp--端点索引号,取值0 ~ 5
返回值 : status--端点最后处理的状态
********************************************/
uchar Read_LttransSta(uchar endp)
{
uchar status;
OutB(CMD,0x40+endp); //输出读取最后处理状态寄存器命令
Delayus(5);
status=InB( );
return status; //读取状态
}
/*******************************************
函数名称: Set_EPsta
功 能: 设置端点状态
参 数: endp--端点索引号,取值0 ~ 5
stall--设置状态值
返回值 : 无
********************************************/
void Set_EPsta(uchar endp,uchar stall)
{
if(USB_FLAG.in_isr == 0)
UEN_GINT();
OutB(CMD,0x40+endp); //发送设置端点状态命令
Delayus(1);
OutB(CMD,stall); //设置端点状态
if(USB_FLAG.in_isr == 0)
EN_GINT();
}
/*******************************************
函数名称: Set_Sresume
功 能: 设置发送恢复
参 数: 无
返回值 : 无
********************************************/
void Set_Sresume(void)
{
OutB(CMD,0xF6); //设置发送恢复
}
/*******************************************
函数名称: Read_EP
功 能: 读取端点数据
参 数: endp--端点索引号,取值 0 ~ 5
len--要读取的数据长度
buf--接收数据指针
返回值 : num--实际读到的字节数
********************************************/
uchar Read_EP(uchar endp,uchar len,uchar * buf)
{
uchar i,num;
if(USB_FLAG.in_isr == 0)
UEN_GINT();
OutB(CMD,endp); //发送选择端点命令
Delayus(1);
if((InB( )&FULLEMPTY)==0) //如果缓冲区为空
{
if(USB_FLAG.in_isr == 0)
EN_GINT();
return 0; //则返回读到0字节
}
OutB(CMD,0xF0); //发送读缓冲区命令
Delayus(1);
num=InB( ); //读取保留字节
num=InB( ); //读取数据字节的数目/长度
if(num>len) //如果大于要求读的字节数目
{
num=len; //则只读取要求的字节长度
}
for(i=0; i<num; i++)
*(buf+i)=InB( ); //读取要求的字节数目/长度
OutB(CMD,0xF2); //清缓冲区,新的信息包才可以重新被接受
if(USB_FLAG.in_isr == 0)
EN_GINT();
return num; //返回读到的字节数
}
/*******************************************
函数名称: Write_EP
功 能: 将数据写入端点
参 数: endp--端点索引号,取值 0 ~ 5
len--要写入的数据长度
buf--发送数据指针
返回值 : num--实际写入的字节数
********************************************/
uchar Write_EP(uchar endp,uchar len,uchar * buf)
{
uchar i;
if(USB_FLAG.in_isr == 0)
UEN_GINT();
OutB(CMD,endp); //发送选择端点命令
Delayus(1);
i=InB( ); //可选地读取一个字节
OutB(CMD,0xF0); //发送写缓冲区命令
Delayus(1);
OutB(DAT,0); //写入一个保留字节
Delayus(1);
OutB(DAT,len); //写入即将写入的字节数目
Delayus(1);
for(i=0; i<len; i++)
{
OutB(DAT,*(buf+i)); //写入指定的字节
}
Delayus(1);
OutB(CMD,0xFA); //使缓冲区有效
if(USB_FLAG.in_isr == 0)
EN_GINT();
return len; //返回写入的字节数
}
/*******************************************
函数名称: Ack_EP
功 能: 应答Setup
参 数: endp--端点索引号,取值 0 ~ 5
返回值 : 无
********************************************/
void Ack_EP(uchar endp)
{
OutB(CMD,endp); //选择端点
Delayus(1);
OutB(CMD,0xF1); //应答Setup指令
Delayus(1);
if(endp==0)
{
OutB(CMD,0xF2); //清空该端点缓冲区
}
}
/*******************************************
函数名称: Clear_buf
功 能: 清指定端点的缓冲区(包括双缓冲区)
参 数: endp--端点索引号,取值 0 ~ 5
返回值 : 无
********************************************/
void Clear_buf(uchar endp)
{
OutB(CMD,endp); //选择端点
Delayus(1);
OutB(CMD,0xF2); //清空第1个缓冲区
if (endp>=4)
{
OutB(CMD,endp); //选择端点
Delayus(1);
OutB(CMD,0xF2); //清空第2个缓冲区
}
}
/*******************************************
函数名称: Stall_ep0
功 能: 使控制端点处于停止状态
参 数: 无
返回值 : 无
********************************************/
void Stall_ep0(void)
{
Set_EPsta(0,1);
Set_EPsta(1,1);
}
/*******************************************
函数名称: S_trans
功 能: 通过端点索引 1 发送数据(DATA 类型)
参 数: buf--发送数据指针
len--发送数据长度
返回值 : 无
********************************************/
void S_trans(uchar * buf, uchar len)
{
if(len<=EP0_PACKET_SIZE) //长度小于EP0最大信息包大小才允许发送
{
Write_EP(1,len,buf);
}
}
/*******************************************
函数名称: Code_trans
功 能: 通过端点索引 1 发送数据(CODE类型)
参 数: buf--发送数据指针
len--发送数据长度
返回值 : 无
********************************************/
void Code_trans(uchar *pRomData, uint len)
{
ControlData.wCount = 0; //传输字节数计数器清0
if(ControlData.wLength > len)
ControlData.wLength = len; //传输数据总字节数不得超过len
ControlData.pData = pRomData; //传输数据指针指向pRomData
if( ControlData.wLength >= EP0_PACKET_SIZE) //传输数据总字节数大于端点0最大信息包大小
{
Write_EP(1, EP0_PACKET_SIZE, ControlData.pData);//发送端点0最大信息包大小个字节
ControlData.wCount += EP0_PACKET_SIZE; //统计已发送字节数
UEN_GINT();
USB_FLAG.control_state = USB_TRANSMIT; //标志数据发送状态
EN_GINT();
}
else
{
Write_EP(1, ControlData.wLength, pRomData); //写入传输数据总字节数
ControlData.wCount += ControlData.wLength; //统计已发送字节数
UEN_GINT();
USB_FLAG.control_state = USB_IDLE; //标志空闲状态
EN_GINT();
}
}
/*******************************************
函数名称: USB_INT1
功 能: D12中断服务函数
参 数: 无
返回值 : 无
********************************************/
#pragma vector=PORT1_VECTOR
__interrupt void USB_INT1(void)
{
uint int_sta;
if((USBINT_IFG & BIT(D12_INT))==BIT(D12_INT))
{
USBINT_IFG&=~BIT(D12_INT); //清除中断标志
USB_FLAG.in_isr = 1;
int_sta=Read_IntR(); //读取PDIUSBD12中断寄存器值
if(int_sta!=0)
{
if(int_sta&INT_BUSRESET)
USB_FLAG.bus_reset=1; //USB总线复位标志
if(int_sta&INT_ENDP0IN)
Ep0_txdone(); //控制端点发送数据处理
if(int_sta&INT_ENDP0OUT)
Ep0_rxdone(); //控制端点接收数据处理
if(int_sta&INT_ENDP1IN)
Ep1_txdone(); //端点 1发送数据处理
if(int_sta&INT_ENDP1OUT)
Ep1_rxdone(); //端点 1接收数据处理
if(int_sta&INT_ENDP2IN)
Ep2_txdone(); //端点 2发送数据处理
if(int_sta&INT_ENDP2OUT)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -