目录
[Lwip API函数详解](#Lwip API函数详解)
4.编写模块构建配置BUILD.gn(code4/BUILD.gn)
2.构建模块BUILD.gn(code4/BUILD.gn)
六.基于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);
}
}
}
改进
javascriptpackage 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

