HI3861学习笔记(15)——I2C接口使用

Posted Leung_ManWah

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HI3861学习笔记(15)——I2C接口使用相关的知识,希望对你有一定的参考价值。

一、简介

1.1 I2C

I2C(Inter-Integrated Circuit ,内部集成电路) 总线是一种由飞利浦 Philip 公司开发的串行总线。是两条串行的总线,它由一根数据线(SDA)和一根 时钟线(SDL)组成。两条线都需要上拉电阻。I2C 总线上可以接多个 I2C 设备,每个器件都有一个唯一的地址识别。同一时间只能有一个主设备,其他为从设备。通常 MCU 作为主设备控制,外设作为从设备。

1.2 GPIO复用功能

HI3861V100 芯片有 15 个 GPIO,引脚分布如下:


其中 I2C 设备有 2 个,其中 GPIO 可复用成 I2C 的设备如下:

Pin管脚名称复用信号
2GPIO_00I2C1_SDA
3GPIO_01I2C1_SCL
5GPIO_03I2C1_SDA
6GPIO_04I2C1_SCL
27GPIO_09I2C0_SCL
28GPIO_10I2C0_SDA
31GPIO_13I2C0_SDA
32GPIO_14I2C0_SCL

二、API说明

以下 GPIO 接口位于 base\\iot_hardware\\interfaces\\kits\\wifiiot_lite\\wifiiot_gpio.h

2.1 GpioInit

功能初始化GPIO外设
函数定义unsigned int GpioInit(void)
参数
返回错误码

以下扩展 GPIO 接口位于 base\\iot_hardware\\interfaces\\kits\\wifiiot_lite\\wifiiot_gpio_ex.h

2.2 iosetFunc

功能设置GPIO引脚功能
函数定义unsigned int IoSetFunc(WifiIotIoName id, unsigned char val)
参数id:表示GPIO引脚号
val:表示IO复用功能
返回错误码

以下 I2C 接口位于 base\\iot_hardware\\interfaces\\kits\\wifiiot_lite\\wifiiot_i2c.h

业务BUILD.gn中包含路径

include_dirs = [
        "//utils/native/lite/include",
        "//kernel/liteos_m/components/cmsis/2.0",
        "//base/iot_hardware/interfaces/kits/wifiiot_lite",
    ]

2.3 I2cInit

功能用指定的频率初始化I2C设备
函数定义unsigned int I2cInit(WifiIotI2cIdx id, unsigned int baudrate)
参数id:I2C设备ID
baudrate:I2C频率
返回错误码

2.4 I2cWrite

功能将数据写入I2C设备
函数定义unsigned int I2cWrite(WifiIotI2cIdx id, unsigned short deviceAddr, const WifiIotI2cData *i2cData)
参数id:I2C设备ID
deviceAddr:I2C设备地址
i2cData:表示写入的数据
返回错误码

2.5 I2cRead

功能从I2C设备读取数据。读取的数据将保存到i2cData指定的地址
函数定义unsigned int I2cRead(WifiIotI2cIdx id, unsigned short deviceAddr, const WifiIotI2cData *i2cData)
参数id:I2C设备ID
deviceAddr:I2C设备地址
i2cData:表示要读取的数据指向的指针
返回错误码

以下扩展 I2C 接口位于 base\\iot_hardware\\interfaces\\kits\\wifiiot_lite\\wifiiot_i2c_ex.h

2.6 I2cSetBaudrate

功能为I2C设备设置频率
函数定义unsigned int I2cSetBaudrate(WifiIotI2cIdx id, unsigned int baudrate)
参数id:I2C设备ID
baudrate:I2C频率
返回错误码

三、作为主机与BH1750光照强度传感器通信

编译时在业务BUILD.gn中包含路径

include_dirs = [
        "//utils/native/lite/include",
        "//kernel/liteos_m/components/cmsis/2.0",
        "//base/iot_hardware/interfaces/kits/wifiiot_lite",
    ]

BH1750芯片使用的是I2C协议,I2C_SCL与GPIO_0相连接,I2C_SDA与GPIO_1相连接,所以需要编写软件使用GPIO_0和GPIO_1产生I2C信号去控制BH1750芯片

#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"

#define I2C_TASK_STACK_SIZE 1024 * 8
#define I2C_TASK_PRIO 25

#define WRITE_BIT           0x00
#define READ_BIT            0x01

#define BH1750_SLAVE_ADDR   0x23 // 从机地址
#define BH1750_PWR_DOWN     0x00 // 关闭模块
#define BH1750_PWR_ON       0x01 // 打开模块等待测量指令
#define BH1750_RST          0x07 // 重置数据寄存器值在PowerOn模式下有效
#define BH1750_CON_H        0x10 // 连续高分辨率模式,1lx,120ms
#define BH1750_CON_H2       0x11 // 连续高分辨率模式,0.5lx,120ms
#define BH1750_CON_L        0x13 // 连续低分辨率模式,4lx,16ms
#define BH1750_ONE_H        0x20 // 一次高分辨率模式,1lx,120ms,测量后模块转到PowerDown模式
#define BH1750_ONE_H2       0x21 // 一次高分辨率模式,0.5lx,120ms,测量后模块转到PowerDown模式
#define BH1750_ONE_L        0x23 // 一次低分辨率模式,4lx,16ms,测量后模块转到PowerDown模式

/**
 @brief I2C写数据函数
 @param slaveAddr -[in] 从设备地址
 @param regAddr -[in] 寄存器地址
 @param pData -[in] 写入数据
 @param dataLen -[in] 写入数据长度
 @return 错误码
*/
int I2C_WriteData(uint8_t slaveAddr, uint8_t regAddr, uint8_t *pData, uint16_t dataLen)
{
    int ret;
    WifiIotI2cData i2c_data = {0};

    if(0 != regAddr)
    {
        i2c_data.sendBuf = &regAddr;
        i2c_data.sendLen = 1;
        ret = I2cWrite(WIFI_IOT_I2C_IDX_1, (slaveAddr << 1) | WRITE_BIT, &i2c_data);
        if(ret != 0)
        {
            printf("===== Error: I2C write status1 = 0x%x! =====\\r\\n", ret);
            return 0;
        }
    }

    i2c_data.sendBuf = pData;
    i2c_data.sendLen = dataLen;
    ret = I2cWrite(WIFI_IOT_I2C_IDX_1, (slaveAddr << 1) | WRITE_BIT, &i2c_data);
    if(ret != 0)
    {
        printf("===== Error: I2C write status1 = 0x%x! =====\\r\\n", ret);
        return 0;
    }

    return 1;
}

/**
 @brief I2C读数据函数
 @param slaveAddr -[in] 从设备地址
 @param regAddr -[in] 寄存器地址
 @param pData -[in] 读出数据
 @param dataLen -[in] 读出数据长度
 @return 错误码
*/
int I2C_ReadData(uint8_t slaveAddr, uint8_t regAddr, uint8_t *pData, uint16_t dataLen)
{
    int ret;
    WifiIotI2cData i2c_data = {0};

    if(0 != regAddr)
    {
        i2c_data.sendBuf = &regAddr;
        i2c_data.sendLen = 1;
        ret = I2cWrite(WIFI_IOT_I2C_IDX_1, (slaveAddr << 1) | WRITE_BIT, &i2c_data);
        if(ret != 0)
        {
            printf("===== Error: I2C write status = 0x%x! =====\\r\\n", ret);
            return 0;
        }
    }

    i2c_data.receiveBuf = pData;
    i2c_data.receiveLen = dataLen;
    ret = I2cRead(WIFI_IOT_I2C_IDX_1, (slaveAddr << 1) | READ_BIT, &i2c_data);
    if(ret != 0)
    {
        printf("===== Error: I2C read status = 0x%x! =====\\r\\n", ret);
        return 0;
    }

    return 1;
}

static void I2CTask(void)
{
    int ret;
    uint8_t sensor_data[2] = {0};
    uint8_t sensor_data_h, sensor_data_l;
    int cnt = 0;
    uint8_t data;

    GpioInit();

    //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);

    printf("I2C Test Start\\n");

    while (1)
    {
        printf("test cnt: %d", cnt++);
        data = BH1750_PWR_ON;              // 发送启动命令
        I2C_WriteData(BH1750_SLAVE_ADDR, 0, &data, 1);
        data = BH1750_ONE_L;               // 设置一次低分辨率模式,测量后模块转到PowerDown模式
        I2C_WriteData(BH1750_SLAVE_ADDR, 0, &data, 1);
        usleep(30000);                     // 设置完成后要有一段延迟
        ret = I2C_ReadData(BH1750_SLAVE_ADDR, 0, sensor_data, 2);
        sensor_data_h = sensor_data[0];
        sensor_data_l = sensor_data[1];
        if(ret == 0) 
        {
            printf("I2C Error");
        } 
        else if(ret == 1)
        {
            printf("*******************\\n");
            printf("MASTER READ SENSOR( BH1750 )\\n");
            printf("*******************\\n");
            printf("data_h: %02x\\n", sensor_data_h);
            printf("data_l: %02x\\n", sensor_data_l);
            printf("sensor val: %.02f [Lux]\\n", (sensor_data_h << 8 | sensor_data_l) / 1.2);
        }

        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);

查看打印:


• 由 Leung 写于 2021 年 10 月 10 日

• 参考:【鸿蒙2.0设备开发教程】小熊派HarmonyOS 鸿蒙·季 开发教程
    BearPi-HM_Nano开发板传感器驱动开发——E53_SC1读取光照强度

以上是关于HI3861学习笔记(15)——I2C接口使用的主要内容,如果未能解决你的问题,请参考以下文章

HI3861学习笔记(12)——GPIO输入接口使用

HI3861学习笔记(14)——ADC接口使用

HI3861学习笔记(18)——UART串口使用

HI3861学习笔记(19)——WiFi接口使用(STA和AP模式)

HI3861学习笔记(13)——PWM接口使用

HI3861学习笔记——CMSIS-RTOS2接口