OpenHarmony GPIO应用开发-LED

学习于:

https://docs.openharmony.cn/pages/v5.0/zh-cn/device-dev/driver/driver-platform-gpio-develop.md

https://docs.openharmony.cn/pages/v5.0/zh-cn/device-dev/driver/driver-platform-gpio-des.md

通过OpenHarmony官方文档指导可获知:芯片厂商应当按照系统的平台驱动接口实现GPIO控制器驱动后,设备开发人员就可以按照系统GPIO的HDI接口使用GPIO,具体接口函数有:

其中函数参数gpioName指定IO口名,gpio指定IO口的ID,参数具体值由芯片厂商在.hcs配置文件中描述,如海思Hi3516中GPIO控制器驱动的描述:

Hi3516 GPIO控制器驱动自定义属性的描述:

其中属性groupNum指定Hi3516共有12组IO口,bitNum指定每组有8个IO口,由0 ~ 95数值分别表示96个IO,如GPIO2_3,则由数值19表示(2*8 + 3 = 19)。

属性gpioCustomName指定IO口的名称,依此名称可通过函数GpioGetByName获取IO口对应的ID。

接下来通过应用GPIO实现LED驱动:
开发板LED原理图

通过原理图可发现有: GPIO2_3 GPIO3_4 GPIO5_1控制LED的工作。

简单的LED驱动

在上篇简单的HDF驱动驱动源码基础上加入控制一个LED的代码,具体驱动源码:

c 复制代码
#include <hdf_device_desc.h>
#include <hdf_log.h>
#include <hdf_base.h>
#include <gpio_if.h>  // GPIO驱动调用接口

static int idGpio = 0;

static int32_t myDispatch(
    struct HdfDeviceIoClient *client, int id, struct HdfSBuf *data, struct HdfSBuf *reply)
{
    HDF_LOGD("### in %s : %d\n", __func__, id);
    GpioWrite(idGpio, id%2); //配置GPIO输出高低电平
    return HDF_SUCCESS;
}

int32_t myBind(struct HdfDeviceObject *obj)
{
    static struct IDeviceIoService testService = {
        .Dispatch = myDispatch,
    };
    obj->service = &testService;
    HDF_LOGD("#### in %s\n", __func__);

    idGpio = GpioGetByName("GPIO2_3"); //获取GPIO的ID
    GpioSetDir(idGpio, GPIO_DIR_OUT); //配置GPIO作输出用途

    return HDF_SUCCESS;
}
int32_t myInit(struct HdfDeviceObject *obj)
{
    HDF_LOGD("#### in %s\n", __func__);
    return HDF_SUCCESS;
}
void myRelease(struct HdfDeviceObject *obj)
{
    HDF_LOGD("#### in %s\n", __func__);
}

struct HdfDriverEntry myTestEntry = {
    .Bind = myBind,
    .Init = myInit,
    .Release = myRelease,
    .moduleName = "myTestDriver",
    .moduleVersion = 1
};
HDF_INIT(myTestEntry);

沿用上篇里的应用程序,当应用程序执行起来后,开发板的LED会在GPIO输出高电平时亮,低电平时熄。

硬件资源分离与可重用的LED驱动

按照OpenHarmony文档指导,硬件相关的资源应当在.hcs配置文件中描述。这里三个LED分别作为一个设备进行描述 :

然后在vendor/hisilicon/hispark_taurus/hdf_config/目录下创建myLight文件夹,并在文件夹里创建myLight.hcs配置文件,描述设备自定义的属性:

每个节点通过match_attr与设备节点的deviceMatchAttr进行匹配,相同值表示此节点资源由对应的设备使用。 gpioName自定义属性向LED驱动提供LED设备的控制IO。

然后修改vendor/hisilicon/hispark_taurus/hdf_config/hdf.hcs配置文件,增加myLight.hcs文件的使用:

驱动源文件myTestDriver.c代码修改为:

c 复制代码
#include <hdf_device_desc.h>
#include <hdf_log.h>
#include <hdf_base.h>
#include <gpio_if.h>
#include <device_resource_if.h>
#include <osal_mem.h>

struct myLightService {
    struct IDeviceIoService service;
    int idGpio;
    const char *gpioName;
};

static int32_t myDispatch(
    struct HdfDeviceIoClient *client, int id, struct HdfSBuf *data, struct HdfSBuf *reply)
{
    struct HdfDeviceObject *obj = client->device;
    struct myLightService *srv = (struct myLightService *)(obj->service);

    HDF_LOGD("### in %s, %s  %d\n", __func__,  srv->gpioName, id);
    GpioWrite(srv->idGpio, !!id);
    return HDF_SUCCESS;
}

int32_t myBind(struct HdfDeviceObject *obj)
{

    struct myLightService *srv = NULL;

    struct DeviceResourceIface *dr = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);

    srv = OsalMemCalloc(sizeof(struct myLightService));
    dr->GetString(obj->property, "gpioName", &srv->gpioName, NULL);
    srv->service.Dispatch = myDispatch;
    srv->idGpio = GpioGetByName(srv->gpioName);

    GpioSetDir(srv->idGpio, GPIO_DIR_OUT);

    obj->service = &srv->service;

    return HDF_SUCCESS;
}
int32_t myInit(struct HdfDeviceObject *obj)
{
    return HDF_SUCCESS;
}
void myRelease(struct HdfDeviceObject *obj)
{
    struct myLightService *srv = (struct myLightService *)(obj->service);
    OsalMemFree(srv);
}

struct HdfDriverEntry myTestEntry = {
    .Bind = myBind,
    .Init = myInit,
    .Release = myRelease,
    .moduleName = "myTestDriver",
    .moduleVersion = 1
};
HDF_INIT(myTestEntry);

应用程序mytest.c代码修改为:

c 复制代码
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include "hdf_log.h"
#include "hdf_sbuf.h"
#include "hdf_io_service_if.h"

int main(int argc, char *argv[])
{
    if (3 != argc)
    {
        printf("usage: %s  serviceName  num \n", argv[0]);
        return 1;
    }

    struct HdfIoService *srv = HdfIoServiceBind(argv[1]);
    if (srv == NULL) {
        printf("fail to get service\n");
        return 1;
    }

    int ret = srv->dispatcher->Dispatch(&srv->object, atoi(argv[2]), NULL, NULL);
    printf("test end\n");

    HdfIoServiceRecycle(srv);
    return 0;
}

应用程序执行时通过指定不同的服务名与电平值控制LED,如:

c 复制代码
  ./bin/mytest  myTestService0   1      
  ./bin/mytest  myTestService1   1    
相关推荐
坚果派·白晓明18 小时前
常用URL语法传输数据开源命令行工具curl鸿蒙化构建过程深度解析
开源·openharmony·开源鸿蒙·开源软件termony
坚果派·白晓明20 小时前
通过开源鸿蒙终端工具Termony完成Zlib 命令行工具构建过程深度解读
openharmony·开源鸿蒙·开源软件termony
坚果派·白晓明1 天前
Tree 命令行工具鸿蒙化构建过程问题及解决方法
openharmony·开源鸿蒙·开源软件termony
坚果派·白晓明1 天前
开源鸿蒙化构建GNU Tar 1.35:完整过程与验证
openharmony·开源鸿蒙·开源软件termony
坚果派·白晓明2 天前
通过开源鸿蒙终端工具Termony完成Libarchive 命令行工具构建过程深度解读
openharmony·开源鸿蒙·开源软件termony
坚果派·白晓明2 天前
通过开源鸿蒙终端工具Termony完成Zstd 命令行工具构建过程深度解读
openharmony·开源鸿蒙·开源软件termony
坚果派·白晓明3 天前
通过开源鸿蒙终端工具Termony完成Vim命令行工具构建过程深度解读
vim·openharmony·开源鸿蒙·开源软件termony
坚果派·白晓明3 天前
通过开源鸿蒙终端工具Termony完成Coremark 命令行工具构建过程深度解读
openharmony·命令行工具·开源鸿蒙·开源软件termony
坚果派·白晓明3 天前
通过开源鸿蒙终端工具Termony完成Ncurses 命令行工具构建过程深度解读
openharmony·开源鸿蒙·开源软件termony
A懿轩A3 天前
【2025版 OpenHarmony】GitCode 口袋工具 v1.0.1 更新发布:Flutter + HarmonyOS 封装导航栏进行跳转
flutter·harmonyos·openharmony·gitcode·开源鸿蒙