首页 > 编程语言 >参考iictools源码实现HP203b气压温度传感器读取

参考iictools源码实现HP203b气压温度传感器读取

时间:2023-02-18 21:01:35浏览次数:49  
标签:温度传感器 addr msgs int HP203B 源码 寄存器 HP203b data

参考i2ctools源码实现HP203B气压温度传感器读取

由于开发的设备中要用到HP203B气压温度传感器,此设备要用到i2c协议进行数据的读取,我将以韦东山老师课程为指引,参考经典的i2c-tools源码,实现预期功能。
我的需求是:运用HP203B传感器,读取温度及气压,并显示出来。

1、 HP203B设备简介

1.1、功能简介

HP203B是一款超小型集高精度气压计、高度计和温度计于一体的传感器。内部集成了24位ADC,硅传感芯片,以及存放内部参数的OTP。该传感器通过设计公司获得的专利补偿算法在传感器器件片内进行采样,信号处理以及运算,最终计算出实际的直接结果值,所以外部应用MCU只需发出信号采集命令,待完成后,再通过I²C接口直接读取压力,温度及绝对海拔高度三者的实际值。
它的典型电路:
img
长这样:
img
img

1.2、寄存器的操作

我们可以通过操作寄存器,设置我们检测各种参数的阈值,中断,并启用/禁用数据补偿;从0x00-0x0A是用来设置参数如补偿、阈值,0x0B-0x0D是用于中断的控制。
其寄存器列表如下图所示:
img

1.3、使用命令

img
发送不同的命令,我们就可以从其中读取相相应的数据,进行解析:

  • SOFT_RST (0x06)
    软复位命令。不管当时传感器的工作模式,一旦接收到此命令,传感器就立即自动复位,内部所有的寄存器将被重置为默认值后重新进入睡眠状态,等待接受主机来的命令。
  • ADC_CVT (010, 3-bit OSR, 2-bit CHNL)
    这个命令选择传感器内部的过采样率 OSR、传感信号输入通道 CHNL 及执行 ADC 的转换。前两位用于告诉传感器数据从哪个通道输出,接下来的三位用于设置采样率:

img

  • READ_PT (0x10)
    温度数据由 20 位 2 的补码格式组成,单位为摄氏度。温度的值由 24位 OUT_T_MSB,OUT_T_CSB,OUT_T_LSB 存储。最高 4 位的数据是无用,而最低有效 20 位代表温度的值。我们应当把这 20 位以 2 的补码的二进制值转换成一个整数,然后整数除以 100 获得最终结果。气压数据由 20 位 2 的补码格式组成,单位为帕。气压的值由 24 位 OUT_T_MSB,OUT_T_CSB OUT_T_LSB存储。最高 4 位的数据是无用,而最低有效 20 位代表气压的值。用户应当把这 20 位以 2 的补码的二进制值转换成一个整数,然后整数除以 100 获得最终结果。

img

  • READ_AT (0x11)
    温度数据由 20 位 2 的补码格式组成,单位为摄氏度。温度的值由 24 位 OUT_T_MSB,OUT_T_CSB
    OUT_T_LSB 存储。最高 4 位的数据是无用,而最低有效 20 位代表温度的值。用户应当把这 20 位以 2 的补码的二进制值转换成一个整数,然后整数除以 100 获得最终结果。
    高度数据由 20 位 2 的补码格式组成,单位为米。高度的值由 24 位 OUT_T_MSB,OUT_T_CSB OUT_T_LSB存储。最高 4 位的数据是无用,而最低有效 20 位代表高度的值。用户应当把这 20 位以 2 的补码的二进制值转换成一个整数,然后整数除以 100 获得最终结果。

img

  • READ_P (0x30)
  • READ_A (0x31)
  • READ_T (0x32)
    这三种是单独读取气压,温度,海拔的数据的说明,数据格式和前文一样,感兴趣可以看数据手册。
  • ANA_CAL (0x28)
    重新校准内部模块,一般用不到。
  • READ_REG (0x80+6位寄存器地址)
    读取控制寄存器
  • WRITE_REG (0xC0+6位寄存器地址)
    写入控制寄存器

1.4、传感器的I2C接口

img
该传感器遵循I2C传输协议,当SCL拉低,SDA线上的信号开始变化,这是寄存器的地址和报文格式:
设备地址和CSB的引脚有关:
img
eg:CSB借VDD,写状态:11101100 :0xEC
I2C协议:

  • 单字节命令
    img
  • 写入寄存器
    img
  • 主机从设备读取寄存器的类型
    第一帧是发送包含高 2 位二进制数 10 及后面跟着低 6 位的寄存器地址
    的 READ_REG 命令。第一帧的格式与单字节的相同。在第二帧,该传感器将发送回寄存器中的数据当收到正确的设备地址及读位(R)之后。这种类型仅适用于使用 READ_REG 命令。
    img
    img
  • 主机从设备读 3 字节或 6 字 ADC 数据
    img
    我们连接到设备上看一下:使用的工具是I2C-tools,使用的开发板是RP-rv1126。
    img
    此刻出现了一个问题,明明地址写的是0xEC,为什么在这表现的是0x76?博主比较疑惑,分析了一下,才发现,我们所写的0xEC是根据I2C格式的指令,我们看一下他含有什么?
    img
    实际上,第一个帧数据包含两个部分,一个是设备地址,一个是R/W,那就是说,我们发送的0xEC,也是包含这两个部分,11101100(0xEC) 由 111 0110(device address) 和 0(W)组成,实际的地址就是:0111 0110 (0x76)。

2. 结合i2ctools源码分析

写程序要比源码考虑的东西少很多,并且由于自身有限,有些地方还是比较模糊,所以摘抄关键的部分进行解析,然后提炼到自己的程序当中。
我们先看i2ctransfer.c
img
第一个框是一些参数的选择,我们来看主要的部分:
img
lookup_i2c_bus:解析命令,返回一个BUS的数值,我们本程序可以不用,直接输入i2cbus就行。
img
接下来就是打开设备,linux系统中设备也是以文件的形式存在,我们需要用open打开设备,看是否正常。
img
open_i2c_dev:传入了BUS的值,构造了设备名称,,并且打开了设备。
img
接下来两个函数,他们本质上是完成了一个功能,第一个函数用于解析地址,第二个函数传入地址,我们看看set_slave_address干了什么事情:
img
set_slave_addr:我们前面打开了设备,但是设备中可能会挂载很多的地址,那么哪个才是我们需要的传感器的地址呢?我们就需要设置我们要操作哪个设备,下图可以看到,传入的参数中有force,什么是强制,一般来说,当设备显示UU,则证明已经有对应的驱动,不能直接访问,要通过驱动访问,如果我们要跳出驱动,坚持访问,就直接设置force为1即可。
img
设置完地址,我们就能找到设备了,接下来我们就该进行数据的传输了。
img
传输用到ioctl函数,控制这些函数我们都需要这个函数,没什么好说的,重点是他传输的数据,我们可以看到有一个重要的结构体:
img
这个结构体包含了什么,我们去linux源码看看,在\Linux-4.9.88\include\uapi\linux\i2c-dev.h中:
img
我们从给ioctl函数中传入这样的结构体地址,也就是说,我们所有需要传输的信息就包含在内,我们可以看到里面有一个结构体,i2c_msg,我们再看看这个是怎么定义的:
img
里面包含了addr,flags,len,buf还有一些宏定义,我们看看在整个i2ctransfer.c中,这个结构体是怎么设置的:
img
初始化buf
img
addr就是我们的设备的地址,buf里面就是需要写或者读的数据,flags用来表示传输方向,bit0等于0表示写,bit0等于I2C_M_RD表示读。
之后就是数据的发送了,可以看出,我们整体的流程就是:
打开设备->设置地址->设置传输的信息->发送信息即可,所以我们的主程序也这样来写:

int main (int argc, char** argv) {
    /*打开设备*/
    open_i2c_dev(i2cbus, filename, sizeof(filename), 0);
    /*设置设备地址*/
    set_slave_addr(file, _ADDRESS, 0);
    /*检查是否准备好,看寄存器的数值*/
    int HP203B_reg_read (int fd, unsigned char reg_addr, unsigned char * data_buf,int len);
    /*发送,写入命令,发送*/
    int HP203B_reg_write_cmd (int fd, unsigned char cmd);
    int HP203B_reg_read (int fd, unsigned char reg_addr, unsigned char * data_buf,int len);
}

这是大概的思路,具体的实现代码如下:

#include <sys/ioctl.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include "i2cbusses.h"
/*./iic 3*/

#define _ADDRESS 0x76


int HP203B_reg_write_cmd (int fd, unsigned char cmd) {
    struct i2c_rdwr_ioctl_data data;
    struct i2c_msg msgs;
    msgs.buf = NULL;
    msgs.addr = _ADDRESS;
    msgs.flags = 0;/*表示写*/
    msgs.len = 1;
    msgs.buf = &cmd;
    data.msgs = &msgs;
    data.nmsgs = 1;
    if (ioctl(fd, I2C_RDWR,&data) < 0) {
        printf("HP203B_reg_write_cmd err ! \n");
        return -1;
    }
    return 0;

}/*发送单字节命令*/
int HP203B_reg_read (int fd, unsigned char reg_addr, unsigned char * data_buf,int len) {
    int i ;
    struct i2c_rdwr_ioctl_data data;
    struct i2c_msg msgs[2];
    for (i = 0; i < 2; i++) msgs[i].buf = NULL;
    msgs[0].addr = _ADDRESS;
    msgs[0].flags = 0;/*表示写*/
    msgs[0].len = 1;
    msgs[0].buf = &reg_addr;
    msgs[1].addr =  _ADDRESS;
    msgs[1].flags = I2C_M_RD;/*读*/
    msgs[1].len = len;
    msgs[1].buf = data_buf;
    data.msgs = msgs;
    data.nmsgs = 2;
    if (ioctl(fd, I2C_RDWR,&data) < 0) {
        printf("HP203B_reg_read err ! \n");
        return -1;
    }
    return 0;
}/*读取寄存器的值*/
int main(int argc, char** argv) {
    int i ;
    char filename[20];
    int file, i2cbus;
    unsigned char flag_ready;
    unsigned char rx_buf[10];
    float Temperature;
    unsigned int temp;
    unsigned int Pressure;
    if (argc != 2) {
        printf("usage is : ./iic [deviceNumber] \
        eg: ./iic 3 \n");
    }
    /*open device*/
    i2cbus = atoi(argv[1]);
    file = open_i2c_dev(i2cbus, filename, sizeof(filename), 0);
    if (file < 0) {
        printf("can't open %s\n", filename);
        return -1;
    }
    /*set slave addr*/
    if(set_slave_addr(file, _ADDRESS, 0)) {
        printf("can't set_slave_addr\n");
		return -1;
    }
    while (1) {
    HP203B_reg_read(file, 0x80|0x0D, &flag_ready, 1);/*查看设备是否处于ready的状态*/
    sleep(1);
    if (flag_ready == 0x40) {
        HP203B_reg_write_cmd(file, 0x40| 2<<2);
        usleep(25);
        HP203B_reg_read(file, 0x10, rx_buf,6);
        temp = rx_buf[0] << 8 | rx_buf[1] | rx_buf[2];
        if(temp&0x800000)
        temp|=0xff000000;
        Pressure = rx_buf[3] << 8 | rx_buf[4] | rx_buf[5];
        Temperature = temp ;
        printf("Temperature : %fC       Pressure : %dPa    \n", Temperature, Pressure);
    }
    }
    close(file);
    return 0;
}

参考:韦东山嵌入式课程,HP203B数据手册

标签:温度传感器,addr,msgs,int,HP203B,源码,寄存器,HP203b,data
From: https://www.cnblogs.com/zhaowenrui-life/p/17133577.html

相关文章

  • SpringMVC源码(九):无异常View视图解析
    在MVC请求流程中,处理Controller控制器逻辑后获取到的ModelAndView对象并不能直接返回到浏览器,需要通过对ModelAndView中的View属性做解析获取视图,并用Model属性中的数......
  • 【Spring IOC】【五】容器源码解析- 属性填充populateBean
    1 前言好了,我们这篇文章讲解下populateBean,也就是bean的属性填充,并不仅仅是设置值,还有很多事情要做的。比如你的属性值类型转换、表达式解析等,关于属性填充的一些知识,本......
  • linux源码解析13- 反向映射RAMP详解
    1.什么是反向映射是一种物理地址反向映射虚拟地址的方法;正向映射:用户访问的虚拟地址,经过多级页表转化,最终映射到物理页面;反向映射:根据物理页面,找到所有映射到这个页面的......
  • ZYNQ FSBL源码分析
    ​ FSBL是ZYNQ的bootloader虽然不是第一个启动的,但属于用户可以更改的启动程序,因此对源码分析是非常有必要的(在FSBL之前有bootRom,这个已经固化)zynq在运行完芯片内固......
  • 摄像头视频云台控制PTZ前端html css原生样式源码分享
        ​<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width,initial-scale=1.0">......
  • 智慧校园:带微信小程序端源码
    智慧校园-基础数据管理1、学校信息:支持管理员对学校对基本学校信息进行编辑并浏览,通过编辑提交后全校可查看2、学科设置:支持管理添加并编辑以及删除学科,添加学科时系统自动......
  • Linux系列教程(十三)——Linux软件包管理之源码包、脚本安装包
    上篇博客我们讲解了网络yum源和光盘yum源的搭建步骤,然后详细介绍了相关的yum命令,yum最重要是解决了软件包依赖性问题。在安装软件时,我们使用yum命令将会简单方便很多。......
  • Semaphore源码解析
    Semaphore源码解析描述:一个计数信号量。从概念上讲,信号量维护一组许可。每个acquire()方法在必要时阻塞,直到获得许可,然后才能使用它。每次release()释放一个许可,潜在......
  • 阅读GitHub上的项目源码有以下几种方法
    GitHub是一个非常流行的代码托管平台,上面有很多优秀的开源项目。阅读这些项目的源码可以帮助我们学习和提高编程技能。阅读GitHub上的项目源码有以下几种方法:1、下载源码到......
  • 多线程等待所有子线程执行完使用总结(3)——CyclicBarrier使用和源码初步分析
    问题背景我们在日常开发和学习过程中,经常会使用到多线程的场景,其中我们经常会碰到,我们代码需要等待某个或者多个线程执行完再开始执行,上一篇文章中(参考https://blog.51cto......