梅科尔工作室-#14天鸿蒙设备开发实战#驱动子系统开发笔记 原创 精华

发布于 2022-8-6 17:13
浏览
2收藏

@toc

HarmonyOS驱动子系统开发

操作GPIO

参考:

GPIO API介绍

GPIO(General-purpose input/output)意思为通用输入/输出端口,通用型之输入输出的简称,用于电信号在电路中的输入输出,以方便控制电路部件。通俗地说,就是一些引脚,可以通过它们输出高低电平或者通过它们读入引脚的状态-是高电平或是低电平。

wifiiot_gpio.h接口简介

这个.h中包含声明GPIO接口函数,这些功能用于初始化GPIO。

接口名 功能描述
Gpiolnit 初始化GPIO
GpioDeinit 取消初始化GPIO
GpioSetDir 设置GPIO引脚方向
GpioGetDir 获取GPIO引脚方向
GpioSetOutputVal 设置GPIO引脚输出电平值
GpioGetOutputVal 获取GPIO引脚输出电平值

源码在base\iot_hardware\interfaces\kits\wifiiot_lite\wifiiot_gpio.h路径下,可以从案例目录下的BUILD.gn文件中查找

梅科尔工作室-#14天鸿蒙设备开发实战#驱动子系统开发笔记-开源基础软件社区

  • GpioInit()

    unsigned int GpioInit (void )

    描述: 初始化GPIO外设

  • IoSetFunc()

    unsigned int IoSetFunc (WifiIotIoName id, unsigned char val )

    描述: 设置GPIO引脚复用功能

    参数:

    名字 描述
    id 表示GPIO引脚号.
    val 表示GPIO复用功能
  • GpioSetDir()

    unsigned int GpioSetDir (WifiIotGpioIdx id, WifiIotGpioDir dir )

    描述: 设置GPIO输出方向

    参数:

    名字 描述
    id 表示GPIO引脚号
    dir 表示GPIO输出方向

wifiiot_gpio_ex.h接口简介

这个.h中包含声明扩展的GPIO接口函数,这些功能用于设置GPIO拉力和驱动器强度。

接口名 功能描述
loSetPull 设置GPIO引脚上拉
loGetPull 获取GPIO引脚上拉
loSetFunc 设置GPIO引脚功能
loGetFunc 获取GPIO引脚功能
IOSetDriverStrength 设置GPIO驱动能力
lOGetDriverStrength 获取GPIO驱动能力

查看LED对应的GPIO引脚

梅科尔工作室-#14天鸿蒙设备开发实战#驱动子系统开发笔记-开源基础软件社区

LED对应的GPIO引脚是GPIO2,通过控制GPIO2输出的的电平信号来实现LED灯的闪烁。

  • 高电平时点亮LED灯。

  • 低电平时熄灭LED灯。

    梅科尔工作室-#14天鸿蒙设备开发实战#驱动子系统开发笔记-开源基础软件社区

操作GPIO点亮LED

源码在applications\BearPi\BearPi-HM_Nano\sample\B1_basic_led_blink\led_example.c路径下,以下添加了部分注释:

/*LED以1S的频率闪烁*/
#include <stdio.h>
#include <unistd.h>

#include "ohos_init.h"
#include "cmsis_os2.h"
#include "wifiiot_gpio.h"
#include "wifiiot_gpio_ex.h"

static void LedTask(void)
{
    //初始化GPIO
    GpioInit();

    //设置GPIO_2的复用功能为普通GPIO
    IoSetFunc(WIFI_IOT_IO_NAME_GPIO_2, WIFI_IOT_IO_FUNC_GPIO_2_GPIO);  // 参数分别表示GPIO引脚号、GPIO复用功能

    //设置GPIO_2为输出模式
    GpioSetDir(WIFI_IOT_GPIO_IDX_2, WIFI_IOT_GPIO_DIR_OUT);  // 参数分别表示GPIO引脚号、GPIO输出方向

    while (1)
    {
        //设置GPIO_2输出高电平点亮LED灯
        GpioSetOutputVal(WIFI_IOT_GPIO_IDX_2, 1);  // 参数分别表示GPIO引脚号、电平高低(1为高电平、0为低电平)

        //延时1s
        usleep(1000000);

        //设置GPIO_2输出低电平熄灭LED灯
        GpioSetOutputVal(WIFI_IOT_GPIO_IDX_2, 0);

        //延时1s
        usleep(1000000);
    }
}

static void LedExampleEntry(void)
{
    // 创建一个任务
    osThreadAttr_t attr;

    attr.name = "LedTask";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 512;
    attr.priority = 25;

    if (osThreadNew((osThreadFunc_t)LedTask, NULL, &attr) == NULL)
    {
        printf("Falied to create LedTask!\n");
    }
}

APP_FEATURE_INIT(LedExampleEntry);

修改applications\BearPi\BearPi-HM_Nano\sample路径下的BUILD.gn文件,指定led_example,编译、烧录,按一下复位按键,可以看到开发板上的LED灯以1s的频率闪烁

GPIO扩展实验

源码:

/*读取GPIO的输出模式,读取GPIO的高低电平,*/
#include <stdio.h>
#include <unistd.h>

#include "ohos_init.h"
#include "cmsis_os2.h"
#include "wifiiot_gpio.h"
#include "wifiiot_gpio_ex.h"

static void LedTask(void)
{
    //初始化GPIO
    GpioInit();

    //设置GPIO_2的复用功能为普通GPIO
    IoSetFunc(WIFI_IOT_IO_NAME_GPIO_2, WIFI_IOT_IO_FUNC_GPIO_2_GPIO);  // 参数分别表示GPIO引脚号、GPIO复用功能

    //设置GPIO_2为输出模式
    GpioSetDir(WIFI_IOT_GPIO_IDX_2, WIFI_IOT_GPIO_DIR_OUT);  // 参数分别表示GPIO引脚号、GPIO输出方向

    WifiIotGpioDir val = {0};  // 定义变量,存储GPIO输出方向指针的地址

    GpioGetDir(WIFI_IOT_GPIO_IDX_2, &val);  // 读取GPIO的输出模式,并赋值给val
    printf("GPIO_2 Dir is %d\r\n", val);  // 打印,0是输入(WIFI_IOT_GPIO_DIR_IN),1是输出(WIFI_IOT_GPIO_DIR_OUT)

    WifiIotGpioValue OutputVal = {0};  // 定义变量,存储GPIO高低电平指针的地址

    while (1)
    {
        //设置GPIO_2输出高电平点亮LED灯
        GpioSetOutputVal(WIFI_IOT_GPIO_IDX_2, 1);  // 参数分别表示GPIO引脚号、电平高低(1为高电平、0为低电平)
        
        GpioGetOutputVal(WIFI_IOT_GPIO_IDX_2, &OutputVal);  // 读取GPIO的高低电平,并赋值给OutputVal
        printf("GPIO_2 OutputVal is %d\r\n", OutputVal);

        //延时1s
        usleep(1000000);

        //设置GPIO_2输出低电平熄灭LED灯
        GpioSetOutputVal(WIFI_IOT_GPIO_IDX_2, 0);

        GpioGetOutputVal(WIFI_IOT_GPIO_IDX_2, &OutputVal);  // 读取GPIO的高低电平,并赋值给OutputVal
        printf("GPIO_2 OutputVal is %d\r\n", OutputVal);

        //延时1s
        usleep(1000000);
    }
}

static void LedExampleEntry(void)
{
    // 创建一个任务
    osThreadAttr_t attr;

    attr.name = "LedTask";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 512;
    attr.priority = 25;

    if (osThreadNew((osThreadFunc_t)LedTask, NULL, &attr) == NULL)
    {
        printf("Falied to create LedTask!\n");
    }
}

APP_FEATURE_INIT(LedExampleEntry);

编译、烧录、打印日志

日志如下:

梅科尔工作室-#14天鸿蒙设备开发实战#驱动子系统开发笔记-开源基础软件社区

GPIO中断

GPIO中断API介绍

参考:

wifiiot_gpio.h接口简介

接口名 功能描述
GpioRegisterlsrFunc 设置GPIO引脚中断功能
GpioUnregisterlsrFunc 取消GPIO引脚中断功能
GpioSetlsrMask 屏蔽GPIO引脚中断功能
GpioSetlsrMode 设置GPIO引脚中断触发模式
  • GpioRegisterIsrFunc()
    unsigned int GpioRegisterIsrFunc (WifiIotGpioIdx id, WifiIotGpioIntType intType, WifiIotGpioIntPolarity intPolarity, GpioIsrCallbackFunc func, char * arg )
    描述:

    启用GPIO引脚的中断功能。这个函数可以用来为GPIO pin设置中断类型、中断极性和中断回调。

    参数:

    名字 描述
    id 表示GPIO引脚号
    intType 表示中断类型,可设置为WIFI_IOT_INT_TYPE_LEVEL(电平触发)和WIFI_IOT_INT_TYPE_EDGE(边沿触发),电平触发是指GPIO为高电平或低电平时触发,边沿触发是指GPIO电平跳变时触发,即高电平变为低电平(下降沿)或低电平变为高电平(上升沿)
    intPolarity 表示中断极性,可设置为WIFI_IOT_GPIO_EDGE_FALL_LEVEL_LOWWIFI_IOT_GPIO_EDGE_RISE_LEVEL_HIGH,如果设置为WIFI_IOT_GPIO_EDGE_FALL_LEVEL_LOW,中断类型为电平触发时,表示低电平触发,中断类型为边沿触发时,表示下降沿触发;设置为WIFI_IOT_GPIO_EDGE_RISE_LEVEL_HIGH则相反
    func 表示中断回调函数,中断期间执行的函数
    arg 表示中断回调函数中使用的参数的指针,可以向中断回调函数传递参数

源码在base\iot_hardware\interfaces\kits\wifiiot_lite\wifiiot_gpio.h路径下

查看按键对应的GPIO引脚

F1和F2按键对应的GPIO引脚是分别是GPIO11和GPIO12,通过检测GPIO的电平信号来判断按键的状态。

梅科尔工作室-#14天鸿蒙设备开发实战#驱动子系统开发笔记-开源基础软件社区

GPIO中断读取按键状态

源码在applications\BearPi\BearPi-HM_Nano\sample\B2_basic_button\button_example.c路径下,以下添加了部分注释:

/*按一下F1,LED灯会被点亮,再按一下F2,LED灯会被熄灭*/
#include <stdio.h>
#include <unistd.h>

#include "ohos_init.h"
#include "cmsis_os2.h"
#include "wifiiot_gpio.h"
#include "wifiiot_gpio_ex.h"

static void F1_Pressed(char *arg)
{
    (void)arg;
    GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_2, 1);  // 设置GPIO引脚为高电平
}
static void F2_Pressed(char *arg)
{
    (void)arg;
    GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_2, 0);  // 设置GPIO引脚为低电平
}
static void ButtonExampleEntry(void)
{
    GpioInit();  // 初始化GPIO

    //初始化LED灯
    IoSetFunc(WIFI_IOT_IO_NAME_GPIO_2, WIFI_IOT_IO_FUNC_GPIO_2_GPIO);

    GpioSetDir(WIFI_IOT_IO_NAME_GPIO_2, WIFI_IOT_GPIO_DIR_OUT);  // 设置GPIO_2为输出模式

    //初始化F1按键,设置为下降沿触发中断
    IoSetFunc(WIFI_IOT_IO_NAME_GPIO_11, WIFI_IOT_IO_FUNC_GPIO_11_GPIO);  // 设置GPIO_11的复用功能为普通GPIO

    GpioSetDir(WIFI_IOT_IO_NAME_GPIO_11, WIFI_IOT_GPIO_DIR_IN);  // 设置GPIO_2为输入模式
    IoSetPull(WIFI_IOT_IO_NAME_GPIO_11, WIFI_IOT_IO_PULL_UP);  // 设置GPIO引脚为上拉
    GpioRegisterIsrFunc(WIFI_IOT_IO_NAME_GPIO_11, WIFI_IOT_INT_TYPE_EDGE, WIFI_IOT_GPIO_EDGE_FALL_LEVEL_LOW, F1_Pressed, NULL);  // 边沿触发,设置GPIO引脚中断功能
    // GpioRegisterIsrFunc(WIFI_IOT_IO_NAME_GPIO_11, WIFI_IOT_INT_TYPE_LEVEL, WIFI_IOT_GPIO_EDGE_FALL_LEVEL_LOW, F1_Pressed, NULL);  // 电平触发,设置GPIO引脚中断功能


    //初始化F2按键,设置为下降沿触发中断
    IoSetFunc(WIFI_IOT_IO_NAME_GPIO_12, WIFI_IOT_IO_FUNC_GPIO_12_GPIO);

    GpioSetDir(WIFI_IOT_IO_NAME_GPIO_12, WIFI_IOT_GPIO_DIR_IN);
    IoSetPull(WIFI_IOT_IO_NAME_GPIO_12, WIFI_IOT_IO_PULL_UP);
    GpioRegisterIsrFunc(WIFI_IOT_IO_NAME_GPIO_12, WIFI_IOT_INT_TYPE_EDGE, WIFI_IOT_GPIO_EDGE_FALL_LEVEL_LOW, F2_Pressed, NULL);
}

APP_FEATURE_INIT(ButtonExampleEntry);

修改applications\BearPi\BearPi-HM_Nano\sample路径下的BUILD.gn文件,指定button_example,编译、烧录,按一下复位按键,按一下F1,LED灯会被点亮,再按一下F2,LED灯会被熄灭

GPIO中断扩展实验

源码

/*通过GpioSetIsrMode改变中断触发模式,通过GpioSetIsrMask屏蔽GPIO引脚中断功能,第一次按下F1、F2都能打印日志,第二次F1按键被按下时不会打印日志,松开之后才会打印出来,再按下F2不会打印出日志*/
#include <stdio.h>
#include <unistd.h>

#include "ohos_init.h"
#include "cmsis_os2.h"
#include "wifiiot_gpio.h"
#include "wifiiot_gpio_ex.h"

static void F1_Pressed(char *arg)
{
    (void)arg;
    GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_2, 1);  // 设置GPIO引脚为高电平
    printf("This is F1_Pressed\r\n");
    GpioSetIsrMode(WIFI_IOT_IO_NAME_GPIO_11, WIFI_IOT_INT_TYPE_EDGE, WIFI_IOT_GPIO_EDGE_RISE_LEVEL_HIGH);  // 设置GPIO引脚中断触发模式为上升沿
}
static void F2_Pressed(char *arg)
{
    (void)arg;
    GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_2, 0);  // 设置GPIO引脚为低电平
    printf("This is F2_Pressed\r\n");
    GpioSetIsrMask(WIFI_IOT_IO_NAME_GPIO_12, 1);  // 屏蔽GPIO_12引脚中断功能(1为屏蔽,0为不屏蔽)
}
static void ButtonExampleEntry(void)
{
    GpioInit();  // 初始化GPIO

    //初始化LED灯
    IoSetFunc(WIFI_IOT_IO_NAME_GPIO_2, WIFI_IOT_IO_FUNC_GPIO_2_GPIO);

    GpioSetDir(WIFI_IOT_IO_NAME_GPIO_2, WIFI_IOT_GPIO_DIR_OUT);  // 设置GPIO_2为输出模式

    //初始化F1按键,设置为下降沿触发中断
    IoSetFunc(WIFI_IOT_IO_NAME_GPIO_11, WIFI_IOT_IO_FUNC_GPIO_11_GPIO);  // 设置GPIO_11的复用功能为普通GPIO

    GpioSetDir(WIFI_IOT_IO_NAME_GPIO_11, WIFI_IOT_GPIO_DIR_IN);  // 设置GPIO_2为输入模式
    IoSetPull(WIFI_IOT_IO_NAME_GPIO_11, WIFI_IOT_IO_PULL_UP);  // 设置GPIO引脚为上拉
    GpioRegisterIsrFunc(WIFI_IOT_IO_NAME_GPIO_11, WIFI_IOT_INT_TYPE_EDGE, WIFI_IOT_GPIO_EDGE_FALL_LEVEL_LOW, F1_Pressed, NULL);  // 边沿触发,设置GPIO引脚中断功能
    // GpioRegisterIsrFunc(WIFI_IOT_IO_NAME_GPIO_11, WIFI_IOT_INT_TYPE_LEVEL, WIFI_IOT_GPIO_EDGE_FALL_LEVEL_LOW, F1_Pressed, NULL);  // 电平触发,设置GPIO引脚中断功能

    //初始化F2按键,设置为下降沿触发中断
    IoSetFunc(WIFI_IOT_IO_NAME_GPIO_12, WIFI_IOT_IO_FUNC_GPIO_12_GPIO);

    GpioSetDir(WIFI_IOT_IO_NAME_GPIO_12, WIFI_IOT_GPIO_DIR_IN);
    IoSetPull(WIFI_IOT_IO_NAME_GPIO_12, WIFI_IOT_IO_PULL_UP);
    GpioRegisterIsrFunc(WIFI_IOT_IO_NAME_GPIO_12, WIFI_IOT_INT_TYPE_EDGE, WIFI_IOT_GPIO_EDGE_FALL_LEVEL_LOW, F2_Pressed, NULL);
}

APP_FEATURE_INIT(ButtonExampleEntry);

编译、烧录、打印日志

日志如下:

梅科尔工作室-#14天鸿蒙设备开发实战#驱动子系统开发笔记-开源基础软件社区

PWM输出

参考:

PWM API介绍

wifiiot_pwm.h接口简介

这个wifiiot_pwm.h中包含声明PWM接口函数

接口名 功能描述
PwmInit 初始化PWM
PwmDeinit 取消初始化PWM
PwmStart 根据输入参数输出PWM
PwmStop 停止PWM输出

原代码在base\iot_hardware\interfaces\kits\wifiiot_lite\wifiiot_pwm.h路径下

  • PwmStart()
    unsigned int PwmStart (WifiIotPwmPort port, unsigned short duty, unsigned short freq)

    描述:

    根据输入参数输出PWM信号。

    参数:

    名字 描述
    port PWM端口号
    duty 占空比
    freq 分频倍数

查看LED对应的GPIO引脚

LED对应的GPIO引脚是GPIO2,通过控制GPIO2输出的的电平信号来实现LED灯的闪烁。

  • 高电平时点亮LED灯。
  • 低电平时熄灭LED灯。

输出PWM改变LED亮度

源码在applications\BearPi\BearPi-HM_Nano\sample\B3_basic_pwm_led\pwm_example.c路径下,以下添加了部分注释:

/*LED由最暗变亮,变到最亮时,又变灰最暗,循环往复*/
#include <stdio.h>

#include <unistd.h>

#include "ohos_init.h"
#include "cmsis_os2.h"
#include "wifiiot_pwm.h"
#include "wifiiot_gpio.h"
#include "wifiiot_gpio_ex.h"

#define PWM_TASK_STACK_SIZE 512
#define PWM_TASK_PRIO 25

static void PWMTask(void)
{
    unsigned int i;

    //初始化GPIO
    GpioInit();

    //设置GPIO_2引脚复用功能为PWM
    IoSetFunc(WIFI_IOT_IO_NAME_GPIO_2, WIFI_IOT_IO_FUNC_GPIO_2_PWM2_OUT);

    //设置GPIO_2引脚为输出模式
    GpioSetDir(WIFI_IOT_IO_NAME_GPIO_2, WIFI_IOT_GPIO_DIR_OUT);

    //初始化PWM2端口
    PwmInit(WIFI_IOT_PWM_PORT_PWM2);

    while (1)
    {
        for (i = 0; i < 40000; i += 100)
        {
            //输出不同占空比的PWM波
            PwmStart(WIFI_IOT_PWM_PORT_PWM2, i, 40000);  // 参数分别表示PWM端口号、占空比、分频系数

            usleep(10);
        }
        i = 0;
    }
}

static void PWMExampleEntry(void)
{
    // 创建一个任务
    osThreadAttr_t attr;

    attr.name = "PWMTask";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 512;
    attr.priority = 25;

    if (osThreadNew((osThreadFunc_t)PWMTask, NULL, &attr) == NULL)
    {
        printf("Falied to create PWMTask!\n");
    }
}

APP_FEATURE_INIT(PWMExampleEntry);

修改applications\BearPi\BearPi-HM_Nano\sample路径下的BUILD.gn文件,指定pwm_example,编译、烧录,按一下复位按键,可以看到LED呼吸的效果,由暗变亮再变到最暗,再重复这个过程

PWM扩展实验

源码:

/*PwmStop和PwmDeinit的使用,使用PwmStop时,可以看到LED灯变得很暗,但是还是在逐渐变亮再变到最暗,以此重复;使用PwmDeinit时,可以看到当LED灯由暗变亮再变暗经过5次后,LED灯保持常亮*/
#include <stdio.h>

#include <unistd.h>

#include "ohos_init.h"
#include "cmsis_os2.h"
#include "wifiiot_pwm.h"
#include "wifiiot_gpio.h"
#include "wifiiot_gpio_ex.h"

#define PWM_TASK_STACK_SIZE 512
#define PWM_TASK_PRIO 25

static void PWMTask(void)
{
    unsigned int i;

    //初始化GPIO
    GpioInit();

    //设置GPIO_2引脚复用功能为PWM
    IoSetFunc(WIFI_IOT_IO_NAME_GPIO_2, WIFI_IOT_IO_FUNC_GPIO_2_PWM2_OUT);

    //设置GPIO_2引脚为输出模式
    GpioSetDir(WIFI_IOT_IO_NAME_GPIO_2, WIFI_IOT_GPIO_DIR_OUT);

    //初始化PWM2端口
    PwmInit(WIFI_IOT_PWM_PORT_PWM2);

    uint8_t j = 0;

    while (1)
    {
        for (i = 0; i < 40000; i += 100)
        {
            //输出不同占空比的PWM波
            PwmStart(WIFI_IOT_PWM_PORT_PWM2, i, 40000);  // 参数分别表示PWM端口号、占空比、分频系数
            // PwmStop(WIFI_IOT_PWM_PORT_PWM2);  // 停止PWM输出

            usleep(10);
        }
        i = 0;

        j++;
        if (j == 5)
        {
            PwmDeinit(WIFI_IOT_PWM_PORT_PWM2);  // 取消初始化PWM
        }
    }
}

static void PWMExampleEntry(void)
{
    // 创建一个任务
    osThreadAttr_t attr;

    attr.name = "PWMTask";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 512;
    attr.priority = 25;

    if (osThreadNew((osThreadFunc_t)PWMTask, NULL, &attr) == NULL)
    {
        printf("Falied to create PWMTask!\n");
    }
}

APP_FEATURE_INIT(PWMExampleEntry);

使用PwmStop时,将PwmDeinit有关语句注释掉,编译、烧录,按一下复位按键,可以看到LED灯在逐渐变亮再变到最暗,但LED灯整体变得很暗,以此重复

使用PwmDeinit时,将PwmStop有关语句注释掉,编译、烧录,按一下复位按键,可以看到当LED灯由暗变亮再变暗经过5次后,LED灯保持常亮,亮度不再变化

ADC采样

参考:

ADC API介绍

wifiiot_adc.h接口简介

这个wifiiot_adc.h中包含声明ADC接口函数

接口名 功能描述
AdcRead 根据输入参数从指定的ADC通道读取一段采样数据

源码在ohos_bundles\@ohos\iot_controller\interfaces\kits\wifiiot_lite\wifiiot_adc.h路径下

  • AdcRead()
    unsigned int AdcRead (WifiIotAdcChannelIndex channel, unsigned short * data, WifiIotAdcEquModelSel equModel, WifiIotAdcCurBais curBais, unsigned short rstCnt )

    描述:

    根据输入参数从指定的ADC通道读取一段采样数据

    参数:

    名字 描述
    channel 表示ADC通道
    data 表示指向存储读取数据的地址的指针
    equModel 表示平均算法的次数
    curBais 表示模拟功率控制模式
    rstCnt 表示从重置到转换开始的时间计数。一次计数等于334纳秒。值的范围必须从0到0xFF

查看ADC对应的GPIO引脚

本案例将使用板载用户按键F1来模拟GPIO口电压的变化。GPIO_11对应的是ADC Channel 5,所以需要编写软件去读取ADC Channel 5的电压。GPIO对应的哪个ADC通道需要从芯片手册查看。芯片手册参见附件。

梅科尔工作室-#14天鸿蒙设备开发实战#驱动子系统开发笔记-开源基础软件社区

ADC读取GPIO的电压值

源码在applications\BearPi\BearPi-HM_Nano\sample\B4_basic_adc\adc_example.c路径下,以下添加了部分注释:

/*当没有按F1键的时候电压约为3.336V,按下F1键未松手的时候电压约为0.223V,松手后电压又变成约为3.336V*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <math.h>

#include "ohos_init.h"
#include "cmsis_os2.h"
#include "wifiiot_gpio_ex.h"
#include "wifiiot_errno.h"
#include "wifiiot_adc.h"

#define ADC_TASK_STACK_SIZE 1024 * 8
#define ADC_TASK_PRIO 24

/***** 获取电压值函数 *****/
static float GetVoltage(void)
{
    unsigned int ret;
    unsigned short data;

    ret = AdcRead(WIFI_IOT_ADC_CHANNEL_5, &data, WIFI_IOT_ADC_EQU_MODEL_8, WIFI_IOT_ADC_CUR_BAIS_DEFAULT, 0xff);  // 参数分别表示ADC通道,由GPIO对应的ADC通道确定、存储读取数据的地址的指针、平均算法的次数、模拟功率控制模式,此处为默认模式、从重置到转换开始的时间计数
    if (ret != WIFI_IOT_SUCCESS)
    {
        printf("ADC Read Fail\n");
    }

    return (float)data * 1.8 * 4 / 4096.0;  // 计算出电压值并返回
}

static void ADCTask(void)
{
    float voltage;

    //上拉,让按键未按下时GPIO_11保持高电平状态
    IoSetPull(WIFI_IOT_IO_NAME_GPIO_11, WIFI_IOT_IO_PULL_UP);
    while (1)
    {
        printf("=======================================\r\n");
        printf("***************ADC_example*************\r\n");
        printf("=======================================\r\n");

        //获取电压值
        voltage = GetVoltage();
        printf("vlt:%.3fV\n", voltage);

        //延时1s
        usleep(1000000);
    }
}

static void ADCExampleEntry(void)
{
    // 创建一个任务
    osThreadAttr_t attr;

    attr.name = "ADCTask";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = ADC_TASK_STACK_SIZE;
    attr.priority = ADC_TASK_PRIO;

    if (osThreadNew((osThreadFunc_t)ADCTask, NULL, &attr) == NULL)
    {
        printf("[ADCExample] Falied to create ADCTask!\n");
    }
}

APP_FEATURE_INIT(ADCExampleEntry);

修改applications\BearPi\BearPi-HM_Nano\sample路径下的BUILD.gn文件,指定adc_example,编译、烧录,打印日志

日志结果如下:

梅科尔工作室-#14天鸿蒙设备开发实战#驱动子系统开发笔记-开源基础软件社区

当没有按F1键的时候电压约为3.336V,按下F1键未松手的时候电压约为0.223V,松手后电压又变成约为3.336V

I2C总线

参考:

(I2C可以读作“I方C”)

I2C API介绍

wifiiot_i2c.h接口简介

wifiiot_i2c.h中包含声明I2C接口函数

接口名 功能描述
l2clnit 初始化I2C
I2cDeinit 取消l2C初始化
l2cWrite 将数据写入到I2C设备
l2cRead 从I12C设备读取数据

源码见ohos_bundles\@ohos\iot_controller\interfaces\kits\wifiiot_lite\wifiiot_i2c.h

I2cInit()
unsigned int I2cInit (WifiIotI2cIdx id, unsigned int baudrate )

描述:

用指定的频率初始化I2C设备

参数:

名字 描述
id I2C设备ID
baudrate I2C频率,一般设置为400000或者100000
I2cWrite()
unsigned int I2cWrite (WifiIotI2cIdx id, unsigned short deviceAddr, const WifiIotI2cData * i2cData )

描述:

将数据写入I2C设备

参数:

名字 描述
id I2C设备ID
deviceAddr I2C设备地址
i2cData 表示写入的数据
I2cRead()
unsigned int I2cRead (WifiIotI2cIdx id, unsigned short deviceAddr, const WifiIotI2cData * i2cData )

描述:

从I2C设备读取数据。读取的数据将保存到i2cData指定的地址

参数:

名字 描述
id I2C设备ID
deviceAddr I2C设备地址
i2cData 表示要读取的数据指向的指针

wifiiot_i2c_ex.h接口简介

wifiiot_i2c_ex.h中包含声明扩展I2C接口函数

接口名 功能描述
l2cWriteread 向I2C设备发送数据并接受数据响应
l2cSetBaudrate 设置I2C频率

源码见ohos_bundles\@ohos\iot_controller\interfaces\kits\wifiiot_lite\wifiiot_i2c_ex.h

I2cSetBaudrate()
unsigned int I2cSetBaudrate (WifiIotI2cIdx id, unsigned int baudrate )

描述:

为I2C设备设置频率,一般用于代码运行过程中,修改I2C频率

参数:

名字 描述
id I2C设备ID
baudrate I2C频率

查看NFC的I2C对应的GPIO引脚

NFC芯片的I2C对应的GPIO引脚是分别是GPIO0和GPIO1,所以需要编写软件使用GPIO_0和GPIO_1产生I2C信号去控制NFC芯片。

梅科尔工作室-#14天鸿蒙设备开发实战#驱动子系统开发笔记-开源基础软件社区

I2C读写NFC芯片

源码在applications\BearPi\BearPi-HM_Nano\sample\B5_basic_i2c_nfc\i2c_example.c路径下,以下添加了部分注释:

/*使用具有NFC功能的手机去触碰开发板NFC天线,可以看到手机读出写入的数据*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "ohos_init.h"
#include "cmsis_os2.h"
#include "wifiiot_errno.h"
#include "wifiiot_gpio.h"
#include "wifiiot_gpio_ex.h"
#include "wifiiot_i2c.h"
#include "wifiiot_i2c_ex.h"
#include "nfc.h"

#define I2C_TASK_STACK_SIZE 1024 * 8
#define I2C_TASK_PRIO 25

#define TEXT "Welcome to BearPi-HM_Nano!"
#define WEB "harmonyos.com"

static void I2CTask(void)
{
    uint8_t ret;
    GpioInit();  // 初始化GPIO

    //GPIO_0复用为I2C1_SDA
    IoSetFunc(WIFI_IOT_IO_NAME_GPIO_0, WIFI_IOT_IO_FUNC_GPIO_0_I2C1_SDA);

    //GPIO_1复用为I2C1_SCL
    IoSetFunc(WIFI_IOT_IO_NAME_GPIO_1, WIFI_IOT_IO_FUNC_GPIO_1_I2C1_SCL);

    //baudrate: 400kbps
    I2cInit(WIFI_IOT_I2C_IDX_1, 400000);

    I2cSetBaudrate(WIFI_IOT_I2C_IDX_1, 400000);  // 为I2C设备设置频率,一般用于代码运行过程中,修改I2C频率

    printf("I2C Test Start\n");

    ret = storeText(NDEFFirstPos, (uint8_t *)TEXT);  // 写入文本文件到第一个位置,参数分别表示写的位置(可以是NDEFFirstPos、NDEFMiddlePos、NDEFLastPos三个位置,所以要保证I2C写入三个以内的数据)、写入的内容,写入成功则返回1
    if (ret != 1)
    {
        printf("NFC Write Data Falied :%d ", ret);
    }
    ret = storeUrihttp(NDEFLastPos, (uint8_t *)WEB);  // 写入http网址到最后一个位置,参数分别表示写的位置、写入的内容,写入成功则返回1。如果要在手机触碰I2C芯片的时候,手机自动打开网页,则要将http网址写入到第一个位置
    if (ret != 1)
    {
        printf("NFC Write Data Falied :%d ", ret);
    }
    while (1)
    {
        printf("=======================================\r\n");
        printf("***********I2C_NFC_example**********\r\n");
        printf("=======================================\r\n");
        printf("Please use the mobile phone with NFC function close to the development board!\r\n");
        usleep(1000000);
    }
}

static void I2CExampleEntry(void)
{
    // 创建一个任务
    osThreadAttr_t attr;

    attr.name = "I2CTask";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = I2C_TASK_STACK_SIZE;
    attr.priority = I2C_TASK_PRIO;

    if (osThreadNew((osThreadFunc_t)I2CTask, NULL, &attr) == NULL)
    {
        printf("Falied to create I2CTask!\n");
    }
}

APP_FEATURE_INIT(I2CExampleEntry);

修改applications\BearPi\BearPi-HM_Nano\sample路径下的BUILD.gn文件,指定i2c_example,编译、烧录,烧录到开发板上后按一下开发板复位按键,之后将具有NFC功能的手机去触碰开发板NFC天线,可以看到手机已经读出了写入的数据

梅科尔工作室-#14天鸿蒙设备开发实战#驱动子系统开发笔记-开源基础软件社区

如何查看手机是否具有NFC功能,可参考如何查看手机有没有NFC功能_百度知道 (baidu.com)

UART读写

参考:

UART API介绍

通用异步收发传输器(Universal Asynchronous Receiver/Transmitter,通常称作UART)是一种串行、异步、全双工的通信协议,在嵌入式领域应用的非常广泛。

wifiiot_uart.h接口简介

wifiiot_uart.h中包含声明UART接口函数

源码在base\iot_hardware\interfaces\kits\wifiiot_lite\wifiiot_uart.h路径下

接口名 功能描述
Uartlnit 初始化UART
UartDeinit 取消UART初始化
UartRead 从UART读取数据
UartWrite 将数据写入UART
UartSetFlowCtrl 设置UART流控制
UartInit()
unsigned int UartInit (WifiIotUartIdx id, const WifiIotUartAttribute * param, const WifiIotUartExtraAttr * extraAttr)

描述:

配置一个UART设备。
参数:

名字 描述
id UART端口号
param 表示基本UART属性
extraAttr 表示扩展UART属性
UartWrite()
int UartWrite (WifiIotUartIdx id, const unsigned char * data, unsigned int dataLen)

描述:
将数据写入UART设备,也就是通过UART来发送数据

参数:

名字 描述
id UART端口号
data 表示指向要写入数据的起始地址的指针
dataLen 表示读取数据的长度
UartRead()
int UartRead (WifiIotUartIdx id, unsigned char * data, unsigned int dataLen)

描述:

从UART设备读取数据。

参数:

名字 描述
id UART端口号
data 表示指向要读取数据的起始地址的指针
dataLen 表示读取数据的长度

查看UART1对应的GPIO引脚

UART1对应的GPIO引脚是分别是GPIO5和GPIO6,将使用GPIO5和GPIO6进行UART数据的收发。

梅科尔工作室-#14天鸿蒙设备开发实战#驱动子系统开发笔记-开源基础软件社区

UART读写数据

源码在applications\BearPi\BearPi-HM_Nano\sample\B6_basic_uart\uart_example.c路径下,以下添加了部分注释:

/*UART读出写入的数据*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "ohos_init.h"
#include "cmsis_os2.h"
#include "wifiiot_errno.h"
#include "wifiiot_gpio.h"
#include "wifiiot_gpio_ex.h"
#include "wifiiot_adc.h"
#include "wifiiot_uart.h"

#define UART_TASK_STACK_SIZE 1024 * 8
#define UART_TASK_PRIO 25
#define UART_BUFF_SIZE 1000

static const char *data = "Hello, BearPi!\r\n";

static void UART_Task(void)
{
    uint8_t uart_buff[UART_BUFF_SIZE] = {0};
    uint8_t *uart_buff_ptr = uart_buff;
    uint32_t ret;

    // 基本UART属性
    WifiIotUartAttribute uart_attr = {

        //baud_rate: 9600
        .baudRate = 9600,  // 波特率,这个波特率要和接到UART端口上的设备波特率匹配

        //data_bits: 8bits
        .dataBits = 8,  // 数据位
        .stopBits = 1,  // 停止位
        .parity = 0,  // 奇偶校验位
    };

    //Initialize uart driver
    ret = UartInit(WIFI_IOT_UART_IDX_1, &uart_attr, NULL);  // 参数分别表示UART的端口号、UART基本的属性、UART扩展属性
    if (ret != WIFI_IOT_SUCCESS)
    {
        printf("Failed to init uart! Err code = %d\n", ret);
        return;
    }
    printf("UART Test Start\n");
    while (1)
    {
        printf("=======================================\r\n");
        printf("*************UART_example**************\r\n");
        printf("=======================================\r\n");

        //通过串口1发送数据
        UartWrite(WIFI_IOT_UART_IDX_1, (unsigned char *)data, strlen(data));  // 参数分别表示UART的端口号、要写入数据的起始地址的指针、数据的长度

        //通过串口1接收数据。将开发板上的UART1_RXD和UART1_TXD短接,可以实现自发自收的功能
        UartRead(WIFI_IOT_UART_IDX_1, uart_buff_ptr, UART_BUFF_SIZE);// 参数分别表示UART的端口号、要接收数据的起始地址的指针、能够读取的最大数据长度

        printf("Uart1 read data:%s", uart_buff_ptr);
        usleep(1000000);
    }
}

static void UART_ExampleEntry(void)
{
    // 创建一个任务
    osThreadAttr_t attr;

    attr.name = "UART_Task";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = UART_TASK_STACK_SIZE;
    attr.priority = UART_TASK_PRIO;

    if (osThreadNew((osThreadFunc_t)UART_Task, NULL, &attr) == NULL)
    {
        printf("[ADCExample] Falied to create UART_Task!\n");
    }
}

APP_FEATURE_INIT(UART_ExampleEntry);

修改applications\BearPi\BearPi-HM_Nano\sample路径下的BUILD.gn文件,指定uart_example,编译、烧录,烧录到开发板上后将开发板上的UART1_RXD和UART1_TXD短接,以实现自发自收的功能,能够看到效果,之后按一下开发板复位按键,打印日志

日志结果如下:

梅科尔工作室-#14天鸿蒙设备开发实战#驱动子系统开发笔记-开源基础软件社区

本章学习中的案例源码及BearPi_HM Nano 芯片手册见附件。

感悟

驱动子系统开发的学习相较于内核开发部分的学习要轻松许多,但是本部分的I2C总线部分,中间讲解NFC驱动的部分还是有些不理解,属于勉强能够接受,因为本人还未系统的学习过关于物联网、通讯等相关的理论知识,博客中解释不到位的地方或者是错误还请各位大佬指正,以后的学习中我有更深的理解我也会再进行补充。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
驱动子系统开发案例源码及芯片手册.zip 601.91K 22次下载
已于2022-8-6 17:15:44修改
4
收藏 2
回复
举报
回复
添加资源
添加资源将有机会获得更多曝光,你也可以直接关联已上传资源 去关联
    相关推荐