课程

课程 讲师

大气压力传感器

2018-06-08 16:54 来自小组

一、模块简介

    大气压力传感器使用I2C接口进行通讯,模块J1接口连接到IMX6魔法师Cortex-A系列底板的P1接口。

airpress.jpg

1.1 大气压力传感器

大气压力传感器是可以检测温度和大气压力,采用压阻效应技术。压阻效应是指当半导体受到应力作用时,由于应力引起能带的变化,能谷的能量移动,使其电阻率发生变化的现象。

大气压力传感器具有稳定的电磁兼容性、高精度、线性性以及稳定性特点,可以应用在导航系统、航海系统、天气检测等方面。

二、操作步骤

1、线路连接

首先将大气压力传感器的J1接口通过连接线连接到魔法师Cortex-A系列底板的P1接口;然后使用串口线将魔法师Cortex-A系列底板的串口COM1与电脑连接,如果电脑没有串口,请使用USB转串口模块连接电脑的USB接口;最后连接魔法师Cortex-A系列底板的电源线。

2、测试模块

打开超级终端或者其他串口工具,设置波特率为115200,数据位为8,奇偶校验为无,停止位为1,数据流控制为无,设置完成后点击确定连接串口。打开平台的电源开关,待平台启动后,在串口终端中输入命令,进入模块目录:

root@imx6dlsabresd:~# cd vendor/test/module/BMP180/

执行测试程序:

root@imx6dlsabresd:/vendor/test/module/BMP180 # ./install.sh

3、运行结果

运行测试程序后,会在终端上打印出温度(temperature)和压力(BMP180)值。

终端运行结果: temp=26.4℃ press = 101.63Kpa

用手指触摸模块芯片,可观察到温度变化。

三、硬件原理

1、模块接口

    大气压力传感器接口为一个5V电源引脚,一个SCL引脚,一个SDA引脚。该模块接口对应魔法师Cortex-A系列底板的P1接口。

sc.png

1.3 大气压力传感器接口原理图


2、大气压力传感器原理

    本模块上通过BMP芯片读取温度和压力值。SCL引脚是I2C时钟引脚,SDA引脚是I2C数据引脚,XCLR是重置引脚(未使用),EOC是转换完毕状态引脚(未使用)。本模块操作简单,使用时直接通过I2C接口传输指令即可。具体操作指令请查看程序源码或芯片手册。

17.png

1.4 大气压力传感器原理图

四、LinuxI2C驱动框架

    I2C驱动代码在内核中分布如下图所示:

22.png

4.1 I2C驱动代码目录

i2c-core.c实现了i2c核心功能,i2c-dev.c实现了与应用的交互接口。至于algos里面主要实现的是总线适配,busses主要就是一些控制器相关的和gpio模拟的i2c代码。

LinuxI2C体系结构符合Linux总线-设备-驱动开发模型,总体分为3个组成部分:

I2C核心:将与具体适配器无关的代码以及探测设备,检测设备地址的上层代码提取到一块,为I2C总线驱动和设备驱动提供注册、注销以及通信方法,负责I2C驱动与I2C设备的匹配工作。

I2C总线驱动:I2C总线驱动是对I2C硬件体系结构中适配器端的实现,适配器可由CPU控制,甚至可以直接集成在CPU内部。

I2C设备驱动:I2C设备驱动(也称为客户驱动)是对I2C硬件体系结构中设备端的实现,设备一般挂接在受CPU控制的I2C适配器上,通过I2C适配器与CPU交换数据。Linux I2C驱动架构图如下图所示:

030.png

4.2 Linux i2c驱动架构图

其中adaptori2c的总线驱动,驱动CPU内部的i2c适配器的工作,在内核引入设备树之后,这部分的工作变为修改设备树了,设备树内容下个章节会讲到。devdriverclienti2c的设备驱动,提供用户层统一的API,这部分的代码是通用的。


五、IMX6 I2C设备树分析

分析imx6设备树文件imx6dl-sabresd.dts,包括它包含的.dtsi文件"imx6qdl.dtsi""imx6dl.dtsi""imx6qdl-sabresd.dtsi"。提取i2c相关信息,可以发现imx6dl处理器上有三条i2c总线("imx6qdl.dtsi"文件中)i2c0引用的是i2c1这个属性内容,“&”作用相当于C语言里面的指针。我们就以i2c0为例,带领读者分析一下imx6dl i2c设备树,最终找到i2c0所使用gpio引脚。

i2c0 = &i2c1;

i2c1 = &i2c2;

i2c2 = &i2c3;

继续查找i2c1,在"imx6qdl.dtsi"文件中有如下内容:

i2c1: i2c@021a0000 {

             #address-cells = ;

             #size-cells = ;

             compatible = "fsl,imx6q-i2c", "fsl,imx21-i2c";

             reg = ;

             interrupts = ;

             clocks = ;

             status = "disabled";

};

它定义了&i2c1节点(也就是i2c0)的各个属性及内容,具体属性含义可参考内核文档手册Documentation/devicetree/bindings/i2c/下各个txt文档。

继续搜索&i2c1节点,看在别的地方还有没有补充说明它的,发现在“imx6qdl-sabresd.dtsi”中还有&i2c1属性的一些内容,

&i2c1 {

    clock-frequency = ;

    pinctrl-names = "default";

    pinctrl-0 = ;

    status = "okay";

};

&i2c1里面的子节点都是挂载在它上面的设备,pinctrl-0 = ;表明pinctrl-0属性的内容引用的是pinctrl_i2c1。搜索pinctrl_i2c1,得到内容如下:

pinctrl_i2c1: i2c1grp {

         fsl,pins = ;

};

MX6QDL_PAD_CSI0_DAT8__I2C1_SDAMX6QDL_PAD_CSI0_DAT9__I2C1_SCL都是定义在“imx6dl-pinfunc.h”中的宏定义,它们为五组数据,加上后面的0x4001b8b1,组成六组数据供设备树解析代码处理,具体的解析过程需要详细阅读内核源代码。我们也可以通过名字看到,该宏定义的作用就是将CSI0_DAT8配置为I2C1SDA,将CSI0_DAT9配置为I2C1SCL

我们打开imx6dl处理器的数据手册IMX6SDLRM.pdf,搜索CSI0_DAT8CSI0_DAT9可以看到:

65221.png

CSI0_DAT8CSI0_DAT9引脚是可以配置成I2C1SDASCL的。

六、源码分析

bmp085_test.c文件是大气压力传感器的数据采集代码,该代码使用Linux系统调用函数openioctlreadwrite操作i2c设备节点/dev/i2c-0,实现对传感器模块数据的读写。

源代码里面封装了两个函数read_BMP085write_BMP085具体负责读写操作。

/**********************************************

*函数名      read_BMP085

*描述        :读取传感器数据

*输入参数   

*   @int fd         文件描述符

*   @void *buff     缓存地址

*   @unsigned char addr 数据地址

*   @size_t count       读取子节数

*输出参数    *buff

*返回值      :出错:-1  成功:返回读取的字节数        

***********************************************/

static int read_BMP085(int fd, void *buff, unsigned char addr, size_t count)

{

int res;

 

if(write(fd,&addr,1)!=1){   //发送读取地址

     printf("write_BMP085 err on line %d\n",__LINE__);

     return -1;

}

 

res=read(fd,buff,count);    //读取count个字节数据数据到buff缓存区

return res;

}

/**********************************************

*函数名      write_BMP085

*描述        :向模块写入数据

*输入参数   

*   @int fd         文件描述符

*   @unsigned char data 写入数据

*   @unsigned char addr 写入地址

*   @size_t count       写入子节数

*返回值      :出错:-1  成功:写入的字节数        

***********************************************/

static int write_BMP085(int fd, unsigned char data, unsigned char addr, size_t count)

{

int res;

char  sendbuffer[count+1];

 

sendbuffer[0] = addr;

sendbuffer[1] = data;

 

res=write(fd,sendbuffer,count + 1);

return res;

}

main()函数中,首先使用open()函数打开I2C_DEV

/*设备节点名字*/

#define I2C_DEV      "/dev/i2c-0"

 

fd = open(I2C_DEV, O_RDWR);          //打开i2c设备节点

if(fd < 0){

     printf("####i2c test device open failed####\n");

     return (-1);

}

然后使用ioctl进行操作配置,传感器模块设备地址位为7bit,先使用I2C_TENBIT命令设置i2c设备地址位长度为7bit(即参数为0,参数为1则设置为10bit),然后使用I2C_SLAVE命令设置从设备地址(这里定义宏CHIP_ADDR为从设备地址)

if(-1 == ioctl(fd,I2C_TENBIT,0)){        //设置地址位长度为 7bit

     printf("ioctl error on line %d\n",__LINE__);

     return (-1);

}

if(-1 == ioctl(fd,I2C_SLAVE,CHIP_ADDR)){    //设置从设备地址

     printf("ioctl error on line %d\n",__LINE__);

     return (-1);

}  

然后使用bmp085Init()函数获取校正系数的值。

/* 获取校正系数 */

bmp085Init();

 

/**********************************************

*函数名      bmp085Init

*描述        :获取校正系数

*输入参数    :无

*返回值      :无        

***********************************************/

void bmp085Init(void)

{

unsigned char buf[PAGE_SIZE];


read_BMP085(fd,buf,0xAA,2);

ac1 = buf[0]  13;

     x2 = (b1 * (b6 * b6 >> 12)) >> 16;

     x3 = ((x1 + x2) + 2) >> 2;

     b4 = (ac4 * (unsigned long) (x3 + 32768)) >> 15;

     b7 = ((unsigned long) up - b3) * (50000 >> OSS);

     if( b7 < 0x80000000)

         p = (b7 * 2) / b4 ;

     else 

         p = (b7 / b4) * 2;

     x1 = (p >> 8) * (p >> 8);

     x1 = (x1 * 3038) >> 16;

     x2 = (-7357 * p) >> 16;

     press = p + ((x1 + x2 + 3791) >> 4);

    

     printf("temp = %5.1f \t press = %5.2f Kpa\r",(float)temp/10,(float)press/1000);

     fflush(stdout);

     usleep(500*1000);      

}

这里使用while1)加usleep()方法,不停的读取数据,想要终止程序的话可以使用CTRL+C组合键强制退出该程序。

七、源码编译

先进入到测试程序目录中,再执行make命令。

root@uptech:~# cd /home/magic/module/BMP180/test

root@uptech:~# make clean

root@uptech:~# make

编译成功后会在当前目录下生成BMP180_test文件。





关注官方微信