本文主要介绍了一款基于ATtiny85微控制器的四通道温度计,该温度计可以同时监测四个温度传感器的温度,并且实时在小型128x32 OLED液晶屏上进行显示。
该温度计可以用于任何需要监控多个温度点的应用中,例如控制温室、检查功率放大器中的输出晶体管、监控超频游戏PC中的关键点、监控Raspberry Pi上的芯片,或者检查家里各个房间的温度。
以下示例是使用四通道温度计监视A类功率放大器功率晶体管的温度:
简介
这款四通道温度计采用了ATtiny85微控制器来读取四个DS18B20或MAX31820温度传感器的数据,使用1-Wire协议,并在小型OLED液晶屏上显示温度。
我选择了一个128x32 OLED显示屏,它是一个宽约2.5厘米(1寸)的小型显示屏,具有非常清晰、明亮的单色显示屏和SPI接口,可从Adafruit 或Proto-PIC购买。Aliexpress也提供了类似的显示屏。
对于传感器,我使用的是TO-92封装的DS12B20温度传感器,电源范围为3.0V至5.5V。 MAX31820也可以满足应用,而且价格便宜,但是其最大供电电压为3.7V。或者,您可以在Banggood上找到一包10个DS18B20。 DS18B20温度传感器也可以封装在防水电缆中。
您可以使用数米的双绞线连接温度传感器;使用长电缆时,建议使用线性拓扑结构,而不是星形配置。
该程序使用简单的1-Wire例程。以下是全部的电路图:
33kΩ电阻和0.1μF电容确保在首次供电时显示屏能够正常复位。
四通道温度计的使用方法
要使用四通道温度计,您首先需要设置如下:
■ 连接您将要使用的DS18B20 / MAX31820温度传感器中的额一个,然后通电。
传感器的序列号将被读取并存储在ATtiny85的EEPROM中,显示屏会显示第一个显示位置的温度。
■ 剩下的三个温度传感器重复进行操作,一次连接一个温度传感器,然后通电。
剩余的三个序列号将会存储在EEPROM中。
■ 最后,在1-Wire总线上并联所有四个温度传感器。
显示屏将显示所有四个温度,动态更新。
请注意,如果尝试运行程序而没有连接任何传感器,显示屏将显示“?”。如果您一次连接两个或多个传感器,而没有进行“学习”步骤,显示屏将保持空白。
工作原理
所有1-Wire器件都使用ROM中唯一的48位序列号进行编程,以便识别连接到同一1-Wire总线的多个器件。
要从特定的DS18B20 / MAX31820传感器读取温度,您需要发送Match ROM命令,然后发送要访问的传感器的序列号。
要找到1-Wire总线上所有设备的序列号,您可以使用一个称为Search ROM的特殊例程,该程序一次测试48位,以产生冲突,然后构建设备序列号的树。这是一个复杂的过程;如果你想这样做,使用1-Wire库之一。幸运的是,找到序列号的方法要简单得多:您可以一次将设备连接到1-Wire总线,并使用Read ROM命令直接读取每个序列号。这是我在这个应用程序中使用的方法。
四通道温度计使用ATtiny85上的EEPROM来存储四个温度传感器的签名。要“训练”四通道温度计,您可以连接四个要使用的温度传感器之一,并施加电力。在setup()中,程序会尝试读取ROM命令,如果读回的数据有一个有效的CRC,它就知道它已经读取了一个有效的序列号,并存储在EEPROM中: - void loop () {
- for (int i=0; i<4; i++) {
- int line = (i / 2)*2;
- int col = (i % 2)*11;
- // Display temperatures of all devices on bus
- cli(); // No interrupts
- if (OneWireReset() != 0) {
- sei();
- PlotChar('?', line, col);
- } else if (EepromLoad(i) == 0) {
- OneWireWrite(MatchROM);
- OneWireWriteBytes(8);
- OneWireWrite(ConvertT);
- while (OneWireRead() != 0xFF);
- OneWireReset();
- OneWireWrite(MatchROM);
- OneWireWriteBytes(8);
- OneWireWrite(ReadScratchpad);
- OneWireReadBytes(9);
- sei(); // Interrupts
- if (OneWireCRC(9) == 0) {
- int temp = DataBytes[1]<<8 | DataBytes[0];
- PlotTemperature(temp>>4, line, col);
- } else PlotChar('X', line, col);
- }
- }
- }
复制代码
最多可以学习四个传感器,然后将它们全部连接到电路。 这次Read ROM命令失败,因为总线冲突,所以程序的训练阶段被忽略。
请注意,如果由于某种原因要擦除存储在EEPROM中的序列号,例如使用不同的传感器,请在setup()开始时取消注释EepromClear()调用,并运行程序一次。
显示温度
主程序在loop()中依次从EEPROM读取每个签名,使用Match ROM命令访问适当的传感器,读取温度,并调用PlotTemperature()将其显示在显示屏上的适当位置: - void loop () {
- for (int i=0; i<4; i++) {
- int line = (i / 2)*2;
- int col = (i % 2)*11;
- // Display temperatures of all devices on bus
- cli(); // No interrupts
- if (OneWireReset() != 0) {
- sei();
- PlotChar('?', line, col);
- } else if (EepromLoad(i) == 0) {
- OneWireWrite(MatchROM);
- OneWireWriteBytes(8);
- OneWireWrite(ConvertT);
- while (OneWireRead() != 0xFF);
- OneWireReset();
- OneWireWrite(MatchROM);
- OneWireWriteBytes(8);
- OneWireWrite(ReadScratchpad);
- OneWireReadBytes(9);
- sei(); // Interrupts
- if (OneWireCRC(9) == 0) {
- int temp = DataBytes[1]<<8 | DataBytes[0];
- PlotTemperature(temp>>4, line, col);
- } else PlotChar('X', line, col);
- }
- }
- }
复制代码
如果在读取其中一个温度时发生CRC错误,程序在该位置显示“X”。 这通常意味着您断开了该传感器。
cli()和sei()调用禁用1-Wire例程周围的中断; 它们是可选的,但没有它们,由于Arduino millis()中断,温度读数偶尔会给出CRC错误。
温度通过例程PlotTemperature()写入显示器,调用PlotChar()来绘制从-99°C到999°C的字符宽度为五个字符的温度的各个字符。 这涵盖DS18B20支持的范围,-55°C至125°C: - void PlotTemperature (int temp, int line, int column) {
- boolean dig = false;
- unsigned int j = 100;
- if (temp < 0) {
- PlotChar('-', line, column);
- temp = - temp;
- column = column + Scale;
- j = 10;
- }
- for (int d=j; d>0; d=d/10) {
- char c = DigitChar(temp, d);
- if (c == '0' && !dig) c = ' '; else dig = true;
- PlotChar(c, line, column);
- column = column + Scale;
- }
- PlotChar('`', line, column); column = column + Scale;
- PlotChar('C', line, column);
- }
复制代码
绘制字符
为了避免需要一个内存缓冲区,大约需要512字节或RAM,超出ATtiny85提供的资源,字符直接从字符定义绘制到显示器。
为了灵活性,PlotChar()例程提供了在6x8像素字符单元格上显示正常大小的字符或占用12x16像素的双倍大小的字符的选项。 您可以使用双重字符在显示屏上以°C的四种温度调节,这使得显示器更易读。 如果要显示更多的通道,或十分之一度的精度,可以使用正常大小的字符,或者混合使用两者。 字符大小由全局变量Scale控制: - oid PlotChar(char c, int line, int column) {
- PINB = 1<<cs; // cs low
- // Set column address range
- Command(0x21); Command(column*6); Command(column*6 + Scale*6 - 1);
- // Set page address range
- Command(0x22); Command(line); Command(line + Scale - 1);
- for (uint8_t col = 0 ; col < 6; col++) {
- int bits = pgm_read_byte(&CharMap[c-32][col]);
- if (Scale == 1) Data(bits);
- else {
- bits = Stretch(bits);
- for (int i=2; i--;) { Data(bits); Data(bits>>8); }
- }
- }
- PINB = 1<<cs; // cs high
- }
复制代码
参数行和列用正常大小的字符指定屏幕上绘制字符的位置;所以行可以在0和5之间,列可以在0和20之间,其中(0,0)对应于左上角的字符位置。
图形显示是基于我早期的项目Tiny Terminal,修改为128x32显示,显示双字符字符的技术来自我的项目Big Text for Little Display。
编译程序
我使用Spence Konde的ATTiny Core编译了该程序,该内核取代了早期的ATtiny内核。在Boards菜单的ATtiny Universal标题下选择ATtiny x5 series选项。然后在后续菜单中选择Timer 1 Clock: CPU, B.O.D. Disabled, ATtiny85, 8 MHz (internal)。选择 Burn Bootloader正确设置保险丝。然后使用ISP(系统内编程)上传程序;我使用的是Sparkfun的Tiny AVR Programmer Board。
更多建议
1-Wire的优势在于,通过菊花链的方式可以轻松添加更多器件到1-Wire总线。当然您可以添加更多DS18B20或MAX31820温度传感器,以满足更多的测量需求。您可以使用DS2417添加时间显示,DS2417是1-Wire晶体控制的实时时钟。您可以使用1-Wire非易失性存储器芯片添加用于数据记录的非易失性存储器,例如提供20kb非易失性存储器的DS28EC20。您也可以添加一个1-Wire开关,例如DS2413或DS2408,以控制外部设备,尽管使用具有更多输出的ATtiny芯片(如ATtiny84)可能更有意义。
|