RT

您所在的位置:网站首页 wiz测试 RT

RT

2023-07-21 02:32| 来源: 网络整理| 查看: 265

1 准备 硬件准备:STM32F407ZG、ST-Link、USB 转串口模块(有板载的串口通信接口也行) 软件准备:RT-Thread Studio 2 流程

整个项目简单流程

        整个项目流程都是在 RT-Thread Studio 上完成的,RT-Thread Studio 的图形化配置对于使用者来说会非常方便,前提是项目使用的是 RT-Thread 标准版或者 Smart 版,如果使用的是 Nano 版,那将无法使用组件包。

3 创建项目

        创建项目的方法非常简单,只需要在新建项目时选择对应的芯片型号即可,我使用的是 STM32F407ZG 芯片,默认情况下 RT-Thread Studio 中是没有 STM32F4 系列的芯片包支持的,所以需要手动下载。

3.1 下载 STM32F4 系列芯片包

        步骤 1:点击左上角的「文件」,选择「新建」-->「RT-Thread 项目」。

        步骤 2:在新出现的窗口中找到「系列:」,点击后面的下拉框选择「添加更多」。

        步骤 3:接下来找到「STM32F4」选项,勾选并点击安装。大概率是安装不成功的,因为下载这个资源的时候需要认证,防止恶意访问(我猜的),所以我们只能使用手动下载的方法。

        步骤 4:按照下载时在下载窗口下面看到的下载网址输入到浏览器地址栏(可以用 QQ 截图的图片转文字功能),按步骤进行下载。

        步骤 5:将下载后的资源解压,并将解压后的文件夹名称改为「STM32F4」,然后将文件夹复制到 RT-Thread Studio 安装目录下的 repo\Extract\Chip_Support_Packages\RealThread 目录下,如:D:\RT-ThreadStudio\repo\Extract\Chip_Support_Packages\RealThread。(注意:解压后的文件夹是文件,而不是另一个同名文件夹)

        步骤 6:完成,现在到 RT-Thread Studio 中创建项目时应该会出现 STM32F4 系列的芯片包。

        步骤 1 的截图 步骤 2 的截图 步骤 3 的截图 步骤 4 的截图 步骤 5 的截图

3.2 创建项目

        点击左上角的「文件」,选择「新建」-->「RT-Thread 项目」,输入项目名称并选择相应的芯片以及要使用的调试器,点击完成。

        创建项目的截图

4 配置 SPI

        步骤 1 :双击打开「RT-Thread Sertting」,找到 SPI 组件,点击打开并使用 CTRL+S 按键保存。

        步骤 2 :双击打开「CubeMX Settings」,进行时钟、引脚复用功能等配置。具体如何进行配置,可以自行搜索或者参考文章最后的「附」。

        步骤 3 :配置完成后点击「编译」按钮编译,保证目前代码的正确性(左上角的小锤子就是编译按钮,选中项目的时候才能点,不然编译器不知道要编译哪个项目)。

        步骤 1 的截图 步骤 2 的截图 步骤 3 的截图

5 配置 W5500 软件包

        步骤 1 :使用 RT-Thread Settings 添加 W5500 软件包。点击「RT-Thread Studio」-->「添加软件包」,在新窗口中搜索 W5500 并点击「添加」按钮。

        步骤 2 :添加完成后可以看到 RT-Thread Settings 的页面上多出了一个 WIZnet 图标。

        步骤 3 :右击 WIZnet 图标,选择「配置」,然后点击「WIZnet device configure」下拉框,配置 SPI 的属性,配置完成后 CTRL+S 按键保存,如果此时编译,编译会有很多警告。

此处配置时,主要配置的是 WIZnet device configure 选项下的 SPI 设备名和引脚编号。

引脚编号在 drivers/drv_gpio.c 文件中可以查看。

        步骤 4 :挂载 SPI 设备(之前做的 SPI 配置只是向内核注册了 SPI 总线,设备还需要手动挂载,此处的设备为 W5500)。由于 之前保存了 WIZnet 的配置,所以 RT-Thread Studio 会在项目目录下生成一个 packages 目录。打开 packages/src/wiz.c 文件,在文件中找到 int wiz_init(void) 函数,在函数中有一句注释「/* I think you can attach w5500 into spi bus at here. You can use this function to realize.*/」,取消注释的下一行关于代码的注释,并且按照这个函数声明来挂载 SPI 设备。

        步骤 5 :在 packagew/src/wiz.c 文件最上面添加 #include 来增加 GPIO_Typedef 类型的定义,否则编译时会找不到 GPIO_Typedef 的定义,最后就可以编译下载程序看是否成功挂载设备。

        步骤 1 的截图 步骤 2 的截图 步骤 3 的截图 步骤 4 的截图 步骤 5 的截图

6 测试 W5500

        下载后可以通过 finish shell 测试 W5500 驱动是否能够正常使用。通过 ifconfig 命令可以查看是否获取到 IP 地址(测试 DHCP 是否起作用),通过 ping 命令可以测试能否正常连接网络。

测试 W5500 驱动

此时的 MAC 地址是默认的「00-E0-81-DC-53-1A」,如果想要修改可以调用「int wiz_set_mac(const char *mac);」函数来修改。

7 正式使用

        客户端、HTTP 客户端、select 实现的客户端、TCP 服务端、UDP 服务端,这些在官方的 API 参考手册中都有相应的例程,比我写的更好,可以参考:here。

        下面的例程是我基于自己的理解写的,仅作为参考,实际以官方为准。

7.1 实现一个简单的 TCP 客户端

        我简单画了一个TCP 客户端与服务端建立通信的流程,基于这个流程再简单细化一下就可以简单建立 TCP 通信。

TCP客户端简单流程

开始的等待 DHCP 获取 IP 地址是最简单但也是最容易忽视的地方,如果还没有获取到 Ip 地址就开始创建套接字,那必然创建失败。

等待 DHCP 获取 IP         等待 DHCP 获取 IP 的问题在于如何知道 IP 地址是否已经获取到,一个简单高效的方法就是反复读取网卡的 IP,能读取到即认为 DHCP 获取成功。不过,采用这种方法前,还需要获取一下网卡设备的对象,这样便于我们读取网卡的 IP。         获取网卡设备的对象使用 struct netdev *net_dev = netdev_get_by_name("W5500"); 来实现。获取到网卡对象后,可以使用每 1s 读取一次 net_dev->ip_addr.addr,如果没有获取到则数值为 0,读取到则数值不为 0。

创建 socket 套接字         创建套接字的方法很简单,使用 int socketfd = socket(AF_INET, SOCK_STREAM, 0); 即可创建一个套接字。

客户端绑定 socket 套接字         客户端想要绑定套接字,首先需要决定使用哪个协议(IPV4/IPV6)、哪个网卡(IP 地址)以及哪个端口来通信,将这些数据赋值到 sockaddr_in 结构体中,然后调用 bind(socketfd, (struct sockaddr *)&client_addr, sizeof(struct sockaddr)); 这个函数就可以绑定套接字。

客户端连接服务端         与客户端绑定套接字类似,需要知道想要连接的服务器的具体信息,然后通过 connect(socketfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) 函数即可连接服务器。

客户端向服务端发送数据         发送数据使用 int send_size = send(socketfd, msg, strlen(msg), 0);即可发送,参数分别为:套接字描述符,发送字符串的头指针,字符串长度,0。

等待接收服务端数据         等待接收服务器数据也较为简单,使用 recv_size = recv(socketfd, recv_buffer, 1024, 0); 即可以阻塞的方式等待服务器的一个数据,参数分别为:套接字描述符,接收数据的数组,接收数据的最大长度,0。

具体代码如下:(直接看不好看的可以看图片:代码)

/* * Date Author Notes * 2022-03-13 徐浚策 简单的 Socket 使用 Demo */ #include // 在这个示例中没用到 #include // 提供 strlen() 函数 #include #define DBG_TAG "main" #define DBG_LVL DBG_LOG #include // 提供 LOG_D() 等函数,没用到 #include // 提供一些设备的定义,没用到 #include // 提供 socket 的标准函数,如:bind()、connect()等 #include // 提供了获取 host 的方法,没有到 #include // 提供了网卡相关的定义和函数 #define SERVER_HOST "192.168.31.36" // 服务器 IP 地址 #define SERVER_PORT 15370 // 服务器使用的端口 int main(void) { struct sockaddr_in client_addr; // 客户端套接字地址 struct sockaddr_in server_addr; // 服务端套接字地址 struct netdev *net_dev = RT_NULL; // netdev 网卡设备 int socketfd = -1; // 套接字文件描述符 /* 通过网卡名称获取 netdev 网卡对象 */ net_dev = netdev_get_by_name("W5500"); if (net_dev == RT_NULL){ rt_kprintf("get network interface device(%s) failed!\n", "W5500"); return -RT_ERROR; }rt_kprintf("get network interface device(%s) success!\n", "W5500"); /* 等待 DHCP 获取 IP 地址成功,超时时间 20s。如果没有 IP 地址,Socket 无法创建。 */ int count = 20; while(count-- && !(net_dev->ip_addr.addr)){ rt_thread_mdelay(1000); } if(!count){ rt_kprintf("get ip failed!\n"); return -RT_ERROR; } /* 创建一个套接字 */ if((socketfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){ rt_kprintf("create socket failed!\n"); return -RT_ERROR; }rt_kprintf("create socket success!\n"); /* 初始化需要绑定的客户端地址 */ client_addr.sin_family = AF_INET; // IPV4 client_addr.sin_port = htons(8080); // 客户端使用的端口 client_addr.sin_addr.s_addr = net_dev->ip_addr.addr; // 获取网卡对象中的 IP 地址,这个地址是由 DHCP 获取的,没有地址时为 0 rt_memset(&(client_addr.sin_zero), 0, sizeof(client_addr.sin_zero)); // 这个字段只起填充作用,使得 sockaddr_in 与 sockaddr 长度一样 /* 客户端绑定套接字 */ if (bind(socketfd, (struct sockaddr *)&client_addr, sizeof(struct sockaddr)) < 0){ rt_kprintf("socket bind failed!\n"); closesocket(socketfd); return -RT_ERROR; }rt_kprintf("socket bind network interface device(%s) success!\n", net_dev->name); /* 初始化预连接的服务端地址(配置服务端地址) */ server_addr.sin_family = AF_INET; // IPV4 server_addr.sin_port = htons(SERVER_PORT); // 服务端使用的端口 server_addr.sin_addr.s_addr = inet_addr(SERVER_HOST); // 服务器的 IP 地址 rt_memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero)); // 无实际作用,填充长度 /* 连接到服务端 */ if (connect(socketfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) < 0){ rt_kprintf("socket connect failed!\n"); closesocket(socketfd); return -RT_ERROR; }rt_kprintf("socket connect success!\n"); /* 向服务端发送数据 */ int send_size = 0; // 发送的数据长度 static const char *msg = "Hello, i am stm32f407zg.\n"; // 准备向服务端发送的数据 if ((send_size = send(socketfd, msg, strlen(msg), 0))


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3