0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于小凌派RK2206开发板wifi-tcp通信实验

福州市凌睿智捷电子有限公司 2022-06-14 11:10 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

基于小凌派RK2206开发板wifi-tcp通信实验

在开发过程中想要与开发板进行通信一般使用串口通信,当开发板使用串口与pc通信还需要专门的串口转换工具才行。而小凌派开发板自带wifi功能。因此与pc通信时可以使用wifi功能进行tcp通信这样就不需要专门的转换工具非常方便。

一、在使用小凌派开发板wifi进行tcp通信的步骤

1、要确定pc机所连接路由的wifi名称和密码。通过修改代码使小凌派连接到与pc同一网络。

修改文件device/rockchip/rk2206/sdk_liteos/board/src/config_network.c 中的SSID 即wifi名称,和PASSWORD 即wifi密码。

#define SSID "凌智电子"

#define PASSWORD "********"


2、确认小凌派wifi功能是否开启

查看device/rockchip/rk2206/sdk_liteos/board/main.c 文件

是否调用ExternalTaskConfigNetwork();


3、确认小凌派开发板与开发板在同一网段。

在修改以上配置后先编译烧录程序然后查看log确认小凌派开发板获取到的ip地址。

c34bbe36-e735-11ec-a2f4-dac502259ad0.png

在确认pc的ip地址,在控制台输入ipconfig

c3782674-e735-11ec-a2f4-dac502259ad0.png

可以看到两个ip地址都是点2网段,说明已经在同一局域网。


4、 修改wifi_tcp 例程中服务地址及端口

#define OC_SERVER_IP "192.168.2.49"

#define SERVER_PORT 6666

这个ip地址即PC的ip地址,修改后重新编译烧录程序。


5、 pc上打开两个网络调试工具,一个客户端和一个服务端,并设置ip地址和端口号

服务端 ip地址:0.0.0.0

端口号:6666

客户端ip地址:192.168.2.50 (之前查看到小凌派的ip地址)

端口号:6666

c3b1886a-e735-11ec-a2f4-dac502259ad0.png

6 、查看log等待小凌派的tcp客户端和服务端任务启动


c3de5a2a-e735-11ec-a2f4-dac502259ad0.png

可以看到客户端连接地址192.168.2.49:6666 即pc的ip地址

服务端监听端口为6666

这表示小凌派tcp客户端和服务端任务都已经启动。


7、 在pc网络调试助手点击启动客户端和服务端

c43ac86e-e735-11ec-a2f4-dac502259ad0.png

可以观察到网络调试助手服务端有设备连接成功并且接收到了调试数据。

网络调试助手的客户端也显示连接成功。


8、 使用网络调试助手发送数据

c46782be-e735-11ec-a2f4-dac502259ad0.png

可以查看log发现小凌派开发板已经可以正常收发数据了。

这样就可以通过使用wifi与pc进行通信。


二、接下来分析一下代码的工作流程。

首先包含必要的头文件

#include "ohos_init.h"#include "cmsis_os2.h"#include "los_task.h"#include "lz_hardware.h"#include "config_network.h"#include "lwip/tcp.h"#include "lwip/ip_addr.h"#include "lwip/priv/tcp_priv.h"#include "lwip/stats.h"#include "lwip/inet_chksum.h"



这些定义主要是 ip地址和端口号以及缓存大小

#define LOG_TAG "tcp"#define OC_SERVER_IP "192.168.2.49"#define SERVER_PORT 6666#define BUFF_LEN 256



这部分是获取wifi连接信息,通过查询wifi连接信息确认wifi是否连接成功。只有wifi连接成功了才能进行tcp通信

int get_wifi_info(WifiLinkedInfo *info){ int ret = -1; int gw, netmask; memset(info, 0, sizeof(WifiLinkedInfo)); unsigned int retry = 15; while (retry) { if (GetLinkedInfo(info) == WIFI_SUCCESS) { if (info->connState == WIFI_CONNECTED) { if (info->ipAddress != 0) { LZ_HARDWARE_LOGD(LOG_TAG, "rknetwork IP (%s)", inet_ntoa(info->ipAddress)); if (WIFI_SUCCESS == GetLocalWifiGw(&gw)) { LZ_HARDWARE_LOGD(LOG_TAG, "network GW (%s)", inet_ntoa(gw)); } if (WIFI_SUCCESS == GetLocalWifiNetmask(&netmask)) { LZ_HARDWARE_LOGD(LOG_TAG, "network NETMASK (%s)", inet_ntoa(netmask)); } if (WIFI_SUCCESS == SetLocalWifiGw()) { LZ_HARDWARE_LOGD(LOG_TAG, "set network GW"); } if (WIFI_SUCCESS == GetLocalWifiGw(&gw)) { LZ_HARDWARE_LOGD(LOG_TAG, "network GW (%s)", inet_ntoa(gw)); } if (WIFI_SUCCESS == GetLocalWifiNetmask(&netmask)) { LZ_HARDWARE_LOGD(LOG_TAG, "network NETMASK (%s)", inet_ntoa(netmask)); } ret = 0; goto connect_done; } } } LOS_Msleep(1000); retry--; }

connect_done: return ret;}



这部分是tcp服务端接收消息处理

先进入accept()会处于阻塞状态,即没有客户端连接时一直阻塞。

单客户端连接后又进入接收数据状态,此状态也是阻塞状态。

没有数据时一直阻塞,不过需要注意的是在此状态下当客户端断开连接时recv会返回-1

接收到pc客户端的消息后通过send()发响应消息给PC客户端。

void tcp_server_msg_handle(int fd){ char buf[BUFF_LEN]; //接收缓冲区 socklen_t client_addr_len; int cnt = 0, count; int client_fd; struct sockaddr_in client_addr = {0}; printf("waitting for client connect...\n"); /* 监听socket 此处会阻塞 */ client_fd = accept(fd, (struct sockaddr*)&client_addr, &client_addr_len); // client_fd = lwip_accept(fd, (struct sockaddr*)&client_addr, &client_addr_len); printf("[tcp server] accept <%s:%d>\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); while (1) { memset(buf, 0, BUFF_LEN); printf("-------------------------------------------------------\n"); printf("[tcp server] waitting client msg\n"); count = recv(client_fd, buf, BUFF_LEN, 0); //read是阻塞函数,没有数据就一直阻塞 // count = lwip_read(client_fd, buf, BUFF_LEN); //read是阻塞函数,没有数据就一直阻塞 if (count == -1) { printf("[tcp server] recieve data fail!\n"); LOS_Msleep(3000); break; } printf("[tcp server] rev client msg:%s\n", buf); memset(buf, 0, BUFF_LEN); sprintf(buf, "I have recieved %d bytes data! recieved cnt:%d", count, ++cnt); printf("[tcp server] send msg:%s\n", buf); send(client_fd, buf, strlen(buf), 0); //发送信息给client // lwip_write(client_fd, buf, strlen(buf)); //发送信息给client } lwip_close(client_fd); lwip_close(fd);}



这部分是tcp服务端任务代码

服务端处理流程

socket-->bind-->listen-->accept-->recv-->send-->lwip_close

先通过socket()接口打开一个服务端socket文件

然后设置需要绑定的服务端ip地址及端口号。

在进行监听,需要注意的是此处监听不会处于阻塞态。

int wifi_server(void* arg){ int server_fd, ret;

while(1) { server_fd = socket(AF_INET, SOCK_STREAM, 0); //AF_INET:IPV4;SOCK_STREAM:TCP // server_fd = lwip_socket(AF_INET, SOCK_STREAM, 0); //AF_INET:IPV4;SOCK_STREAM:TCP if (server_fd < 0) { printf("create socket fail!\n"); return -1; }

/*设置调用close(socket)后,仍可继续重用该socket。调用close(socket)一般不会立即关闭socket,而经历TIME_WAIT的过程。*/ int flag = 1; ret = setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(int)); if (ret != 0) { printf("[CommInitTcpServer]setsockopt fail, ret[%d]!\n", ret); } struct sockaddr_in serv_addr = {0}; serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); //IP地址,需要进行网络序转换,INADDR_ANY:本地地址 // serv_addr.sin_addr.s_addr = inet_addr(OC_SERVER_IP); //IP地址,需要进行网络序转换,INADDR_ANY:本地地址 serv_addr.sin_port = htons(SERVER_PORT); //端口号,需要网络序转换 /* 绑定服务器地址结构 */ ret = bind(server_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); // ret = lwip_bind(server_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); if (ret < 0) { printf("socket bind fail!\n"); lwip_close(server_fd); return -1; } /* 监听socket 此处不阻塞 */ ret = listen(server_fd, 64); // ret = lwip_listen(server_fd, 64); if(ret != 0) { printf("socket listen fail!\n"); lwip_close(server_fd); return -1; } printf("[tcp server] listen:%d<%s:%d>\n",server_fd, inet_ntoa(serv_addr.sin_addr), ntohs(serv_addr.sin_port)); tcp_server_msg_handle(server_fd); //处理接收到的数据 LOS_Msleep(1000); }}

这部分是tcp客户端的接收消息处理函数

先进行尝试连接pc机的服务端,如果失败则延迟5秒后重新连接直到连接成功。

连接成功后先发消息给PC的服务端,然后进入接收状态,此状态是阻塞态。

当接收到pc的消息后进入循环发送状态。

void tcp_client_msg_handle(int fd, struct sockaddr* dst){ socklen_t len = sizeof(*dst);

int cnt = 0, count = 0; while (connect(fd, dst, len) < 0) { printf("connect server failed...%d\n", ++count); lwip_close(fd); LOS_Msleep(5000); fd = socket(AF_INET, SOCK_STREAM, 0); //AF_INET:IPV4;SOCK_STREAM:TCP } while (1) { char buf[BUFF_LEN]; sprintf(buf, "TCP TEST cilent send:%d", ++cnt); count = send(fd, buf, strlen(buf), 0); //发送数据给server // count = lwip_write(fd, buf, strlen(buf)); //发送数据给server printf("------------------------------------------------------------\n"); printf("[tcp client] send:%s\n", buf); printf("[tcp client] client sendto msg to server %d,waitting server respond msg!!!\n", count); memset(buf, 0, BUFF_LEN); count = recv(fd, buf, BUFF_LEN, 0); //接收来自server的信息 // count = lwip_read(fd, buf, BUFF_LEN); //接收来自server的信息 if(count == -1) { printf("[tcp client] recieve data fail!\n"); LOS_Msleep(3000); break; } printf("[tcp client] rev:%s\n", buf); } lwip_close(fd);}

这部分代码是tcp客户端代码

客户端处理流程

socket-->connect-->send-->recv-->lwip_close

先通过socket()接口创建客户端的socket文件。

然后设置客户端连接PC服务端的ip地址及端口号。

在进行connect连接。

int wifi_client(void* arg){ int client_fd, ret; struct sockaddr_in serv_addr; while(1) { client_fd = socket(AF_INET, SOCK_STREAM, 0);//AF_INET:IPV4;SOCK_STREAM:TCP if (client_fd < 0) { printf("create socket fail!\n"); return -1; }

/*设置调用close(socket)后,仍可继续重用该socket。调用close(socket)一般不会立即关闭socket,而经历TIME_WAIT的过程。*/ int flag = 1; ret = setsockopt(client_fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(int)); if (ret != 0) { printf("[CommInitTcpServer]setsockopt fail, ret[%d]!\n", ret); } memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = inet_addr(OC_SERVER_IP); serv_addr.sin_port = htons(SERVER_PORT); printf("[tcp client] connect:%d<%s:%d>\n",client_fd, inet_ntoa(serv_addr.sin_addr), ntohs(serv_addr.sin_port)); tcp_client_msg_handle(client_fd, (struct sockaddr*)&serv_addr); LOS_Msleep(1000); }

return 0;}

这部分是tcp创建客户端和服务端任务

可以看到在创建客户端和服务端任务前先阻塞判断wifi的连接状态。

只有wifi连接成功后才创建客户端和服务端任务。

void wifi_process(void *args){ unsigned int threadID_client, threadID_server; unsigned int ret = LOS_OK; WifiLinkedInfo info;

while(get_wifi_info(&info) != 0) ;

CreateThread(&threadID_client, wifi_client, NULL, "client@ process"); CreateThread(&threadID_server, wifi_server, NULL, "server@ process");}

这部分是创建wifi tcp 通信任务主要是为了使用APP_FEATURE_INIT(wifi_tcp_example);

这样当OpenHarmony初始化完成后会自动执行此任务。

void wifi_tcp_example(void){ unsigned int ret = LOS_OK; unsigned int thread_id; TSK_INIT_PARAM_S task = {0}; printf("%s start ....\n", __FUNCTION__);

task.pfnTaskEntry = (TSK_ENTRY_FUNC)wifi_process; task.uwStackSize = 10240; task.pcName = "wifi_process"; task.usTaskPrio = 24; ret = LOS_TaskCreate(&thread_id, &task); if (ret != LOS_OK) { printf("Falied to create wifi_process ret:0x%x\n", ret); return; }}APP_FEATURE_INIT(wifi_tcp_example);


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 小凌派
    +关注

    关注

    0

    文章

    28

    浏览量

    1652
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    精灵(ElfBoard)技术贴|如何在ELF-RK3506开发板上实现GPIO复用

    2026年全国大学生嵌入式芯片与系统设计竞赛报名已正式启动。本次瑞芯微&飞嵌入式赛题共设置了三个参赛平台(ELF2开发板、ELF-RV1126B开发板、ELF-RK3506
    的头像 发表于 03-16 14:55 6582次阅读
    飞<b class='flag-5'>凌</b>精灵(ElfBoard)技术贴|如何在ELF-<b class='flag-5'>RK</b>3506<b class='flag-5'>开发板</b>上实现GPIO复用

    基于ZYNQ-MZ702P开发板实现以太网通信

    本章以太网通信实验是基于ZYNQ-MZ702P开发板进行实现,在配置方面,需要读者自主修改不同的地方。文章末尾有本项目原工程压缩包,提供参考。
    的头像 发表于 02-11 11:42 2869次阅读
    基于ZYNQ-MZ702P<b class='flag-5'>开发板实现以太网通信</b>

    OpenHarmony开发开源资料!-RK3568开发板:从入门到实战的全栈硬件平台

    点的利器: - RK3568 开发板,以及它的核心开源资源站——Gitee 仓库(https://gitee.com/xie-shancai/lockzhiner-
    的头像 发表于 02-05 13:56 740次阅读
    OpenHarmony<b class='flag-5'>开发</b>开源资料!<b class='flag-5'>凌</b>蒙<b class='flag-5'>派</b>-<b class='flag-5'>RK</b>3568<b class='flag-5'>开发板</b>:从入门到实战的全栈硬件平台

    【超值首选!仅88元】ELF-RK3506开发板限时优惠震撼来袭

    ElfBoard特别推出了ELF-RK3506开发板,助力大家快速掌握实际应用场景下的嵌入式Linux开发技能。【性能卓越,技术领先】ELF-RK3506
    的头像 发表于 01-16 16:41 1440次阅读
    【超值首选!仅88元】ELF-<b class='flag-5'>RK</b>3506<b class='flag-5'>开发板</b>限时优惠震撼来袭

    性能跃迁,鸿蒙开发新纪元!RK3566鸿蒙开发板,开启全场景开发之旅

    【导语】还在为鸿蒙开发寻找强劲、稳定、高效的硬件平台?RK3566鸿蒙开发板震撼登场!集高性能、全接口、强生态于一身,专为鸿蒙
    的头像 发表于 12-11 17:58 2825次阅读
    性能跃迁,鸿蒙<b class='flag-5'>开发</b>新纪元!<b class='flag-5'>凌</b>羽<b class='flag-5'>派</b><b class='flag-5'>RK</b>3566鸿蒙<b class='flag-5'>开发板</b>,开启全场景<b class='flag-5'>开发</b>之旅

    【迅为工业RK3568稳定可靠】itop-3568开发板驱动开发第4章驱动模块传参实验

    【迅为工业RK3568稳定可靠】itop-3568开发板驱动开发第4章驱动模块传参实验
    的头像 发表于 11-06 14:25 619次阅读
    【迅为工业<b class='flag-5'>RK</b>3568稳定可靠】itop-3568<b class='flag-5'>开发板</b>驱动<b class='flag-5'>开发</b>第4章驱动模块传参<b class='flag-5'>实验</b>

    如何移植EtherCAT Igh--基于米尔RK3576开发板

    本文将介绍基于米尔电子MYD-LR3576开发板(米尔基于瑞芯微RK3576开发板)的端移植EtherCATIgh方案的开发测试。摘自优秀
    的头像 发表于 09-26 08:04 1w次阅读
    如何移植EtherCAT Igh--基于米尔<b class='flag-5'>RK</b>3576<b class='flag-5'>开发板</b>

    【作品合集】飞嵌入式OK527N-C开发板测评

    T527N开发板试用】使用WiFi传输文件,烧写固件 【飞T527N开发板试用】7寸RGB屏幕适配与TP驱动 【飞
    发表于 09-22 15:54

    RK3506开发板Linux开发板极致性价比之选

    RK3506开发板Linux开发板极致性价比之选瑞芯微RK3506开发板,3核Cortex-A7@1.5GHz+Cortex-M0,Linu
    的头像 发表于 09-11 16:26 4073次阅读
    <b class='flag-5'>RK</b>3506<b class='flag-5'>开发板</b>Linux<b class='flag-5'>开发板</b>极致性价比之选

    迅为RK3568开发板模型推理测试实战LPRNet 车牌识别

    迅为RK3568开发板模型推理测试实战LPRNet 车牌识别
    的头像 发表于 08-25 14:55 1673次阅读
    迅为<b class='flag-5'>RK</b>3568<b class='flag-5'>开发板</b>模型推理测试实战LPRNet 车牌识别

    RK3568 EVB开发板 深度休眠与快速醒的工作流程

    RK3568 EVB开发板关于深度休眠和唤醒流程的分析
    的头像 发表于 07-22 09:49 1184次阅读
    <b class='flag-5'>RK</b>3568 EVB<b class='flag-5'>开发板</b> 深度休眠与快速醒的工作流程

    RK3568开发板暗藏32位兼容开关?飞嵌入式带你一键解锁!

    RK3568是一款64位处理器,飞嵌入式为其提供的交叉编译器也是64位的,然而部分用户可能需要在RK3568开发板上运行32位应用。本文将详细阐述如何使用32位交叉编译器,编译出32
    的头像 发表于 07-19 08:49 4661次阅读
    <b class='flag-5'>RK</b>3568<b class='flag-5'>开发板</b>暗藏32位兼容开关?飞<b class='flag-5'>凌</b>嵌入式带你一键解锁!

    睿擎RK3506J开发板开箱记录、初步调试

    睿擎基于RK3506J开发RK3506J是一款三核A7+M0的入门级工业MPU,由于其价位低,性能优异,近期收到热捧,各家都出了很多RK
    的头像 发表于 06-20 20:43 2785次阅读
    睿擎<b class='flag-5'>派</b><b class='flag-5'>RK</b>3506J<b class='flag-5'>开发板</b>开箱记录、初步调试

    迅为RK3562开发板Buildroot系统功能测试

    迅为RK3562开发板Buildroot系统功能测试
    的头像 发表于 06-13 13:46 2361次阅读
    迅为<b class='flag-5'>RK</b>3562<b class='flag-5'>开发板</b>Buildroot系统功能测试

    迅为RK3568开发板驱动指南GPIO子系统三级节点操作函数实验

    迅为RK3568开发板驱动指南GPIO子系统三级节点操作函数实验
    的头像 发表于 05-26 15:39 1745次阅读
    迅为<b class='flag-5'>RK</b>3568<b class='flag-5'>开发板</b>驱动指南GPIO子系统三级节点操作函数<b class='flag-5'>实验</b>