LED的C语言应用程序

引言

在本文中,用C语言编写一个LED灯的应用程序,对文章《基于HDF的LED驱动程序开发》(1)(2)中开发的LED灯的驱动程序进行测试。

另外,在编写LED灯的应用程序时,我们会用到很多由HDF框架提供的API。为了便于查阅这这些API的用法,建议大家在阅读本文的同时,打开文章《HDF驱动框架的API》(1)(2)(3)。在这几篇文章中汇集了本文所用到的API。当然,你也可以直接去阅读这些API的源码和官方说明文档。

本文参考了小熊派BearPi-HM_Micro_Small开发板的部分教程。

https://gitee.com/bearpi/bearpi-hm_micro_small  

在阅读本文之前,确保已阅读了《小熊派BearPi-HM_Micro_Small之Hello_World》

一、编写源程序

首先,在路径applications/BearPi/BearPi-HM_Micro/samples/dandelion下新建一个文件夹:my_led_app

然后,在文件夹my_led_app中新建一个文件:my_led_app.c,接下来我们在这个文件中编写源程序。

这个应用程序没有用户图形界面,只能以命令行的形式运行:./my_led 参数 ,命令参数有三种取值:0、1、2,分别控制LED关闭、打开和状态切换。

在源程序my_led_app.c中,除了一些头文件和宏定义之外,主要包括以下两个函数:

函数 描述
int main(int argc, char **argv) 应用程序的主函数
static int LedWriteRead(struct HdfIoService *serv, uint8_t sendData, uint8_t *recvData) 向驱动程序发送数据,然后接收驱动程序的响应。

1.1 头文件、宏定义

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdio.h>

#include "hdf_log.h"
#include "hdf_sbuf.h"
#include "hdf_io_service_if.h"

#define LED_WRITE_READ  1         //应用程序下发给LED驱动的命令字。1:写;0:读。
#define LED_SERVICE     "hdf_led" //LED驱动对外提供的服务的名称,与驱动配置中的名称一致。

1.2 主函数

int main(int argc, char **argv)
{
    int i;
    
    // 打印输出在终端中输入的命令行
    for (i=0; i < argc; i++)
    {
        printf("\r\nArgument %d is %s.\r\n", i, argv[i]);
    }

    // 获取驱动提供的服务 
    struct HdfIoService *serv = HdfIoServiceBind(LED_SERVICE);
    if (serv == NULL)
    {
        printf("fail to get service %s!\r\n", LED_SERVICE);
        return HDF_FAILURE;
    }
    
    // 向驱动发送LED的控制数据,从驱动接收LED当前的状态
    uint8_t replyData = 0;
    LedWriteRead(serv, atoi(argv[1]), &replyData);
    printf("\r\nGet reply is: %d\r\n", replyData);

    // 回收资源
    HdfIoServiceRecycle(serv);

	// 退出程序
    printf("exit");
    return HDF_SUCCESS;
}

main函数中,使用到了HDF提供的接口函数:HdfIoServiceBindHdfIoServiceRecycle,以及结构体HdfIoService

1.3 LedWriteRead函数

LedWriteRead函数在主函数main中被调用,用于与内核态的驱动程序交换数据。第1个参数serv:指向驱动服务对象(HdfIoService结构体)的指针;第2个参数sendData:向驱动程序下发的数据;第3个参数recvData:指向一个变量的指针,该变量用于存放从驱动函数收到的应答数据。

static int LedWriteRead(struct HdfIoService *serv, uint8_t sendData, uint8_t *recvData)
{
    int ret = HDF_SUCCESS;

    // 创建一个缓冲区,用于向驱动发送数据
    struct HdfSBuf *data = HdfSBufObtainDefaultSize();
    if (data == NULL)
    {
        printf("fail to obtain sbuf data!\r\n");
        return HDF_FAILURE;
    }

    // 创建一个缓冲区,用于从驱动接收响应
    struct HdfSBuf *reply = HdfSBufObtainDefaultSize();
    if (reply == NULL)
    {
        printf("fail to obtain sbuf reply!\r\n");
        ret = HDF_DEV_ERR_NO_MEMORY;
        goto out;
    }

    // 把要下发给驱动的数据写入缓冲区 
    if (!HdfSbufWriteUint8(data, sendData))
    {
        printf("fail to write sbuf!\r\n");
        ret = HDF_FAILURE;
        goto out;
    }

    // 调用应用态的Dispatch函数与驱动交互 
    ret = serv->dispatcher->Dispatch(&serv->object, LED_WRITE_READ, data, reply);
    if (ret != HDF_SUCCESS)
    {
        printf("fail to send service call!\r\n");
        goto out;
    }

    // 从缓冲区中读取驱动的响应数据
    if (!HdfSbufReadUint8(reply, recvData))
    {
        printf("fail to get service call reply!\r\n");
        ret = HDF_ERR_INVALID_OBJECT;
        goto out;
    }

out:
    // 回收缓冲区
    HdfSBufRecycle(data);
    HdfSBufRecycle(reply);
    
    return ret;
}

main函数中,使用到了HDF提供的接口函数:HdfSBufObtainDefaultSizeHdfSbufWriteUint8HdfSbufReadUint8HdfSBufRecycle,以及结构体HdfSBufHdfIoService

二、编写/修改编译脚本

1、在文件夹my_led_app下新建一个文件:BUILD.gn,在这个文件中编写源程序my_led_app.c的编译脚本:

import("//build/lite/config/component/lite_component.gni")

HDF_FRAMEWORKS = "//drivers/framework"

executable("my_led_exe") {
    output_name = "my_led"     
    sources = [
        "my_led_app.c",
    ]   
    include_dirs = [
    "$HDF_FRAMEWORKS/ability/sbuf/include",
    "$HDF_FRAMEWORKS/core/shared/include",
    "$HDF_FRAMEWORKS/core/host/include",
    "$HDF_FRAMEWORKS/core/master/include",
    "$HDF_FRAMEWORKS/include/core",
    "$HDF_FRAMEWORKS/include/utils",
    "$HDF_FRAMEWORKS/utils/include",
    "$HDF_FRAMEWORKS/include/osal",
    "//drivers/adapter/uhdf/posix/include",
    "//third_party/bounds_checking_function/include",
    "//base/hiviewdfx/hilog_lite/interfaces/native/innerkits",
    ]
    deps = [
        "//base/hiviewdfx/hilog_lite/frameworks/featured:hilog_shared",
        "//drivers/adapter/uhdf/manager:hdf_core",
        "//drivers/adapter/uhdf/posix:hdf_posix_osal",
    ]
}

executable("my_led_exe")用于声明一个名为my_led_exe的、类型为executable的目标(target),指示编译构建子系统将源码my_led_app.c编译成名为my_led的可执行文件。

output_name用于指定编译生成的可执行文件的名称。

sources列表中是编译构建所需要的源码文件。

include_dirs列表中是源码文件中引用的头文件的路径。

deps列表中是编译构建时需要依赖的其他库。

2、修改文件夹dandelion下的编译脚本文件:BUILD.gn

import("//build/lite/config/component/lite_component.gni")

lite_component("dandelion_app") {
    features = [
        "hello_world:hello_world_exe",
        "my_led_app:my_led_app",
    ]
}

lite_component是在build/lite/config/component/lite_component.gni中定义的一个template,用于将上面那个名为my_led_exe的target纳入到名为my_led_app的编译构建目标里面。

三、编译、烧写

参考《小熊派BearPi-HM_Micro_Small之Hello_World》第五、六部分。

四、测试

待系统启动完毕后,在串口终端中依次执行以下命令:

./bin/my_led 1
./bin/my_led 0
./bin/my_led 2

将分别控制小熊派BearPi-HM_Micro_Small开发板上的LED点亮、熄灭、状态切换,串口终端终端输出入下图所示:

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/u013819452/article/details/126133324