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,还请不吝赐教。若有时间,帮忙看看我的驱动程序是否存在问题也是
万分感谢的!~