一、前言

目的:使用 STM32F103 从 0 开始实现 USB 调试代码。

硬件:正点原子战舰开发板。

软件

  • USB:用于实现各种功能

  • 串口:打印日志信息

  • LED:显示运行状态

  • 其他:根据需要进行添加

参考:STM 官方 USB 库。

二、工程目录说明

三、常用驱动说明

1、时钟配置

2、数据结构设计

1、循环队列

1、数据类型

#define QUEUE_MAXSIZE 128typedef struct{unsigned char data[QUEUE_MAXSIZE];unsigned int front,rear;            // fornt:对头、rear:队尾
}queue_t;

2、相关操作

#include "queue.h"int init_queue(queue_t *q)
{q->front = q->rear = 0;return 0;
}int en_queue(queue_t *q,unsigned char c)
{if((q->rear+1)%QUEUE_MAXSIZE == q->front) return 1;     // 队列满q->data[q->rear] = c;                                   // 将 x 插入队尾q->rear = (q->rear+1)%QUEUE_MAXSIZE;                    // 队尾指针后移return 0;
}int de_queue(queue_t *q,unsigned char *c)
{if(q->rear == q->front) return 1;       // 队列为空*c = q->data[q->front];                 // 提取对头元素q->front = (q->front+1)%QUEUE_MAXSIZE;  // 队头后移return 0;
}

3、UART

1、缓存设计

1、发送数据

发送数据不进行设计,根据需求进行。

2、接收数据

接收数据采用循环队列完成。

typedef struct{queue_t data;
}uart_t;

2、初始化

int uart_init(unsigned int rate)
{GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);//USART1_TX   GPIOA.9GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_Init(GPIOA, &GPIO_InitStructure);//USART1_RX      GPIOA.10GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOA, &GPIO_InitStructure);// NVICNVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);// USART 配置USART_InitStructure.USART_BaudRate = rate;USART_InitStructure.USART_WordLength = USART_WordLength_8b;USART_InitStructure.USART_StopBits = USART_StopBits_1;USART_InitStructure.USART_Parity = USART_Parity_No;USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;USART_Init(USART1, &USART_InitStructure);USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);USART_Cmd(USART1, ENABLE);// 初始化init_queue(&uart_data.data);return 0;
}

3、发送数据

uart 作为日志数据发送,需要兼容不同格式类型数据,因此发送数据通过重定向 printf 完成。

#if 1
#pragma import(__use_no_semihosting)
struct __FILE
{ int handle; }; FILE __stdout;
void _sys_exit(int x)
{ x = x;
}
int fputc(int ch, FILE *f)
{      while((USART1->SR&0X40)==0);USART1->DR = (u8) ch;      return ch;
}
#endif

4、接收数据

uart 接收数据为了能够及时响应,因此使用中断来完成。

int uart_recive_data(unsigned char c)
{en_queue(&uart_data.data,c); // 数据入队return 0;
}void USART1_IRQHandler(void)
{if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET){USART_ClearITPendingBit(USART1, USART_IT_RXNE);uart_recive_data(USART_ReceiveData(USART1));}
}

3、LED

int led_init(void)
{GPIO_InitTypeDef  GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_SetBits(GPIOB,GPIO_Pin_5);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;GPIO_Init(GPIOE, &GPIO_InitStructure);GPIO_SetBits(GPIOE,GPIO_Pin_5);return 0;
}void led0_on(void)
{GPIO_ResetBits(GPIOB,GPIO_Pin_5);
}void led0_off(void)
{GPIO_SetBits(GPIOB,GPIO_Pin_5);
}void led1_on(void)
{GPIO_ResetBits(GPIOE,GPIO_Pin_5);
}void led1_off(void)
{GPIO_SetBits(GPIOE,GPIO_Pin_5);
}

4、delay

延时使用 Systick 定时器完成,设计思想如下:

1、将 Systick 配置成每 1ms 中断一次。

2、根据延时时间设置中断次数。

代码如下:

static __IO unsigned int timing_delay;int delay_init(void)
{if(SysTick_Config(SystemCoreClock / 1000)){printf("delay_init failed\r\n");}return 0;
}void delay_ms(__IO unsigned int nTime)
{ timing_delay = nTime;while(timing_delay != 0);
}void timing_delay_decrement(void)
{if (timing_delay != 0x00){ timing_delay--;}
}void SysTick_Handler(void)
{timing_delay_decrement();
}

四、usb 驱动

说明:参考 STM 提供 USB 库。

1、GPIO 配置

static int usb_gpio_init(void)
{GPIO_InitTypeDef  GPIO_InitStructure;// 配置时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);// 配置 USB DM/DP 引脚GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_Init(GPIOA, &GPIO_InitStructure);return 0;
}

2、时钟配置

static int usb_clock_init(void)
{// 设置 USBCLK 时钟RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5);// 设置 USB 时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE);return 0;
}

3、中断配置

static int usb_interrupts_config(void)
{NVIC_InitTypeDef NVIC_InitStructure;// USB低优先级中断(通道20):可由所有USB事件触发(正确传输,USB复位等)NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);// USB高优先级中断(通道19):仅能由同步和双缓冲批量传输的正确传输事件触发,目的是保证最大的传输速率NVIC_InitStructure.NVIC_IRQChannel = USB_HP_CAN1_TX_IRQn;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;// USB唤醒中断(通道42):由USB挂起模式的唤醒事件触发NVIC_InitStructure.NVIC_IRQChannel = USBWakeUp_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_Init(&NVIC_InitStructure);return 0;
}

特别说明:中断优先级等级根据需要进行调整。
中断处理函数如下:

int usb_istr(void)
{unsigned int r_istr = 0;r_istr = _GetISTR();if(r_istr & ISTR_SOF){_SetISTR((uint16_t)CLR_SOF);printf("ISTR_SOF IRQHandler\r\n");}if(r_istr & ISTR_CTR){printf("ISTR_CTR IRQHandler\r\n");}if(r_istr & ISTR_RESET){_SetISTR((uint16_t)CLR_RESET);printf("ISTR_RESET IRQHandler\r\n");}if(r_istr & ISTR_DOVR){_SetISTR((uint16_t)CLR_DOVR);printf("ISTR_DOVR IRQHandler\r\n");}if(r_istr & ISTR_ERR){_SetISTR((uint16_t)CLR_ERR);printf("ISTR_ERR IRQHandler\r\n");}if(r_istr & ISTR_WKUP){_SetISTR((uint16_t)CLR_WKUP);printf("ISTR_WKUP IRQHandler\r\n");}if(r_istr & ISTR_SUSP){_SetISTR((uint16_t)CLR_SUSP);printf("ISTR_SUSP IRQHandler\r\n");}if(r_istr & ISTR_ESOF){_SetISTR((uint16_t)CLR_ESOF);printf("ISTR_ESOF IRQHandler\r\n");}return 0;
}void USB_LP_CAN1_RX0_IRQHandler(void)
{usb_istr();printf("USB_LP_CAN1_RX0_IRQHandler\r\n");
}void USB_HP_CAN1_TX_IRQHandler(void)
{printf("USB_HP_CAN1_TX_IRQHandler\r\n");
}void USBWakeUp_IRQHandler(void)
{printf("USBWakeUp_IRQHandler\r\n");
}

4、usb外设配置

int usb_register_init(void)
{// 1、强制复位_SetCNTR(CNTR_FRES);// 2、清除 USB_CNTR 寄存器所有信号_SetCNTR(0);// 3、等待 USB 复位请求完成while((_GetISTR()&ISTR_RESET) == 1);// 4、清除无效挂起中断_SetISTR(0);// 5、开启USB复位中断、挂起中断、唤醒中断_SetCNTR(CNTR_RESETM | CNTR_SUSPM | CNTR_WKUPM);// 6、清除无效挂起中断_SetISTR(0);// 7、开启正确传输中断、唤醒中断、挂起中断、出错中断、帧首中断、期望帧首中断、USB复位中断_SetCNTR(CNTR_CTRM|CNTR_WKUPM|CNTR_SUSPM|CNTR_ERRM|CNTR_SOFM|CNTR_ESOFM|CNTR_RESETM);return 0;
}

五、工程模板测试

1、串口打印日志如下

[16:49:54.963] uart init successful!
[16:49:54.963] ISTR_ESOF IRQHandler
[16:49:54.963] USB_LP_CAN1_RX0_IRQHandler
[16:49:54.963] ISTR_SUSP IRQHandler
[16:49:54.963] ISTR_ESOF IRQHandler
……
[16:49:55.052] USB_LP_CAN1_RX0_IRQHandler
[16:49:55.055] ISTR_RESET IRQHandler
[16:49:55.101] USB_LP_CAN1_RX0_IRQHandler
[16:49:55.113] ISTR_SOF IRQHandler
[16:49:55.113] USB_LP_CAN1_RX0_IRQHandler
[16:49:55.113] ISTR_SOF IRQHandler
[16:49:55.113] USB_LP_CAN1_RX0_IRQHandler
[16:49:55.113] ISTR_SOF IRQHandler
[16:49:55.122] USB_LP_CAN1_RX0_IRQHandler
……
[16:49:57.084] USB_LP_CAN1_RX0_IRQHandler
[16:49:57.084] ISTR_SOF IRQHandler
[16:49:57.084] USB_LP_CAN1_RX0_IRQHandler
[16:49:57.084] ISTR_SOF IRQHandler
[16:49:57.092] USB_LP_CAN1_RX0_IRQHandler
[16:49:57.092] ISTR_SOF IRQHandler
[16:49:57.092] USB_LP_CAN1_RX0_IRQHandler
[16:49:57.092] ISTR_SOF IRQHandler
[16:49:57.102] ISTR_ESOF IRQHandler
[16:49:57.102] USB_LP_CAN1_RX0_IRQHandler
[16:49:57.102] ISTR_SUSP IRQHandler
[16:49:57.102] ISTR_ESOF IRQHandler
[16:49:57.111] USB_LP_CAN1_RX0_IRQHandler
[16:49:57.111] ISTR_SUSP IRQHandler
[16:49:57.111] ISTR_ESOF IRQHandler
[16:49:57.111] USB_LP_CAN1_RX0_IRQHandler
[16:49:57.123] ISTR_SUSP IRQHandler
[16:49:57.123] ISTR_ESOF IRQHandler
[16:49:57.123] USB_LP_CAN1_RX0_IRQHandler
[16:49:57.123] ISTR_SUSP IRQHandler
[16:49:57.123] ISTR_ESOF IRQHandler
[16:49:57.132] USB_LP_CAN1_RX0_IRQHandler
……
  • SOF:USB 模块检测到总线上的 SOF 分组时由硬件置位,标志一个新的 USB 帧的开始。中断服务程序可以通过检测 SOF 事件来完成与主机的 1ms 同步,并正确读出寄存器在收到 SOF 分组时 的更新内容(此功能在同步传输时非常有意义)。

  • ESOF:USB 模块未收到期望的 SOF 分组时由硬件置位。主机应该每毫秒都发送 SOF 分组,但如果 USB 模块没有收到,挂起定时器将触发此中断。如果连续发生 3 次 ESOF 中断也就是连续 3 次未收到 SOF 分组,将产生 SUSP 中断。

  • SUSP:USB 线上超过 3ms 没有信号传输时由硬件置位,用以指示一个来自 USB 总线的挂起请求。USB 复位后硬件立即使能对挂起信号的检测,但在挂起模式下(FSUSP=1)硬件不会再检 测挂起信号直到唤醒过程结束。

2、PC 枚举 usb 模块

USB 协议整理 九:USB 协议调试工程说明相关推荐

  1. 基于AOA协议的android USB通信

    摘 要:AOA协议是Google公司推出的用于实现Android设备与外围设备之间USB通信的协议.该协议拓展了Android设备USB接口的功能,为基于Android系统的智能设备应用于数据采集和设 ...

  2. Zynq7000 USB2.0协议解析及USB控制器详解

    USB 2.0规范及控制器 文章目录 USB 2.0规范及控制器 USB2.0 Univerasl Serial Bus USB Host USB总线 接口标准 总线信号 USB拓扑结构 数据流模型 ...

  3. linux下uvc协议访问usb摄像头,Ubuntu调用USB摄像头

    FreeBSD Webcam:传送门 1 查看摄像头USB驱动 CMD ls /dev/v* Result /dev/vcs /dev/vcs4 /dev/vcsa1 /dev/vcsa5 /dev/ ...

  4. 5、USB协议学习:USB的枚举过程

    文章目录 枚举顺序 枚举过程 标准请求 bmRequestType bReqest 请求类型 GetDescriptor 设备描述符 设备描述符定义 获取设备描述符 返回设备描述符 配置描述符 配置描 ...

  5. HSIC一种基于USB的高速芯片通讯协议

    从下面的资料可看出: ①USB+PHY 之后通过USB cable 连接. ②USB2.0可以直接通过HSIC直连,属于芯片间的连接方案.速度可达480M,是IIC的理想替代. 芯片间USB(IC-U ...

  6. USB协议与Windows USB设备驱动程序笔记

    USB概述 USB主控制器负责数据处理,USB根集线器(ROOT HUB)提供一个连接USB主控制器与USB设备之间的接口和通路.USB集线器(USB HUB)可以对原有的USB端口在数量上进行扩展. ...

  7. 三菱FX系列PLC串口通讯协议整理

    三菱FX系列PLC串口通讯协议整理 记录原因 项目要求 工具与资料 通讯格式 读寄存器 写寄存器 PLC回复数据 最后附几张上位机截图 记录原因 因项目需求,要写上位机与PLC进行通讯,查了诸多资料与 ...

  8. (转载)9个主流的开源许可协议[整理]

    http://univasity.iteye.com/blog/1292658 关于开源许可 现今存在的开源协议很多,而经过Open Source Initiative 组织通过批准的开源协议目前有6 ...

  9. WIFI基本知识及802.11协议整理

    WIFI基本知识及802.11协议整理 2015-11-11 fredzeng linux 主要内容: 一.基本概述 二.实践基础 三.一些原理 四.补充 五.其它 一.基本概述 ========== ...

最新文章

  1. pytorch笔记:09)Attention机制
  2. nginx日志中文变成类似\xE9\xA6\x96\xE9\xA1\xB5-\xE6\x8E\xA8\xE8\x8D\x90的东西,治本方案
  3. SLAM:SLAM相机简介、SLAM五步流程简介(VO+BEO+LCD+M)之详细攻略
  4. java word 在线编辑图片_java开发实现word在线编辑及流转
  5. 人工智能:一种现代方法汇总
  6. SpringMVC+MyBatis 返回时间格式转换的解决方案
  7. 施密特正交化的几何解释
  8. c语言从入门到精通_C语言基本概念(上)【C语言入门到精通】
  9. 李宏毅机器学习笔记【未完】
  10. 『词向量』用Word2Vec训练中文词向量(一)—— 采用搜狗新闻数据集
  11. 全球及中国汽车节能减排行业投资可行性及十四五发展趋势研究报告2021-2027年
  12. soj.1004 I Conduit!
  13. 安卓游戏《罗马帝国》游戏心得
  14. 完美解决:“已损坏,无法打开。 您应该将它移到废纸篓。”
  15. 【JPA/ddl-auto】关于JPA下hibernate通过设置ddl-auto完成数据库自动创建表格
  16. 计算机专业实用设计专利例子,计算机类实用新型专利有几个发明人
  17. L1-035 情人节
  18. 获取图片上任意一点的颜色值
  19. android高德地图上加自定义菜单,自定义UI控件-UI界面定制-开发指南-Android 导航SDK | 高德地图API...
  20. AutoCAD 2007创建块

热门文章

  1. 二叉树 | 二叉树的深度
  2. SIMXXX 在高德地图定位到我的位置
  3. 【cs224n学习作业】Assignment 1 - Exploring Word Vectors【附代码】
  4. JSONObject遍历并替换部分json值
  5. 修改了部分原理图后如何更新到pcb
  6. 美国大学计算机课程教材,美国大学计算机基础教学课程结构一瞥.pdf
  7. MATLAB随机森林回归模型
  8. C++ 数据结构(三)列表(3)有序列表
  9. RBF神经网络简单介绍与MATLAB实现
  10. 个人总结/IPC方法的优缺点和适用场景