这里会显示出您选择的修订版和当前版本之间的差别。
后一修订版 | 前一修订版 | ||
icore3_arm_hal_23 [2020/08/01 18:03] fmj 创建 |
icore3_arm_hal_23 [2022/03/18 15:11] (当前版本) sean |
||
---|---|---|---|
行 2: | 行 2: | ||
|技术支持电话|**0379-69926675-801** ||| | |技术支持电话|**0379-69926675-801** ||| | ||
|技术支持邮件|Gingko@vip.163.com ||| | |技术支持邮件|Gingko@vip.163.com ||| | ||
- | |技术论坛|http://www.eeschool.org ||| | ||
^ 版本 ^ 日期 ^ 作者 ^ 修改内容 ^ | ^ 版本 ^ 日期 ^ 作者 ^ 修改内容 ^ | ||
| V1.0 | 2020-08-01 | gingko | 初次建立 | | | V1.0 | 2020-08-01 | gingko | 初次建立 | | ||
行 10: | 行 9: | ||
\\ | \\ | ||
\\ | \\ | ||
+ | |||
===== STM32CubeMX教程二十三——LAN_TCPC实验 ===== | ===== STM32CubeMX教程二十三——LAN_TCPC实验 ===== | ||
行 126: | 行 126: | ||
{{ :icore3:icore3_arm_hal_23_10.png?direct |}} | {{ :icore3:icore3_arm_hal_23_10.png?direct |}} | ||
* Sn_DPORT (Socket n 目标端口寄存器) [R/W] [0x0010-0x0011] [0x00] | * Sn_DPORT (Socket n 目标端口寄存器) [R/W] [0x0010-0x0011] [0x00] | ||
- | * Sn_DPORT 配置或指示了 Socket n 的目标主机端口号,在 TCP/UDP 模式下生 | + | * Sn_DPORT 配置或指示了 Socket n 的目标主机端口号,在 TCP/UDP 模式下生效。在 TCP 客户端模式下,在 CONNET 配置命令前,该寄存器配置了 TCP Server监听的端口号。例如: Socket 0 的目标端口号 = 5000(0x1388) ,配置应如下: |
- | 效。在 TCP 客户端模式下,在 CONNET 配置命令前,该寄存器配置了 TCP Server | + | |
- | 监听的端口号。例如: Socket 0 的目标端口号 = 5000(0x1388) ,配置应如下: | + | |
{{ :icore3:icore3_arm_hal_23_11.png?direct |}} | {{ :icore3:icore3_arm_hal_23_11.png?direct |}} | ||
=== 3、TCPC简介 === | === 3、TCPC简介 === | ||
行 135: | 行 133: | ||
{{ :icore3:icore3_arm_hal_23_12.png?direct |}} | {{ :icore3:icore3_arm_hal_23_12.png?direct |}} | ||
* 客户端与服务器在使用TCP传输协议时要先建立一个“通道”,在传输完毕之后又要关闭这“通道”,前者可以被形象地成为“三次握手”,而后者则可以被称为“四次挥手”。 | * 客户端与服务器在使用TCP传输协议时要先建立一个“通道”,在传输完毕之后又要关闭这“通道”,前者可以被形象地成为“三次握手”,而后者则可以被称为“四次挥手”。 | ||
+ | |||
* 通道的建立——三次握手: | * 通道的建立——三次握手: | ||
- 在建立通道时,客户端首先要向服务端发送一个SYN同步信号。 | - 在建立通道时,客户端首先要向服务端发送一个SYN同步信号。 | ||
行 145: | 行 144: | ||
- 客户端在收到这个信号之后会回复一个确认信号,在服务端接收到这个信号之后,服务端与客户端的通道也就关闭了 | - 客户端在收到这个信号之后会回复一个确认信号,在服务端接收到这个信号之后,服务端与客户端的通道也就关闭了 | ||
- | ==== 四、 实验程序 ==== | + | ==== 四、 实验原理 ==== |
- | + | * iCore3带有W5500嵌入式以太网控制器,本实验实现TCP客户端功能。以PC作为服务器,iCore3作为客户端,PC的IP地址192.168.0.2,端口号为60001,iCore3的IP地址为192.168.0.10,端口随机。当客户端连接到服务器,TCP建立成功即可进行数据信息传输。以下为实验原理图。 | |
- | === 1. 主函数 === | + | {{ :icore3:icore3_arm_hal_23_13.png?direct |}} |
+ | ==== 五、 实验程序 ==== | ||
+ | === 1. main()函数中建立的客户端程序 === | ||
<code c> | <code c> | ||
- | int main(void) | + | while (1) |
- | { | + | { |
- | HAL_Init(); | + | //处理TCP client信息 |
- | SystemClock_Config(); | + | switch(getSn_SR(0)) /*获取socket0的状态*/ |
- | MX_GPIO_Init(); | + | { |
- | MX_USB_DEVICE_Init(); | + | case SOCK_INIT: /*socket初始化完成*/ |
- | MX_SDIO_SD_Init(); | + | connect(0, remote_ip ,60001); /*在TCP模式下向服务器发送连接请求*/ |
- | while (1) | + | break; |
- | { | + | case SOCK_ESTABLISHED: /*socket连接建立*/ |
- | LED_RED_ON; | + | if(getSn_IR(0) & Sn_IR_CON) |
- | LED_GREEN_OFF; | + | { |
- | LED_BLUE_OFF; | + | setSn_IR(0, Sn_IR_CON); /*Sn_IR的第0位置1*/ |
- | HAL_Delay(500); | + | } |
- | LED_RED_OFF; | + | receive_length = getSn_RX_RSR(0); /*len为已接收数据的大小*/ |
- | LED_GREEN_ON; | + | if(receive_length > 0) |
- | LED_BLUE_OFF; | + | { |
- | HAL_Delay(500); | + | memset(receive_buffer,0,sizeof(receive_buffer)); |
- | LED_RED_OFF; | + | recv(0,receive_buffer,receive_length); |
- | LED_GREEN_OFF; | + | /*W5500接收来自Sever的数据*/ |
- | LED_BLUE_ON; | + | send(0,receive_buffer,receive_length); |
- | HAL_Delay(500); | + | } |
- | } | + | break; |
+ | case SOCK_CLOSE_WAIT: /*socket等待关闭状态*/ | ||
+ | disconnect(0); | ||
+ | break; | ||
+ | case SOCK_CLOSED: /*socket关闭*/ | ||
+ | local_port = rand() % 10000 + 50000; | ||
+ | socket(0,Sn_MR_TCP,local_port,Sn_MR_ND); | ||
+ | /*打开socket0的一个端口*/ | ||
+ | break; | ||
+ | } | ||
} | } | ||
+ | |||
</code> | </code> | ||
- | * Main函数中对SDIO与USB分别进行了初始化,在while循环中用三色灯循环点亮表明程序正在运行。 | + | |
- | === 2. 初始化函数 === | + | === 2. SPI初始化配置 === |
+ | * 初始化SPI 主要是对SPI要使用到的引脚以及SPI通信协议中时钟相位和极性进行设置 | ||
<code c> | <code c> | ||
- | void MX_SDIO_SD_Init(void) { | + | void MX_SPI1_Init(void) |
- | hsd.Instance = SDIO; | + | { |
- | hsd.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING; | + | hspi1.Instance = SPI1; |
- | hsd.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE; | + | hspi1.Init.Mode = SPI_MODE_MASTER; //SPI主模式 |
- | hsd.Init.ClockPowerSave=SDIO_CLOCK_POWER_SAVE_DISABLE; | + | hspi1.Init.Direction = SPI_DIRECTION_2LINES; //全双工模式 |
- | hsd.Init.BusWide = SDIO_BUS_WIDE_1B; | + | hspi1.Init.DataSize = SPI_DATASIZE_8BIT; //数据位为8位 |
- | hsd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_ENABLE; | + | hspi1.Init.CLKPolarity = SPI_POLARITY_LOW; //CPOL = 0 |
- | hsd.Init.ClockDiv = 0; | + | hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; //CPHA为数据线的第一个变化沿 |
- | if (HAL_SD_Init(&hsd) != HAL_OK) { | + | hspi1.Init.NSS = SPI_NSS_SOFT; //软件控制NSS |
- | Error_Handler(); | + | hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;//2分频 |
- | } | + | hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB; //最高位先发送 |
- | if (HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B) != HAL_OK) { | + | hspi1.Init.TIMode = SPI_TIMODE_DISABLE; //TIMODE模式关闭 |
- | Error_Handler(); | + | hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;//CRC关闭 |
- | } | + | hspi1.Init.CRCPolynomial = 10;//默认值,无效 |
- | } | + | if (HAL_SPI_Init(&hspi1) != HAL_OK)//初始化 |
+ | { | ||
+ | Error_Handler(); | ||
+ | } | ||
+ | } | ||
</code> | </code> | ||
- | === 3. 接口函数 === | + | === 3. SPI读写函数配置 === |
- | * 在usbd_storage_if.c文件中是USB_MSC初始化与读写相关函数。需要在这个文件下编写相关读写SDIO的相关函数,分别为STORAGE_GetCapacity_HS获取容量信息函数STORAGE_Read_HS读SDIO函数与STORAGE_Write_HS写SDIO函数。分别引入SD卡的接口函数。HAL_SD_GetCardInfo获取SD卡信息函数,HAL_SD_ReadBlocks读取SD卡函数,HAL_SD_WriteBlocks写SD卡函数以及HAL_SD_GetCardState获取SD卡状态信息函数。 | + | * HAL_SPI_TransmitReceive()为SPI的HAL库读写函数,一次操作一个字节,数据同时写入同时读出。send_data()函数为单字节读写函数,write()函数为多字节读写函数,可实现多字节数据的读写。 |
- | * 获取容量信息函数 | + | |
<code c> | <code c> | ||
- | int8_t STORAGE_GetCapacity_HS(uint8_t lun, uint32_t *block_num, uint16_t *block_size) | + | static unsigned char send_data(unsigned char data)//SPI读写字节函数 |
- | { | + | { |
- | /* USER CODE BEGIN 10 */ | + | unsigned char receive_data; |
- | HAL_SD_GetCardInfo(&hsd,&SDCardInfo); | + | HAL_SPI_TransmitReceive(&hspi1,&data,&receive_data,1,1000);//接收发送函数 |
- | + | return receive_data;//返回接收到的值 | |
- | *block_num = STORAGE_BLK_NBR; | + | } |
- | *block_size = STORAGE_BLK_SIZ; | + | static int write(int number, unsigned char * buf) //SPI读写多字节函数 |
- | return (USBD_OK); | + | { |
- | /* USER CODE END 10 */ | + | int i; |
- | } | + | SPI1_CS_OFF; //拉低CS引脚 |
+ | for (i = 0; i < number; i++){ | ||
+ | buf[i] = send_data(buf[i]); //调用send_data()函数 | ||
+ | } | ||
+ | SPI1_CS_ON; //拉高CS引脚 | ||
+ | return 0; | ||
+ | } | ||
</code> | </code> | ||
- | * 读SDIO函数 | + | |
+ | === 4. W5500.c中的寄存器读写函数 === | ||
<code c> | <code c> | ||
- | int8_t STORAGE_Read_HS(uint8_t lun, uint8_t *buf, | + | //定义本设备IP地址、默认网关、MAC地址、子网掩码 |
- | uint32_t blk_addr, uint16_t blk_len) | + | W5500_T w5500={ |
- | { | + | .initialize=initialize, |
- | /* USER CODE BEGIN 13 */ | + | .mac = {0x00,0x98,0xdc,0x42,0x61,0x11}, |
- | uint32_t timeout = 10000; | + | .ip = {192,168,0,10}, |
+ | .sub = {255,255,255,0}, | ||
+ | .gw = {192,168,0,1} | ||
+ | }; | ||
+ | //W5500写函数 | ||
+ | void IINCHIP_WRITE (unsigned long int addrbsb, unsigned char data) | ||
+ | { | ||
+ | SPI1_CS_OFF; | ||
+ | spi1.send_data( (addrbsb & 0x00FF0000)>>16); // Address byte 1 | ||
+ | spi1.send_data( (addrbsb & 0x0000FF00)>> 8); // Address byte 2 | ||
+ | spi1.send_data( (addrbsb & 0x000000F8) + 4); | ||
+ | // Data write command and Write data length 1 | ||
+ | spi1.send_data(data); // Data write (write 1byte data) | ||
+ | SPI1_CS_ON | ||
+ | } | ||
- | if(HAL_SD_ReadBlocks(&hsd,buf,blk_addr,(uint32_t)blk_len, timeout) == USBD_OK){ | + | //W5500读函数 |
- | while(HAL_SD_GetCardState(hsd)!= HAL_OK) | + | unsigned char IINCHIP_READ (unsigned long int addrbsb) // Address byte 1 |
- | { | + | { |
- | if (timeout-- == 0) | + | unsigned char data = 0; |
- | { | + | SPI1_CS_OFF; |
- | return -1; | + | spi1.send_data( (addrbsb & 0x00FF0000)>>16); // Address byte 1 |
- | } | + | spi1.send_data( (addrbsb & 0x0000FF00)>> 8); // Address byte 2 |
- | } | + | spi1.send_data( (addrbsb & 0x000000F8)) ; |
- | } | + | // Data read command and Read data length 1 |
- | return (USBD_OK); | + | data = spi1.send_data(0x00); // Data read (read 1byte data) |
- | /* USER CODE END 13 */ | + | SPI1_CS_ON; |
+ | return data; | ||
} | } | ||
</code> | </code> | ||
- | * 写SDIO函数 | + | ==== 六、 实验步骤 ==== |
- | <code c> | + | |
- | int8_t STORAGE_Write_HS(uint8_t lun, uint8_t *buf, | + | |
- | uint32_t blk_addr, uint16_t blk_len) | + | |
- | { | + | |
- | /* USER CODE BEGIN 14 */ | + | |
- | uint32_t timeout = 10000; | + | |
- | + | ||
- | if(HAL_SD_WriteBlocks(hsd,buf, blk_addr, blk_len, timeout) == USBD_OK){ | + | |
- | while(HAL_SD_GetCardState(hsd)!= HAL_OK) | + | |
- | { | + | |
- | if (timeout-- == 0) | + | |
- | { | + | |
- | return -1; | + | |
- | } | + | |
- | } | + | |
- | } | + | |
- | return (USBD_OK); | + | |
- | /* USER CODE END 14 */ | + | |
- | } | + | |
- | </code> | + | |
- | ==== 五、 实验步骤 ==== | + | |
- 把仿真器与iCore3的SWD调试口相连(直接相连或者通过转接器相连); | - 把仿真器与iCore3的SWD调试口相连(直接相连或者通过转接器相连); | ||
- | - 将跳线帽插在USB OTG; | ||
- | - 将Micro SD卡插入TF卡座里面; | ||
- 把iCore3(USB OTG)通过Micro USB线与计算机相连,为iCore3供电; | - 把iCore3(USB OTG)通过Micro USB线与计算机相连,为iCore3供电; | ||
+ | - 把iCore3网口通过网线与计算机网口相连; | ||
+ | - 设置本机电脑IP;(方法见附录1) | ||
- 打开Keil MDK 开发环境,并打开本实验工程; | - 打开Keil MDK 开发环境,并打开本实验工程; | ||
+ | - 打开TCP&UDP测试工具;(安装及使用方法见附录2) | ||
- 烧写程序到iCore3上; | - 烧写程序到iCore3上; | ||
- | - 即可在电脑上操作磁盘。 | + | - 也可以进入Debug 模式,单步运行或设置断点验证程序逻辑。 |
- | + | ||
- | ==== 六、 实验现象 ==== | + | |
- | * 下载程序到iCore3上之后,可以从设备管理器内查看到USB大容量存储设备。同时可以看到设备和驱动器里面多了一个磁盘。可以对该磁盘进行操作,即可读写Micro SD卡。 | + | |
- | {{ :icore3:icore3_arm_hal_22_2.png?direct |}} | + | |
+ | ==== 七、 实验现象 ==== | ||
+ | * 在发送区编辑完要发送的数据信息后,点击发送即可收到发送的数据包。如图所示 | ||
+ | {{ :icore3:icore3_arm_hal_23_14.png?direct |}} | ||
+ | ==== 附录1 ==== | ||
+ | 1、打开控制面板网络和Internet网络和共享中心更改适配器设置以太网属性 | ||
+ | {{ :icore3:icore3_arm_hal_23_14.png?direct |}} | ||
+ | 2、Internet协议版本选择使用下面的IP地址(如下图所示),然后更改IP地址和默认网关 | ||
+ | {{ :icore3:icore3_arm_hal_23_14.png?direct |}} | ||
+ | ==== 附录2 ==== | ||
+ | 1、TCP&UDP测试工具安装 | ||
+ | 双击TCPUDPDebug102_Setup.exe,点击下一步,在这里安装路径我们默认即可,点击安装,然后Finish。 | ||
+ | 2、TCP&UDP测试工具的使用 | ||
+ | (1)打开测试工具,界面如下。点击创建服务器,弹出了设置端口的窗口,端口设置为60001。 | ||
+ | {{ :icore3:icore3_arm_hal_23_14.png?direct |}} | ||
+ | (2)服务器已经创建完成(如下图),点击启动服务器 | ||
+ | {{ :icore3:icore3_arm_hal_23_14.png?direct |}} | ||
+ | (3)iCore3客户端自动连接服务器,即可进行通信。(若连接不上请关闭电脑防火墙) | ||