传感技术
直播中

jf_85136884

2年用户 10经验值
私信 关注
[讨论]

【罗姆传感器评估板试用体验连载】罗姆传感器之Android APK通过i2c总线直接访问气压传感器BM1390GLV

    经过一段时间试用,决定将气压传感器应用到我们Android产品上,成为电子产品的一个实用功能。
IMG_5456.JPG
    程序实现方面,Android系统内核是Linux Kernel,常规做法是写一个新I2C设备驱动用来驱动气压传感器,重新编译内核后内核就可以支持气压传感器。
    不过,这次我决定尝试一种新的做法:从用户空间访问I2C总线,直接和I2C器件进行通讯。这样做的好处显而易见,不需要改kernel代码且无需编译和更新固件,应用程序里就能直接操作I2C设备:气压传感器,编程难度大为降低,代码灵活性大大提高。话不多说,直接上代码:
1. 在用户空间里进行I2C通讯
static char i2c_bus[] = "/dev/i2c-3"; //我的PCBA板子上接的是i2c-3这个总线


static jint i2c_write(uint8_t reg, uint8_t *data, int32_t size){
    int fd;
    int ret;
    unsigned char buf[64];


    fd = open(i2c_bus, O_RDWR);
    LOGI("[i2c_write] Open i2c BUS: %sn", i2c_bus);
    if (fd < 0) {
        LOGI("open i2c dev error!n");
        return -1;
    }


    ret = ioctl(fd, I2C_SLAVE_FORCE, BM1390GLV_DEVICE_ADDRESS);
    if (ret < 0) {
        LOGI("set dev error!n");
        close(fd);
        return ret;
    }
    memset(buf, 0, 64);
    write(fd, buf, 10);


    buf[0] = reg;
    memcpy(&buf[1], data, size);


    ret = write(fd, buf, size + 1);
    if (ret < 0) {
        LOGI("I2C write error!n");
        close(fd);
        return -1;
    }


    close(fd);
    usleep(1000);
    return 0;
}

static jint i2c_read(uint8_t reg, uint8_t *data, int32_t size)
{
    int fd;
    int ret;
    unsigned char buf[64] = { 0 };


    fd = open(i2c_bus, O_RDWR);
    LOGI("[i2c_read] Open i2c BUS: %sn", i2c_bus);


    if (fd < 0) {
        LOGI("open i2c dev error!n");
        return BM1390GLV_COMM_ERROR;
    }
    ret = ioctl(fd, I2C_SLAVE_FORCE, BM1390GLV_DEVICE_ADDRESS);
    if (ret < 0) {
        LOGI("set dev error!n");
        close(fd);
        return ret;
    }


    i2c_write(reg, data, size);


    ret = read(fd, buf, size);
    if (ret < 0) {
        LOGI(" I2C read error!n");
        close(fd);
        return BM1390GLV_COMM_ERROR;
    }


    memcpy(data, buf, size);


    close(fd);
    usleep(1000);
    return BM1390GLV_COMM_OK;
}


2. 初始化传感器
JNIEXPORT jint JNICALL Init(JNIEnv *env, jobject thiz) {
    env->GetJavaVM(&gJavaVM);
    gJavaObj = env->NewGlobalRef(thiz);


    int32_t result;


    result = init_check();
    LOGI("Init %d",result);


    if (result == BM1390GLV_COMM_OK) {
        (void)init_setting();
    }


    return (result);
}


static jint init_check(void)
{
    int32_t result;
    uint8_t id[BM1390GLV_ALL_ID_SIZE];

    result = i2c_read(BM1390GLV_MANUFACTURER_ID_PART_ID, id, BM1390GLV_ALL_ID_SIZE);
    LOGI("init_check %d",result);

    if (result == BM1390GLV_COMM_OK) {
        LOGI("id1 %d", id[BM1390GLV_MANUFACTURER_ID]);
        LOGI("id2 %d", id[BM1390GLV_PART_ID]);

        if ((id[BM1390GLV_MANUFACTURER_ID] != BM1390GLV_MANUFACTURER_ID_VAL) || (id[BM1390GLV_PART_ID] != BM1390GLV_PART_ID_VAL)) {
            result = BM1390GLV_WAI_ERROR;
        }
    }

    return (result);
}
static jint init_setting(void)
{
    int32_t result;
    uint8_t val;

    val = BM1390GLV_POWER_DOWN_VAL;
    result = i2c_write(BM1390GLV_POWER_DOWN, &val, sizeof(val));
    if (result == BM1390GLV_COMM_OK) {
        val = BM1390GLV_RESET_VAL;
        (void)i2c_write(BM1390GLV_RESET, &val, sizeof(val));

        val = BM1390GLV_MODE_CONTROL_VAL;
        (void)i2c_write(BM1390GLV_MODE_CONTROL, &val, sizeof(val));

        ModeCtlVal = val;
    }

    return (result);
}

3. 读取传感器采集到的气压、温度
static float convert_hpa(uint32_t raw_press)
{
    float press;


    press = (float)raw_press / BM1390GLV_COUNTS_PER_HPA;


    return (press);
}


static jfloat convert_degree_celsius(int16_t raw_temp)
{
    float temp;


    temp = (float)raw_temp / BM1390GLV_COUNTS_PER_DEGREE_CELSIUS;


    return (temp);
}


static jint get_value(uint8_t *raw)
{
    int32_t result;


    result = i2c_read(BM1390GLV_PRESSURE_TEMPERATURE, raw, BM1390GLV_ALL_OUT_SIZE);


    return (result);
}


JNIEXPORT jint JNICALL get_val(JNIEnv *env, jobject thi)
{
    int32_t  result;
    uint8_t  raw_data[BM1390GLV_ALL_OUT_SIZE];
    uint32_t raw_press;
    uint16_t  raw_temp;


    result = get_value(raw_data);


    if (result == BM1390GLV_COMM_OK) {


        raw_press  = (uint32_t)raw_data[BM1390GLV_PRESS_OUT_MSB] << 16;
        raw_press |= (uint32_t)raw_data[BM1390GLV_PRESS_OUT_LSB] << 8;
        raw_press |= (uint32_t)raw_data[BM1390GLV_PRESS_OUT_XL];


        raw_temp  = (uint16_t)raw_data[BM1390GLV_TEMP_OUT_MSB] << 8;
        raw_temp |= (uint16_t)raw_data[BM1390GLV_TEMP_OUT_LSB];


        jfloat press = convert_hpa(raw_press);
        jfloat temp = convert_degree_celsius(raw_temp);
        LOGI("Pressure(hPa): %f", press);
        LOGI("Temperature(degree Celsius): %f", temp);


    };


    return (result);
}




最后,来看一下效果。先来一张示波器量到的波形,证明用户空间直接通过I2C总线访问I2C器件是成功的:
IMG_5455.JPG

接着看一下通过传感器读取到的气压值和温度值。没有在APK界面上显示,将就一下从PCBA板子的串口看打印信息吧:
QQ图片20220524191237.png






更多回帖

发帖
×
20
完善资料,
赚取积分