当前位置: 首页 > 科技观察

基于OpenHarmony的实时水流监控管理系统(一)_0

时间:2023-03-23 01:21:40 科技观察

了解更多开源请访问:开源基础软件社区https://ost.51cto.com1.前言学习后OpenHarmony开发系统有一段时间,和朋友一起完成了一个简单的小项目,一个基于OpenHarmony的实时水流监控管理系统。二、准备工作1、BearPi-HMMicro开发板2、配置开发环境,搭建开发环境。3.熟悉官方写程序点亮LED灯的步骤。编写一个程序来打开LED灯。三、实战1、系统组成及功能说明(一)物联网典型架构总体介绍:终端:在传感器模块上,使用的水表传感器不同于常见的流量/流量水表,以及霍尔传感器作为水流量的测量依据。Tube:BearPi板载wifi模块使用UDP协议将数据发送到云端。云端:云端使用华为云服务器接收熊派UDP协议发送的数据,同时建立一个TCP服务器(即使用socket库开发的http服务器)打开httpget接口来小程序。使用:微信小程序。用户可以通过小程序轻松了解自己的用水情况。(2)在每个模块的引入端连接一个水流传感器到BearPi-HMMicro开发板,获取水流信息。霍尔水流传感器由塑料阀体、水流转子组件和霍尔传感器组成。安装在进水口处,用于检测进水流量。当水流过水流转子组件时,磁转子旋转,速度随水流变化。霍尔传感器输出相应的脉冲信号,反馈给控制器。确定水流量的大小并进行调整。所以只要我们知道连接的传感器引脚上的水位值变化,我们就可以知道水流。查找OpenHarmony设备开发文档以了解如何使用GPIO进行开发。OpenHarmony设备开发文档-使用GPIO的平台驱动程序。●设置GPIO引脚方向在读写GPIO引脚之前,需要通过以下函数设置GPIO引脚方向:int32_tGpioSetDir(uint16_tgpio,uint16_tdir)。●通过GpioRead()函数读取GPIO引脚电平:int32_tGpioRead(uint16_tgpio,uint16_t*val)。在点亮LED灯demo的基础上,是否可以通过稍微修改LED业务代码,直接读取管脚电平值呢?添加包含GPIO的头文件,可以直接使用头文件中的函数,这样就可以跳过驱动的编写#include#include#include#include#include"hdf_sbuf.h"#include"hdf_io_service_if.h"/*添加代码#include"gpio_if.h"#defineLED_WRITE_READ1#defineLED_SERVICE"hdf_led"staticintSendEvent(structHdfIoService*serv,uint8_teventData){intret=0;结构HdfSBuf*数据=HdfSBufObtainDefaultSize();if(data==NULL){printf("获取sbuf数据失败!\r\n");返回1;}structHdfSBuf*reply=HdfSBufObtainDefaultSize();if(reply==NULL){printf("获取sbuf回复失败!\r\n");ret=HDF_DEV_ERR_NO_MEMORY;出去;}/*写入数据*/if(!HdfSbufWriteUint8(data,eventData)){printf("写入sbuf失败!\r\n");ret=HDF_FAILURE;出去;}/*通过Dispatch发送给驱动*/ret=serv->dispatcher->Dispatch(&serv->object,LED_WRITE_READ,data,reply);if(ret!=HDF_SUCCESS){printf("发送服务调用失败!\r\n");出去;}intreplyData=0;/*从驱动读取回复数据*/if(!HdfSbufReadInt32(reply,&replyData)){printf("获取服务调用回复失败!\r\n");ret=HDF_ERR_INVALID_OBJECT;出去;}/*添加代码GpioSetDir(6,GPIO_DIR_IN);/*添加代码ret=GpioRead(6,&val);/*添加代码printf("\r\nGetreplyis:%d\r\n",val);printf("\r\n得到的回复是:%d\r\n",replyData);out:HdfSBufRecycle(data);HdfSBufRecycle(回复);returnret;}intmain(intargc,char**argv){inti;/*获取服务*/structHdfIoService*serv=HdfIoServiceBind(LED_SERVICE);if(serv==NULL){printf("获取服务%s失败!\r\n",LED_SERVICE);返回HDF_FAILURE;}for(i=0;idevice==NULL){HDF_LOGE("LeddriverdeviceisNULL");返回HDF_ERR_INVALID_OBJECT;}switch(cmdCode){/*从用户态接收LED_WRITE_READ命令*/caseLED_WRITE_READ:/*读取data中的数据并赋值给control*/HdfSbufReadUint8(data,&control);switch(control){/*打开灯*/caseLED_ON:/*Newcode*/GpioSetDir(6,GPIO_DIR_IN);/*新代码*/ret=GpioRead(6,&val);/*新代码*/status=val;/*新代码*/if(status!=flag){/*新代码*/GpioWrite(g_Stm32Mp1ILed.gpioNum,GPIO_VAL_LOW);/*新代码*/status1++;/*新代码*/flag=!flag;/*添加新代码*/}else{/*添加新代码*/GpioWrite(g_Stm32Mp1ILed.gpioNum,GPIO_VAL_HIGH);}休息;/*关灯*/caseLED_OFF:GpioWrite(g_Stm32Mp1ILed.gpioNum,GPIO_VAL_HIGH);状态=0;休息;/*状态切换*/caseLED_TOGGLE:if(status==0){GpioWrite(g_Stm32Mp1ILed.gpioNum,GPIO_VAL_LOW);状态=1;}else{GpioWrite(g_Stm32Mp1ILed.gpioNum,GPIO_VAL_HIGH);状态=0;}休息;默认值:中断;}/*将LED的状态值写入reply,可以带给用户程序*/if(!HdfSbufWriteInt32(reply,status)){HDF_LOGE("replayisfail");返回HDF_FAILURE;}休息;默认值:中断;}returnHDF_SUCCESS;}//读取驱动私有配置staticint32_tStm32LedReadDrs(structStm32Mp1ILed*led,conststrDeviceResourceNode*node){int32_tret;结构DeviceResourceIface*drsOps=NULL;drsOps=DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);if(drsOps==NULL||drsOps->GetUint32==NULL){HDF_LOGE("%s:无效的drsops!",__func__);返回HDF_FAILURE;}/*读取led.hcs中led_gpio_num的值*/ret=drsOps->GetUint32(node,"led_gpio_num",&led->gpioNum,0);if(ret!=HDF_SUCCESS){HDF_LOGE("%s:readledgpionumfail!",__func__);返还;}returnHDF_SUCCESS;}//驱动对外提供的服务能力,绑定相关服务接口到HDF框架int32_tHdfLedDriverBind(structHdfDeviceObject*deviceObject){if(deviceObject==NULL){HDF_LOGE("Leddriverbindfailed!);返回HDF_ERR_INVALID_OBJECT;}staticstructIDeviceIoServiceledDriver={.Dispatch=LedDriverDispatch,};deviceObject->service=(structIDeviceIoService*)(&ledDriver);HDF_LOGD("Led驱动绑定成功");returnHDF_SUCCESS;}//接口int32_t驱动自身业务初始化HdfLedDriverInit(structHdfDeviceObject*device){structStm32Mp1ILed*led=&g_Stm32Mp1ILed;int32_t退役;if(device==NULL||device->property==NULL){HDF_LOGE("%s:deviceorpropertyNULL!",__func__);返回HDF_ERR_INVALID_OBJECT;}/*读取hcs私有属性值*/ret=Stm32LedReadDrs(led,设备->属性);if(ret!=HDF_SUCCESS){HDF_LOGE("%s:getleddeviceresourcefail:%d",__func__,ret);返还;}/*GPIO引脚配置为输出*/ret=GpioSetDir(led->gpioNum,GPIO_DIR_OUT);if(ret!=0){HDF_LOGE("GpioSerDir:failed,ret%d\n",ret);返还;}HDF_LOGD("Led驱动初始化成功");returnHDF_SUCCESS;}//驱动资源释放接口voidHdfLedDriverRelease(structHdfDevijceObect*deviceObject){if(deviceObject==NULL){[请添加链接说明](https://docs.openharmony.cn/pages/v3.1/zh-cn/device-dev/driver/driver-hdf-message-management.md/)}HDF_LOGD("Led驱动发布成功");return;}//定义驱动入口的对象,必须是HdfDriverEntry类型的全局变量(在hdf_device_desc.h中定义)structHdfDriverEntryg_ledDriverEntry={.moduleVersion=1,.moduleName="HDF_LED",.Bind=HdfLedDriverBind,.Init=HdfLedDriverInit,.Release=HdfLedDriverRelease,};//调用HDF_INIT将驱动入口注册到HDF框架HD中F_INIT(g_ledDriverEntry);在此之前,你需要先了解OpenHarmony的驱动框架HDF(HardwareDriverFoundation),内核态驱动和用户态应用是如何相互传递消息的官方文档:驱动消息机制管理详解,可以参考这位开发者的文章:[FFH]为HDF驱动程序开发编写驱动程序代码。简单总结一下,主要是靠Dispatch这个功能。用户态获取服务接口并向驱动程序发送消息。ret=serv->dispatcher->Dispatch(&serv->object,LED_WRITE_READ,data,reply);if(ret!=HDF_SUCCESS){printf("发送服务调用失败!\r\n");出去;驱动程序接收用户模式消息。//Dispatch用于处理来自用户模式的消息。int32_tLedDriverDispatch(structHdfDeviceIoClient*client,intcmdCode,structHdfSBuf*data,structHdfSBuf*reply)驱动向用户模式发送消息。/*将LED的状态值写入reply,可以带给用户程序*/if(!HdfSbufWriteInt32(reply,status1)){HDF_LOGE("replayisfail");返回HDF_FAILURE;}用户程序不能直接访问驱动程序是的,只有当驱动程序将服务器暴露给用户态时,用户程序才可以通过Dispatch向驱动程序发送指令,并且可以携带用户态数据给驱动程序,并且也可以从驱动程序中读取数据,如下图所示为用户态程序与驱动程序自身数据交互的过程。在该用户态界面中,可以得到GPIO电平变化次数:根据实测,500ml水引起的GPIO电平变化次数为320次,因此可以通过公式计算累计水流量。流量=(T/320)?500(ml)表示。了解更多开源知识,请访问:开源基础软件社区https://ost.51cto.com。