开发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 Farenheitint 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 resolutioncurrentResolution = 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版本描述。
user151383853:
数据手册的图 11,12,13 详细描述了读温度寄存器的时序
上来是先读16位温度, 仔细研究一下吧.
CHAOXI WANG:
回复 user151383853:
你好,
1. 我已经很仔细的研究了数据手册中的时序,并且都做过实验,用示波器抓取过读取的时序;
2. 时序上表示的是:CS拉低读取16位的温度,但是事实好像并非如此。
3. 我的驱动是按照数据手册开发的,但是读取不到温度。
PS: 不知是不是LM95172使用的人比较少,在网络和各大论坛上,其相关资料比较少,可供
参考资料除了数据手册,也很少有其他资料;我已请我们技术小组的硬件工程师、技术主管和
我们公司的首席科学家研究过这个问题,但是问题一直没有解决。
如果你使用过lm95172,还请不吝赐教。若有时间,帮忙看看我的驱动程序是否存在问题也是
万分感谢的!~