【鸿蒙智能硬件】(四)基于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

相关推荐
周淳APP2 小时前
【HTTP相关及RESTful】风萧萧兮易水寒之壮士学习不复返
前端·javascript·网络·网络协议·http·restful·jsonp
萝卜白菜。2 小时前
http头Location是相对路径还是绝对路径
网络·网络协议·http
Swift社区2 小时前
鸿蒙 ArkUI 项目为什么容易变成“巨型页面文件”?
华为·harmonyos
韭菜张师傅2 小时前
Ceph环境完全重置指南:彻底清理集群环境
java·网络·ceph
周淳APP2 小时前
【计算机网络之HTTP、TCP、UDP、HTTPS、Socket网络连接】
前端·javascript·网络·网络协议·http·前端框架
博语小屋2 小时前
HTTP详解
网络·网络协议·http
XiaoLeisj2 小时前
Android 网络编程入门到实战:HttpURLConnection、JSON 处理、OkHttp 与 Retrofit2
android·网络·okhttp·json·gson·retrofit2·jsonobjecy
Saniffer_SH2 小时前
【高清视频】介绍一个自动化测试辅助小工具 - 上下电测试适用于电脑冷启动的掉电盒
网络·人工智能·驱动开发·嵌入式硬件·测试工具·计算机外设·压力测试
JNU freshman2 小时前
Ceph 18(Reef)生产级调优手册
网络·ceph
快敲啊死鬼2 小时前
机试day5
算法·华为od·华为