电子发烧友App

硬声App

0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示
电子发烧友网>电子资料下载>电子资料>PT1000探头的温度数据记录器

PT1000探头的温度数据记录器

2022-11-01 | zip | 0.53 MB | 次下载 | 免费

资料介绍

描述

介绍

我的目的是开发一种温度测量和数据记录设备,因为我没有。

它应该在显示器上显示温度测量数据,同时将其存储在 SD 卡上。这是我给自己设定的主要要求。此外,它应该有电池用于无线操作,因此整个系统必须设计为低功耗。

该应用程序非常简单,您打开记录器并开始操作。您可以对记录器操作进行各种设置。视频中,您可以看到具有两个活动通道和每 5 秒自动测量一次的设置。

 

设计

pYYBAGNgg4uAb79xABKPj58hem4501.png
电路板原理图
 

我选择的 µC 是 Atmega32U4,因为它具有内置 USB 接口,并且易于通过 Arduino IDE 进行编程一切都由一个 3.3V 的线性稳压器 (TPS782) 供电,这是该应用的最佳选择,因为它在运行期间仅消耗 500nA。三节 AAA 电池提供电源。PT1000 的电压由差分放大器放大一次,并由 Atmega 的模拟输入测量。测量范围定义为 -25°C 至 120°C,对应于 0V 至 3.3V 的电压。测量数据在 128x64 Oled 上显示一次,并可选择存储在 FAT16 SD 卡上。时间和日期由实时时钟 (RV3028C7) 提供,在空闲模式下仅消耗 45nA。此外,菜单中有三个用于导航的用户按钮,背面有一个重置按钮。以及两个用户指示灯和一个 USB 接口。几乎所有可从外部访问的部件仍然配备 ESD 钳位二极管

集会

第 1 步:PCB 和焊膏

 
 
 
poYBAGNgg6eAVNoOAA71IIKWZkc861.jpg
 
1 / 4PCB 和焊接模板
 

PCB组装的第一步是使用焊接模板应用焊膏。之后,焊盘上的任何地方都应该有一层薄薄的糊状物,而不会溢出到其他焊盘上。

第 2 步:PCB 零件组装和回流工艺

粘贴后,所有 SMD 元件必须放置在正确的位置。这对于具有许多引脚的小型组件尤其困难,例如 Atmega32U4。

当所有元件都放置在焊盘上后,需要将 PCB 放入回流炉中并根据焊膏的焊接曲线对其进行加热。或者,您可以使用热风枪熔化糊状物,但不幸的是我没有任何经验。

最后,必须焊接 THT 组件,即 oled 显示器和电池座。

第 3 步:电缆组装

 
 
 
pYYBAGNgg6-AJ0VNAAMnhI96gXA068.png
 
1 / 2电缆计划 PT1000
 

下一步是使用 PT1000 压接和焊接电缆。实现了 3 线测量,因此必须将两条电缆焊接到一个引脚。PT1000 的另一个引脚连接到杜邦连接器的中间引脚,因此连接器的插入方式无关紧要。

第 4 步:测试

 
 
 
pYYBAGNgg9KAZw9OAA4skyXFNdM797.jpg
 
1 / 5
 

一切都组装好后,我会检查整个电路是否短路,如有必要,用烙铁重新加工。

编程

第 1 步:引导加载程序

作为编程的第一步,您需要加载一个额外的板,Sparkfun Pro micro。在 Arduino IDE → Board Manager → SparkFun AVR Boards 中可用我通过 Arduino Uno 和 Arduino 作为 ISP 对 Bootloader 进行了编程,但您必须小心,因为您需要一个从 5V 到 3V3 的电平转换器。请参阅:作为 ISP 的 Arduino 和 Arduino Bootloaders | Arduino在 PCB 的背面,您可以使用标准线路 MOSI、MISO、SCK、RST、GND、+3V3 访问编程焊盘。我为这个焊盘构建了一个带有集成电平转换器的适配器,也许我会做一个项目其中。

第 2 步:编程

最后一步是通过 USB 接口对软件进行编程。代码需要额外的库。

程序的不同功能都可以在OLED显示的菜单中选择。其中有一个正常的记录仪操作,它在每次5s-100min之间的某个时间间隔内测量并存储一次温度。在这种模式下,OLED 也可以被关闭以实现小于 1mA 的功耗。

手动模式,持续测量和输出温度。

还有另一个设置菜单,可以设置所有内容,例如时间、测量之间的延迟时间、活动通道以及显示是否应该活动。

在每种模式下,我都尝试使用尽可能少的电量。这就是为什么我每次都让 µC 进入睡眠模式。它由用户按钮或看门狗定时器唤醒以更新时间。所有硬件都可以主动关闭,包括差分放大器、OLED和SD卡。

/* Autor: Hummer L.
   Datum: 21.4.2021
   Software fuer den Temperatur Datalogger
   Revision:
    V0.16: Temperatur curve adjusted and compared with thermoelement
    
   Anmerkung:
*/

//---------- Libraries einbinden ----------
#include 
#include 
#include "SSD1306Ascii.h"
#include "SSD1306AsciiWire.h"
#include 
#include 
#include 
#include 

//---------- I2C Adressen definieren ----------
#define oled_address 0x3C
#define rtc_address 0x52

//---------- REGISTERS RTC RV3028 ----------
//Clock registers
#define RV3028_SECONDS   0x00
#define RV3028_MINUTES   0x01
#define RV3028_HOURS     0x02
//Calendar registers
#define RV3028_WEEKDAY   0x03
#define RV3028_DATE      0x04
#define RV3028_MONTHS    0x05
#define RV3028_YEARS     0x06
#define RV3028_STATUS    0x0E

//---------- Objekte fuer SD und Oled erstellen ----------
SSD1306AsciiWire oled;
SdCard sd;
Fat16 file;

//---------- Pinnummer einem Namen zuweisen ----------
#define led_g  30 // TX LED
#define led_b  17 // RX LED 
#define button1 1
#define button2 0
#define button3 7
#define temp1_enb 5
#define temp2_enb A5
#define temp3_enb 6
#define temp4_enb 8
#define temp1_adc A1
#define temp2_adc A2
#define temp3_adc A0
#define temp4_adc A3
#define bat_adc A4
#define sd_io 9
#define sd_cs 10
#define sd_enb 12
#define oled_enb 11
#define opv_enb 13



//---------- Struktur ber wichtige Infos des Datalogger ----------
struct fileinfo {
  float temp_value[4];
  bool temp_active[4];
  word _time[7]; //0..sek 1..min 2..hour 3..day 4..date 5..month 6..year
  word pasttime[7];
  volatile bool buttonstate[3];
  unsigned long starttime;
  byte delay_time; //Zeit zwischen zwei Messungen in sek / Gibt den Index der delay_choice funktion an
  bool oled_state;
  int id; //Gibt die Anzahl an Messungen an
};
fileinfo datalogger = {0};

//---------- Zusatzliche globale Variablen deklarieren ----------
#define bounce_time  50
#define eep_add_temp  0
#define eep_add_oled  1
#define eep_add_time  2

byte rows;      // Rows per line.

volatile word choice = 0;
char data[30];
byte bounce_count[3] = {0};
volatile bool wdt_status = 0;
const  word delay_choice[10] = {5, 15, 30, 60, 180, 300, 600, 900, 1800, 6000 };
byte channel_sel = 0;
char filename[] = "XX_XXLog.csv";
bool sleep_status = 0;
byte daycount = 0;
byte day_old = 0;
const byte samples = 5; //Anzahl der Messungen, aus der Anzahl wird dann das endgltige Ergebniss gemittelt, hhere Genausigkeit

void setup() {
  Wire.begin();
  Wire.setClock(400000L);


  //---------- Pin Deklaration, ob In oder Output ----------
  pinMode(led_g, OUTPUT);
  pinMode(led_g, OUTPUT);
  pinMode(temp1_enb, OUTPUT);
  pinMode(temp2_enb, OUTPUT);
  pinMode(temp3_enb, OUTPUT);
  pinMode(temp4_enb, OUTPUT);
  pinMode(sd_enb, OUTPUT); //Vorerst nicht mglich
  pinMode(sd_cs, OUTPUT);
  pinMode(oled_enb, OUTPUT);
  pinMode(opv_enb, OUTPUT);

  pinMode(button1, INPUT);
  pinMode(button2, INPUT);
  pinMode(button3, INPUT);
  pinMode(sd_io, INPUT);

  digitalWrite(sd_cs, 1);
  digitalWrite(led_g, 1);
  digitalWrite(led_b, 1);

  //---------- Start Konfiguration ----------
  if (EEPROM.read(eep_add_oled) > 1)EEPROM.write(eep_add_oled, 1);
  datalogger.oled_state = EEPROM.read(eep_add_oled);
  if (EEPROM.read(eep_add_time) > 9)EEPROM.write(eep_add_time, 0);
  datalogger.delay_time = EEPROM.read(eep_add_time);
  channel_sel = EEPROM.read(eep_add_temp);
  if (channel_sel > 9)EEPROM.write(eep_add_temp, 0b0011);
  datalogger.temp_active[0] = 0b0001 & channel_sel;
  datalogger.temp_active[1] = 0b0010 & channel_sel;
  datalogger.temp_active[2] = 0b0100 & channel_sel;
  datalogger.temp_active[3] = 0b1000 & channel_sel;
  channel_sel = 0;

  //---------- RTC Konfiguration ----------
  rtc_initalize(); //Alle anderen Werte sind default, wie 24h Format

  //---------- Timer Konfiguration ----------
  // TIMER 1 for interrupt frequency 1000 Hz:
  cli(); // stop interrupts
  TCCR1A = 0; // set entire TCCR1A register to 0
  TCCR1B = 0; // same for TCCR1B
  TCNT1  = 0; // initialize counter value to 0
  // set compare match register for 1000 Hz increments
  OCR1A = 7999; // = 8000000 / (1 * 1000) - 1 (must be <65536)
  // turn on CTC mode
  TCCR1B |= (1 << WGM12);
  // Set CS12, CS11 and CS10 bits for 1 prescaler
  TCCR1B |= (0 << CS12) | (0 << CS11) | (1 << CS10);
  // enable timer compare interrupt
  TIMSK1 |= (1 << OCIE1A);
  sei(); // allow interrupts

  //---------- Interrupts Konfiguration ----------
  attachInterrupt(digitalPinToInterrupt(button1), int1_event, LOW);
  attachInterrupt(digitalPinToInterrupt(button2), int2_event, LOW);
  attachInterrupt(digitalPinToInterrupt(button3), int3_event, LOW);
  //gab sonst probleme, beim aktivieren der Tasterinterrupts erst alle Tastervariablen reseten
  datalogger.buttonstate[0] = 0;
  datalogger.buttonstate[1] = 0;
  datalogger.buttonstate[2] = 0;
}
void loop() {
  //bei jedem WDT aufruf, wird diese Funktion ausgefhrt, weil wdt_status in der wdt Routine 1 gesetzt wird
  if (wdt_status == 1) {
    rtc_gettime();
    oled_displaytime();
    wdt_status = 0;
  }

  //Menstruktur fr die unterschiedlichen Flle, wie Manuell, Logger oder Einstellungen
  switch (choice) {
    //---------- Startsetting erste Frage, ob hndisch, auomatik betrieb oder einstellungen ------------------------------------------------------------
    case 0:
      //---------- Watch Dog Timer Konfiguration ----------
      wdt_setE5(1);
      //---------- OLED Konfiguration ----------
      if (digitalRead(oled_enb) == 0) {
        digitalWrite(oled_enb, 1);
        oled.begin(&Adafruit128x64, oled_address);
        oled.setFont(Callibri11); // Auswahl der Schriftart
        rows = oled.fontRows();
        oled.clear();
        oled.setContrast(10);
        datalogger.pasttime[4] = 0;
        datalogger.pasttime[2] = 111;
        datalogger.pasttime[1] = 111;
        oled_displaytime();
        rtc_gettime();

      }
      //Text auf das Display ausgeben
      oled_displaybat();
      oled.setLetterSpacing(2);
      oled_print(1, -1, 0, "-----Betriebsart-----");
      oled.setLetterSpacing(1);
      choice = 1;
      break;
    case 1:
      oled_print(2, -1, 0, "Logger | Manuell | Setting");
      choice = 2;
      break;
    case 2:
      oled_print(3, -1, 0, "Logger");
      choice = 7;
      break;
    case 3:
      oled_print(3, -1, 0, "Manuell");
      choice = 8;
      break;
    case 4: //Case fr Einsellung, welche in 200 abgearbeitet werden
      oled_print(3, -1, 0, "Setting");
      choice = 9;
      break;

    case 7: //Abfrage fr den logger Betrieb
      //enter_sleep(); //Ers setzten, wenn alles fertig sonst probleme mit uart
      but_do(10, 3, 4);
      break;
    case 8://Abfrage fr den Manuellen Betrieb
      enter_sleep();
      but_do(100, 4, 2);
      break;
    case 9:// Abfrage fr den Einstellungscase
      enter_sleep();
      but_do(200, 2, 3);
      break;

    //---------- Logger Betrieb ------------------------------------------------------------
    case 10: //Logger Betrieb
      oled.clear(0, 128 , rows, 3 * rows + rows - 1);
      oled_print(1, -1, 0, "Datalogger");
      oled.setCursor(0, 2 * rows);
      if (datalogger.temp_active[0] == 1)oled.print("1 ");
      if (datalogger.temp_active[1] == 1)oled.print("2 ");
      if (datalogger.temp_active[2] == 1)oled.print("3 ");
      if (datalogger.temp_active[3] == 1)oled.print("4 ");
      sprintf(data, "On | Time: %dsek", delay_choice[datalogger.delay_time]);
      oled.print(data);
      oled_displaybat();
      oled_print(3, -1, 0, "<-Back | v Start v | -----");
      choice = 11;
      break;
    case 11: //Logger Betrieb
      enter_sleep();
      if (but_do(12, -1, 0) == 1 && digitalRead(sd_io) == 1) {
        choice = 14;
        //Startvariablen fr Loggerbetrieb vergeben
        datalogger.starttime = rtc_gettime(); //Startzeit der Messung
        datalogger.id = 1; //ID ist 1
        sd_config(); //SD initalisieren
      }
      break;
    case 12: //Case Fehler keine SD-Karte
      oled_print(2, -1, 0, "SD-Card missing");
      choice = 13;
      break;
    case 13: //Case warten, bis nochmal start gedrckt  und SD vorhanden nochmals berprfen
      enter_sleep();
      if (but_do(11, -1, 0) == 1) {
        datalogger.buttonstate[0] = 1;
      }
      break;
    case 14: //Alles ok, es kann gestartet werden
      //Je nach delayzeit anderen wdt setzen
      if (datalogger.delay_time > 2 && datalogger.delay_time <= 4) {
        wdt_set2E(1);
      }
      else if (datalogger.delay_time > 4) {
        wdt_set8E(1);
      }
      digitalWrite(oled_enb, datalogger.oled_state); //OLED an/aus, je nach konfiguraion
      oled.clear(0, 128, rows, 2 * rows + rows - 1);
      oled_displayvalue(0, 1);
      oled_print(3, 0, 0, "<-Back");
      oled_print(3, 50, 50, "ID: ");
      opv_getvalue();
      //Ersten Messwert aufnehmen
      oled_displayvalue(1, 0);
      oled_displaybat();
      sd_update();
      choice = 16;
      break;
    case 15: //Case Logger Messausfhrung
      enter_sleep();
      //Datenerfassung
      if (rtc_gettime() >= datalogger.starttime + delay_choice[datalogger.delay_time]*datalogger.id) {
        datalogger.id++;
        opv_getvalue();
        oled_displayvalue(1, 0);
        sd_update();
        oled_displaybat();
        choice = 16;
      }
      //Im Betrieb OLED an-Aus schalten und Konfigurieren
      if (but_do(-1, 15, 0) == 2) {
        datalogger.oled_state = !datalogger.oled_state;
        if (datalogger.oled_state == 1) {
          if (digitalRead(oled_enb) == 0) {
            digitalWrite(oled_enb, 1);
            oled.begin(&Adafruit128x64, oled_address);
            oled.setFont(Callibri11); // Auswahl der Schriftart
            rows = oled.fontRows();
            oled.clear();
            oled.setContrast(10);
            datalogger.pasttime[4] = 0;
            datalogger.pasttime[2] = 111;
            datalogger.pasttime[1] = 111;
            oled_displaytime();
            rtc_gettime();
            oled_displaytime();
            oled_displaybat();
            oled.clear(0, 128, rows, 3 * rows + rows - 1);
            oled_displayvalue(0, 1);

            oled_print(3, 0, 0, "<-Back");
            oled_print(3, 50, 150, "ID: ");
            sprintf(data, "%d", datalogger.id);
            oled_print(3, 65, 65, data);
          }
        }
        else {
          digitalWrite(oled_enb, 0);
        }

      }
      break;
    case 16: //Neue ID am OLED ausgeben
      sprintf(data, "%d", datalogger.id);
      oled_print(3, 65, 65, data);
      choice = 15;
      break;

    //---------- Manueller Betrieb ------------------------------------------------------------
    case 100: //Manueller Betrieb Einmalsetting
      oled.clear(0, 128, rows, 2 * rows + rows - 1);
      oled_displayvalue(0, 1);
      oled_print(3, 0, 0, "<-Back");
      choice = 101;
      break;
    case 101: //Datenerfassung + Ausgabe
      opv_getvalue();
      oled_displayvalue(1, 0);
      enter_sleep();
      but_do(-1, -1, 0);
      break;

    //---------- Settings Menstruktur ------------------------------------------------------------
    case 200:
      oled_displaybat();
      oled_print(1, -1, 0, "Settings");
      choice = 201;
      break;
    case 201:
      oled_print(2, -1, 0, "Tim | Del | Act | Dis | Back");
      choice = 206;
      break;
    case 202:
      oled_print(3, -1, 0, "Time");
      choice = 207;
      break;
    case 203:
      oled_print(3, -1, 0, "Delay");
      choice = 208;
      break;
    case 204:
      oled_print(3, -1, 0, "ADC active");
      choice = 209;
      break;
    case 205:
      oled_print(3, -1, 0, "Display");
      choice = 210;
      break;
    case 206:
      oled_print(3, -1, 0, "Back");
      choice = 211;
      break;
    case 207: //Case zur Zeiteinstellung auswahl
      enter_sleep();
      but_do(300, 203, 206);
      break;
    case 208://Case zur Einstellung der Zeit zwischen Messung
      enter_sleep();
      but_do(230, 204, 202);
      break;
    case 209: //Case Einstellung welcher Channel Aktiv
      enter_sleep();
      but_do(240, 205, 203);
      break;
    case 210://Case Oled an aus
      enter_sleep();
      but_do(250, 206, 204);
      break;
    case 211://Case zurck zum Start
      //enter_sleep();
      but_do(0, 202, 205);
      break;

    //---------- Delay Settings ------------------------------------------------------------
    case 230:
      oled_print(1, -1, 0, "Delay Settings");
      oled_print(3, -1, 0, "<- -- | v Set v | ++ ->");
      choice = 231;
      break;
    case 231:
      sprintf(data, "Delaytime: %dsek", delay_choice[datalogger.delay_time]);
      oled_print(2, 0, 0, data);
      choice = 232;
      break;
    case 232:
      enter_sleep();
      switch (but_do(200, 231, 231)) {
        case 1:
          EEPROM.update(eep_add_time, datalogger.delay_time);
          break;
        case 2:
          datalogger.delay_time++;
          if (datalogger.delay_time > 9) {
            datalogger.delay_time = 0;
          }
          break;
        case 3:
          datalogger.delay_time--;
          if (datalogger.delay_time < 0 || datalogger.delay_time > 9) {
            datalogger.delay_time = 9;
          }
          break;
      }
      break;

    //---------- Channel Aktiv Settings ------------------------------------------------------------
    case 240:
      oled_print(1, -1, 0, "ADC actice Settings");
      oled_print(3, -1, 0, "<-Back | vOn-Offv | Next->");
      choice = 241;
      break;
    case 241:
      sprintf(data, "Channel T%d: ", channel_sel + 1);
      oled_print(2, 0, 0, data);
      oled_print(2, 60, 60, datalogger.temp_active[channel_sel] ? "On" : "Off");
      choice = 242;
      break;
    case 242:
      enter_sleep();
      switch (but_do(241, 241, 200)) {
        case 1:
          datalogger.temp_active[channel_sel] = !datalogger.temp_active[channel_sel];
          break;
        case 2:
          channel_sel++;
          if (channel_sel > 3) {
            channel_sel = 0;
          }
          break;
        case 3:
          EEPROM.update(eep_add_temp, datalogger.temp_active[0] | datalogger.temp_active[1] << 1 | datalogger.temp_active[2] << 2 | datalogger.temp_active[3] << 3);
          channel_sel = 0;
          break;
      }
      break;

    //---------- Display aktiv Settings ------------------------------------------------------------
    case 250:
      oled_print(1, -1, 0, "Display Settings");
      oled_print(2, 0, 0, "Display: ");
      oled_print(3, 0, 0, "<-Back | vOn-Offv | ");

      choice = 251;
      break;
    case 251:
      oled_print(2, 46, 46, datalogger.oled_state ? "On" : "Off");
      choice = 252;
      break;
    case 252:
      enter_sleep();
      switch (but_do(251, -1, 200)) {
        case 1:
          datalogger.oled_state = !datalogger.oled_state;
          break;
        case 3:
          EEPROM.update(eep_add_oled, datalogger.oled_state);
          break;
      }
      break;

    //---------- Zeiteinstellung Settings ------------------------------------------------------------
    case 300:
      oled_print(1, -1, 0, "Time Settings");
      oled_print(3, -1, 0, "<- -- | v Next v | ++ ->");
      wdt_setE5(0);
      choice = 301;
      break;
    case 301: //Jahr ndern
      sprintf(data, "Year: %d", datalogger._time[6] + 2000);
      oled_print(2, 0, 0, data);
      choice = 302;
      break;
    case 302:
      switch (but_do(303, 301, 301)) {
        case 2:
          datalogger._time[6] ++;
          break;
        case 3:
          datalogger._time[6] --;
          break;
      }
      break;
    case 303: //Monat ndern
      sprintf(data, "Month: %d", datalogger._time[5]);
      oled_print(2, 0, 0, data);
      choice = 304;
      break;
    case 304:
      switch (but_do(305, 303, 303)) {
        case 2:
          datalogger._time[5] ++;
          break;
        case 3:
          datalogger._time[5] --;
          break;
      }
      if (datalogger._time[5] < 1 || datalogger._time[5] > 12)datalogger._time[5] = 1;
      break;
    case 305: //Tag ndern
      sprintf(data, "Day: %d", datalogger._time[4]);
      oled_print(2, 0, 0, data);
      choice = 306;
      break;
    case 306:
      switch (but_do(307, 305, 305)) {
        case 2:
          datalogger._time[4] ++;
          break;
        case 3:
          datalogger._time[4] --;
          break;
      }
      if (datalogger._time[4] < 1 || datalogger._time[4] > 31)datalogger._time[4] = 1;
      break;
    case 307: //Stunde ndern
      sprintf(data, "Hour: %d", datalogger._time[2]);
      oled_print(2, 0, 0, data);
      choice = 308;
      break;
    case 308:
      switch (but_do(309, 307, 307)) {
        case 2:
          datalogger._time[2] ++;
          break;
        case 3:
          datalogger._time[2] --;
          break;
      }
      if (datalogger._time[2] < 0 || datalogger._time[2] > 24)datalogger._time[2] = 1;
      break;
    case 309: //Minute ndern
      sprintf(data, "Minute: %d", datalogger._time[1]);
      oled_print(2, 0, 0, data);
      choice = 310;
      break;
    case 310:
      switch (but_do(311, 309, 309)) {
        case 2:
          datalogger._time[1] ++;
          break;
        case 3:
          datalogger._time[1] --;
          break;
      }
      if (datalogger._time[1] < 0 || datalogger._time[1] > 60)datalogger._time[1] = 1;
      break;
    case 311: //Setzten der zuvor eingestellten Zeit
      datalogger._time[0] = 0;
      rtc_settime();
      datalogger.pasttime[4] = 0;
      datalogger.pasttime[2] = 111;
      datalogger.pasttime[1] = 111;
      wdt_setE5(1);
      choice = 200;
      break;

    //---------- Default Fehler ------------------------------------------------------------
    default:
      choice = 0;
      oled_print(2, -1, 0, "Fehler");
      oled_print(3, -1, 0, "Restart");
      delay(2000);
      break;
  }
}
byte but_do(int16_t choice_0, int16_t choice_1, int16_t choice_2) {//---------- Tastervariablenabfrage ----------
  //Abfrage der Tastervariablen, welche in der ISR gesetzt werden und je nach Stellungen, wird die choice gendert, also die cases
  byte x = 0; //Hilfsvariable
  //Wenn Tastervariable gesetzt, die choice je nach bergabewert ndern bzw. , wenn negativ dann ignorieren und Tastervariable NULL setzen
  if (datalogger.buttonstate[0] == 1) {
    if (choice_0 >= 0) {
      choice = choice_0;
    }
    x = 1;
    datalogger.buttonstate[0] = 0;
  }
  //Wenn Tastervariable gesetzt, die choice je nach bergabewert ndern bzw. , wenn negativ dann ignorieren und Tastervariable NULL setzen
  else if (datalogger.buttonstate[1] == 1) {
    if (choice_1 >= 0) {
      choice = choice_1;
    }
    x = 2;
    datalogger.buttonstate[1] = 0;
  }
  //Wenn Tastervariable gesetzt, die choice je nach bergabewert ndern bzw. , wenn negativ dann ignorieren und Tastervariable NULL setzen
  else if (datalogger.buttonstate[2] == 1) {
    if (choice_2 >= 0) {
      choice = choice_2;
    }
    x = 3;
    datalogger.buttonstate[2] = 0;
  }
  return x; //Rckgabewert, je nach ausgefhrten case 0..keine Variabele gesetzt 1.. taster1 2..taster2 3..taster3
}
void sd_update() {//---------- Sd Karte mit Messwerte beschreiben ----------
  //String mit allen Daten, wie timestamp, ID und Messwerte bilden
  String dataString = "";
  dataString += String(datalogger.id);
  sprintf(data, ";%02d.%02d.%04d ", datalogger._time[4], datalogger._time[5], datalogger._time[6] + 2000);
  dataString += String(data);
  sprintf(data, "%02d:%02d:%02d;", datalogger._time[2], datalogger._time[1], datalogger._time[0]);
  dataString += String(data);
  //Die 4 Messwerte in String einfgen und je nach aktiv oder nicht, den Wert oder "inactice" schreiben
  for (int i = 0; i < 4; i++) {
    if (datalogger.temp_active[i] == 1) {
      sprintf(data, "%d,%d;", (int)datalogger.temp_value[i], abs((int)(datalogger.temp_value[i] * 10) % 10));
    }
    else {
      sprintf(data, "inactive;");
    }
    dataString += String(data);
  }
  digitalWrite(sd_enb, 1);
  //File append ffnen und den zuvor kreiierten String hineinschreiben
  file.open(filename, O_CREAT | O_APPEND | O_WRITE);
  if (file.isOpen()) {
    file.println(dataString);
    file.close();
  }
  digitalWrite(sd_enb, 0);
}
void sd_config() { //---------- SD Karte Konfiguration ----------
  digitalWrite(sd_enb, 1);
  if (sd.begin(sd_cs)) { //SD initalisieren
    Fat16::init(&sd);
    //Name fr die csv Datei ndern
    filename[0] = (int)(datalogger._time[2] / 10) + '0';
    filename[1] = datalogger._time[2] % 10 + '0';
    filename[3] = datalogger._time[1] / 10 + '0';
    filename[4] = datalogger._time[1] % 10 + '0';
  }
  file.open(filename, O_CREAT | O_APPEND | O_WRITE); //File ffnen mit dem zuvor genderten Namen
  if (file.isOpen()) { //Wenns File offen, dann...
    file.println("ID;Timestamp;Temp1 [*C];Temp2 [*C];Temp3 [*C];Temp4 [*C]"); //...Starttext in die erste Zeile der csv Datei schreiben
    file.close(); //File schlieen
  }
  digitalWrite(sd_enb, 0);
}
void oled_print(uint8_t row_, int8_t cur, uint8_t start_del, char text[30]) {//---------- OLED Test ausgeben und lschen ----------
  oled.clear(start_del, 128 , row_ * rows, row_ * rows + rows - 1); //bestimmte Zeile lschen
  //Auswhlen, ob Text an best. Stelle oder in der Mitte vom Display
  if (cur < 0) { //Case in der Mitte
    oled.setCursor(64 - oled.strWidth(text) / 2, row_ * rows);
  }
  else { //Case best. Stelle
    oled.setCursor(cur, row_ * rows);
  }
  oled.print(text);//Text ausgeben an der zuvorig gesetzten Stelle
}
void oled_displaytime() {//---------- OLED Zeit ausgeben ----------

  //Die aktuelle Zeit ausgeben, aber nur wenn sie sich zur vorherigen unterscheidet
  // case fr Datum
  if (datalogger._time[4] != datalogger.pasttime[4]) {
    oled.clear(0, 45,  0 * rows, rows - 1);
    sprintf(data, "%02d.%02d.%02d", datalogger._time[4], datalogger._time[5], datalogger._time[6]);
    oled.print(data);
  }
  // case fr Stunden
  if (datalogger._time[2] != datalogger.pasttime[2]) {
    oled.clear(46, 60,  0 * rows, rows - 1);
    sprintf(data, "%02d:", datalogger._time[2]);
    oled.print(data);
  }
  // case fr Minuten
  if (datalogger._time[1] != datalogger.pasttime[1]) {
    oled.clear(61, 75,  0 * rows, rows - 1);
    sprintf(data, "%02d:", datalogger._time[1]);
    oled.print(data);
  }
  // case fr Sekunden
  if (datalogger._time[0] != datalogger.pasttime[0]) {
    oled.clear(76, 90,  0 * rows, rows - 1);
    sprintf(data, "%02d", datalogger._time[0]);
    oled.print(data);
  }
  //Die aktuelle Zeit der alten Zeit zuweisen, damit er dann beim nchsten Mal wieder alt und neu berprfen kann
  memcpy(datalogger.pasttime, datalogger._time, sizeof(datalogger.pasttime));
}
void oled_displaybat() {//---------- OLED BatterieSpannung asugeben ----------
  float x = analogRead(bat_adc) * 0.026316 - 8.0263; //Spannung messen und in V umwandeln
  sprintf(data, "%d.%02dV", (int)x, (int)(x * 100) % 100); //Umwandeln in char[], weil mit float inkompatibel, zweimal x und Modulo Funktion(Trick)
  oled_print(0, 128 - oled.strWidth(data), 128 - oled.strWidth(data), data);//ausgeben am OLED
}
void oled_displayvalue(uint8_t aktual, bool preset) {//---------- OLED Messwerte ausgeben ----------
  //Hilfsvariablen erstellen
  uint8_t col_number = 0;
  uint8_t row_number = 0;
  char buf1 [6];
  char buf2 [5];
  char buf3 [4];
  //For schleife fr die 4 Messwerte
  for (uint8_t i = 0; i < 4; i++) {

    switch (i) {
      case 0:
        col_number = 0;
        row_number = 1;
        break;
      case 1:
        col_number = 1;
        row_number = 1;
        break;
      case 2:
        col_number = 0;
        row_number = 2;
        break;
      case 3:
        col_number = 1;
        row_number = 2;
        break;
    }

    sprintf(buf1, "T%d: ", (int)(i + 1));

    //Nur aktuellen Wert beschreiben, wenn berhaupt aktiv
    if (datalogger.temp_active[i] == 1) {
      if (aktual == 1) { //Aktualisierungscase nur Zahl wird ausgegeben
        //oled.clear(col_number * 65 + oled.strWidth(buf1), col_number * 65 + oled.strWidth(buf1) + oled.strWidth(buf2) , row_number * rows, row_number * rows + rows - 1);
        sprintf(buf2, "%04d.%01d", (int)datalogger.temp_value[i], abs((int)(datalogger.temp_value[i] * 10) % 10));
        oled.clear(col_number * 65 + oled.strWidth(buf1), col_number * 65 + oled.strWidth(buf1)+oled.strWidth(buf2) , row_number * rows, row_number * rows + rows - 1);
        
        oled.print(buf2);
      }
      else { //Einmalcase am Anfang, Zahl und Text wird ausgeegeben
        oled.clear(col_number * 65, col_number * 65 + 66 , row_number * rows, row_number * rows + rows - 1);
        sprintf(buf2, "%04d.%01d", (int)datalogger.temp_value[i], abs((int)(datalogger.temp_value[i] * 10) % 10));
        oled.print(buf1);
        oled.print(buf2);
        //oled.print("*C"); //Wieso Probleme????????????????????
        sprintf(buf3, "*C");
        oled.print(buf3);
      }
    }
    //Falls man die Voreinstellungen macht, wird "inactive" geschrieben, wenn der Channel inaktiv ist
    else if (preset == 1) {
      oled.clear(col_number * 65, col_number * 65 + 65 , row_number * rows, row_number * rows + rows - 1);
      oled.print(buf1);
      oled.print("inactive");
    }
  }
}
void rtc_initalize() {//---------- RTC Initalisierung ----------
  Wire.beginTransmission(rtc_address); //Kommunikation an RTC adress starten
  Wire.write(RV3028_STATUS); //Ins Status register schreiben
  Wire.write((0x00)); //0 schreiben, weil das alle bedrfnisse abdeckt
  Wire.endTransmission();
}
void rtc_settime() {//---------- RTC Zeit ndern ----------
  Wire.beginTransmission(rtc_address); //Kommunikation an RTC adress starten
  Wire.write(RV3028_SECONDS); //als erstes in sekunden register schreiben, wird auto. inkrementiert fr die anderen register
  for (byte i = 0; i < 7; i++) { //Write multiple Registers
    Wire.write(DECtoBCD(datalogger._time[i])); //Die eingestellte Zeit der RTC bergeben
  }
  Wire.endTransmission();
  oled_displaytime(); //Zeit ausgeben
}
unsigned long rtc_gettime() {//---------- RTC Zeit auslesen ----------
  Wire.beginTransmission(rtc_address); //Kommunikation an RTC adresse starten
  Wire.write(RV3028_SECONDS);// das Sekunden register auswhlen

  Wire.requestFrom(rtc_address, 7); //Dann 7Byte auslesen, also Sekunden bis Jahr
  while (Wire.available()) {
    for (byte i = 0; i < 7; i++) { //Read multiple Registers
      datalogger._time[i] = BCDtoDEC(Wire.read());
    }
  }
  Wire.endTransmission();

  // Die Zeit in Sekunden zurckgeben, damit man dann die Messzeitpunkte zwischen alt und neu abgleichen kann
  if (datalogger._time[4] != day_old) { //Die vergangenen Tag zhlen, damit mein kein Problem bei einem Monatssprung hat
    daycount ++;;
    day_old = datalogger._time[4];
  }
  return datalogger._time[0] + 60 * datalogger._time[1] + 3600 * datalogger._time[2] + 24 * 3600 * daycount;
}
byte BCDtoDEC(uint8_t val) {//---------- BCD zu DEC formatieren ----------
  return ((val / 0x10) * 10) + (val % 0x10);
}
byte DECtoBCD(uint8_t val) {//---------- DEC zu BCD formatieren ----------
  return ((val / 10) * 0x10) + (val % 10);
}
void opv_getvalue() {//---------- Temperaturspannung messen ----------
  digitalWrite(led_b, 0); //led anschalten
  digitalWrite(opv_enb, 1); //Opv aktivieren
  //Die Channels aktivieren, wie in Settings
  digitalWrite(temp1_enb, datalogger.temp_active[0]);
  digitalWrite(temp2_enb, datalogger.temp_active[1]);
  digitalWrite(temp3_enb, datalogger.temp_active[2]);
  digitalWrite(temp4_enb, datalogger.temp_active[3]);
  delay(15);

  //Den aktuellen und aktiven Channel den Hilfsvariablen zuweisen, damit mit for-schleife mglich
  for (byte i = 0; i < 4; i++) {
    datalogger.temp_value[i] = 0;
    int pin = 0;
    int pin_read = 0;
    if (datalogger.temp_active[i] == 1) {

      switch (i) {
        case 0:
          pin = temp1_enb;
          pin_read = temp1_adc;
          break;
        case 1:
          pin = temp2_enb;
          pin_read = temp2_adc;
          break;
        case 2:
          pin = temp3_enb;
          pin_read = temp3_adc;
          break;
        case 3:
          pin = temp4_enb;
          pin_read = temp4_adc;
          break;
      }
      for(byte j = 0; j < samples; j++){
      datalogger.temp_value[i] += analogRead(pin_read); //Spannung an best. Channel messen und in Temp umwandeln
      delayMicroseconds(200);
      }
      datalogger.temp_value[i] =  ((datalogger.temp_value[i]/samples)*0.153479)-27.23; //10bit ADC Wert in Temp umwandel
      digitalWrite(pin, 0); //Channel ausschalten
    }
  }

  digitalWrite(opv_enb, 0); //OPV deaktivieren
  digitalWrite(led_b, 1); //Led ausschalten
}
void int1_event() {//---------- Interrupt Event Taster 1 ----------
  if (bounce_count[0] == 0) {     //Nur wenn Entprell Routine wieder zurckgesetzt wurde, interrupt erlauben
    if (sleep_status == 1) {      //Nur wenn im Sleep mode
      sleep_disable();            //...dann Sleep mode aussschalten
      sleep_status = 0;           //...und variable zurcksetzen
    }
    datalogger.buttonstate[0] = 1;//Tastervariable setzen
    bounce_count[0] = 1;
  }
}
void int2_event() {//---------- Interrupt Event Taster 2 ----------
  if (bounce_count[1] == 0) {     //Nur wenn Entprell Routine wieder zurckgesetzt wurde, interrupt erlauben
    if (sleep_status == 1) {          //Nur wenn im Sleep mode
      sleep_disable();            //...dann Sleep mode aussschalten
      sleep_status = 0;           //...und variable zurcksetzen
    }
    datalogger.buttonstate[1] = 1;//Tastervariable setzen
    bounce_count[1] = 1;
  }
}
void int3_event() {//---------- Interrupt Event Taster 3 ----------
  if (bounce_count[2] == 0) {     //Nur wenn Entprell Routine wieder zurckgesetzt wurde, interrupt erlauben
    if (sleep_status == 1) {      //Nur wenn im Sleep mode
      sleep_disable();            //...dann Sleep mode aussschalten
      sleep_status = 0;           //...und variable zurcksetzen
    }
    datalogger.buttonstate[2] = 1;//Tastervariable setzen
    bounce_count[2] = 1;
  }
}
void wdt_setE5(bool enable) {//---------- WDT konfiguration 0,5s ----------
  wdt_reset(); // Reset Watchdog Timer
  cli();//Interrupts verhindern
  MCUSR &= ~(1 << WDRF);           /* WDT reset flag loeschen */
  WDTCSR |= (1 << WDCE) | (1 << WDE); /* WDCE setzen, Zugriff auf Presclaler etc. */
  WDTCSR = 1 << WDP0 | 1 << WDP2;  /* Prescaler auf 0.5 s */
  WDTCSR |= enable << WDIE;
  sei();//Interrupts wieder erlauben
}
void wdt_set2E(bool enable) {//---------- WDT konfiguration 2s ----------
  wdt_reset(); // Reset Watchdog Timer
  cli();//Interrupts verhindern
  MCUSR &= ~(1 << WDRF);           /* WDT reset flag loeschen */
  WDTCSR |= (1 << WDCE) | (1 << WDE); /* WDCE setzen, Zugriff auf Presclaler etc. */
  WDTCSR = 1 << WDP0 | 1 << WDP1 | 1 << WDP2; /* Prescaler auf 2.0 s */
  WDTCSR |= enable << WDIE;
  sei();//Interrupts wieder erlauben
}
void wdt_set8E(bool enable) {//---------- WDT konfiguration 8s ----------
  wdt_reset(); // Reset Watchdog Timer
  cli();  //Interrupts verhindern
  MCUSR &= ~(1 << WDRF);           /* WDT reset flag loeschen */
  WDTCSR |= (1 << WDCE) | (1 << WDE); /* WDCE setzen, Zugriff auf Presclaler etc. */
  WDTCSR = 1 << WDP0 | 1 << WDP3;  /* Prescaler auf 8.0 s */
  WDTCSR |= enable << WDIE;
  sei();  //Interrupts wieder erlauben
}
ISR(WDT_vect) {//---------- Watchdog Timer Interrupt Service Routine ----------
  wdt_status = 1;
}
void enter_sleep(void) {//---------- Sleep Funktion ----------
  sleep_status = 1;  //Status setzen, wenn Sleep Mode aktiv, wird in der ISR fr Taster verwendet
  //digitalWrite(led_g, 1);
  bounce_count[0] = 0;
  bounce_count[2] = 0;
  bounce_count[1] = 0;
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);   /* Es geht auch SLEEP_MODE_PWR_DOWN */
  sleep_enable();
  power_adc_disable();    /* Analog-Eingaenge abschalten */
  power_spi_disable();    /* SPI abschalten */
  power_timer0_disable(); /* Timer0 abschalten */
  power_timer1_disable(); /* Timer1 abschalten */
  power_timer2_disable(); /* Timer2 abschalten */
  power_twi_disable();    /* TWI abschalten */
  sleep_mode();
  sleep_disable();        //Sleep mode disable
  power_all_enable();     /* Komponenten wieder aktivieren */
  //digitalWrite(led_g, 0);
  sleep_status = 0;
}
ISR(TIMER1_COMPA_vect) {//---------- Timerinterrupt  1000Hz ----------
  // Entprellen des Tasters 1, wenn gedrckt wird 1, dann bis bounce_time hochzhlen, dann taster erst wieder freigegeben
  if (bounce_count[0] >= 1) {
    bounce_count[0]++;
    if (bounce_count[0] >= bounce_time) {
      bounce_count[0] = 0;
    }
  }
  // Entprellen des Tasters 2, wenn gedrckt wird 1, dann bis bounce_time hochzhlen, dann taster erst wieder freigegeben
  if (bounce_count[1] >= 1) {
    bounce_count[1]++;
    if (bounce_count[1] >= bounce_time) {
      bounce_count[1] = 0;
      //Serial.println("BounceCount Zeit erreicht");
    }
  }
  // Entprellen des Tasters 3, wenn gedrckt wird 1, dann bis bounce_time hochzhlen, dann taster erst wieder freigegeben
  if (bounce_count[2] >= 1) {
    bounce_count[2]++;
    if (bounce_count[2] >= bounce_time) {
      bounce_count[2] = 0;
    }
  }
}

测量值以 csv 文件的形式存储在 SD 卡上,以后可以在合适的程序中进行分析。

pYYBAGNgg9SALoB5AAFCejmcCgo224.png
 

加元

 

2 使用双挤压打印机打印的组件外壳。

材料 1:PLA(外壳坚固/顶部坚固)
材料 2:TPU(外壳柔软/顶部柔软)

 

pYYBAGNgg9iAT2MSAADmsxEo2eM269.png
 

 

概括

  • -25°C 至 120°C 之间的 4 通道温度测量
  • 由三节 AAA 电池供电
  • Atmega 32U4 作为 µC
  • 图形用户界面(OLED / LED)
  • 3 个用户按钮
  • 低功耗 ~5mA On with OLED<1mA while measure OLED off<1µA off off, only RTC
  • USB接口
  • 电源开关
  • 实时时钟

下载该资料的人也在下载 下载该资料的人还在阅读
更多 >

评论

查看更多

下载排行

本周

  1. 1山景DSP芯片AP8248A2数据手册
  2. 1.06 MB  |  532次下载  |  免费
  3. 2RK3399完整板原理图(支持平板,盒子VR)
  4. 3.28 MB  |  339次下载  |  免费
  5. 3TC358743XBG评估板参考手册
  6. 1.36 MB  |  330次下载  |  免费
  7. 4DFM软件使用教程
  8. 0.84 MB  |  295次下载  |  免费
  9. 5元宇宙深度解析—未来的未来-风口还是泡沫
  10. 6.40 MB  |  227次下载  |  免费
  11. 6迪文DGUS开发指南
  12. 31.67 MB  |  194次下载  |  免费
  13. 7元宇宙底层硬件系列报告
  14. 13.42 MB  |  182次下载  |  免费
  15. 8FP5207XR-G1中文应用手册
  16. 1.09 MB  |  178次下载  |  免费

本月

  1. 1OrCAD10.5下载OrCAD10.5中文版软件
  2. 0.00 MB  |  234315次下载  |  免费
  3. 2555集成电路应用800例(新编版)
  4. 0.00 MB  |  33566次下载  |  免费
  5. 3接口电路图大全
  6. 未知  |  30323次下载  |  免费
  7. 4开关电源设计实例指南
  8. 未知  |  21549次下载  |  免费
  9. 5电气工程师手册免费下载(新编第二版pdf电子书)
  10. 0.00 MB  |  15349次下载  |  免费
  11. 6数字电路基础pdf(下载)
  12. 未知  |  13750次下载  |  免费
  13. 7电子制作实例集锦 下载
  14. 未知  |  8113次下载  |  免费
  15. 8《LED驱动电路设计》 温德尔著
  16. 0.00 MB  |  6656次下载  |  免费

总榜

  1. 1matlab软件下载入口
  2. 未知  |  935054次下载  |  免费
  3. 2protel99se软件下载(可英文版转中文版)
  4. 78.1 MB  |  537798次下载  |  免费
  5. 3MATLAB 7.1 下载 (含软件介绍)
  6. 未知  |  420027次下载  |  免费
  7. 4OrCAD10.5下载OrCAD10.5中文版软件
  8. 0.00 MB  |  234315次下载  |  免费
  9. 5Altium DXP2002下载入口
  10. 未知  |  233046次下载  |  免费
  11. 6电路仿真软件multisim 10.0免费下载
  12. 340992  |  191187次下载  |  免费
  13. 7十天学会AVR单片机与C语言视频教程 下载
  14. 158M  |  183279次下载  |  免费
  15. 8proe5.0野火版下载(中文版免费下载)
  16. 未知  |  138040次下载  |  免费