LM95172温度芯片读取问题
开发TI的LM95172芯片的驱动时,DATASHEET上的时序是:每次片选CS拉低,第一个读取的16位数据就是温度寄存器里的值。但是,我在实现的过程中发现,好像事实并非如此。在实现的过程中,我的驱动对于有地址的寄存器的读/写是没有问题的。
===============================================================================
对此,我有两个疑问:
问题1:由于温度寄存器并没有地址,是否是在每次拉低CS时读取?除了在上电时需要复位,在读取温度寄存器之前是否还需要其他的操作?如设置控制/状态寄存器里的值?
问题2:温度是如何转换的?如何判断温度转换完成了?我除了在上电后,第一次拉低CS后读取的16位数据为0x7FFE外,其他的情况下,拉低CS,读取的16位数据都是0.
===============================================================================
以下简要说明操作LM95172的顺序:
(备注:SCK频率为38K; 黄色CS;绿色SCK;蓝色SIO)
- 上电时复位。

(1)拉低CS;读取温度寄存器(所有寄存器没有配置,读取的值为0x7FFE);发送8位读取控制/状态寄存器命令(0x81);读取控制/状态寄存器(读取得到的值为0x0800);拉高CS;

(2)拉低CS;读取温度寄存器(此时读取的值为0x0000);发送8位写入控制/状态寄存器命令(0x01);将(1)中读取的状态值最高位置1,写入控制/状态寄存器(SHUTDOWN状态控制位);延时100ms;拉高CS;

(3)拉低CS;读取温度寄存器(此时读取的值为0x0000);发送8位写入控制/状态寄存器命令(0x01);将(1)中读取的状态值最高位置0,写入控制/状态寄存器;延时100ms;拉高CS;

2. 读取温度:拉低CS;发送16位的串行时钟移入16位数据(移入的是温度寄存器中的数据吗?读取的数据一直是0x0000);拉高CS;

===============================================================================
这里还有一个现象,如果上电复位后,在读取温度是执行以下操作:
拉低片选 => 读入16位数据(是温度寄存器的值吗?)=> 写入一条8位的命令(如写入0x81,表示读取控制/状态寄存器) => 读取控制/状态寄存器。
则每次读取的值都不一样,读取的数值三次或是四次一个循环周期,还经常出现如下时序,
这个时序图的异常时由什么引起的?

===============================================================================
以下为驱动代码:
#ifndef LM95172_H
#define LM95172_H
#include <Arduino.h>
class LM95172 {
public:
static const int READ = 1;
static const int WRITE = 0;
static const int CELSIUS = 1;
static const int FAHRENHEIT = 0;
static const byte REG_CTL = 0x1;
static const byte REG_TH = 0x2;
static const byte REG_TL = 0x3;
static const byte REG_ID = 0x7;
static const byte CTRL_SHUT_DOWN = 15;
static const byte CTRL_ONE_SHOT = 14;
static const byte CTRL_OVERTEMP_RST = 13;
static const byte CTRL_CONV_TOGGLE = 12;
static const byte CTRL_OVERTEMP_STAT = 11;
static const byte CTRL_T_HIGH = 10;
static const byte CTRL_T_LOW = 9;
static const byte CTRL_DATA_AVAIL = 8;
static const byte CTRL_OVERTEMP_DIS = 7;
static const byte CTRL_OVERTEMP_POL = 6;
static const byte CTRL_RES_1 = 5;
static const byte CTRL_RES_0 = 4;
static const byte RES_13 = 0x0;
static const byte RES_14 = 0x1 << 4;
static const byte RES_15 = 0x2 << 4;
static const byte RES_16 = 0x3 << 4;
int currentResolution;
int currentUnit; //Celsius or Farenheit
int PIN_CS;
int PIN_CLK;
int PIN_SIO;
LM95172(int pinCS, int pinClk, int pinSIO) {
PIN_CS = pinCS;
PIN_CLK = pinClk;
PIN_SIO = pinSIO;
//default resolution
currentResolution = 13;
}
/**
* Initialize the sensor and reset
* the default unit is Farenheit
*/
void init();
void init(int theUnit)
{
init();
currentUnit = theUnit;
}
/**
* Device reset according to datasheet
* needs to be performed on power up.
*/
void resetSensor();
/**
* Change temperature reading resolution
* res: 13 - 16 bits
*/
void changeResolution(byte res);
/**
* Returns current temperature in Celsius
*/
double getTempC();
/**
*Returns current temperature in Fahrenheit
*/
double getTempF() {
return 1.8 * getTempC() + 32.0;
}
/**
*Returns the current temperature depending
*on the unit setting. The default unit is
*Fahrenheit.
*/
double getTempReading();
/**
* Set over temperature trip point
* tHigh: trip temperature
* tLow: hysteresis
*/
void setTripTemperatureC(double tLow, double tHigh);
/**
* Get the current trip temperature threshold
*/
void getTripTemperatureC(double& tLow, double& tHigh);
/**
* Enable or disable OneShot temperature measurement
* In OneShot mode, the device goes to shutdown mode
* once a measurement is made
*/
void enableOneShot(boolean enabled);
/**
* Send Command (either read or write) to the sen
* reg: register
* rw: READ or WRITE
* val: 16bit value (if READ, the value is return
*/
void sendCmd(byte reg, int rw, unsigned int &val);
};
#endif
#include "LM95172.h"
void LM95172::resetSensor()
{
unsigned int v = 0;
digitalWrite(PIN_CS, LOW);
getTempC();
sendCmd(REG_CTL, READ, v);
digitalWrite(PIN_CS, HIGH);
v = v | (1 << CTRL_SHUT_DOWN); //set shutdown bit;
digitalWrite(PIN_CS, LOW);
getTempC();
sendCmd(REG_CTL, WRITE, v);
delay(100);
digitalWrite(PIN_CS, HIGH);
v = ~(1 << CTRL_SHUT_DOWN) & v; //clear shutdown bit;
digitalWrite(PIN_CS, LOW);
getTempC();
sendCmd(REG_CTL, WRITE, v);
delay(100);
digitalWrite(PIN_CS, HIGH);
}
void LM95172::init() {
pinMode(PIN_CS, OUTPUT);
pinMode(PIN_CLK, OUTPUT);
pinMode(PIN_SIO, INPUT);
digitalWrite(PIN_CS, HIGH);
digitalWrite(PIN_CLK, LOW);
digitalWrite(PIN_SIO, HIGH);
currentUnit = FAHRENHEIT;
resetSensor();
}
void LM95172::changeResolution(byte res)
{
unsigned int v = 0;
digitalWrite(PIN_CS, LOW);
getTempC();
sendCmd(REG_CTL, READ, v);
digitalWrite(PIN_CS, HIGH);
v = v & 0xFFC0; //clear the lower 5 bits;
currentResolution = res;
if (res == 13) v = v | RES_13;
else if (res == 14) v = v | RES_14;
else if (res == 15) v = v | RES_15;
else v = v | RES_16;
digitalWrite(PIN_CS, LOW);
getTempC();
sendCmd(REG_CTL, WRITE, v);
digitalWrite(PIN_CS, HIGH);
}
double LM95172::getTempC()
{
double result = 0.0;
pinMode(PIN_SIO, INPUT);
byte h = shiftIn(PIN_SIO, PIN_CLK, MSBFIRST);
byte l = shiftIn(PIN_SIO, PIN_CLK, MSBFIRST);
unsigned int v = (h << 8) | l;
if (currentResolution == 13) {
if (v >= 4096) {
result = (4096.0 - (v >> 3)) * 0.0625;
} else {
result = (v >> 3) * 0.0625;
}
} else if (currentResolution == 14) {
if (v >= 8192) {
result = (8192.0 - (v >> 2)) * 0.03125;
} else {
result = (v >> 2) * 0.03125;
}
} else if (currentResolution == 15) {
if (v >= 16384) {
result = (16384.0 - (v >> 1)) * 0.015625;
} else {
result = (v >> 1) * 0.015625;
}
} else {
if (v >= 32768l) {
result = (32768.0 - v) * 0.0078125;
} else {
result = v * 0.0078125;
}
}
return result;
}
double LM95172::getTempReading()
{
double t = 0.0;
digitalWrite(PIN_CS, LOW);
if (currentUnit == CELSIUS) t = getTempC();
else t = getTempF();
digitalWrite(PIN_CS, HIGH);
return t;
}
void LM95172::setTripTemperatureC(double tLow, double tHigh)
{
unsigned int tl, th, v;
th = (unsigned int) (tHigh * 32 * 4) & 0xFFE0;
tl = (unsigned int) (tLow * 32 * 4) & 0xFFE0;
digitalWrite(PIN_CS, LOW);
getTempC();
sendCmd(REG_CTL, READ, v);
sendCmd(REG_TH, WRITE, th);
sendCmd(REG_TL, WRITE, tl);
digitalWrite(PIN_CS, HIGH);
}
void LM95172::getTripTemperatureC(double& tLow, double& tHigh)
{
unsigned int tl, th, v;
digitalWrite(PIN_CS, LOW);
getTempC();
sendCmd(REG_CTL, READ, v);
sendCmd(REG_TH, READ, th);
sendCmd(REG_TL, READ, tl);
digitalWrite(PIN_CS, HIGH);
tHigh = (double) th / 32.0 * 0.25;
tLow = (double) tl / 32.0 * 0.25;
}
void LM95172::enableOneShot(boolean enabled)
{
unsigned int v = 0;
digitalWrite(PIN_CS, LOW);
getTempC();
sendCmd(REG_CTL, READ, v);
digitalWrite(PIN_CS, HIGH);
if (enabled) {
v = v | (1 << CTRL_SHUT_DOWN) | ( 1 << CTRL_ONE_SHOT);
} else {
v = v & ~(1 << CTRL_SHUT_DOWN) & ~( 1 << CTRL_ONE_SHOT);
}
digitalWrite(PIN_CS, LOW);
getTempC();
sendCmd(REG_CTL, WRITE, v);
digitalWrite(PIN_CS, HIGH);
}
void LM95172::sendCmd(byte reg, int rw, unsigned int &val)
{
byte cmdByte = 0;
if (rw == READ) cmdByte = 0x80 | reg;
else cmdByte = reg;
pinMode(PIN_SIO, OUTPUT);
shiftOut(PIN_SIO, PIN_CLK, MSBFIRST, cmdByte);
if (rw == READ) {
pinMode(PIN_SIO, INPUT);
byte h = shiftIn(PIN_SIO, PIN_CLK, MSBFIRST);
byte l = shiftIn(PIN_SIO, PIN_CLK, MSBFIRST);
val = (h << 8) | l;
} else {
byte h = (val & 0xff00) >> 8;
byte l = val & 0xff;
shiftOut(PIN_SIO, PIN_CLK, MSBFIRST, h);
shiftOut(PIN_SIO, PIN_CLK, MSBFIRST, l);
}
}
附件是本问题的WORD版本描述。
数据手册的图 11,12,13 详细描述了读温度寄存器的时序
上来是先读16位温度, 仔细研究一下吧.
你好,
1. 我已经很仔细的研究了数据手册中的时序,并且都做过实验,用示波器抓取过读取的时序;
2. 时序上表示的是:CS拉低读取16位的温度,但是事实好像并非如此。
3. 我的驱动是按照数据手册开发的,但是读取不到温度。
PS: 不知是不是LM95172使用的人比较少,在网络和各大论坛上,其相关资料比较少,可供
参考资料除了数据手册,也很少有其他资料;我已请我们技术小组的硬件工程师、技术主管和
我们公司的首席科学家研究过这个问题,但是问题一直没有解决。
如果你使用过lm95172,还请不吝赐教。若有时间,帮忙看看我的驱动程序是否存在问题也是
万分感谢的!~
