1. 非门电路
这个很简单,不细说了哈
2. MAX31865 "MAX31865 是易于使用的电阻数字转换器,针对铂电阻温度检测器(RTD)进行了优化。外部电阻设置所用RTD的灵敏度,而精密Δ-ΣADC则可转换RTD电阻比。 MAX31865的输入具有高达Q45V的过压故障保护,并具有可编程检测RTD和电缆开路和短路情况的功能"
——来自datasheet
项目需要使用了两个Adafuit设计的MAX31865,同时Adafruit还提供了[Arduino library](https://github.com/adafruit/Adafruit_MAX31865) ,我们小改即可
Adafuit版本的原理图:
3. 一个CS引脚控制两个MAX31865片选
理想电路
使用Fritzing 绘制
PS:灵魂走线(小声bb)
原理图
也是用Fritzing整的
细心的读者会发现,该电路少了开篇非门电路的上拉电阻,因为Adafuit版本的原理图已经将CS上拉10k,所以这里可以省略😳
PS:感觉没有Eagle顺手(小声bb)
实测电路
为了更显情调,在D2引脚上加了一个💡串联一个510Ω接地,这样会随着D2(CS信号)变化Blink
为啥还有一个arduino?
arduino,引出的三条线:
color
使用GPIO
功能
红线
A0
测右边模块CS电平,对应下文Demo的MAX_02
绿线
A1
测左边模块CS电平,对应下文Demo的MAX_01
蓝线
A2
测D2(CS信号)变化电平,其实和绿线电平变化相同
arduino当示波器用,虽然只有3k采样频率,但是总比没有好😅
该示波器基于processing,使用Uno的A0-A3引脚,支持4通道,项目地址
4. 修改库
修改的行都上了注释,若太多原库代码的用"......"表示
Adafruit_MAX31865.h
1 2 3 4 5 6 typedef enum max31865_numwires { MAX31865_2WIRE = 0 , MAX31865_3WIRE = 1 , MAX31865_4WIRE = 0 , MAX31865_Double_one_cs_pin = 2 } max31865_numwires_t ;
1 2 3 4 5 6 7 8 9 class Adafruit_MAX31865 { public : ...... static unsigned int trans; static bool change_cs; private : ...... };
Adafruit_MAX31865.cpp
1 2 3 unsigned int Adafruit_MAX31865::trans = 0 ; bool Adafruit_MAX31865::change_cs = false ;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 boolean Adafruit_MAX31865::begin (max31865_numwires_t wires) { pinMode (_cs, OUTPUT ); if (wires == MAX31865_Double_one_cs_pin) { wires = MAX31865_4WIRE; ++trans; if (trans % 2 == 0 ) { change_cs = true ; Serial .print (" MAX_02: " ); digitalWrite (_cs, LOW ); } else { change_cs = false ; Serial .print ("MAX_01: " ); digitalWrite (_cs, HIGH ); } } else digitalWrite (_cs, HIGH ); ...... }
最后将Adafruit_MAX31865::readRegisterN()
和Adafruit_MAX31865::writeRegister8()
的
1 digitalWrite (_cs, HIGH );
分别替换为:
1 2 3 4 if (change_cs == false ) digitalWrite (_cs, LOW ); else digitalWrite (_cs, HIGH );
1 2 3 4 if (change_cs == false ) digitalWrite (_cs, HIGH ); else digitalWrite (_cs, LOW );
5. arduino IDE程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 #include <Adafruit_MAX31865.h> #define RREF 430.0 #define RNOMINAL 100.0 #define MAX_CS 4 #define MISO 13 #define MOSI 12 #define SCLK 14 int chAverage = 1 ; float maxAverageTemp (Adafruit_MAX31865) ; Adafruit_MAX31865 maxESP = Adafruit_MAX31865(MAX_CS, MISO, MOSI, SCLK); void setup () { Serial .begin (115200 ); Serial .println (); Serial .println ("Double MAX31865 4 wire PT100 Sensor Test!" ); } void loop () { static unsigned int tabline = false ; ++tabline; maxESP.begin (MAX31865_Double_one_cs_pin); Serial .print (maxAverageTemp(maxESP)); if (tabline %2 == 0 ) Serial .println (); } float maxAverageTemp (Adafruit_MAX31865 _maxESP) { float averageTemp = 0 ; for (int i = 0 ; i < chAverage; ++i) { averageTemp += _maxESP.temperature(RNOMINAL, RREF); } return averageTemp /= chAverage; }
6. Demo
右侧为arduino示波器,红绿蓝三种电平变化对应上文提及的功能😃
7. 关于修改过的库
度云链接 提取码:p9kl
8MHz总线速度测试正常
没有降低该库的spi速率,全文在提高到8MHz测试的
Adafruit_MAX31865.h
1 static SPISettings max31865_spisettings = SPISettings(8000000 , MSBFIRST, SPI_MODE1);
优化Adafruit_MAX31865::readRTD(),避免看门狗复位
另外,我还修改了该库,可在Adafruit_MAX31865.h中选择禁用Adafruit_MAX31865::readRTD()所有的delay(),用milis()和yield()代替,关键代码如下:
Adafruit_MAX31865.h
1 2 3 4 5 6 #define NODELAY #ifdef NODELAY static unsigned long previousMillis = 0 ; #endif
Adafruit_MAX31865.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 uint16_t Adafruit_MAX31865::readRTD (void ) { clearFault(); enableBias(true ); static uint16_t rtd; #ifndef NODELAY delay (10 ); uint8_t t = readRegister8(MAX31856_CONFIG_REG); t |= MAX31856_CONFIG_1SHOT; writeRegister8(MAX31856_CONFIG_REG, t); delay (65 ); rtd = readRegister16(MAX31856_RTDMSB_REG); rtd >>= 1 ; return rtd; #elif defined NODELAY while (true ) { unsigned long currentMillis_1 = millis (); if (currentMillis_1 - previousMillis >= 10 ) { previousMillis = currentMillis_1; uint8_t t = readRegister8(MAX31856_CONFIG_REG); t |= MAX31856_CONFIG_1SHOT; writeRegister8(MAX31856_CONFIG_REG, t); while (true ) { unsigned long currentMillis_2 = millis (); if (currentMillis_2 - previousMillis >= 65 ) { previousMillis = currentMillis_2; rtd = readRegister16(MAX31856_RTDMSB_REG); rtd >>= 1 ; return rtd; } yield (); } } yield (); } #endif }
yield()简单介绍 - - 来自Sparkfun
由ESP8266 Arduino库的创造者实现,该函数调用后台函数以允许他们执行其任务。
例如,如果您的草图正在等待某人按下连接到引脚12的按钮,则这样的循环将使ESP8266不会崩溃:
1 2 3 4 pinMode (12 , INPUT_PULLUP ); while (digitalRead (12 ) == HIGH ) yield (); Serial .println ("Button is pressed!" );
实测,禁用delay()后,我在上文中的maxAverageTemp()采样可以提高到20次以上,而不会使看门狗复位,(原先5次以上就很容易复位)😳
最后来个单CS读两个MAX31865每一次采样20次的波形😄
8.后记
74HC138 复用CS
如法炮制,可以用cmos器件74HC138实现3个CS引脚片选8个spi设备
以下来自百度百科:
74HC138译码器可接受3位二进制加权地址输入(A0, A1和A2)
当使能时,提供8个互斥的低有效输出 (Y0至Y7),简直太合适了有木有😂