【鸿蒙智能硬件】(四)基于Hi3861的网络开发

目录

六.基于Hi3861的网络开发

LwIP概述

lwIP支持的特性

lwIP小型化的特性

TCP客户端应用开发

TCP/IP的通信流程

TCP客户端应用开发流程

[Lwip API函数详解](#Lwip API函数详解)

TCP客户端示例代码

1.引入头文件及wifi模块的驱动文件

2.编写tcp/ip客户端程序

3.编写运行的主文件main.c

4.编写模块构建配置BUILD.gn(code4/BUILD.gn)

使用TCP/IP编程,上报环境监测数据到服务器**

服务器使用java进行编写

编写java服务器端应用

1.构建业务

改进

2.构建主运行类并启动多线程

构建环境监测的客户端应用

2.构建模块BUILD.gn(code4/BUILD.gn)

3.注册模块到app子系统(app/BUILD.gn)

4.编译下载烧写运行


六.基于Hi3861的网络开发

LwIP概述

LwIP是一个Light Weight (轻型)的TCP/IP协议栈,是 TCP/IP 协议套件的小型独立实现,有无操作系统的支持都可以运行。LwIP实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用,它只需十几KB的RAM和40K左右的ROM就可以运行,这使LwIP协议栈适合在低端的嵌入式系统中使用。

lwIP是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈,现在由全球开发人员网络开发和维护。

lwIP支持的特性

  • 网际协议版本4(IPv4:Internet Protocol version 4)
  • 互联网控制消息协议(ICMP:Internet Control Message Protocol)
  • 用户数据报协议(UDP:User Datagram Protocol)
  • 传输控制协议(TCP:Transmission Control Protocol)
  • 域名解析器(DNS:Domain Name System)客户端
  • 动态主机配置协议(DHCP)客户端和服务器
  • RFC 2131偏差标准
  • 以太网地址解析协议(ARP)
  • 因特网组管理协议(IGMP)
  • socket接口类型
  • TCP选择性确认选项

lwIP不支持的特性或协议如下:

PPPoS/PPPOE

SNMP代理(目前,lwIP仅支持私有MIB)

通过多个网络接口实现IP转发

路由功能(仅支持终端设备功能)

lwIP小型化的特性

简单网络时间协议(Simple Network Time Protocol)是一种基于包交换、可变延迟数据网络

的计算机系统之间的时钟同步网络协议。lwIP支持基于RFC 2030协议的SNTP版本4。

lwIP支持AutoIP模块。

lwIP提供设置Wi-Fi驱动状态的接口

lwIP提供设置Wi-Fi驱动状态为lwIP栈的接口。

lwIP在SOCK_RAW上提供PF_PACKET选项。

TCP客户端应用开发

TCP/IP的通信流程

服务器与客户端的交互是通过Socket套接字进行通信。可以把Socket理解为管道或者桥梁

TCP客户端应用开发流程

调用socket,分配套接字并返回文件描述符sockfd

调用connect,向TCP服务器发送连接请求

调用send,发送数据给TCP服务器

调用recv,接收来自TCP服务器的数据

调用closesocket,断开与服务器的连接

Lwip API函数详解

int socket ( int domain, int type, int protocol)---返回值成功失败值

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)

int send (int socketfd, void *buffer , size_t length, int flags)

int recv (int socketfd, void *buffer , size_t length, int flags)

int closesocket ( int socketfd )

TCP客户端示例代码

1.引入头文件及wifi模块的驱动文件

修改wifi_utils.c,更改wifi账号和密码

cs 复制代码
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "ohos_init.h"
#include "cmsis_os2.h"
#include "wifi_device.h"
#include "lwip/netifapi.h"
#include "lwip/api_shell.h"

void connect_wifi(void)
{

    WifiErrorCode errCode;
    WifiDeviceConfig apConfig = {};
    int netId = -1;

    // setup your AP params
    // strcpy(apConfig.ssid, "TP-LINK_888");        //
    // strcpy(apConfig.preSharedKey, "Cto888.com"); //密码
    strcpy(apConfig.ssid, "wifi账号");       //wifi账号
    //strcpy(apConfig.bssid, "f4:2a:7d:14:cf:da");       //74-E5-F9-BB-19-6C
    //strcpy(apConfig.bssid, "74:E5:F9:BB:19:6C");
    strcpy(apConfig.preSharedKey, "wifi密码"); //密码
    apConfig.securityType = WIFI_SEC_TYPE_PSK;

    errCode = EnableWifi();
    errCode = AddDeviceConfig(&apConfig, &netId);

    errCode = ConnectTo(netId);
    printf("ConnectTo(%d): %d\r\n", netId, errCode);
    usleep(1000 * 1000);

    struct netif *iface = netifapi_netif_find("wlan0");
    if (iface)
    {
        err_t ret = netifapi_dhcp_start(iface);
        printf("netifapi_dhcp_start: %d\r\n", ret);

        usleep(2000 * 1000);
        ret = netifapi_netif_common(iface, dhcp_clients_info_show, NULL);
        printf("netifapi_netif_common: %d\r\n", ret);
    }
}
2.编写tcp/ip客户端程序

tcpclientdemo.h

cs 复制代码
#ifndef TCP_CLIENT
#define TCP_CLIENT

void conent_tcp_server(const char* host, unsigned short port);
#endif

tcpclientdemo.c

cs 复制代码
#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "hi_wifi_api.h"
#include "lwip/ip_addr.h"
#include "lwip/netifapi.h"
#include "lwip/sockets.h"

static char request[] = "HelloServer";
static char response[128] = "";

void conent_tcp_server(const char *host, unsigned short port)
{
    ssize_t retval = 0;
    int sockfd = socket(AF_INET, SOCK_STREAM, 0); // TCP socket

    struct sockaddr_in serverAddr = {0};
    serverAddr.sin_family = AF_INET;   // AF_INET表示IPv4协议
    serverAddr.sin_port = htons(port); // 端口号,从主机字节序转为网络字节序
    if (inet_pton(AF_INET, host, &serverAddr.sin_addr) <= 0)
    { // 将主机IP地址从"点分十进制"字符串 转化为 标准格式(32位整数)
        printf("inet_pton failed!\r\n");
        goto do_cleanup;
    }

    // 尝试和目标主机建立连接,连接成功会返回0 ,失败返回 -1
    if (connect(sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0)
    {
        printf("connect failed!\r\n");
        goto do_cleanup;
    }
    printf("connect to server %s success!\r\n", host);

    // 建立连接成功之后,这个TCP socket描述符 ------ sockfd 就具有了 "连接状态",发送、接收 对端都是 connect 参数指定的目标主机和端口
    retval = send(sockfd, request, sizeof(request), 0);
    if (retval < 0)
    {
        printf("send request failed!\r\n");
        goto do_cleanup;
    }
    printf("send request{%s} %ld to server done!\r\n", request, retval);

    retval = recv(sockfd, response, sizeof(response), 0);
    if (retval <= 0)
    {
        printf("send response from server failed or done, %ld!\r\n", retval);
        goto do_cleanup;
    }
    response[retval] = '\0';
    printf("recv response{%s} %ld from server done!\r\n", response, retval);

do_cleanup:
    printf("do_cleanup...\r\n");
}
3.编写运行的主文件main.c
cs 复制代码
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "ohos_init.h"
#include "cmsis_os2.h"
#include "wifi_device.h"
#include "lwip/netifapi.h"
#include "lwip/api_shell.h"
#include "wifi_utils.h"
#include "tcpclientdemo.h"

static void NetWorkTask(void *arg)
{
    (void)arg;
    connect_wifi(); //连接AP
    printf("begin demo\n");
    unsigned short port = 5001;
    conent_tcp_server("192.168.43.246", port);//连接服务器,ip地址和端口号

    
}

static void NetWorkDemo(void)
{
    osThreadAttr_t attr;

    attr.name = "NetWorkTask";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 10240;
    attr.priority = osPriorityNormal;

    if (osThreadNew(NetWorkTask, NULL, &attr) == NULL)
    {
        printf("[NetWorkDemo] Falied to create WifiConnectTask!\n");
    }
}

APP_FEATURE_INIT(NetWorkDemo);
4.编写模块构建配置BUILD.gn(code4/BUILD.gn)
cs 复制代码
static_library("wifiappdemo") {
    sources = [
        "main.c",
        "wifi_utils.c",
        "tcpclientdemo.c",
        #"oled_ssd1306.c",
        #"aht20.c",         
       ]
     include_dirs = [
        "//utils/native/lite/include",
        "//kernel/liteos_m/components/cmsis/2.0",
        "//base/iot_hardware/interfaces/kits/wifiiot_lite",
        "//vendor/hisi/hi3861/hi3861/third_party/lwip_sack/include",
        "//foundation/communication/interfaces/kits/wifi_lite/wifiservice",
        
    ]
}

5.注册模块到app子系统(app/BUILD.gn)

cs 复制代码
#youdianjike/code1是模块的工程相对路径
#helloapp是添加的模块,指向./applications/sample/wifi-iot/app/youdianjike/code1/BUILD.gn中的static_library("helloapp")。

import("//build/lite/config/component/lite_component.gni")

lite_component("app") {
    features = [
        "youdianjike/code4:wifiappdemo",
    ]
}

6.编译下载烧写运行测试

使用TCP/IP编程,上报环境监测数据到服务器**

服务器使用java进行编写

数据库使用MySql进行存储,数据名为envdb

表名:env

字段:id--编号,主键自增,

Tmp--温度 字符串varchar(50),

Him--湿度字符串varchar(50),

Gan--气味字符串varchar(50),

Cdate--日期--date

cs 复制代码
#新建数据库envdb
CREATE DATABASE envdb;

#打开数据库
USE envdb;

#创建环境监测表
CREATE TABLE env(
  id INT PRIMARY KEY AUTO_INCREMENT COMMENT '主键自增',
  tmp VARCHAR(50) COMMENT '温度值',
  him VARCHAR(50) COMMENT '湿度值',
  gan VARCHAR(50) COMMENT '气味值',
  cdate DATE COMMENT '日期'
);

SELECT * FROM env;

编写java服务器端应用

1.构建业务

EnvService.java

javascript 复制代码
package com.service;
import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;

public class EnvService implements Runnable{
    private Socket socket;
    private InputStream in;//输入流对象
    private OutputStream os;//输出流对象

    public EnvService(Socket socket){
        this.socket=socket;
        try {
            this.in=this.socket.getInputStream();//通过套接字获取输入流对象
            this.os=this.socket.getOutputStream();//通过套接字获取输出流对象
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    @Override
    public void run() {
        try {
            //接收客户端传递的数据===================
            //1.定义要接受的字节数组
            byte[] b=new byte[1024];
            //2.使用输入流对象获取套接字中的字节流传递给字节数组
            in.read(b);
            //3.将字节数组转为字符串
            String msg=new String(b,"UTF-8");
            //4.输出客户端传递的字节信息
            System.out.println("客户端传递的信息:"+msg.trim());
            //5.结束套接字输入
            this.socket.shutdownInput();
            //===========结束输入=======================
            //=======向客户端发送响应=====================
            //1定义要发送的字符串信息
            String rst="serverok";
            //2写出消息
            os.write(rst.getBytes(StandardCharsets.UTF_8));
            os.flush();//3.清空缓冲
            //4.结束发送
            this.socket.shutdownOutput();
            //============响应结束==========================
        } catch (IOException e) {
            throw new RuntimeException(e);
        }


    }
}
改进
javascript 复制代码
package com.service;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.StandardCharsets;

public class EnvService implements Runnable{
    private Socket socket;
    private InputStream in;//输入流对象
    private OutputStream os;//输出流对象

    public EnvService(Socket socket){
        this.socket=socket;
        try {
            this.in=this.socket.getInputStream();//通过套接字获取输入流对象
            this.os=this.socket.getOutputStream();//通过套接字获取输出流对象
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }
/*
    @Override
    public void run() {
        try {
            //接收客户端传递的数据===================
            //1.定义要接受的字节数组
            byte[] b=new byte[1024];
            //2.使用输入流对象获取套接字中的字节流传递给字节数组
            in.read(b);
            //3.将字节数组转为字符串
            String msg=new String(b,"UTF-8");
            //4.输出客户端传递的字节信息
            System.out.println("客户端传递的信息:"+msg.trim());
            //5.结束套接字输入
            this.socket.shutdownInput();
            //===========结束输入=======================
            //=======向客户端发送响应=====================
            //1定义要发送的字符串信息
            String rst="serverok";
            //2写出消息
            os.write(rst.getBytes(StandardCharsets.UTF_8));
            os.flush();//3.清空缓冲
            //4.结束发送
            this.socket.shutdownOutput();
            //============响应结束==========================
        } catch (IOException e) {
            throw new RuntimeException(e);
        }


    }

 */
/*
    @Override
    public void run() {
        try {
            while (true) {
                // 接收客户端传递的数据
                byte[] b = new byte[1024];
                int len = in.read(b);
                if (len == -1) {
                    // 客户端关闭连接
                    break;
                }
                // 将字节数组转为字符串
                String msg = new String(b, 0, len, "UTF-8");
                // 输出客户端传递的字节信息
                System.out.println("客户端传递的信息:" + msg.trim());

                // 向客户端发送响应
                String rst = "serverok";
                os.write(rst.getBytes(StandardCharsets.UTF_8));
                os.flush();
            }
        } catch (IOException e) {
            System.out.println("客户端连接关闭");
        } finally {
            try {
                if (in != null) in.close();
                if (os != null) os.close();
                if (socket != null) socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
*/
@Override
public void run() {
    try {
        while (true) {
            byte[] b = new byte[1024];
            int len = in.read(b);
            if (len == -1) {
                break;
            }

            // 处理接收到的数据,去除NULL字符和乱码
            String msg = new String(b, 0, len, "UTF-8");
            // 去除NULL字符
            msg = msg.replaceAll("\\x00", "");
            // 只保留数字、逗号和小数点
            msg = msg.replaceAll("[^0-9.,]", "");
            System.out.println("客户端传递的信息:" + msg);

            // 向客户端发送响应
            String rst = "serverok";
            os.write(rst.getBytes(StandardCharsets.UTF_8));
            os.flush();
        }
    } catch (IOException e) {
        System.out.println("客户端连接关闭");
    } finally {
        try {
            if (in != null) in.close();
            if (os != null) os.close();
            if (socket != null) socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

}
2.构建主运行类并启动多线程

MainServer.java

javascript 复制代码
package com.server;
import java.io.*;
import java.util.*;
import java.net.*;
import com.service.*;
import com.sun.tools.javac.Main;

public class MainServer {
    private ServerSocket serverSocket;//服务器Socket对象
    private Socket socket;
    public MainServer(){
        try {
            //创建服务器的套接字
            serverSocket=new ServerSocket(5001);
            System.out.println("服务器已经启动请勿关闭......");
            while (true){
                this.socket=this.serverSocket.accept();//接受并监听客户端请求
                //创建环境监测的服务对象
                EnvService envService=new EnvService(this.socket);
                //创建线程对象
                Thread th=new Thread(envService);
                //启动线程
                th.start();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {
        //创建服务器对象
        new MainServer();
    }
}

启动服务器,测试是否能拿到客户端的消息:

出现HelloServer表示已经获取鸿蒙主板客户端传递的消息

构建环境监测的客户端应用

1.编写客户端文件

编写前,先将以前的文件驱动复制到code4工程目录下

aht20.c

aht20.h

oled_fonts.h

oled_ssd1306.c

oled_ssd1306.h

wifi_app.c

wifi_utilis.c

wifi_utils.h


envclientdemo.h

cs 复制代码
#ifndef TCP_CLIENT
#define TCP_CLIENT

void conent_tcp_server(const char* host, unsigned short port);
#endif

envclientdemo.c

cs 复制代码
#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "hi_wifi_api.h"
#include "lwip/ip_addr.h"
#include "lwip/netifapi.h"
#include "lwip/sockets.h"

//传感器需要的头文件
#include "wifiiot_i2c.h"
#include "wifiiot_gpio.h"
#include "wifiiot_gpio_ex.h"
#include "wifiiot_errno.h"
#include "aht20.h"
#include "wifiiot_adc.h"
#include "oled_ssd1306.h"

#define GAS_SENSOR_CHAN_NAME WIFI_IOT_ADC_CHANNEL_5//传感器通道
#define AHT20_BAUDRATE 400 * 1000
#define AHT20_I2C_IDX WIFI_IOT_I2C_IDX_0

static char request[] = "HelloServer";
static char response[128] = "";

//初始化I2C
void init(void)
{
    GpioInit();
    OledInit();//初始化OLED    
    IoSetFunc(WIFI_IOT_IO_NAME_GPIO_13, WIFI_IOT_IO_FUNC_GPIO_13_I2C0_SDA);
    IoSetFunc(WIFI_IOT_IO_NAME_GPIO_14, WIFI_IOT_IO_FUNC_GPIO_14_I2C0_SCL);
    I2cInit(AHT20_I2C_IDX, AHT20_BAUDRATE);
}

void conent_tcp_server(const char *host, unsigned short port)
{
    ssize_t retval = 0;
    int sockfd = socket(AF_INET, SOCK_STREAM, 0); // TCP socket

    struct sockaddr_in serverAddr = {0};
    serverAddr.sin_family = AF_INET;   // AF_INET表示IPv4协议
    serverAddr.sin_port = htons(port); // 端口号,从主机字节序转为网络字节序

   



    if (inet_pton(AF_INET, host, &serverAddr.sin_addr) <= 0)
    { // 将主机IP地址从"点分十进制"字符串 转化为 标准格式(32位整数)
        printf("inet_pton failed!\r\n");
        goto do_cleanup;
    }

    // 尝试和目标主机建立连接,连接成功会返回0 ,失败返回 -1
    if (connect(sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0)
    {
        printf("connect failed!\r\n");
        goto do_cleanup;
    }
    printf("connect to server %s success!\r\n", host);

     //======================处理传感器的数据================================================
     init();//调用设备初始化
    uint32_t retval = 0;//返回值
    unsigned short data = 0;//读取的气味传感器数据
    float humidity = 0.0f;//湿度值
    float temperature = 0.0f;//温度值
    OledFillScreen(0x00);//清空屏幕,填充背景颜色
    while (WIFI_IOT_SUCCESS != AHT20_Calibrate()){//AHT20校准
        printf("AHT20 sensor init failed!\r\n");
        sleep(5);//等待1ms
    }
    //循环获取温湿度传感器的数据
    while (1){
        retval = AHT20_StartMeasure();//触发AHT20测量
        printf("retval:%d\n", retval);
        if (retval != WIFI_IOT_SUCCESS){//触发AHT20测量失败
            printf("trigger measure failed!\r\n");
            sleep(5);
        }else {
             //读取可燃气体值
            //.equ_model 4: 12位分辨率,1.2V参考电压
            //.cur_bais_default: 默认电流基准
            if (AdcRead(GAS_SENSOR_CHAN_NAME, &data, WIFI_IOT_ADC_EQU_MODEL_4, WIFI_IOT_ADC_CUR_BAIS_DEFAULT, 0) == WIFI_IOT_SUCCESS)
            {
                printf("qi wei value:%d\n", data);
            }
            //读取温湿度传感器的数据    
            retval = AHT20_GetMeasureResult(&temperature, &humidity);//获取AHT20测量结果
            printf("temp: %.2f,  humi: %.2f\n", temperature, humidity);//打印AHT20测量结果

            OledShowString(0, 0, "Env data:", 1);//在屏幕上显示字符串0列0行呈现字符信息
            //将温度值转为字符串
            char temp_str[10];
            snprintf(temp_str, sizeof(temp_str), "Temp: %.2f", temperature);
            OledShowString(0, 1, temp_str, 1);//在屏幕上显示字符串0列2行呈现字符信息
            //将湿度值转为字符串
            char humi_str[10];
            snprintf(humi_str, sizeof(humi_str), "Humi: %.2f", humidity);
            OledShowString(0, 2, humi_str, 1);//在屏幕上显示字符串0列2行呈现字符信息
            //将可燃气体值转为字符串
            char gas_str[10];
            snprintf(gas_str, sizeof(gas_str), "Gas: %d", data);
            OledShowString(0, 3, gas_str, 1);//在屏幕上显示字符串0列3行呈现字符信息
        }
        sleep(1);
        //拼接温度湿度气味传感器的值为字符串并使用,号分隔
        char env_data[32];
        snprintf(env_data, sizeof(env_data), "%.2f,%.2f,%d", temperature, humidity, data);
        // 建立连接成功之后,这个TCP socket描述符 ------ sockfd 就具有了 "连接状态",发送、接收 对端都是 connect 参数指定的目标主机和端口
        retval = send(sockfd, env_data, sizeof(env_data), 0);
        if (retval < 0)
        {
            printf("send request failed!\r\n");
            goto do_cleanup;
        }
        printf("send env_data:{%s} %ld to server done!\r\n", env_data, retval);
        //接收服务器发回的响应
        retval = recv(sockfd, response, sizeof(response), 0);
        if (retval <= 0)
        {
            printf("send response from server failed or done, %ld!\r\n", retval);
            goto do_cleanup;
        }
        response[retval] = '\0';
        printf("recv response{%s} %ld from server done!\r\n", response, retval);
    }

    //=====================================================================================


   

    
    

do_cleanup:
    printf("do_cleanup...\r\n");
}

改进1

cs 复制代码
#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "hi_wifi_api.h"
#include "lwip/ip_addr.h"
#include "lwip/netifapi.h"
#include "lwip/sockets.h"

//传感器需要的头文件
#include "wifiiot_i2c.h"
#include "wifiiot_gpio.h"
#include "wifiiot_gpio_ex.h"
#include "wifiiot_errno.h"
#include "aht20.h"
#include "wifiiot_adc.h"
#include "oled_ssd1306.h"

#define GAS_SENSOR_CHAN_NAME WIFI_IOT_ADC_CHANNEL_5//传感器通道
#define AHT20_BAUDRATE 400 * 1000
#define AHT20_I2C_IDX WIFI_IOT_I2C_IDX_0

//static char request[] = "HelloServer";
static char response[128] = "";

//初始化I2C
void init(void)
{
    GpioInit();
    OledInit();//初始化OLED    
    IoSetFunc(WIFI_IOT_IO_NAME_GPIO_13, WIFI_IOT_IO_FUNC_GPIO_13_I2C0_SDA);
    IoSetFunc(WIFI_IOT_IO_NAME_GPIO_14, WIFI_IOT_IO_FUNC_GPIO_14_I2C0_SCL);
    I2cInit(AHT20_I2C_IDX, AHT20_BAUDRATE);
}

void conent_tcp_server(const char *host, unsigned short port)
{
    ssize_t retval = 0;
    int sockfd = socket(AF_INET, SOCK_STREAM, 0); // TCP socket

    struct sockaddr_in serverAddr = {0};
    serverAddr.sin_family = AF_INET;   // AF_INET表示IPv4协议
    serverAddr.sin_port = htons(port); // 端口号,从主机字节序转为网络字节序

   



    if (inet_pton(AF_INET, host, &serverAddr.sin_addr) <= 0)
    { // 将主机IP地址从"点分十进制"字符串 转化为 标准格式(32位整数)
        printf("inet_pton failed!\r\n");
        goto do_cleanup;
    }

    // 尝试和目标主机建立连接,连接成功会返回0 ,失败返回 -1
    if (connect(sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0)
    {
        printf("connect failed!\r\n");
        goto do_cleanup;
    }
    printf("connect to server %s success!\r\n", host);

     //======================处理传感器的数据================================================
     init();//调用设备初始化
    int retclientval = 0;//返回值
    unsigned short data = 0;//读取的气味传感器数据
    float humidity = 0.0f;//湿度值
    float temperature = 0.0f;//温度值
    OledFillScreen(0x00);//清空屏幕,填充背景颜色
    while (WIFI_IOT_SUCCESS != AHT20_Calibrate()){//AHT20校准
        printf("AHT20 sensor init failed!\r\n");
        sleep(5);//等待1ms
    }
    //循环获取温湿度传感器的数据
    while (1){
        retval = AHT20_StartMeasure();//触发AHT20测量
        printf("retval:%d\n", retval);
        if (retval != WIFI_IOT_SUCCESS){//触发AHT20测量失败
            printf("trigger measure failed!\r\n");
            sleep(5);
        }else {
             //读取可燃气体值
            //.equ_model 4: 12位分辨率,1.2V参考电压
            //.cur_bais_default: 默认电流基准
            if (AdcRead(GAS_SENSOR_CHAN_NAME, &data, WIFI_IOT_ADC_EQU_MODEL_4, WIFI_IOT_ADC_CUR_BAIS_DEFAULT, 0) == WIFI_IOT_SUCCESS)
            {
                printf("qi wei value:%d\n", data);
            }
            //读取温湿度传感器的数据    
            retval = AHT20_GetMeasureResult(&temperature, &humidity);//获取AHT20测量结果
            printf("temp: %.2f,  humi: %.2f\n", temperature, humidity);//打印AHT20测量结果

            OledShowString(0, 0, "Env data:", 1);//在屏幕上显示字符串0列0行呈现字符信息
            //将温度值转为字符串
            char temp_str[10];
            snprintf(temp_str, sizeof(temp_str), "Temp: %.2f", temperature);
            OledShowString(0, 1, temp_str, 1);//在屏幕上显示字符串0列2行呈现字符信息
            //将湿度值转为字符串
            char humi_str[10];
            snprintf(humi_str, sizeof(humi_str), "Humi: %.2f", humidity);
            OledShowString(0, 2, humi_str, 1);//在屏幕上显示字符串0列2行呈现字符信息
            //将可燃气体值转为字符串
            char gas_str[10];
            snprintf(gas_str, sizeof(gas_str), "Gas: %d", data);
            OledShowString(0, 3, gas_str, 1);//在屏幕上显示字符串0列3行呈现字符信息
        }
        sleep(1);
        //拼接温度湿度气味传感器的值为字符串并使用,号分隔
        char env_data[32];
        snprintf(env_data, sizeof(env_data), "%.2f,%.2f,%d", temperature, humidity, data);

        // 建立连接成功之后,这个TCP socket描述符 ------ sockfd 就具有了 "连接状态",发送、接收 对端都是 connect 参数指定的目标主机和端口
        retclientval = send(sockfd, env_data, sizeof(env_data), 0);
        if (retclientval < 0)
        {
            printf("send request failed!\r\n");
            goto do_cleanup;
        }
        printf("send env_data:{%s} %ld to server done!\r\n", env_data, retclientval);
        //接收服务器发回的响应
        retclientval = recv(sockfd, response, sizeof(response), 0);
        if (retclientval <= 0)
        {
            printf("send response from server failed or done, %ld!\r\n", retclientval);
            goto do_cleanup;
        }
        response[retclientval] = '\0';
        printf("recv response{%s} %ld from server done!\r\n", response, retclientval);



        do_cleanup:
            printf("do_cleanup...\r\n");
    }

    //=====================================================================================


   

    
    


}

改进2

cs 复制代码
#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "hi_wifi_api.h"
#include "lwip/ip_addr.h"
#include "lwip/netifapi.h"
#include "lwip/sockets.h"

//传感器需要的头文件
#include "wifiiot_i2c.h"
#include "wifiiot_gpio.h"
#include "wifiiot_gpio_ex.h"
#include "wifiiot_errno.h"
#include "aht20.h"
#include "wifiiot_adc.h"
#include "oled_ssd1306.h"

#define GAS_SENSOR_CHAN_NAME WIFI_IOT_ADC_CHANNEL_5//传感器通道
#define AHT20_BAUDRATE 400 * 1000
#define AHT20_I2C_IDX WIFI_IOT_I2C_IDX_0

//static char request[] = "HelloServer";
static char response[128] = "";

//初始化I2C
void init(void)
{
    GpioInit();
    OledInit();//初始化OLED    
    IoSetFunc(WIFI_IOT_IO_NAME_GPIO_13, WIFI_IOT_IO_FUNC_GPIO_13_I2C0_SDA);
    IoSetFunc(WIFI_IOT_IO_NAME_GPIO_14, WIFI_IOT_IO_FUNC_GPIO_14_I2C0_SCL);
    I2cInit(AHT20_I2C_IDX, AHT20_BAUDRATE);
}

void conent_tcp_server(const char *host, unsigned short port)
{
    ssize_t retval = 0;
    int sockfd = socket(AF_INET, SOCK_STREAM, 0); // TCP socket

    struct sockaddr_in serverAddr = {0};
    serverAddr.sin_family = AF_INET;   // AF_INET表示IPv4协议
    serverAddr.sin_port = htons(port); // 端口号,从主机字节序转为网络字节序

   



    if (inet_pton(AF_INET, host, &serverAddr.sin_addr) <= 0)
    { // 将主机IP地址从"点分十进制"字符串 转化为 标准格式(32位整数)
        printf("inet_pton failed!\r\n");
        goto do_cleanup;
    }

    // 尝试和目标主机建立连接,连接成功会返回0 ,失败返回 -1
    if (connect(sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0)
    {
        printf("connect failed!\r\n");
        goto do_cleanup;
    }
    printf("connect to server %s success!\r\n", host);

     //======================处理传感器的数据================================================
     init();//调用设备初始化
    int retclientval = 0;//返回值
    unsigned short data = 0;//读取的气味传感器数据
    float humidity = 0.0f;//湿度值
    float temperature = 0.0f;//温度值
    OledFillScreen(0x00);//清空屏幕,填充背景颜色
    while (WIFI_IOT_SUCCESS != AHT20_Calibrate()){//AHT20校准
        printf("AHT20 sensor init failed!\r\n");
        sleep(5);//等待1ms
    }
    //循环获取温湿度传感器的数据
    while (1){
        retval = AHT20_StartMeasure();//触发AHT20测量
        printf("retval:%d\n", retval);
        if (retval != WIFI_IOT_SUCCESS){//触发AHT20测量失败
            printf("trigger measure failed!\r\n");
            sleep(5);
        }else {
             //读取可燃气体值
            //.equ_model 4: 12位分辨率,1.2V参考电压
            //.cur_bais_default: 默认电流基准
            if (AdcRead(GAS_SENSOR_CHAN_NAME, &data, WIFI_IOT_ADC_EQU_MODEL_4, WIFI_IOT_ADC_CUR_BAIS_DEFAULT, 0) == WIFI_IOT_SUCCESS)
            {
                printf("qi wei value:%d\n", data);
            }
            //读取温湿度传感器的数据    
            retval = AHT20_GetMeasureResult(&temperature, &humidity);//获取AHT20测量结果
            printf("temp: %.2f,  humi: %.2f\n", temperature, humidity);//打印AHT20测量结果

            OledShowString(0, 0, "Env data:", 1);//在屏幕上显示字符串0列0行呈现字符信息
            //将温度值转为字符串
            char temp_str[10];
            snprintf(temp_str, sizeof(temp_str), "Temp: %.2f", temperature);
            OledShowString(0, 1, temp_str, 1);//在屏幕上显示字符串0列2行呈现字符信息
            //将湿度值转为字符串
            char humi_str[10];
            snprintf(humi_str, sizeof(humi_str), "Humi: %.2f", humidity);
            OledShowString(0, 2, humi_str, 1);//在屏幕上显示字符串0列2行呈现字符信息
            //将可燃气体值转为字符串
            char gas_str[10];
            snprintf(gas_str, sizeof(gas_str), "Gas: %d", data);
            OledShowString(0, 3, gas_str, 1);//在屏幕上显示字符串0列3行呈现字符信息
        }
        sleep(1);
        //拼接温度湿度气味传感器的值为字符串并使用,号分隔
        char env_data[32];
        snprintf(env_data, sizeof(env_data), "%.2f,%.2f,%d", temperature, humidity, data);

        // 建立连接成功之后,这个TCP socket描述符 ------ sockfd 就具有了 "连接状态",发送、接收 对端都是 connect 参数指定的目标主机和端口
        //retclientval = send(sockfd, env_data, sizeof(env_data), 0);
        // 确保env_data是正确终止的字符串
        // 计算有效长度(不包含终止符)
        int data_len = strlen(env_data);
        // 只发送有效长度的数据
        retclientval = send(sockfd, env_data, data_len, 0);


        if (retclientval < 0)
        {
            printf("send request failed!\r\n");
            goto do_cleanup;
        }

        //printf("send env_data:{%s} %ld to server done!\r\n", env_data, retclientval);
      
        printf("send env_data:{%s} %d to server done!\r\n", env_data, data_len);



        //接收服务器发回的响应
        retclientval = recv(sockfd, response, sizeof(response), 0);
        if (retclientval <= 0)
        {
            printf("send response from server failed or done, %ld!\r\n", retclientval);
            goto do_cleanup;
        }
        response[retclientval] = '\0';
        printf("recv response{%s} %ld from server done!\r\n", response, retclientval);



        do_cleanup:
            printf("do_cleanup...\r\n");
    }

    //=====================================================================================


   

    
    


}
2.构建模块BUILD.gn(code4/BUILD.gn)
cs 复制代码
static_library("wifiappdemo") {
    sources = [
        "main.c",
        "wifi_utils.c",
        "envclientdemo.c",
        "oled_ssd1306.c",
        "aht20.c",         
       ]
     include_dirs = [
        "//utils/native/lite/include",
        "//kernel/liteos_m/components/cmsis/2.0",
        "//base/iot_hardware/interfaces/kits/wifiiot_lite",
        "//vendor/hisi/hi3861/hi3861/third_party/lwip_sack/include",
        "//foundation/communication/interfaces/kits/wifi_lite/wifiservice",
        
    ]
}
3.注册模块到app子系统(app/BUILD.gn)
cs 复制代码
import("//build/lite/config/component/lite_component.gni")

lite_component("app") {
    features = [
        "youdianjike/code4:wifiappdemo",
    ]
}

修改main.c

cs 复制代码
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "ohos_init.h"
#include "cmsis_os2.h"
#include "wifi_device.h"
#include "lwip/netifapi.h"
#include "lwip/api_shell.h"
#include "wifi_utils.h"
#include "envclientdemo.h"


static void NetWorkTask(void *arg)
{
    (void)arg;
    connect_wifi(); //连接AP
    printf("begin demo\n");
    unsigned short port = 5001;
    conent_tcp_server("192.168.43.246", port);//连接服务器,ip地址和端口号

    
}

static void NetWorkDemo(void)
{
    osThreadAttr_t attr;

    attr.name = "NetWorkTask";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 10240;
    attr.priority = osPriorityNormal;

    if (osThreadNew(NetWorkTask, NULL, &attr) == NULL)
    {
        printf("[NetWorkDemo] Falied to create WifiConnectTask!\n");
    }
}

APP_FEATURE_INIT(NetWorkDemo);
4.编译下载烧写运行

改进结果1

改进结果2

相关推荐
不会写DN19 小时前
其实跨域问题是后端来解决的? CORS
服务器·网络·面试·go
Harvy_没救了19 小时前
【网络架构】Keepalived + LVS(DR) + MariaDB 双主备实践
网络·架构·lvs
大鹏说大话1 天前
SSL证书自动化的未来:ACME协议与Let’s Encrypt实践
网络·安全
被摘下的星星1 天前
网际协议(IP协议)
网络·tcp/ip
Huanzhi_Lin1 天前
Laya导出的鸿蒙NEXT工程目录说明
华为·harmonyos·鸿蒙·laya·deveco·devecostudio·layaair
积水成渊,蛟龙生焉1 天前
鸿蒙手势处理篇(滑动冲突、基础手势、组合手势)
华为·arkts·鸿蒙·滑动冲突·手势冲突·基础手势·组合手势
爱学习的小囧1 天前
ESXi VMkernel 端口 MTU 最佳设置详解
运维·服务器·网络·php·虚拟化
TechubNews1 天前
Base 发布首个独立 OP Stack 框架的网络升级 Azul,将是 L2 自主迭代的开端?
大数据·网络·人工智能·区块链·能源
多年小白1 天前
中科院 Ouroboros 晶圆级存算一体芯片深度解析
大数据·网络·人工智能·科技·ai
发光小北1 天前
IEC104 转 Modbus TCP 网关如何应用?
网络·网络协议·tcp/ip