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

    文章

    18491

    浏览量

    180194
  • OLED
    +关注

    关注

    119

    文章

    6200

    浏览量

    224181
  • 鸿蒙系统
    +关注

    关注

    183

    文章

    2634

    浏览量

    66339

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

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

收藏 人收藏

    评论

    相关推荐

    XKCON祥控仓库存储环境温湿度在线监测系统能够取代人工巡检,实现远程仓库存储环境温湿度变化的实时

    仓库作为储物的场所,其环境温湿度会随着季节更替而发生变化,这种变化会对存储物品的质量与安全产生较大的影响。因此,仓库的温湿度数据就成为仓储安全监管的一个重要的指标。 济南祥控自动化设备有限公司开发
    的头像 发表于 11-20 11:20 182次阅读
    XKCON祥控仓库存储环境<b class='flag-5'>温湿度</b>在线监测系统能够取代人工巡检,实现远程仓库存储环境<b class='flag-5'>温湿度</b>变化的<b class='flag-5'>实时</b>

    LORA无线温湿度监测系统

    LORA无线温湿度监测系统,作为现代环境监测技术的重要组成部分,正日益受到各行各业的广泛关注和应用。 LORA无线温湿度监测系统,利用LORA无线通信技术,对环境中温度和湿度实时监测
    的头像 发表于 11-07 16:57 332次阅读

    温湿度控制器的功能和应用

    温湿度控制器在电阻柜中的应用主要涉及以下几个方面: 温湿度控制器的功能 检测与控制:温湿度控制器可以同时检测和控制环境中的温度和湿度。它通常由传感器、控制器和加热器三部分组成。传感器负
    的头像 发表于 11-07 15:08 208次阅读

    温湿度监测系统应用

    在现代化工业生产、仓储管理、农业种植以及智能家居等领域,温湿度监测已成为不可或缺的一环。温湿度作为环境控制的关键因素,直接影响着产品质量、存储安全、作物生长效率以及居住舒适度。因此,一套高效、精准
    的头像 发表于 07-26 16:15 405次阅读

    药品仓库温湿度监控系统

    和有效使用具有重要意义。 药品仓库温湿度监控系统,结合物联网、无线通讯等技术,主要由传感器、数据采集器、传输设备、管理云平台等组成。针对药品仓库的温湿度进行实时监控,及时发现并调整不利的环境条件,是确保药品
    的头像 发表于 07-26 10:12 352次阅读

    库房温湿度自动监测系统

    对库房内温湿度实时、自动监测。在线实时采集库房内的温湿度数据,无线传输并汇总到管理平台上,进行存储、分析、报警等操作,随时查看库房内的温湿度
    的头像 发表于 07-09 18:00 704次阅读

    粮仓温湿度监测解决方案

    温湿度是影响粮食储存品质的重要因素。过高的温度会加速粮食的呼吸作用,导致水分散失和品质下降。因此,粮仓的温湿度管理,成为了确保粮食储存安全和质量稳定的关键因素。方便及时发现粮仓的发热点,及时减少粮食
    的头像 发表于 07-04 16:37 349次阅读

    想要准确地测量环境温湿度温湿度传感器是关键!

    温湿度是生产生活中最重要的环境指标之一,不仅人需要在适宜的温湿度条件下保持良好的精神状态和敏捷的思维,食品、药品、各种仪器设备等都对环境温湿度有特殊的要求。基于对环境温湿度的要求,
    的头像 发表于 07-04 08:48 565次阅读

    无线温湿度监控系统

    无线温湿度监控系统,作为现代环境监测技术的杰出代表,已经广泛应用于各个行业和领域。利用无线通信技术,实现对环境温湿度实时、远程监控,从而保障了各种设备和物品的安全运行和保存。 无线温湿度
    的头像 发表于 05-30 16:43 762次阅读

    应用案例 | 如何实时监测和管理冷链仓库温湿度

    宏集温湿度监测解决方案帮助客户实时监测冷链仓库的温湿度,保障货物的品质和安全,降低货损并提高效率。
    的头像 发表于 05-23 14:13 470次阅读
    应用案例 | 如何<b class='flag-5'>实时</b>监测和管理冷链仓库<b class='flag-5'>温湿度</b>?

    项目分享|基于ELF 1开发板的MQTT远程温湿度监测系统

    今天非常荣幸向各位小伙伴详细展示一个由共创社成员完成的MQTT远程温湿度监控系统项目。该项目借助ELF1开发板作为核心技术支撑,成功实现了对各类环境空间中温湿度数据的实时、远程、稳定监
    的头像 发表于 04-26 09:54 501次阅读
    项目分享|基于ELF 1<b class='flag-5'>开发板</b>的MQTT远程<b class='flag-5'>温湿度</b>监测系统

    温湿度传感器有哪些应用场景?

    温湿度传感器在众多领域,特别是在实时记录温湿度变化的工作中最为广泛。温湿度传感器可以根据所记录的内容,对其进行科学有效的管理、分析和归纳。下面我们就
    的头像 发表于 02-19 16:28 1357次阅读
    <b class='flag-5'>温湿度</b>传感器有哪些应用场景?

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

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

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

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

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

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