这里会显示出您选择的修订版和当前版本之间的差别。
后一修订版 | 前一修订版 | ||
icore4tx_39 [2020/11/13 09:37] zgf 创建 |
icore4tx_39 [2022/04/01 11:32] (当前版本) sean |
||
---|---|---|---|
行 3: | 行 3: | ||
|技术支持电话|**0379-69926675-801**||| | |技术支持电话|**0379-69926675-801**||| | ||
|技术支持邮件|Gingko@vip.163.com||| | |技术支持邮件|Gingko@vip.163.com||| | ||
- | |技术论坛|http://www.eeschool.org||| | ||
^ 版本 ^ 日期 ^ 作者 ^ 修改内容 ^ | ^ 版本 ^ 日期 ^ 作者 ^ 修改内容 ^ | ||
- | | V1.0 | 2020-07-30 | gingko | 初次建立 | | + | | V1.0 | 2020-9-26 | zgf | 初次建立 | |
\\ | \\ | ||
\\ | \\ | ||
\\ | \\ | ||
\\ | \\ | ||
- | \\ | + | ===== STM32CubeMX教程三十九——LWIP_TCP_CLIENT输出实验 ===== |
- | ===== STM32CubeMX教程三十八——USBD_HID实验(FS) ===== | + | |
- | 1.在主界面选择File-->New Project 或者直接点击ACCEE TO MCU SELECTOR | + | 1. 在主界面选择File-->New Project或者直接点击ACCEE TO MCU SELECTOR |
- | {{ :icore4tx:icore4tx_cube_38_1.png?direct |}} | + | {{ :icore4t:icore4t_cube_39_1.jpg?direct |}} |
- | 2.出现芯片型号选择,搜索自己芯片的型号,双击型号,或者点击Start Project进入配置 | + | 2. 出现芯片型号选择,搜索自己芯片的型号,双击型号,或者点击Start Project进入配置在搜索栏的下面,提供的各种查找方式,可以选择芯片内核,型号,等等,可以帮助你查找芯片。本实验选取的芯片型号为:STM32H750IBKx。 |
- | 在搜索栏的下面,提供的各 种查找方式,可以选择芯片内核,型号,等等,可以帮助你查找芯片。本实验选取的芯片型号为:STM32H750IBKx。 | + | {{ :icore4t:icore4t_cube_39_2.jpg?direct |}} |
- | {{ :icore4tx:icore4tx_cube_38_2.png?direct |}} | + | 3. 配置RCC,使用外部时钟源 |
- | 3.配置RCC,使用外部时钟源 | + | {{ :icore4t:icore4t_cube_39_3.jpg?direct |}} |
- | {{ :icore4tx:icore4tx_cube_38_3.png?direct |}} | + | 4. 配置调试引脚 |
- | 4.时基源选择SysTick | + | {{ :icore4t:icore4t_cube_39_4.jpg?direct |}} |
- | {{ :icore4tx:icore4tx_cube_38_4.png?direct |}} | + | 5. 将PA10,PB7,PB8设置为GPIO_Output |
- | 5.将PA10,PB7,PB8设置为GPIO_Output | + | {{ :icore4t:icore4t_cube_39_5.jpg?direct |}} |
- | {{ :icore4tx:icore4tx_cube_38_5.png?direct |}} | + | 6. 引脚模式配置 |
- | 6.将ARM_KEY对应的引脚PH7设置为GPIO_Intput | + | {{ :icore4t:icore4t_cube_39_6.jpg?direct |}} |
- | {{ :icore4tx:icore4tx_cube_38_6.png?direct |}} | + | {{ :icore4t:icore4t_cube_39_7.jpg?direct |}} |
- | 7.引脚模式配置 | + | 7. 配置以太网 |
- | {{ :icore4tx:icore4tx_cube_38_7.png?direct |}} | + | {{ :icore4t:icore4t_cube_39_8.jpg?direct |}} |
- | {{ :icore4tx:icore4tx_cube_38_8.png?direct |}} | + | {{ :icore4t:icore4t_cube_39_9.jpg?direct |}} |
- | {{ :icore4tx:icore4tx_cube_38_9.png?direct |}} | + | {{ :icore4t:icore4t_cube_39_10.jpg?direct |}} |
- | 8.配置USB_OTG_FS | + | {{ :icore4t:icore4t_cube_39_11.jpg?direct |}} |
- | {{ :icore4tx:icore4tx_cube_38_10.png?direct |}} | + | 8. 时钟设置,选择外部高速时钟源,配置为最大主频 |
- | 9.配置USB_DEVICE | + | {{ :icore4t:icore4t_cube_39_12.jpg?direct |}} |
- | {{ :icore4tx:icore4tx_cube_38_11.png?direct |}} | + | 9. 工程文件的设置, 这里就是工程的各种配置 我们只用到有限几个,其他的默认即可 IDE我们使用的是 MDK5.27 |
- | 10.时钟源设置,选择外部高速时钟源,配置为最大主频 | + | {{ :icore4t:icore4t_cube_39_13.jpg?direct |}} |
- | {{ :icore4tx:icore4tx_cube_38_12.png?direct |}} | + | 10. 点击Code Generator,进行进一步配置 |
- | {{ :icore4tx:icore4tx_cube_38_13.png?direct |}} | + | {{ :icore4t:icore4t_cube_39_14.jpg?direct |}} |
- | 11.工程文件的设置, 这里就是工程的各种配置 我们只用到有限几个,其他的默认即可 IDE我们使用的是 MDK V5.27 | + | |
- | {{ :icore4tx:icore4tx_cube_38_14.png?direct |}} | + | |
- | 12.点击Code Generator,进行进一步配置 | + | |
- | {{ :icore4tx:icore4tx_cube_38_15.png?direct |}} | + | |
* **Copy all used libraries into the project folder** | * **Copy all used libraries into the project folder** | ||
* 将HAL库的所有.C和.H都复制到所建工程中 | * 将HAL库的所有.C和.H都复制到所建工程中 | ||
行 54: | 行 49: | ||
* 缺点:复制到其他电脑上或者软件包位置改变,就需要修改相对应的路径 | * 缺点:复制到其他电脑上或者软件包位置改变,就需要修改相对应的路径 | ||
* 自行选择方式即可 | * 自行选择方式即可 | ||
- | 13.然后点击GENERATE CODE 创建工程 | + | 11. 然后点击GENERATE CODE 创建工程 |
- | {{ :icore4tx:icore4tx_cube_38_16.png?direct |}} | + | {{ :icore4t:icore4t_cube_39_15.jpg?direct |}} |
创建成功,打开工程。 | 创建成功,打开工程。 | ||
\\ | \\ | ||
\\ | \\ | ||
- | \\ | + | |
- | ===== 实验三十八:USBD_HID实验(FS)——双向数据传输 ===== | + | |
+ | ===== 实验三十九:LWIP_TCP_CLIENT实验——以太网数据传输 ===== | ||
==== 一、 实验目的与意义 ==== | ==== 一、 实验目的与意义 ==== | ||
- | - 了解STM32 USB SLAVE结构。 | + | - 了解LwIP协议栈和LAN8720物理层。 |
- | - 了解STM32 USB SLAVE特征。 | + | - 掌握TCP CLIENT的使用方法。 |
- | - 掌握USB SLAVE HID的使用方法。 | + | - 掌握STM32 HAL库中ETH的配置方法。 |
- | - 掌握STM32 HAL库中USB SLAVE属性的配置方法。 | + | - 掌握KEILMDK 集成开发环境使用方法。 |
- | - 掌握KEIL MDK 集成开发环境使用方法。 | + | |
==== 二、 实验设备及平台 ==== | ==== 二、 实验设备及平台 ==== | ||
- | - iCore4TX 双核心板[[https://item.taobao.com/item.htm?spm=a1z10.1-c-s.w4004-22598974120.3.29da532fLkazHH&id=614919247574|点击购买]]。 | + | - iCore3 双核心板; |
- | - iCore4TX 扩展底板。 | + | - JLINK(或相同功能)仿真器; |
- | - JLINK(或相同功能)仿真器。[[https://item.taobao.com/item.htm?id=554869837940|点击购买]] | + | - Micro USB线缆、网线; |
- | - Micro USB线缆。 | + | - Keil MDK 开发平台; |
- | - Keil MDK 开发平台。 | + | - STM32CubeMX开发平台; |
- | - STM32CubeMX开发平台。 | + | |
- 装有WIN XP(及更高版本)系统的计算机。 | - 装有WIN XP(及更高版本)系统的计算机。 | ||
==== 三、 实验原理 ==== | ==== 三、 实验原理 ==== | ||
- | === 1.USB HID简介 === | + | === 1、LwIP简介 === |
- | * USB HID是Human Interface Device的缩写,由其名称可以了解HID设备是直接与人交互的设备,例如键盘、鼠标与游戏杆等。不过HID设备并不一定要有人机接口,只要符合HID类别规范的设备都是HID设备。 | + | |
- | * 交换的数据存储在称为报表(report)的结构内,设备的固件必须支持HID报表的格式。主机在控制与中断传输中传送与要求报表,来传送与接收数据。报表的格式非常有弹性,可以处理任何类别的数据。 | + | |
- | * 设备除了HID接口之外,它可能同时还包含有其他的USB接口。例如影像显示设备可能使用HID接口来做亮度,对比,与更新率的软件控制,而使用传统的影 像接口来传送要显示的数据。USB扩音器可以使用实时传输来播放语音,同时使用HID接口来控制音量,震荡,与低音等。HID接口通常比传统的控制接口来得便宜。 | + | |
- | * Wndows操作系统最先支持的HID设备。在windows98以及后来的版本中内置有HID设备的驱动程序,应用程序可以直接使用这些驱动程序来与设备通信。 | + | |
- | * 在设计一个USB接口的计算机外部设备时,如果HID类型的设备可以满足需要,可以将其设计为HID类型设备,这样可以省去比较复杂的USB驱动程序的编写,直接利用Windows操作系统对标准的HID类型USB设备的支持。 | + | |
- | ==== 2.HID设备特点 ==== | + | |
- | * (1) 交换的数据储存在称为报表(Report)的结构内,设备的固件必须支持HID报表的格式。主机通过控制和中断传输中的传送和请求报表来传送和接收数据。报表的格式非常灵活。 | + | |
- | * (2) 每一笔事务可以携带小量或中量的数据。低速设备每一笔事务最大是8B,全速设备每一笔事务最大是64B,高速设备每一笔事务最大是1024B。一个报表可以使用多笔事务。 | + | |
- | * (3) 设备可以在未预期的时间传送信息给主机,例如键盘的按键或是鼠标的移动。所以主机会定时轮询设备,以取得最新的数据。 | + | |
- | * (4) HID设备的最大传输速度有限制。主机可以保证低速的中断端点每10ms内最多1笔事务,每一秒最多是800B。保证全速端点每lms一笔事务,每一秒最多是64000B。保证高速端点每125us三笔事务,每一秒最多是24.576MB。 | + | |
- | * (5) HID设备没有保证的传输速率。如果设备是设置在10ms的时距,事务之间的时间可能等于或小于10ms。除非设备是设置在全速时在每个帧传输数据,或是在高速时在每个微帧传输数据。这是最快的轮询速率,所以端点可以保证有正确的带宽可供使用。 | + | |
- | * HID设备除了传送数据给主机外,它也会从主机接收数据。只要能够符合HID类别规范的设备都可以是HID设备。 | + | |
- | * 设备除了HID接口之外,它可能同时还包含有其他的USB接口。例如影像显示设备可能使用HID接口来做亮度、对比度的软件控制,而使用传统的影像接口来传送要显示的数据。USB扩音器可以使用实时传输来播放语音,同时使用HID接口来控制音量、低音等。 | + | |
- | * HID类别设备的规范文件主要是以下两份: | + | |
- | * Device Class Definition for Human interface Devices | + | |
- | * HID Usabe Tables | + | |
- | === 3.原理图 === | + | |
- | {{ :icore4tx:icore4tx_arm_hal_38_1.png?direct&500 |}} | + | |
- | * USB HID设备无需驱动程序,Windows系统自带HID类的驱动程序。本实验使用STM32H750的USB OTG FS实现iCore4T的USB HID双向数据传输,点击测试软件的灯控按钮来控制iCore4T上的LED灯的亮灭,实现上位机向下位机传输数据并解析相应命令。按下iCore4T的ARM-KEY按钮,测试软件显示ARM-KEY的状态,实现了下位机向上位机的数据传输。 | + | |
- | ==== 四、 实验程序 ==== | + | |
- | === 1.主函数 === | + | * LwIP是Light Weight (轻型)IP协议,有无操作系统的支持都可以运行。LwIP实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用,它只需十几KB的RAM和40K左右的ROM就可以运行,这使LwIP协议栈适合在低端的嵌入式系统中使用。 |
- | <code c> | + | * LwIP协议栈主要关注的是怎么样减少内存的使用和代码的大小,这样就可以让LwIP适用于资源有限的小型平台例如嵌入式系统。为了简化处理过程和内存要求,LwIP对API进行了裁减,可以不需要复制一些数据。 |
- | int main(void) | + | * LwIP提供三种API: |
- | { | + | * 1)RAW API |
- | int i; | + | * 2)LwIP API |
- | unsigned char buffer[64]; | + | * 3)BSD API。 |
- | unsigned char send_buffer[64]; | + | * RAW API把协议栈和应用程序放到一个进程里边,该接口基于函数回调技术,使用该接口的应用程序可以不用进行连续操作。不过,这会使应用程序编写难度加大且代 码不易被理解。为了接收数据,应用程序会向协议栈注册一个回调函数。该回调函数与特定的连接相关联,当该关联的连接到达一个信息包,该回调函数就会被协议 栈调用。这既有优点也有缺点。优点是既然应用程序和TCP/IP协议栈驻留在同一个进程中,那么发送和接收数据就不再产生进程切换。主要缺点是应用程序不 能使自己陷入长期的连续运算中,这样会导致通讯性能下降,原因是TCP/IP处理与连续运算是不能并行发生的。这个缺点可以通过把应用程序分为两部分来克 服,一部分处理通讯,一部分处理运算。 |
- | /* MCU 配置 */ | + | * LwIP API把接收与处理放在一个线程里面。这样只要处理流程稍微被延迟,接收就会被阻塞,直接造成频繁丢包、响应不及时等严重问题。因此,接收与协议处理必须 分开。LwIP的作者显然已经考虑到了这一点,他为我们提供了 tcpip_input() 函数来处理这个问题, 虽然他并没有在 rawapi 一文中说明。讲到这里,读者应该知道tcpip_input()函数投递的消息从哪里来的答案了吧,没错,它们来自于由底层网络驱动组成的接收线程。我们在编写网络驱动时, 其接收部分以任务的形式创建。 数据包到达后, 去掉以太网包头得到IP包, 然后直接调用tcpip_input()函数将其 投递到mbox邮箱。投递结束,接收任务继续下一个数据包的接收,而被投递得IP包将由TCPIP线程继续处理。这样,即使某个IP包的处理时间过长也不 会造成频繁丢包现象的发生。这就是LwIP API。 |
- | + | * BSD API提供了基于open-read-write-close模型的UNIX标准API,它的最大特点是使应用程序移植到其它系统时比较容易,但用在嵌入式系统中效率比较低,占用资源多。这对于我们的嵌入式应用有时是不能容忍的。 | |
- | /* 重置所有外围设备,初始化Flash接口和Systick. */ | + | * 其主要特性如下: |
- | HAL_Init(); | + | * (1) 支持多网络接口下的IP转发; |
- | /* 配置系统时钟 */ | + | * (2) 支持ICMP协议; |
- | SystemClock_Config(); | + | * (3) 包括实验性扩展的UDP(用户数据报协议); |
- | i2c.initialize(); | + | * (4) 包括阻塞控制、RTT 估算、快速恢复和快速转发的TCP(传输控制协议); |
- | axp152.initialize(); | + | * (5) 提供专门的内部回调接口(Raw API),用于提高应用程序性能; |
- | axp152.set_dcdc1(3500);//[ARM & FPGA] | + | * (6) 可选择的Berkeley接口API (在多线程情况下使用) ; |
- | axp152.set_dcdc2(1200);//[FPGA INT] | + | * (7) 在最新的版本中支持ppp; |
- | axp152.set_dcdc3(3300);//[DCOUT3] | + | * (8) 新版本中增加了的IP fragment的支持; |
- | axp152.set_dcdc4(3300);//[DCOUT4] | + | * (9) 支持DHCP协议,动态分配ip地址。 |
+ | === 2、TCP/IP协议 === | ||
- | axp152.set_aldo1(3300);//[BK3] | + | * TCP/IP(Transmission Control Protocol/Internet Protocol,传输控制协议/网际协议)是指能够在多个不同网络间实现信息传输的协议簇。TCP/IP协议不仅仅指的是TCP 和IP两个协议,而是指一个由FTP、SMTP、TCP、UDP、IP等协议构成的协议簇, 只是因为在TCP/IP协议中TCP协议和IP协议最具代表性,所以被称为TCP/IP协议。 |
- | axp152.set_aldo2(3300);//[ALDOOUT2] | + | * TCP/IP传输协议,即传输控制/网络协议,也叫作网络通讯协议。它是在网络的使用中的最基本的通信协议。TCP/IP传输协议对互联网中各部分进行通信的标准和方法进行了规定。并且,TCP/IP传输协议是保证网络数据信息及时、完整传输的两个重要的协议。TCP/IP传输协议是严格来说是一个四层的体系结构,应用层、传输层、网络层和数据链路层都包含其中。 |
- | axp152.set_dldo1(3300);//[BK0] | + | * TCP/IP协议是Internet最基本的协议,其中应用层的主要协议有Telnet、FTP、SMTP等,是用来接收来自传输层的数据或者按不同应用要求与方式将数据传输至传输层;传输层的主要协议有UDP、TCP,是使用者使用平台和计算机信息网内部数据结合的通道,可以实现数据传输与数据共享;网络层的主要协议有ICMP、IP、IGMP,主要负责网络中数据包的传送等;而网络访问层,也叫网路接口层或数据链路层,主要协议有ARP、RARP,主要功能是提供链路管理错误检测、对不同通信媒介有关信息细节问题进行有效处理等。 |
- | axp152.set_dldo2(3300);//[BK1] | + | === 3、STM32H750以太网简介 === |
- | HAL_Delay(200); | + | |
- | /* 初始化所有已配置的外围设备 */ | + | * STM32H750芯片自带以太网模块,通过工业介质独立接口(MII)或简化独立接口(RMII)为以太网LAN通信提供符合IEEE-802.3-2002的媒体访问控制器(MAC)。微控制器需要一个外部物理接口设备(PHY)连接到物理LAN总线。PHY使用17个信号(用于MII)或9个信号(用于RMII)连接到设备MII端口,并且可以使用来自微控制器的25MHz(MII)时钟。 |
- | MX_GPIO_Init(); | + | * STM32H750自带以太网模块特点包括: |
- | MX_USB_DEVICE_Init(); | + | * 实现10M/100Mbit/s的数据传输速率; |
- | /* 无限循环 */ | + | * 专用DMA控制器允许专用SRAM之间高速传输; |
- | while (1) | + | * 标明MAC支持(VLAN支持); |
- | { | + | * 通过符合IEEE802.3的MII/RMII接口与外部以太网PHY进行通信; |
- | if(_250ms_flag == 1){ | + | * 支持全双工和半双工操作; |
- | _250ms_flag = 0; | + | * MAC控制子层(控制帧)支持; |
- | if(hUsbDeviceFS.dev_state == USBD_STATE_CONFIGURED){ | + | * 32位CRC生成和删除; |
- | memset(send_buffer,0,64); | + | * 支持多种灵活的地址过滤模式; |
- | if(ARM_KEY_STATE == KEY_DOWN) | + | * 每次发送或接收32位状态码; |
- | sprintf((char *)send_buffer,"key:KEY PRESS"); | + | * 提供接收和发送两组FIFO; |
- | else | + | * 通过SMI(MDIO)接口配置和管理PHY设备; |
- | sprintf((char *)send_buffer,"key:"); | + | * 支持以太网时间戳(参见IEEE1588-2008),时间戳比较器连接到TIM2输入; |
- | USBD_HID_SendReport(&hUsbDeviceFS,send_buffer,64); | + | * 当系统时间大于目标时间时触发中断。 |
- | } | + | * 支持DMA。 |
- | } | + | * STM32H750以太网功能框图,如图所示: |
- | //接收命令处理 | + | {{ :icore4t:icore4t_arm_hal_39_1.png?direct |}} |
- | if(usb_receive_flag == 1){ | + | === 4、LAN8720A简介 === |
- | usb_receive_flag = 0; | + | |
- | memcpy(buffer,usb_receive_buffer,usb_receive_counter); | + | |
- | memset(usb_receive_buffer,0,usb_receive_counter); | + | |
- | for(i = 0;i < 64;i++){ | + | |
- | buffer[i] = tolower(buffer[i]); | + | |
- | } | + | |
- | command_process(buffer); | + | |
- | } | + | |
- | } | + | |
- | } | + | |
- | </code> | + | * LAN8720A功能框图如图所示: |
- | === 2.USBD_HID_SendReport函数 === | + | {{ :icore4t:icore4t_arm_hal_39_2.png?direct |}} |
- | <code c> | + | * LAN8720A是低功耗的10/100M以太网PHY层芯片,I/O引脚电压符合IEEE802.3-2005标准,支持通过RMII接口与以太网MAC层通信,内置10-BASE-T/100BASE-TX全双工传输模块,支持10Mbps和100Mbps。 |
- | /*发送HID报告*/ | + | * LAN8720A可以通过自协商的方式与目的主机最佳的连接方式(速度和双工模式),支持HPAuto-MDIX自动翻转功能,无需更换网线即可将连接更改为直连或交叉连接。LAN8720A的主要特点如下: |
- | uint8_t USBD_HID_SendReport(USBD_HandleTypeDef *pdev, | + | * 高性能的10/100M以太网传输模块; |
- | uint8_t *report, | + | * 支持RMII接口以减少引脚数; |
- | uint16_t len) | + | * 支持全双工和半双工模式; |
- | { | + | * 两个状态LED输出; |
- | USBD_HID_HandleTypeDef *hhid = (USBD_HID_HandleTypeDef *)pdev->pClassData; | + | * 可以使用25M晶振以降低成本; |
- | if (pdev->dev_state == USBD_STATE_CONFIGURED) | + | * 支持自协商模式; |
- | { | + | * 支持HPAuto-MDIX自动翻转功能; |
- | if (hhid->state == HID_IDLE) | + | * 支持SMI串行管理接口; |
- | { | + | * 支持MAC接口。 |
- | hhid->state = HID_BUSY; | + | === 5、原理图 === |
- | USBD_LL_Transmit(pdev, | + | |
- | HID_EPIN_ADDR, | + | |
- | report, | + | |
- | len); //通过端点传输数据 | + | |
- | } | + | |
- | } | + | |
- | return USBD_OK; | + | |
- | } | + | |
- | </code> | + | * iCore4T带有LAN8720A嵌入式以太网控制器,本实验实现TCP客户端功能。以PC作为服务器,iCore4T作为客户端,PC的IP地址192.168.0.1,端口号为60001,iCore4T的IP地址为192.168.0.10,端口随机。当客户端连接到服务器,TCP建立成功即可进行数据信息传输。实验原理图如下 |
- | === 3.command_process函数 === | + | {{ :icore4t:icore4t_arm_hal_39_3.png?direct |}} |
- | <code c> | + | ==== 四、 实验程序 ==== |
- | static int command_process(unsigned char * buffer) | + | |
- | { | + | |
- | char *p; | + | |
- | p = (char *)buffer; | + | |
- | //led灯命令处理 | + | |
- | if(memcmp(p,"led_red_on",strlen("led_red_on")) == 0){ | + | |
- | LED_ON; | + | |
- | }else if(memcmp(p,"led_red_off",strlen("led_red_off")) == 0){ | + | |
- | LED_OFF; | + | |
- | } | + | |
- | return 0; | + | |
- | } | + | |
- | </code> | + | === 1. 主函数 === |
- | === 4.USB_DEVICE初始化函数 === | + | |
<code c> | <code c> | ||
- | void MX_USB_DEVICE_Init(void) | + | //LWIP初始化 |
- | { | + | NETMPU_Config(); |
- | /* 初始化USB设备库,添加支持的类并启动该库 */ | + | lwip.initialize(); |
- | if (USBD_Init(&hUsbDeviceFS, &FS_Desc, DEVICE_FS) != USBD_OK) | + | eth_tcpc.initialize(); |
+ | while (1) | ||
{ | { | ||
- | Error_Handler(); | + | if((cnt ++ / 800000) % 2){ |
- | }//初始化设备堆栈并加载类驱动程序 | + | LED_RED_ON; |
- | if (USBD_RegisterClass(&hUsbDeviceFS, &USBD_HID) != USBD_OK) | + | }else{ |
- | { | + | LED_RED_OFF; |
- | Error_Handler(); | + | } |
- | }//将类驱动程序链接到Device Core | + | lwip.periodic_handle(); |
- | if (USBD_Start(&hUsbDeviceFS) != USBD_OK) | + | //tcp cilent test |
- | { | + | //热插拔 |
- | Error_Handler(); | + | if(_second_flag == 1){ //在中断中,当counter加到1000时,second_flag置1 |
- | }//启动USB Device Core. | + | _second_flag = 0; |
- | HAL_PWREx_EnableUSBVoltageDetector(); //启用USB电压电平检测器。 | + | if(!eth_tcpc.connect_flag){ |
- | } | + | eth_tcpc.connection_close(eth_tcpc.tcpc_pcb,0); |
+ | eth_tcpc.initialize(); | ||
+ | }else{ | ||
+ | if(lan8720.GetLinkState() == LAN8720_STATUS_LINK_DOWN){ | ||
+ | eth_tcpc.connect_flag = 0; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | if(eth_tcpc.receive_ok_flag == 1){ | ||
+ | eth_tcpc.receive_ok_flag = 0; | ||
+ | eth_tcpc.send_data(eth_tcpc.tcpc_pcb); //当接收到数据以后,将数据发出 | ||
+ | } | ||
+ | } | ||
- | </code> | + | </code> |
- | === 5.USB HID初始化 === | + | |
+ | === 2. LwIP初始化 === | ||
<code c> | <code c> | ||
- | static uint8_t USBD_HID_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) | + | unsigned char initialize(void) |
{ | { | ||
- | /* Open EP IN */ | + | unsigned char retry = 0; |
- | USBD_LL_OpenEP(pdev, HID_EPIN_ADDR, USBD_EP_TYPE_INTR, HID_EPIN_SIZE); | + | Struct netif *Netif_Init_Flag;//调用netif_add()函数时的返回值,用于判断网络初始化是否成功 |
- | //打开低级驱动程序的端点 | + | struct ip_addr ipaddr; //ip地址 |
- | pdev->ep_in[HID_EPIN_ADDR & 0xFU].is_used = 1U; | + | struct ip_addr netmask; //子网掩码 |
- | pdev->pClassData = USBD_malloc(sizeof(USBD_HID_HandleTypeDef)); | + | struct ip_addr gw; //默认网关 |
- | if (pdev->pClassData == NULL) | + | |
- | { | + | while(lan8720.initialize()){ //初始化LAN8720,如果失败的话就重试5次 |
- | return USBD_FAIL; | + | retry++; |
- | } | + | if(retry > 5){ |
- | ((USBD_HID_HandleTypeDef *)pdev->pClassData)->state = HID_IDLE; | + | retry = 0; |
- | return USBD_OK; | + | return 3; |
- | } | + | } //LAN8720初始化失败 |
- | </code> | + | } |
- | === 6.USB HID上位机C#部分源码 === | + | lwip_init(); //初始化LWIP内核 |
+ | IP4_ADDR(&ipaddr,lan8720.ip[0],lan8720.ip[1],lan8720.ip[2],lan8720.ip[3]); | ||
+ | IP4_ADDR(&netmask,lan8720.sub[0],lan8720.sub[1] ,lan8720.sub[2],lan8720.sub[3]); | ||
+ | IP4_ADDR(&gw,lan8720.gw[0],lan8720.gw[1],lan8720.gw[2],lan8720.gw[3]); | ||
+ | //向网卡列表中添加一个网口 | ||
+ | Netif_Init_Flag=netif_add(&lwip_netif,&ipaddr,&netmask,&gw,NULL,ðernetif_init,ðernet_input); | ||
+ | |||
+ | if(Netif_Init_Flag==NULL){ | ||
+ | return 4; //网卡添加失败 | ||
+ | }else{ //网口添加成功后,设置netif为默认值,并且打开netif网口 | ||
+ | netif_set_default(&lwip_netif);//设置netif为默认网口 | ||
+ | netif_set_up(&lwip_netif); //打开netif网口 | ||
+ | } | ||
+ | |||
+ | return 0;//操作OK | ||
+ | } | ||
- | * 此上位机测试软件使用Microsoft Visual Studio开发平台编写,用于实现上位机和下位机的双向数据传输,部分源码如下: | + | </code> |
+ | === 3. eth_tcpc初始化 === | ||
<code c> | <code c> | ||
- | using System; | + | void initialize(void) |
- | using System.Collections.Generic; | + | |
- | using System.ComponentModel; | + | |
- | using System.Data; | + | |
- | using System.Drawing; | + | |
- | using System.Linq; | + | |
- | using System.Text; | + | |
- | using System.Threading.Tasks; | + | |
- | using System.Windows.Forms; | + | |
- | + | ||
- | namespace usb_hid | + | |
{ | { | ||
- | public partial class Form1 : Form | + | //该函数简单的调用tcp_alloc函数为一个谅解分配一个TCP控制块tcp_pcb。tcp_alloc函数首先为新的tcp_pcb分配内存空间, |
- | { | + | //若内存空间不足,则函数会释放出新的pcb空间。 |
- | usb_hid_class usbhid = null; | + | eth_tcpc.tcpc_pcb = tcp_new(); |
- | bool red_flag = true; | + | //创建TCP客户端连接 |
+ | IP4_ADDR(ð_tcpc.rmtipaddr,lan8720.pc_ip[0],lan8720.pc_ip[1],lan8720.pc_ip[2],lan8720.pc_ip[3]); | ||
- | public Form1() | + | tcp_connect(eth_tcpc.tcpc_pcb,ð_tcpc.rmtipaddr,PC_PORT,connected); |
- | { | + | } |
- | InitializeComponent(); | + | |
- | usbhid = new usb_hid_class(); | + | |
- | button_red_on.Enabled = false; | + | |
- | usbhid.DataReceived += usb_hid_data_receive; | + | |
- | usbhid.DeviceRemoved += usb_hid_device_remove; | + | |
- | } | + | |
- | void usb_hid_device_remove(object sender, EventArgs e) | + | |
- | { | + | |
- | if (InvokeRequired) | + | |
- | { | + | |
- | Invoke(new EventHandler(usb_hid_device_remove), new object[] { sender, e }); | + | |
- | } | + | |
- | else | + | |
- | { | + | |
- | MessageBox.Show("设备移除", "提示"); | + | |
- | } | + | |
- | } | + | |
- | void usb_hid_data_receive(object sender, EventArgs e) | + | |
- | { | + | |
- | int temp; | + | |
- | string str; | + | |
- | report myRP = (report)e; | + | |
- | if (InvokeRequired) | + | |
- | { | + | |
- | try | + | |
- | { | + | |
- | Invoke(new EventHandler(usb_hid_data_receive), new object[] { sender, e }); | + | |
- | } | + | |
- | catch (Exception) | + | |
- | { | + | |
- | return; | + | |
- | } | + | |
- | } | + | |
- | else | + | |
- | { | + | |
- | str = usb_hid_class.ByteToHexString(myRP.reportBuff); | + | |
- | temp = str.IndexOf("key:"); | + | |
- | if (temp >= 0) | + | |
- | { | + | |
- | key_display.Text = str.Substring(4, str.Length - 4); | + | |
- | key_display.Select(key_display.TextLength, 0); | + | |
- | key_display.ScrollToCaret(); | + | |
- | } | + | |
- | } | + | |
- | } | + | |
- | private void button_connect_Click(object sender, EventArgs e) | + | |
- | { | + | |
- | int temp; | + | |
- | foreach (string device in usbhid.GetDeviceList()) | + | |
- | { | + | |
- | temp = device.IndexOf("#vid_0483&pid_5720#"); | + | |
- | if (temp >= 0) | + | |
- | { | + | |
- | usbhid.OpenUSBHid(device); | + | |
- | button_red_on.Enabled = true; | + | |
- | button_green_on.Enabled = true; | + | |
- | button_blue_on.Enabled = true; | + | |
- | return; | + | |
- | } | + | |
- | } | + | |
- | MessageBox.Show("未发现设备", "提示"); | + | |
- | } | + | |
- | private void button_red_on_Click(object sender, EventArgs e) | + | |
- | { | + | |
- | string data; | + | |
- | if (red_flag) | + | |
- | { | + | |
- | red_flag = false; | + | |
- | button_red_on.Text = "红灯灭"; | + | |
- | data = " led_red_on"; | + | |
- | while (data.Length < 65) | + | |
- | { | + | |
- | data += ' '; | + | |
- | } | + | |
- | usbhid.WriteUSBHID(data); | + | |
- | } | + | |
- | else | + | |
- | { | + | |
- | red_flag = true; | + | |
- | button_red_on.Text = "红灯亮"; | + | |
- | data = " led_red_off"; | + | |
- | while (data.Length < 65) | + | |
- | { | + | |
- | data += ' '; | + | |
- | } | + | |
- | usbhid.WriteUSBHID(data); | + | |
- | } | + | |
- | } | + | |
- | private void Form1_Load(object sender, EventArgs e) | + | |
- | { | + | |
- | } | + | |
- | } | + | |
- | } | + | |
- | </code> | + | </code> |
==== 五、 实验步骤 ==== | ==== 五、 实验步骤 ==== | ||
- | - 把仿真器与iCore4TX的SWD调试口相连(直接相连或者通过转接器相连); | + | - 把仿真器与iCore4T的SWD调试口相连(直接相连或者通过转接器相连); |
- | - 把iCore4TX(USB DEVICE)通过Micro USB线与计算机相连,为iCore4TX供电; | + | - 把iCore4T通过Micro USB线与计算机相连,为iCore4T供电; |
+ | - 把iCore4T网口通过网线与计算机网口相连; | ||
+ | - 设置本机电脑IP;(方法件附录1) | ||
- 打开Keil MDK 开发环境,并打开本实验工程; | - 打开Keil MDK 开发环境,并打开本实验工程; | ||
- | - 烧写程序到iCore4TX上; | + | - 打开TCP&UDP测试工具;(安装及使用方法件附录2) |
+ | - 烧写程序到iCore4T上; | ||
- 也可以进入Debug 模式,单步运行或设置断点验证程序逻辑。 | - 也可以进入Debug 模式,单步运行或设置断点验证程序逻辑。 | ||
- | - 打开\soft\usb_hid.exe 进行验证。 | + | |
==== 六、 实验现象 ==== | ==== 六、 实验现象 ==== | ||
- | * 点击测试软件的LED控制按钮,iCore4TX上的LED灯状态将发生变化,按下iCore4TX扩展板上的ARM-KEY,按键状态栏将显示按键的状态。(如下图所示) | + | |
- | {{ :icore4tx:icore4tx_arm_hal_38_2.png?direct |}} | + | * 在发送区编辑完要发送的数据信息后,点击发送即可收到发送的数据包。如图所示: |
+ | {{ :icore4t:icore4t_arm_hal_39_9.png?direct |}} | ||
+ | ==== 附录一: ==== | ||
+ | |||
+ | 1、打开控制面板-->网络和Internet-->网络和共享中心-->更改适配器设置-->以太网属性 | ||
+ | {{ :icore4t:icore4t_arm_hal_39_10.png?direct |}} | ||
+ | 2、Internet协议版本4,选择使用下面的IP地址,然后更改IP地址和默认网关 | ||
+ | {{ :icore4t:icore4t_arm_hal_39_11.png?direct |}} | ||
+ | ==== 附录二: ==== | ||
+ | |||
+ | 1、TCP&UDP测试工具安装 | ||
+ | * 双击TCP&UDPDebug102_setup.exe,点击下一步,在这里安装路径默认即可,点击安装。 | ||
+ | 2、TCP&UDP测试工具的使用 | ||
+ | * (1)打开测试工具,点击创建服务器,弹出设置端口的窗口,设置为60001. | ||
+ | {{ :icore4t:icore4t_arm_hal_39_12.png?direct |}} | ||
+ | * (2)服务器已经创建完成(如下图),点击启动服务器 | ||
+ | {{ :icore4t:icore4t_arm_hal_39_13.png?direct |}} | ||
+ | * (3)iCore4T客户端自动连接服务器,即可通信。(若连接不成功,请关闭电脑防火墙) | ||