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

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

3天内不再提示

自制鸿蒙Neptune开发板实时更新温湿度到手机

OpenHarmony技术社区 来源:鸿蒙技术社区 作者:董昱 2021-09-28 09:26 次阅读

好久不见!最近在研究 OpenHarmony,经过一番折腾,终于打通了南向和北向开发。

如下:

自己做了一个鸿蒙开发板

搞定了 HT30 温湿度计的驱动

通过 UDP 广播数据

让我们一起看看效果吧!

自制的 Neptune 开发板实时更新温湿度到手机

这个是我自己做的鸿蒙开发板,里面的核心是 Neptune Wi-Fi 蓝牙模块,通过 IIC 通信连接了一块 0.96 寸的 OLED 显示屏以及一个 HT30 温湿度传感器。另外,这块开发板还包括 3 颗 LED 灯,以及相关的串口通信模块等。

看看这块 OLED 显示屏下面写的什么?

嘻嘻是的!Of course,I Still Love You!致敬一下 StarShip!当然,还有 Powered By OpenHarmony!这个必须有!

接下来,给大家介绍一下这个功能的整个实现过程。

设计开发板

开发板的设计参考了瑞和官方 Neptune 开发板的原理图。电源模块和串口通信模块基本没有什么改动。

原理图贡献给大家:

62b2e4d6-1fc2-11ec-82a8-dac502259ad0.png

这里的温度传感器模块用的是 HT30。然后,就是打样板了:

62fa9c0e-1fc2-11ec-82a8-dac502259ad0.png

真的很不容易,被我干翻的板子已经堆成堆了!唉,只能怪自己脑子进水设计失误,加上焊接技术有点弱。

设计应用程序

①关于 HT30 的驱动程序

由于官方提供的例程是 AHT20 的温度传感器的驱动。所以这里还需要针对 HT30 的数据手册对驱动程序做出一些修改。

看了一下数据手册。除了 HT30 的 I2C 的地址和 AHT20 不同,温湿度的数据读取模式也更加复杂,数据的位数也不同。

因此,设计 HT30 的 I2C 的通信时需要注意一下几个方面:

温度数据是由 16bit 的数据位和 8bit 的 CRC 位组成。湿度数据也是一样的。相比之下,AHT20 的温湿度数据都是 20bit,而且没有 CRC 校验。

HT30 可以开启 clock stretching 模式。这个模式开启与否和重复率的设置这个会影响到转换时间、精度和功耗。

根据这些差异,我自己对 AHT20 的驱动做出了一些修改,形成了 HT30 的驱动。

首先,设置一下 HT30 的地址:

#define HT30_DEVICE_ADDR 0x44#define HT30_READ_ADDR ((HT30_DEVICE_ADDR《《1)|0x1)#define HT30_WRITE_ADDR ((HT30_DEVICE_ADDR《《1)|0x0)

然后,设置 MSB 和 LSB。

#define HT30_CMD_MSB 0x24 // 关闭Clock stretching#define HT30_CMD_LSB 0x16 // 低重复率

这里用的是低重复率和关闭 Clock stretching,这是为了测试的时候让代码更加的简单。童鞋们需要根据自己的实际使用情况做出修改。

最后,设计开始测量和接受测量结果的代码:

// 开始测量uint32_t HT30_StartMeasure(void)

{

uint8_t clibrateCmd[] = {HT30_CMD_MSB, HT30_CMD_LSB}; 设置MSB和LSB

return HT30_Write(clibrateCmd, sizeof(clibrateCmd));

}

// 接收测量结果,拼接转换为标准值uint32_t HT30_GetMeasureResult(float* temp, float* humi)

{

uint32_t retval = 0, i = 0;

if (temp == NULL || humi == NULL) {

return WIFI_IOT_FAILURE;

}

// 获得的返回数据

uint8_t buffer[HT30_STATUS_RESPONSE_MAX];

memset(&buffer, 0x0, sizeof(buffer));

for (i = 0; i 《 HT30_MAX_RETRY; i++) {

osDelay(HT30_MEASURE_TIME);

retval = HT30_Read(buffer, sizeof(buffer)); // recv status command result

if (retval == WIFI_IOT_SUCCESS) {

break;

}

printf(“HT30 device busy, retry %d/%d!

”, i, HT30_MAX_RETRY);

}

//

if (i 》= HT30_MAX_RETRY) {

printf(“HT30 device always busy!

”);

return WIFI_IOT_FAILURE;

}

// 获得温度数据

uint32_t tempRaw = buffer[0];

tempRaw = (tempRaw 《《 8) | buffer[1];

*temp = tempRaw / (float)HT30_RESOLUTION * 175 - 45;

// 获得湿度数据

uint32_t humiRaw = buffer[3];

humiRaw = (humiRaw 《《 8) | buffer[4];

*humi = humiRaw / (float)HT30_RESOLUTION * 100;

printf(“humi = %04X, %f, temp= %04X, %f

”, humiRaw, *humi, tempRaw, *temp);

return WIFI_IOT_SUCCESS;

}

这里的温度和湿度的转化公式为:

这样驱动程序就设计好了。

②关于 OLED 的驱动

这里用的是 0.92 寸的 OLED 屏幕,这块屏幕在 Hi3861 的代码中是用现成的驱动程序的。所以就不需要自己设计了。

分辨率为 128*64。在官方的驱动程序中,这块 OLED 有两种显示模式:8*16 点阵和 6*8 的点阵。

③选用 TCP 还是 UDP 连接

Neptune 是一款 WiFi 蓝牙模块,这里就通过 WiFi 和我们的手机建立连接。连接的方式有两种,分别是 TCP 和 UDP。

由于我们的数据并没有敏感数据,而且丢失其实也不会造成太大影响,因此这里选用了更加简单的 UDP。

UDP 实际上是可以进行广播的,如果有多个设备需要接受温湿度数据的话其实不需要单独的建立连接,所以更加适合这个场景。

最后,给大家看下最终的业务代码:

#include “ht30.h”#include 《stdio.h》#include 《unistd.h》#include 《string.h》#include “ohos_init.h”#include “cmsis_os2.h”#include “wifiiot_gpio.h”#include “wifiiot_gpio_ex.h”#include “wifiiot_i2c.h”#include “wifiiot_gpio_w800.h”#include “oled_ssd1306.h”#include “net_params.h”#include “wifi_connecter.h”#include “net_common.h”#define LED_TASK_STACK_SIZE 512#define LED_TASK_PRIO 25enum LedState {

LED_ON = 0,

LED_OFF,

LED_SPARK,

};

enum LedState g_ledState = LED_SPARK;

static void* GpioTask(const char* arg)

{

(void)arg;

while (1) {

switch (g_ledState) {

case LED_ON:

printf(“ LED_ON!

”);

GpioSetOutputVal(WIFI_IOT_GPIO_PB_00, WIFI_IOT_GPIO_VALUE0);

osDelay(500);

break;

case LED_OFF:

printf(“ LED_OFF!

”);

GpioSetOutputVal(WIFI_IOT_GPIO_PB_00, WIFI_IOT_GPIO_VALUE1);

osDelay(500);

break;

case LED_SPARK:

printf(“ LED_SPARK!

”);

GpioSetOutputVal(WIFI_IOT_GPIO_PB_00, WIFI_IOT_GPIO_VALUE0);

osDelay(500);

printf(“ LED_SPARK!2

”);

GpioSetOutputVal(WIFI_IOT_GPIO_PB_00, WIFI_IOT_GPIO_VALUE1);

osDelay(500);

break;

default:

osDelay(500);

break;

}

}

return NULL;

}

static void GpioIsr(char* arg)

{

(void)arg;

enum LedState nextState = LED_SPARK;

printf(“ GpioIsr entry

”);

GpioSetIsrMask(WIFI_IOT_GPIO_PB_07, 0);

switch (g_ledState) {

case LED_ON:

nextState = LED_OFF;

break;

case LED_OFF:

nextState = LED_ON;

break;

case LED_SPARK:

nextState = LED_OFF;

break;

default:

break;

}

g_ledState = nextState;

}

void HT30TestTask(void* arg)

{

(void) arg;

int times = 0;

uint32_t retval = 0;

WifiDeviceConfig config = {0};

// 准备AP的配置参数, 连接WiFi

strcpy(config.ssid, PARAM_HOTSPOT_SSID);

strcpy(config.preSharedKey, PARAM_HOTSPOT_PSK);

config.securityType = PARAM_HOTSPOT_TYPE;

osDelay(10);

int netId = ConnectToHotspot(&config);

// 建立UDP连接,这里充当了UDP的客户端

int sockfd = socket(AF_INET, SOCK_DGRAM, 0); // UDP socket

struct sockaddr_in toAddr = {0};

toAddr.sin_family = AF_INET;

toAddr.sin_port = htons(PARAM_SERVER_PORT); // 端口号,从主机字节序转为网络字节序

if (inet_pton(AF_INET, PARAM_SERVER_ADDR, &toAddr.sin_addr) 《= 0) { // 将主机IP地址从“点分十进制”字符串 转化为 标准格式(32位整数)

printf(“inet_pton failed!

”);

goto do_cleanup;

}

// I2C和OLED的初始化。

if (I2cInit(WIFI_IOT_I2C_IDX_0, 200*1000)) {

printf(“HT30 test i2c init failed

”);

}

OledInit();

OledFillScreen(0x00);

OledShowString(0, 0, “** HarmonyOS! **”, 1);

osDelay(400);

OledShowString(0, 1, “** HarmonyOS! **”, 1);

OledShowString(0, 2, “****************”, 1);

OledShowString(0, 3, “****************”, 1);

// 每秒测量一次温湿度数据

while (1) {

retval = HT30_StartMeasure();

printf(“HT30_StartMeasure: %d

”, retval);

float temp = 0.0, humi = 0.0;

retval = HT30_GetMeasureResult(&temp, &humi);

printf(“HT30_GetMeasureResult: %d, temp = %.2f, humi = %.2f

”, retval, temp, humi);

times++;

// 将温湿度数据显示在OELD屏幕上

static char line1[32] = {0};

snprintf(line1, sizeof(line1), “** times = [%d]”, times);

OledShowString(0, 1, line1, 1);

static char line2[32] = {0};

snprintf(line2, sizeof(line2), “** temp : %.2f”, temp);

OledShowString(0, 2, line2, 1);

static char line3[32] = {0};

snprintf(line3, sizeof(line3), “** humi : %d”, (int)humi);

OledShowString(0, 3, line3, 1);

// 将温湿度数据作为UDP的消息发送给手机

static char udpmessage[7] = {0};

snprintf(udpmessage, sizeof(udpmessage), “%04d%02d”, (int)(temp*100), (int)humi);

// UDP socket 是 “无连接的” ,因此每次发送都必须先指定目标主机和端口,主机可以是多播地址

retval = sendto(sockfd, udpmessage, sizeof(udpmessage), 0, (struct sockaddr *)&toAddr, sizeof(toAddr));

if (retval 《 0) {

printf(“sendto failed!

”);

goto do_cleanup;

}

printf(“send UDP message {%s} %ld done!

”, udpmessage, retval);

// 延时1秒

osDelay(500);

}

do_cleanup:

printf(“do_cleanup.。.

”);

close(sockfd);

}

void HT30Test(void)

{

GpioInit();

GpioSetDir(WIFI_IOT_GPIO_PB_00, WIFI_IOT_GPIO_DIR_OUTPUT); // output is 0 PB08 control led

GpioSetDir(WIFI_IOT_GPIO_PB_07, WIFI_IOT_GPIO_DIR_INPUT); // input is PB09

IoSetPull(WIFI_IOT_GPIO_PB_07, WIFI_IOT_GPIO_ATTR_PULLHIGH);

GpioRegisterIsrFunc(WIFI_IOT_GPIO_PB_07, WIFI_IOT_INT_TYPE_EDGE, WIFI_IOT_GPIO_EDGE_FALL_LEVEL_LOW, GpioIsr, NULL);

// 温湿度测量线程

osThreadAttr_t attr;

attr.name = “HT30Task”;

attr.attr_bits = 0U;

attr.cb_mem = NULL;

attr.cb_size = 0U;

attr.stack_mem = NULL;

attr.stack_size = 4096;

attr.priority = osPriorityNormal;

if (osThreadNew(HT30TestTask, NULL, &attr) == NULL) {

printf(“[HT30Test] Failed to create HT30TestTask!

”);

}

// OLED闪烁线程

osThreadAttr_t attr2;

attr2.name = “HT30Task2”;

attr2.attr_bits = 0U;

attr2.cb_mem = NULL;

attr2.cb_size = 0U;

attr2.stack_mem = NULL;

attr2.stack_size = 4096;

attr2.priority = osPriorityNormal;

if (osThreadNew(GpioTask, NULL, &attr2) == NULL) {

printf(“[HT30Test] Failed to create HT30TestTask2!

”);

}

}

APP_FEATURE_INIT(HT30Test);

阅读代码时可以注意一下两点:

在 HT30Test 函数中创建了 2 个线程,分别是 HT30TestTask 和 GpioTask。前者用于温湿度测量,后者用于闪烁 LED 灯。GpioTask 没啥用,只是为了好看而已,各位可以删掉他没有关系。

HT30TestTask 中,最终将温湿度数据以 UDP 的消息发送给 UDP 服务器(也就是手机),而这个数据进行了一次粗包装:一共是 6 位,前 4 位表示温度,后四位表示湿度。

例如,“374267”表示 37.42℃ 和相对湿度 67%。这样,后期鸿蒙应用程序拿到数据后就好处理了。

鸿蒙应用程序的开发

在应用程序端,这里充当了 UDP 服务器。使用 Java 的 API 进行开发的:

getGlobalTaskDispatcher(TaskPriority.DEFAULT).asyncDispatch(new Runnable() {

@Override

public void run() {

try {

// 要接收的报文

byte[] bytes = new byte[1024];

DatagramPacket packet = new DatagramPacket(bytes, bytes.length);

// 创建socket并指定端口

DatagramSocket socket = new DatagramSocket(5678);

while (true) {

// 接收socket客户端发送的数据。如果未收到会一致阻塞

socket.receive(packet);

String receiveMsg = new String(packet.getData(),0,packet.getLength());

System.out.println(“packet:” + packet.getLength());

System.out.println(“packet:” + receiveMsg);

getMainTaskDispatcher().asyncDispatch(new Runnable() {

@Override

public void run() {

long number = Long.parseLong(receiveMsg.substring(0, 6));

float temp = ((float)(number / 100)) / 100;

long humi = number % 100;

mText.setText(“温度:” + temp + “ 湿度:” + humi);

}

});

}

// 关闭socket

// socket.close();

} catch (Exception e) {

// TODO: handle exception

e.printStackTrace();

}

}

});

这段代码比较简单:

需要通过 getGlobalTaskDispatcher 获取全局任务分发器,然后通过异步方法进行网络连接,否则会抛出 NetworkOnMainThreadException 异常。

获得到 UDP 报文数据后,通过字符串裁剪和类型转化等方式将其转换为浮点型或整型,然后显示在 mText 组件上。

总结

我自己做的开发板成本是很低的,温湿度传感器、OLED 屏幕和 Neptune 模组都是以很低的价格在网上购买的,总成本可能不超过 30 元。这个开发板很小,可以握持在手中随身携带。

不过,在软件方面,上面的例子充其量算一个 Demo,实际上还有很多工作需要做:

①这里是直接通过 UDP 将开发板和手机连接在一起的,其中的 IP 地址也是硬写入的。所以如果离开 WiFi 环境,那么手机将不会接收到温湿度信息。

如果开发者希望远程获得温湿度,那么需要服务器进行中转。这个中转技术也不复杂,大家可以思考一下如何实现。

②在应用端,这里的温湿度是写在 MainAbilitySlice 中的。其实这种方式也是有待改进的。

至少需要将相关的业务代码写到服务中,这样的话,我们还可以实现高温预警等功能。如果将其以小卡片的形式显示在桌面就更好啦!同样,大家可以思考一下如何实现。

③这块开发板可以进一步微型化,请大家期待下一个版本!

④在获取温湿度数据的时候,我们用了低重复率和关闭 clock stretching 功能。

其实,真正实用化的时候,根据场景的不同大家需要考虑如何配置一下,提高精度的同时降低功耗!

代码:

https://gitee.com/dongyu1009/neptune-harmony-os-wi-fi-link

视频演示:

https://harmonyos.51cto.com/show/8232

在这里,为大家贡献了实例代码和开发板的原理图!如果希望进一步研究,点击“阅读原文”来一起探究竟吧!责任编辑:haq

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

    关注

    66

    文章

    18058

    浏览量

    177055
  • OLED
    +关注

    关注

    118

    文章

    5986

    浏览量

    221443
  • 鸿蒙系统
    +关注

    关注

    183

    文章

    2606

    浏览量

    65270

原文标题:成本30元,鸿蒙手机知晓家中情况!

文章出处:【微信号:gh_834c4b3d87fe,微信公众号:OpenHarmony技术社区】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    温湿度传感器工作原理 温湿度传感器的接线方法

    温湿度传感器是一种用于测量环境温度和相对湿度的装置。它通常用于工业、农业、气象、室内空调等领域。本文将详细介绍温湿度传感器的工作原理和接线方法。 一、温湿度传感器的工作原理
    的头像 发表于 02-14 18:00 4091次阅读

    温湿度监测系统解决方案应用场景

    温湿度监测系统解决方案,将温湿度参数进行测量并按照预定的时间间隔,将其储存在记录仪内部或通过GPRS/4G、WIFI上传管理云平台,可将数据导出,对其分析。可显示实时温湿度值、剩余
    的头像 发表于 01-24 16:21 175次阅读

    4G远程温湿度传感器在养殖场中的应用

    在养殖业中,温湿度是影响动植物生长和健康的关键因素之一。而温湿度传感器则可以实时监测和记录这些数据,帮助养殖户及时发现和解决问题,提高生产效率和动物福利。首先,温湿度传感器可以监测温度
    的头像 发表于 01-09 16:02 170次阅读
    4G远程<b class='flag-5'>温湿度</b>传感器在养殖场中的应用

    基于STM32单片机大棚温湿度检测无线蓝牙APP控制设计方案

    毕业设计的任务是基于STM32单片机,结合风扇控制电路、温湿度传感器电路、1602液晶显示电路和蓝牙模块电路,设计一套大棚环境参数监测系统。此系统旨在实时监测大棚内的温湿度情况,通过蓝牙技术将数据传输
    的头像 发表于 01-08 09:34 629次阅读
    基于STM32单片机大棚<b class='flag-5'>温湿度</b>检测无线蓝牙APP控制设计方案

    温湿度传感器在食品药品安全领域的应用

    被广泛应用于相关场合,实时监测和记录温湿度数据,为管理者提供决策依据。 无线智能温湿度采集终端可以实时监测环境中的温度和湿度,并通过数据传输
    的头像 发表于 01-04 17:55 249次阅读
    <b class='flag-5'>温湿度</b>传感器在食品药品安全领域的应用

    4G远程温湿度传感器在仓库中的应用—蜂窝物联

    。为了更好的观测和掌握温湿度的变化,仓库需要安装温湿度传感器实时监测温湿度状态,确保适宜货物储存的温湿度环境。 蜂窝物联仓库存储环境远程监控
    的头像 发表于 01-02 09:36 159次阅读

    【ELF 1开发板试用】温湿度测试

    1.开发环境-ubuntu20.04 2.测试内容:测试温湿度传感。 测试步骤如下: 1.软件下载 进入官网下载的linux内核代码,修改顶层makefile 修改arch和compile的值 适配
    发表于 12-18 11:59

    【ELF 1开发板试用】板载资源测试4:体验温湿度传感器

    飞凌嵌入式ELF1开发板(以下简称为“开发板”)将温湿度传感器器AHT20集成在了底板上,此次依旧做最基础的测试,以下是测试过程记录。一、实验名称ELF 1开发板板载资源测试2:体验
    发表于 12-18 11:09

    Arduino篇—自制温湿度测量仪

    DHT11数字温湿度传感器:DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器
    的头像 发表于 11-02 10:16 777次阅读
    Arduino篇—<b class='flag-5'>自制</b><b class='flag-5'>温湿度</b>测量仪

    【CW32饭盒派开发板试用体验】+万物互联之温湿度显示

    的图案更加漂亮和美观。对于UI设计,我涉及的面比较窄,以后的好好利用饭盒派这款多接口的带屏幕的开发板。对于刷新,我是500ms调用一次温湿度采集和屏幕刷新程序。特殊的场合有特殊的做法,写程序,必须一句
    发表于 06-26 20:33

    冷库温湿度监测系统——实时监测、智能报警

    监测系统主要提供对冷藏室、冷库等环境空间温度、湿度的严格监控和管理。冷库温湿度监测系统是由测点终端4G型多探头温湿度记录仪以及环境监控云平台组成。 各测点终端对周边环境温湿度进行数据的
    的头像 发表于 06-12 17:30 983次阅读
    冷库<b class='flag-5'>温湿度</b>监测系统——<b class='flag-5'>实时</b>监测、智能报警

    【CW32饭盒派开发板试用体验】+DHT22温湿度检测

    DHT11是一种常见的单总线数字式温湿度,且在开发板上配有该温湿度传感器的接口,见图1所示。 由于手头只有DHT22,就直接以它来进行温湿度的检测,其
    发表于 06-12 10:38

    【CW32饭盒派开发板试用体验】读取自己的温湿度传感器

    周末到了,是时候折腾手里的开发板了。我自己有一个DHT11的温湿度传感器,想想就用开发板读一下这个传感器的数据吧。 DHT11是一款数字温湿度传感器。含有已校准数字信号输出的
    发表于 06-03 11:01

    工业名词解释之POE以太网温湿度变送器

    传感器,它能够让你随时随地了解家中的温湿度变化情况,让你的生活更加舒适和健康。 这款以太网温湿度传感器具有许多优点,比如说,它能够精确地检测室内的温湿度,并通过网络传输数据到手机或电脑
    的头像 发表于 05-30 14:03 329次阅读
    工业名词解释之POE以太网<b class='flag-5'>温湿度</b>变送器

    CW32饭盒派开发板 日历温湿度

    CW32创建日历+温湿度
    的头像 发表于 05-27 14:07 4184次阅读
    CW32饭盒派<b class='flag-5'>开发板</b> 日历<b class='flag-5'>温湿度</b>计