STM32USB使用方法.docx
《STM32USB使用方法.docx》由会员分享,可在线阅读,更多相关《STM32USB使用方法.docx(40页珍藏版)》请在冰点文库上搜索。
![STM32USB使用方法.docx](https://file1.bingdoc.com/fileroot1/2023-5/7/6281363a-2f8e-49ea-b19a-e82ecb2f9109/6281363a-2f8e-49ea-b19a-e82ecb2f91091.gif)
STM32USB使用方法
STM32-USB使用方法
开发板买的是奋斗mini开发板,芯片是:
STM32F103VET6.如果需要源程序keil4-arm工程,上位机vb。
加qq339396264要程序。
USB开发涉及主机和设备,为了避免开发驱动程序,使用Windows自带的驱动程序。
所以设备枚举成HID类设备。
USB鼠标就是标准的USB-HID设备。
不过操作系统阻止了应用程序直接访问USB鼠标返回的报告。
所以本例使用自定义HID设备。
一来免去了开发驱动程序,二来自定义的HID设备应用程序和设备可以自由收发数据(仅指数据内容)。
本文主要介绍STM32的USB模块的简单使用,不会介绍USB协议。
主要是介绍一下STM32F103的USB模块使用。
USB模块从初始化首先是配置和使能时钟
下面是时钟的初始化:
voidSet_USBClock(void)
{
//RCC_USBCLKSource_PLLCLK_1Div5表示【USB时钟=PLL时钟除以1.5】【72/1.5=48MHz】
RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB,ENABLE);//【使能配置好了的USB时钟】
}
首先系统时钟要设置为72MHz,然后配置USB时钟为48MHz并使能。
然后是配置中断
voidUSB_Interrupts_Config(void)
{
#defineUSB_LP_CAN1_RX0_IRQn20
NVIC_InitTypeDefNVIC_InitStructure;
//【使能USB中断】
NVIC_InitStructure.NVIC_IRQChannel=USB_LP_CAN1_RX0_IRQn;//【USB低优先级中断】
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
然后初始化模块的一些寄存器
USART_send_str("USB断开\r\n");
USB_DISCONNECT//这是断开1.5k上拉电阻
delay(0x7AFFFF);//延时一会
USB_CONNECT//使能1.5K上拉电阻
USART_send_str("USB连接\r\n");
DADDR=0x0080;//USB模块使能位。
EF必须置1
CNTR=0x0001;//强制复位
CNTR=0x0000;//退出复位
ISTR=0x0000;//清除可能产生的假中断
CNTR=(I_CTR|I_RESET);//使能一些中断,为了简单这里只使能了【总线复位中断】和【数据正确传输中断】
ISTR=0x0000;//清除可能产生的假中断
自此USB模块初始化完毕。
以后的流程就在USB中断的驱动下执行。
USB中断函数:
voidUSB_LP_CAN1_RX0_IRQHandler(void)
{
u16wIstr;
//USB中断状态寄存器
wIstr=(u16)ISTR;
//【USB复位中断】
if(wIstr&I_RESET)
{
USB_RST_Process();
return;
}
//【正确传输中断】
if(wIstr&I_CTR)
{
USB_CTR_Process();
return;
}
}
在USB中断函数中就是判断中断源,并转向相应的中断服务函数。
USB总线复位后,USB相关的一些寄存器会复位。
在USB总线复位中要配置一下寄存器和数据收发的缓冲区。
程序如下
voidUSB_RST_Process(void)
{
//清除中断
ISTR=(u16)(~I_RESET);//清除ISTR寄存器中断RESET位。
写0清除,写1寄存器位内容不变。
//USART_send_str("【USB】【复】【位】【中】【断】\r\n");
usb_status=0;
//复位处理
DADDR=0x0080;//USB模块使能位。
EF必须置1
BTABLE=0;//复位后默认为0
EP0REG=(u16)(0x0220);//0000001000100000端点0初始化:
控制端点,NAK主机的IN令牌,端点号0
//设置TX/RX起始地址
USB_ADDR0_TX=32;//32-95端点0的发送缓冲区从32开始到95,共64字节
USB_ADDR0_RX=96;//96-159端点0的接收缓冲区从96开始到159,共64字节
//设置端点0接收缓冲区大小:
64Byte
USB_CNT0_RX=0x8400;//1000,0100,0000,0000
//【端点1】
EP1REG=(u16)(0x0621);//0000011000100001端点0初始化:
中断端点,NAK主机的IN令牌,端点号1
//设置TX/RX起始地址
USB_ADDR1_TX=160;//160-223端点1的发送缓冲区从160开始到223,共64字节
USB_ADDR1_RX=224;//224-287端点1的接收缓冲区从224开始到287,共64字节
//设置端点1接收缓冲区大小:
64Byte
USB_CNT1_RX=0x8400;//1000,0100,0000,0000
//设置RXValid.端点0可用于接收
{
u16t=EP0REG;//读出端点0寄存器值
t&=0x8F8F;//1000111110001111由于t位写0不影响原来的值,写1翻转,所以把t位都设置为0
t|=0x8080;//1000000010000000由于w0位写0清除,写1无影响,所以w0位都设置为1
t|=0x3000;//0011000000000000把SRAT_RX[1:
0]设置为1,通过写1翻转来实现。
EP0REG=t;
}
}
下面是正确传输中断
//USB分组正确传输处理
voidUSB_CTR_Process(void)
{
/******************************************【端点0】******************************************/
if((ISTR&0x0F)==0)//端点0
{
if((ISTR&0x10)==0)//in分组
{
//USART_send_str("****************端点0的IN分组发送完成****************\r\n");
if(usb_status==1)
{
usb_status=2;
DADDR=0x80|(usb_addr&0xFF);//设置地址一定要找控制传输的状态完成后写入地址寄存器
//USART_send_str("\r\n【写入地址完成】\r\n");
}
//发送剩余数据
USB_ep0_send();
//清除CTR_TX
{
u16t=EP0REG;
t&=0x8F8F;//1000111110001111把t位都设置为0
t|=0x8080;//1000000010000000把w0位都设置为1
t&=0xFF7F;//1111111101111111把CTR_TX设置为0,清除CTR_RX位
EP0REG=t;
}
}
if(ISTR&0x10)//【OUT】分组or【SETUP】分组
{
u16ep0r=EP0REG;
//清除CTR_RX
{
u16t=EP0REG;
t&=0x8F8F;//1000111110001111把t位都设置为0
t|=0x8080;//1000000010000000把w0位都设置为1
t&=0x7FFF;//0111111111111111把CTR_RX设置为0,清除CTR_RX位
EP0REG=t;
}
if(ep0r&0x0800)//SETUP令牌包
{
//USART_send_str("端点0收到【SETUP】分组\r\n");
//默认控制端点处理——枚举处理
ep0_setup_Process();
memset(USB_rcv_buffer,0x00,sizeof(USB_rcv_buffer));
USB_enable_ep0_rx();
}
else
{
//USART_send_str("控制读传输:
状态阶段\r\n");
USB_read_EP0_buf(USB_rcv_buffer,(u32*)(PMAAddr+96*2));
USB_enable_ep0_rx();
}
}
//else//【IN分组传输成功】
}
/******************************************【端点1】******************************************/
elseif((ISTR&0x0F)==1)
{
USART_send_str("端点1数据完成传输\r\n");
if(ISTR&0x10)//【OUT分组】
{
//清除CTR_RX
{
u16t=EP1REG;
t&=0x8F8F;//1000111110001111把t位都设置为0
t|=0x8080;//1000000010000000把w0位都设置为1
t&=0x7FFF;//0111111111111111把CTR_RX设置为0,清除CTR_RX位
EP1REG=t;
}
USB_read_EP1_buf(USB_rcv_buffer,(u32*)(PMAAddr+224*2));//【读取】端点1数据
//【处理】端点1数据
USB_enable_ep1_rx();//【继续接受】端点1数据
}
else//【IN分组】
{
//清除CTR_TX
{
u16t=EP1REG;
t&=0x8F8F;//1000111110001111把t位都设置为0
t|=0x8080;//1000000010000000把w0位都设置为1
t&=0xFF7F;//1111111101111111把CTR_TX设置为0,清除CTR_RX位
EP1REG=t;
}
//标记发送完成
}
}
/******************************************【端点ERR】******************************************/
else
{
USART_send_str("出错!
端点号是没有开启对端点。
\r\n");
}
}
其他代码:
//设置RXValid.使端点继续接收
voidUSB_enable_ep0_rx(void)
{
u16t=EP0REG;
//USART_send_str("EP0REG=");USART_send_HEX(t>>8);USART_send_HEX(t&0xff);USART_send_str("\r\n");
t&=0x8F8F;//1000111110001111把t位都设置为0
t|=0x8080;//1000000010000000把w0位都设置为1
switch(EP0REG&0x3000)
{
case0x0000:
t|=0x3000;break;
case0x1000:
t|=0x2000;break;
case0x2000:
t|=0x1000;break;
case0x3000:
t|=0x0000;break;
}
EP0REG=t;
//t=EP0REG;
//USART_send_str("EP0REG=");USART_send_HEX(t>>8);USART_send_HEX(t&0xff);USART_send_str("\r\n");
}
//设置RXValid.使端点继续接收
voidUSB_enable_ep1_rx(void)
{
u16t=EP1REG;
t&=0x8F8F;//1000111110001111把t位都设置为0
t|=0x8080;//1000000010000000把w0位都设置为1
switch(EP1REG&0x3000)
{
case0x0000:
t|=0x3000;break;
case0x1000:
t|=0x2000;break;
case0x2000:
t|=0x1000;break;
case0x3000:
t|=0x0000;break;
}
EP1REG=t;
}
//读取端点0收到的数据
u8USB_read_EP0_buf(u8*buf,u32*USB_buf)
{
u16rcv_num;
u8read_cnt;
u8i;
u16temp;
u8j=0;
//接收到的数据
rcv_num=USB_CNT0_RX&0x03FF;
//{
//unsignedchars[32]={0};
//sprintf((char*)s,"端点0读取【%d】字节数据:
",rcv_num);
//USART_send_str(s);
//}
//USART_send_str("\r\n--------------------------------------------------------------------------------\r\n");
//读取次数
read_cnt=(rcv_num+1)>>1;
for(i=0;i{
temp=*USB_buf++;
buf[j++]=temp&0xFF;
buf[j++]=temp>>8;
}
//for(i=0;i//{
//USART_send_HEX(buf[i]);
//if((i+1)%16==0)
//{
//USART_send_str("\r\n");
//}
//}
//USART_send_str("\r\n--------------------------------------------------------------------------------\r\n\r\n");
return(j);
}
//读取端点1收到的数据
u8USB_read_EP1_buf(u8*buf,u32*USB_buf)
{
u16rcv_num;
u8read_cnt;
u8i;
u16temp;
u8j=0;
//接收到的数据
rcv_num=USB_CNT1_RX&0x03FF;
{
unsignedchars[32]={0};
sprintf((char*)s,"【端点1】读取【%d】字节数据:
",rcv_num);
USART_send_str(s);
}
USART_send_str("\r\n--------------------------------------------------------------------------------\r\n");
//读取次数
read_cnt=(rcv_num+1)>>1;
for(i=0;i{
temp=*USB_buf++;
buf[j++]=temp&0xFF;
buf[j++]=temp>>8;
}
for(i=0;i{
USART_send_HEX(buf[i]);
if((i+1)%16==0)
{
USART_send_str("\r\n");
}
}
USART_send_str("\r\n--------------------------------------------------------------------------------\r\n\r\n");
return(j);
}
//通过端点0发送数据
voidUSB_write_EP0_buf(u8*buf,u32*USB_buf,u8len)
{
u8send_cnt;
u8i;
u8j=0;
u16h,l;
//{
//unsignedchars[32]={0};
//sprintf((char*)s,"端点0发送【%d】字节数据:
",len);
//USART_send_str(s);
//}
//
//USART_send_str("\r\n++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\r\n");
//for(i=0;i//{
//USART_send_HEX(buf[i]);
//if((i+1)%16==0)
//{
//USART_send_str("\r\n");
//}
//}
//USART_send_str("\r\n++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\r\n\r\n");
//发送次数
send_cnt=(len+1)>>1;
for(i=0;i{
l=buf[j++];
h=buf[j++]<<8;
*USB_buf=(h|l);
USB_buf++;
}
//要发送数据的长度
USB_CNT0_TX=len;
//使能发送:
设置VALID
{
u16t=EP0REG;
t&=0x8F8F;//1000111110001111把t位都设置为0
t|=0x8080;//1000000010000000把w0位都设置为1
switch(EP0REG&0x0030)
{
case0x0000:
t|=0x0030;break;
case0x0010:
t|=0x0020;break;
case0x0020:
t|=0x0010;break;
case0x0030:
t|=0x0000;break;
}
EP0REG=t;
}
}
//通过端点1发送数据
voidUSB_write_EP1_buf(u8*buf,u32*USB_buf,u8len)
{
u8send_cnt;
u8i;
u8j=0;
u16h,l;
{
unsignedchars[32]={0};
sprintf((char*)s,"端点1发送【%d】字节数据:
",len);
USART_send_str(s);
}
USART_send_str("\r\n++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\r\n");
for(i=0;i{
USART_send_HEX(buf[i]);
if((i+1)%16==0)
{
USART_send_str("\r\n");
}
}
USART_send_str("\r\n++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\r\n\r\n");
//发送次数
send_cnt=(len+1)>>1;
for(i=0;i{
l=buf[j++];
h=buf[j++]<<8;
*USB_buf=(h|l);
USB_buf++;
}
//要发送数据的长度
USB_CNT1_TX=len;
//使能发送:
设置VALID
{
u16t=EP1REG;
t&=0x8F8F;//1000111110001111把t位都设置为0
t|=0x8080;//1000000010000000把w0位都设置为1
switch(EP1REG&0x0030)
{
case0x0000:
t|=0x0030;break;
case0x0010:
t|=0x0020;break;
case0x0020:
t|=0x0010;break;
case0x0030:
t|=0x0