这里会显示出您选择的修订版和当前版本之间的差别。
| 后一修订版 | 前一修订版 | ||
| 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客户端自动连接服务器,即可进行通信。(若连接不上请关闭电脑防火墙) | ||