红外温度传感器一般用于非接触式的温度检测。在我们的系统中经常会有这样的需求。所以我们将其设计为通用的驱动库以备复用。这一篇我们将讲述MLX90614红外温度传感器驱动的设计与实现。

1、功能概述

MLX90614是一种红外温度计,用于非接触式温度测量。红外测温是根据被测物体的红外辐射能量来确定物体的温度,不与被测物体接触,具有不影响被测物体温度分布场,温度分辨率高、响应速度快、测温范围广、不受测温上限的限制、稳定性好等特点。MLX90614被测目标温度和环境温度通过IIC接口输出,适合于汽车空调、室内暖气、家用电器、手持设备以及医疗设备应用等。

1.1、硬件描述

MLX90614 是一款无接触式的红外线温度感应芯片,它在同一TO-39封装内整合了红外热电堆感应器与一款定制的信号调节芯片。MLX90614在信号调节芯片中使用了先进的低噪音放大器,一枚17-bit ADC以及功能强大的DSP元件, 从而实现高精度温度测量。其引脚封装及功能如下:

MLX90614的出厂校准温度范围很广:环境温度为-40°C…125°C,目标温度为-70°C…380°C。测量值是传感器视场中所有物体的平均温度。在室温下,MLX90614的标准精确度为±0.5度。有一种特殊的医疗应用版本,在人体体温的有限温度范围内精确呈现±0.2恒温。

1.2、数据通讯

MLX90614红外温度传感器具有数字PWM和SMBus(系统管理总线)输出。10位PWM作为标准配置,可以在-20…120完美呈现测量温度,输出分辨率为0.14完美呈现。工厂默认的设置是SMBus总线接口。

MLX90614红外温度传感器又有一个参数存储EEPROM内存。在EEPROM内存中有限数量的地址可以由客户更改,这些地址存储着传感器可修改配置信息。整个EEPROM都可以通过SMBus接口读取。具体分配如下:

在这个EEPROM中,我们需要注意的有PWM控制寄存器以及配置寄存器。PWMCTRL寄存器的各位定义如下:

ConfigRegister1由控制位组成,用于配置模拟和数字部分,ConfigRegister1寄存器的各位定义如下:

MLX90614红外温度传感器还拥有一个32个字的RAM。用于存储一些实时更新的数据,如我们的测量数据。这一部分是只读的,其地址分配如下:

我们了解了MLX90614红外温度传感器的EEPROM和RAM的地址分配,它们的地址是分别编码的,似乎看不出差别。那我们如何能来区别访问它们呢?于是MLX90614红外温度传感器定义有如下的功能码:

读写EEPROM和RAM的命令,前三位表示命令,后5为对应所读参数在EEPROM和RAM中的地址。标志位是只读的,MLX90614在16位数据之后返回PEC,其中只有4位是有意义的,如果MD需要它,它可以在第一个字节之后停止通信。读数据和读标志的区别在于后者没有重复的起始位。

MLX90614红外温度传感器设备地址默认为0xB4,可以通过写EEPROM来修改设备地址。

2、驱动设计与实现

我们已经了解了MLX90614红外温度传感器的基本情况,接下来我们将根据这些资料开发MLX90614红外温度传感器的驱动程序。

2.1、对象定义

在使用一个对象之前我们需要获得一个对象。同样的我们想要使用MLX90614红外温度传感器对象就需要先定义MLX90614红外温度传感器的对象。

2.1.1、对象的抽象

我们要得到MLX90614温度传感器对象,需要先分析其基本特性。一般来说,一个对象至少包含两方面的特性:属性与操作。接下来我们就来从这两个方面思考一下MLX90614温度传感器的对象。

先来考虑属性,作为属性肯定是用于标识或记录对象特征的东西。我们来考虑MLX90614红外温度传感器对象属性。作为SMBus总线设备需要一个设备地址,这一地址用来区分总线上不同设备,所以我们将设备地址作为它的一个属性。对象的状态标识,PWM控制寄存器、配置寄存器都只是了MLX90614红外温度传感器当前所处的状态,所以我们将它们也作为属性。设备ID号是唯一标识各个MLX90614红外温度传感器的,我们也将其作为属性。测量的温度信号也表示了MLX90614红外温度传感器当前的状态,我们也将他们作为属性。标志寄存器在MLX90614红外温度传感器中是16位的,但真正有效的只有4位,所以我们以8位表示。

接着我们还需要考虑MLX90614红外温度传感器对象的操作问题。对于MLX90614红外温度传感器来说,我们需要对它进行读数据和写数据,而读写操作依赖于具体的硬件平台,所以我们将其作为对象的操作,以回调函数的方式使用。在操作MLX90614红外温度传感器的过程中,有些时序需要控制,所以需要延时函数,但延时操作依赖于具体的软硬件平台,所以我们将其作为对象的操作,以回调函数的方式使用。

根据上述我们对MLX90614红外温度传感器的分析,我们可以定义MLX90614红外温度传感器的对象类型如下:

typedef struct MLXObject {uint8_t devAddress;           //对象的地址uint8_t flags;                //对象状态标志uint16_t pwmctrl;             //PWM控制寄存器uint16_t ConfigRegister;      //配置寄存器uint16_t ID[4];               //对象的ID值float tempAmbient;            //温度值float tempObject1;            //温度值float tempObject2;            //温度值void (*Read)(struct MLXObject *mlx,uint8_t cmd,uint8_t *rData,uint16_t rSize);    //读数据操作指针void (*Write)(struct MLXObject *mlx,uint8_t cmd,uint8_t *wData,uint16_t wSize);   //写数据操作指针void (*Delayus)(volatile uint32_t nTime);       //延时操作指针
}MLXObjectType;

2.1.2、对象初始化

我们知道,一个对象仅作声明是不能使用的,我们需要先对其进行初始化,所以这里我们来考虑MLX90614红外温度传感器对象的初始化函数。一般来说,初始化函数需要处理几个方面的问题。一是检查输入参数是否合理;二是为对象的属性赋初值;三是对对象作必要的初始化配置。据此我们设计MLX90614红外温度传感器对象的初始化函数如下:

/* 红外温度传感器对象初始化 */
void MLXInitialization(MLXObjectType *mlx,    //MLX90614对象uint8_t address,       //设备地址MLXRead read,          //读数据函数指针MLXWrite write,        //写数据函数指针MLXDelayus delayus      //微秒岩石函数指针)
{if((mlx==NULL)||(read==NULL)||(write==NULL)||(delayus==NULL)){return;}mlx->Read=read;mlx->Write=write;mlx->Delayus=delayus;mlx->tempAmbient=0.0;mlx->tempObject1=0.0;mlx->tempObject2=0.0;if(address>0x00){mlx->devAddress=address;}else{mlx->devAddress=MLXSlaveAddress;}mlx->Delayus(200);GetIDFromMLX90614(mlx);mlx->flags=(uint8_t)ReadFlagFromMLX(mlx);mlx->pwmctrl=ReadDataFromMLX(mlx,EEPROMAccess|PWMCTRL);mlx->ConfigRegister=ReadDataFromMLX(mlx,EEPROMAccess|ConfigRegister1);
}

2.2、对象操作

我们已经完成了MLX90614红外温度传感器对象类型的定义和对象初始化函数的设计。但我们的主要目标是获取对象的信息,接下来我们还要实现面向MLX90614红外温度传感器的各类操作。

2.2.1、读数据操作

我们需要从MLX90614红外温度传感器读取数据,不管这个数据是在EEPROM还是在RAM,我们都可以采用相同的方式读取。我们已经说过,操作EEPROM和RAM的命令字节由3位命令和5位地址组成。我们实现数据读取函数如下:

/*读数据操作*/
static uint16_t ReadDataFromMLX(MLXObjectType *mlx,uint8_t cmd)
{uint8_t data[3];uint16_t tempCode=0;uint8_t pec[6];mlx->Read(mlx,cmd,data,3);pec[0]=mlx->devAddress;pec[1]=cmd;pec[2]=mlx->devAddress+1;pec[3]=data[0];pec[4]=data[1];pec[5]=data[2];if(PECCalculation(pec,6)==0x00){tempCode=(data[1]<<8)+data[0];}return tempCode;
}

2.2.2、写数据操作

我们需要向MLX90614红外温度传感器写一些数据用以配置传感器,这些可写的寄存器处于EEPROM之中,如配置寄存器、PWM控制信息、设备地址等。这里我们设计一个配置这些数据的操作函数。

/* 写数据操作 */
static void WriteDataToMLX(MLXObjectType *mlx,uint8_t cmd,uint16_t data)
{uint8_t wData[3];uint8_t pec[4];pec[0]=mlx->devAddress;pec[1]=cmd;pec[2]=(uint8_t)data;pec[3]=(uint8_t)(data>>8);wData[0]=(uint8_t)data;wData[1]=(uint8_t)(data>>8);wData[2]=PECCalculation(pec,4);mlx->Write(mlx,cmd,wData,3);
}

2.2.3、操作休眠模式

有些时候在我们不使用设备时,我们希望能够让设备休眠以节省资源,在需要时再将其唤醒投入工作。MLX90614具备有休眠的功能,这里我们看看如何使用这一功能。

/* 使设备进入休眠模式 */
void EnterSleepModeForMLX(MLXObjectType *mlx)
{uint8_t cmd;static uint8_t pec;uint8_t data[2];cmd=EnterSLEEPMode;data[0]=mlx->devAddress;data[1]=cmd;pec=PECCalculation(data,2);mlx->Write(mlx,cmd,&pec,1);
}

3、驱动的使用

我们已经设计并实现了MLX90614红外温度传感器的驱动程序。我们还需要对这一驱动进行验证。接下来我们将基于这一驱动程序开发获取MLX90614红外温度传感器数据的简单应用。

3.1、声明并初始化对象

使用基于对象的操作我们需要先得到这个对象,所以我们先要使用前面定义的MLX90614红外温度传感器对象类型声明一个MLX90614红外温度传感器对象变量,具体操作格式如下:

MLXObjectType mlx;

我们声明了这个对象变量,但还不能立即使用。我们还需要使用驱动中定义的初始化函数对这个对象变量进行初始化。初始化函数有一些用于对象初始化的参数需要输入:

MLXObjectType *mlx,MLX90614对象

uint8_t address,设备地址

MLXRead read,读数据函数指针

MLXWrite write,写数据函数指针

MLXDelayus delayus,微秒延时函数指针

对于这些参数,对象变量我们已经定义了,它正是我们需要初始化的对象。在这些参数中,我们需要注意的是几个函数指针,我们需要在应用中定义这几个函数,并将函数指针作为参数。这几个函数的类型如下:

/*定义读MLX90614数据操作指针类型*/
typedef void (*MLXRead)(struct MLXObject *mlx,uint8_t cmd,uint8_t *rData,uint16_t rSize);/*定义写MLX90614数据操作指针类型*/
typedef void (*MLXWrite)(struct MLXObject *mlx,uint8_t cmd,uint8_t *wData,uint16_t wSize);/*定义微秒延时操作指针类型*/
typedef void (*MLXDelayus)(volatile uint32_t nTime);

对于这几个函数我们根据样式定义就可以了,具体的操作可能与使用的软硬件平台有关系。在这里我们使用STM32F4的第2个I2C接口及其外设库,所以具体函数定义如下:

/*从MLX90614接收数据*/
static void ReceiveFromMLX(MLXObjectType *mlx,uint8_t cmd,uint8_t *rData,uint16_t rSize)
{HAL_I2C_Master_Transmit(&hlpti2c,mlx->devAddress,&cmd,1,1000);HAL_I2C_Master_Receive(&hlpti2c, mlx->devAddress,rData, rSize, 1000);
}/*向MLX90614传送数据*/
static void TransmitToMLX(MLXObjectType *mlx,uint8_t cmd,uint8_t *tData,uint16_t tSize)
{uint8_t data[10];data[0]=cmd;for(int i=0;i<tSize;i++){data[i+1]=tData[i];}HAL_I2C_Master_Transmit(&hlpti2c,mlx->devAddress,data,tSize+1,1000);
}

对于延时函数我们可以采用各种方法实现。我们采用的STM32平台和HAL库则可以直接使用HAL_Delay()函数。于是我们可以调用初始化函数如下:

MLXInitialization(&mlx,0xB4,ReceiveFromMLX,TransmitToMLX,HAL_Delay);

3.2、基于对象进行操作

我们定义了对象变量并使用初始化函数给其作了初始化。接着我们就来考虑操作这一对象获取我们想要的数据。我们在驱动中已经将获取数据并转换为转换值的比例值,接下来我们使用这一驱动开发我们的应用实例。

/*读取温度值*/
void GetTemperatureDataFromMLX(void)
{float tempObject;float tempAmbient;GetMLXTemperature(&mlx);tempObject=mlx.tempObject1;tempAmbient=mlx.tempAmbient;
}

4、应用总结

我们设计并实现了MLX90614红外温度传感器的驱动程序,并在此基础上设计了一个简单的应用来验证之。事实上我们在实际项目中也是使用这一驱动程序来实现应用的,并且效果良好。

读标志与读数据在时序控制上是有一些差别的,下发命令与接收数据之间没有重启的操作,这一点在操作它时需要注意。

我们在使用驱动时,一般会选择使用GPIO模拟的I2C收发器,这样稳定性更好。而使用硬件I2C接口及其库函数实现时,经常会有死锁的事情发生。我们曾多次遇到,特别是在STM32的第一路I2C接口。至于第1路I2C接口与其它的I2C接口有什么差异尚未确定。总之使用GPIO模拟I2C收发器更为稳定。

欢迎关注:

外设驱动库开发笔记13:MLX90614红外温度传感器驱动相关推荐

  1. 外设驱动库开发笔记15:DHT11温湿度传感器驱动

    与DS18B20一样DHT11也是采用单总线,但所不同的是DHT11可同时实现温度和湿度的检测.在我们的产品中经常使用它来检测环境的温湿度信息.这一篇我们将设计并封装DHT11的驱动程序,以方便重复使 ...

  2. 外设驱动库开发笔记21:BME680环境传感器驱动

    环境传感器是一类我们很常用的传感器.它可以方便我们获取压力.温度.湿度以及空气质量等数据.在这一篇中,我们将分析BME680环境传感器的功能,并设计和实现BME680环境传感器的驱动. 1.功能概述 ...

  3. 外设驱动库开发笔记19:BMP280压力温度传感器驱动

    压力和温度监测在嵌入式系统开发中是非常常见的需求,特别是对环境大气压力和温度的检测需求就更常见了.我们一般都会选择一些封装较小操作比较方便的压力传感器.BMP280就是满足这一要求的器件.在这一篇中我 ...

  4. 外设驱动库开发笔记45:MS4515DO压力传感器驱动

      很多时候我们需要检测流量和压力这些参数,比如我们要检测大气压,或者通过测量差压来获得输送流体的流量等,都需要用到压力传感器.这一篇我们就来讨论MS4515DO压力传感器的数据获取. 1.功能概述 ...

  5. 外设驱动库开发笔记50:HP203B气压传感器驱动

      在我们的项目中,经常会有需要检测大气压力的时候.这次我们在大气环境监测的过程中用到了HP203B这款气压传感器.所以这一篇中,我们来思考HP203B气压传感器的驱动设计. 1.功能概述   HP2 ...

  6. 外设驱动库开发笔记31:S-Modlue远红外气体传感器驱动

      在气体分析类产品中,我们经常会用到远红外气体传感器.我们就在碳氢类气体成分分析中使用了S-Modlue远红外气体传感器.接下来,我们将讨论S-Modlue远红外气体传感器驱动的设计与实现. 1.功 ...

  7. 外设驱动库开发笔记12:TSEV01CL55红外温度传感器驱动

    有时候我们需要检测一些无法直接接触的器件的温度.为了实现这一需求,我们通常会选择红外温度传感器来实现这一功能.考虑到复用的问题,我们一般会将操作元器件的代码抽象为驱动函数以备调用.这里我们就来设计并实 ...

  8. 外设驱动库开发笔记8:GPIO模拟I2C驱动

    I2C总线简单方便,是我们经常使用的一种总线.但有时候我们的MCU没有足够多的I2C控制器来实现我们的应用,所幸我可以使用普通的GPIO引脚来模拟低速的I2C总线通信.这一节我们就来实现使用软件通过普 ...

  9. 外设驱动库开发笔记0:EPD总体设计

    在产品开发过程中,不可避免需要使用很多外部的元件及传感器,这些元器件也许是板载的,也许是板外的,但不管怎样,为其开发驱动程序都是必须的.每次都需要为这些元器件编写驱动程序.但每次重复编写调试很麻烦,于 ...

最新文章

  1. ORA-04063: view SYS.DBA_REGISTRY has errors
  2. mysql基于传统的log_file及log_pos主从复制
  3. fatal error C1189: #error:MFC does not support WINVER less than 0x0501. Please change the definitio
  4. 全国计算机技术与软件专业技术资格(水平)考试基础知识
  5. java aspose重叠_Aspose.Words - 在特定位置合并两个文档
  6. Stream流的基本使用方法
  7. sqlmap使用_sqlmap于sql labs下使用
  8. linux 内核定时器精度_高精度时钟工作机制简介
  9. linux套接字端口,多端口监听套接字linux(multiport listening socket linux)
  10. iOS 数组模型排序
  11. 【软件测试】基础用例篇
  12. Windows批处理命令
  13. 基于Python的人脸识别
  14. 搜狗站长工具:索引量与收录量的解释,它等同于site的收录吗?
  15. heka 0.11.0源码分析--Elasticsearch OutPut插件
  16. 分布式光伏运维服务器,分布式光伏电站专业运维管理
  17. python提取pdf文字,python 提取pdf文字
  18. ps在褶皱T恤上贴上图案
  19. 小波变换(DWT),短时傅里叶分析(STFT),与快速傅里叶(FFT)之间的关系
  20. 大数据下的90后事业画像

热门文章

  1. Java面试知识点:Object类、Math类、BigDecimal类、自动装箱、拆箱
  2. 14 操作系统第四章 文件管理 文件逻辑结构 文件目录结构
  3. 前端基础之BOM和DOM
  4. 一个XML转换的例子
  5. [leetcode]从中序与后序/前序遍历序列构造二叉树
  6. 交易所行情报盘程序配置
  7. magent + memcached部署过程
  8. “阿基里斯与乌龟”的终结性思考
  9. ubuntu 安装yar和使用
  10. jQuery 的各种练习