Differences

This shows you the differences between two versions of the page.

Link to this comparison view

pm:prj2021:apredescu:pistol-de-masurare-temperatura [2021/06/01 20:45]
ovidiu.stanica
pm:prj2021:apredescu:pistol-de-masurare-temperatura [2021/06/03 17:09] (current)
ovidiu.stanica
Line 7: Line 7:
  
 Pistolul de măsurat temperatura nu intră în contact cu suprafața a cărei temperatură este măsurată.\\ Pistolul de măsurat temperatura nu intră în contact cu suprafața a cărei temperatură este măsurată.\\
-Pentru eșantionarea temperaturii se folosește un senzor de temperatură cu raze infraroșii ​MXL90614.\\ +Pentru eșantionarea temperaturii se folosește un senzor de temperatură cu raze infraroșii ​MLX90614.\\ 
-Pentru măsurarea cât mai potrivită, vor fi introduse 3 moduri de măsurare, specifice unor medii de temperatură.+Pentru măsurarea cât mai potrivită, vor fi introduse 3 moduri de măsurare, specifice unor medii de temperatură.\\ 
 +Se poate folosi exact ca un pistol de măsurat temperatura găsit în supermarket-uri.
  
 ===== Descriere generală ===== ===== Descriere generală =====
Line 16: Line 17:
 Pistolul are 2 butoane prin care e controlată măsurarea temperaturii. Un buton, numit declanșator,​ activează măsurarea temperaturii cât timp e apăsat, în continuu. Temperatura este afișată pe LCD, pe rândul de jos, în partea stângă. În partea dreaptă e afișată temperatura trecută prin filtrul de procesare. Pistolul are 2 butoane prin care e controlată măsurarea temperaturii. Un buton, numit declanșator,​ activează măsurarea temperaturii cât timp e apăsat, în continuu. Temperatura este afișată pe LCD, pe rândul de jos, în partea stângă. În partea dreaptă e afișată temperatura trecută prin filtrul de procesare.
  
-Pistolul oferă ​filtre de procesare:​\\ ​+Pistolul oferă ​filtre de procesare:​\\ ​
  * Minim (MIN) păstrează doar minimul temperaturilor măsurate;​\\  * Minim (MIN) păstrează doar minimul temperaturilor măsurate;​\\
  * Maxim (MAX) păstrează doar minimul temperaturilor măsurate;​\\  * Maxim (MAX) păstrează doar minimul temperaturilor măsurate;​\\
- * Average (AVG) face media temperaturilor măsurate;​\\ 
  * None (---) afișează ultima temperatură măsurată;  * None (---) afișează ultima temperatură măsurată;
    
-Filtrul de procesare e resetat când se începe o nouă măsuratoare (adică când se apasă declanșatorul)+Filtrul de procesare e resetat când se începe o nouă măsuratoare (adică când se apasă declanșatorul).
  
-Carcasa pistolului va fi făcută la o imprimanta 3D(sau cel puțin voi încerca să folosesc un soft de design, Fusion 360)+ 
 +==Schema bloc== 
 +{{:​pm:​prj2021:​apredescu:​schema_bloc_stanica_ovidiu-stefan.jpeg?400|}}
  
 ===== Hardware Design ===== ===== Hardware Design =====
  
 Voi avea nevoie de următoarele componente:​\\ Voi avea nevoie de următoarele componente:​\\
- * Arduino ​Uno\\ + * Arduino ​Nano\\ 
- * LCD 1602 Adaptor I2C\\+ * LCD 1602\\ 
 + ​* ​Adaptor I2C\\
  * Buton schimbat mod măsurare\\  * Buton schimbat mod măsurare\\
  * Buton declanșat măsurarea\\  * Buton declanșat măsurarea\\
Line 37: Line 40:
  * Întrerupător on/off  * Întrerupător on/off
  
-{{:​pm:​prj2021:​apredescu:​schema_bloc_stanica_ovidiu-stefan.jpeg?​400|}} +Display-ul ​și senzorul le-am pus pe aceeași ​"placă", conectate la Arduino printr-un cablu de Ethernet. Am folosit cablu de ethernet pentru ​că are ecranare ​cât de cât bunăși I2C este gândit să fie folosit pe același ​circuit board, deci nu suportă interferențe ​prea mari.
- +
-Display-ul ​si senzorul le-am pus pe aceeasi ​"placa", conectate la Arduino printr-un cablu de Ethernet. Am folosit cablu de ethernet pentru ​ca are ecranare ​cat de cat bunasi I2C este gandit sa fie folosit pe acelasi ​circuit board, deci nu suporta interferente ​prea mari.+
    
-Butoanele sunt conectare direct ​langa Arduino.+Butoanele sunt conectare direct ​lângă ​Arduino.
  
-{{:​pm:​prj2021:​apredescu:​schema_electrica_stanica_ovidiu.jpg?​400|}}+==Schema electrică== 
 +{{:​pm:​prj2021:​apredescu:​schema_electrica_stanica_ovidiu.jpg?​600|}}
  
 ===== Software Design ===== ===== Software Design =====
  
-Am folosit un timer (timer2) pe Atmega ca sa fac citirea senzorului de 2500 ori pe secunda. +Am folosit un timer (timer2) pe Atmega ca să fac citirea senzorului de 2500 ori pe secundă.
- +
-Pentru ca senzorul de temperatura este interfatat pe I2C, si comunicatia pe I2C are nevoie ca interrupt-urile sa fie pornite, nu pot face citirea senzorului direct in interrupt-ul de timer. +
-In loc, interrupt-ul seteaza un flag global. Bucla principala verifica constant acest flag, si daca este setat, il elimina si face o citire a senzorului. +
- +
-Afisarea la display se face de 10 ori pe secunda. In mod ideal, afisare s-ar putea face mai des, dar refresh rate-ul display-ului nu permite (dureaza ~70ms ca un pixel sa-si schimbe starea) +
- +
-Filtrele sunt evaluate odata cu refresh-ul senzorului. Daca se cere schimbarea filtrului, inainte de citire, se reseteaza datele de acumulare si e schimbata functia de filtru. +
- +
-<​code>​ +
-#include <​Wire.h>​  +
-#include <​LiquidCrystal_I2C.h>​ +
-#include <​Adafruit_MLX90614.h>​ +
- +
-byte stage1[] = { +
-  0x00, +
-  0x00, +
-  0x00, +
-  0x10, +
-  0x10, +
-  0x10, +
-  0x18, +
-  0x1C +
-}; +
- +
-byte stage2[] = { +
-  0x1C, +
-  0x18, +
-  0x10, +
-  0x10, +
-  0x10, +
-  0x00, +
-  0x00, +
-  0x00 +
-}; +
-byte stage3[] = { +
-  0x1F, +
-  0x03, +
-  0x01, +
-  0x00, +
-  0x00, +
-  0x00, +
-  0x00, +
-  0x00 +
-}; +
- +
-byte stage4[] = { +
-  0x00, +
-  0x00, +
-  0x00, +
-  0x01, +
-  0x01, +
-  0x01, +
-  0x03, +
-  0x07 +
-}; +
- +
-char line1[19] = { '​C',​ '​U',​ '​R',​ '​R',​ '​E',​ '​N',​ '​T',​ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 0 }; +
-char line2[19] = { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 0 }; +
- +
-Adafruit_MLX90614 mlx = Adafruit_MLX90614();​ +
-LiquidCrystal_I2C lcd(0x3F, 16, 2); +
- +
-bool changeFilterLastState = false; +
-bool measureLastState = false; +
- +
-#define MIN_TEMP (-50) +
-#define MAX_TEMP (+320) +
- +
-typedef int filter_type;​ +
-#define FILTER_MIN (1) +
-#define FILTER_MAX (2) +
-#define FILTER_CUR (0) +
- +
-filter_type currentFilter = FILTER_CUR;​ +
-double accumulator = 0; +
-double immediate = 0; +
- +
-bool measuring = false; +
-int measuringStage = 0; +
- +
-volatile bool readPending = false; +
-long lastRead = 0; +
- +
-filter_type getNextFilter() { +
-  if (currentFilter == FILTER_CUR) return FILTER_MIN;​ +
-  if (currentFilter == FILTER_MIN) return FILTER_MAX;​ +
-  if (currentFilter == FILTER_MAX) return FILTER_CUR;​ +
-  return FILTER_CUR;​ +
-+
- +
-void resetFilter() { +
-  if (currentFilter == FILTER_CUR) accumulator = 0; +
-  if (currentFilter == FILTER_MIN) accumulator = MAX_TEMP; +
-  if (currentFilter == FILTER_MAX) accumulator = MIN_TEMP; +
-+
- +
-void feedFilter(double imm) { +
-  immediate = imm; +
-  if (currentFilter == FILTER_CUR) { +
-    accumulator = imm; +
-  } +
-  if (currentFilter == FILTER_MIN) { +
-    accumulator = accumulator > imm ? imm : accumulator;​ +
-  }  +
-  if (currentFilter == FILTER_MAX) { +
-    accumulator = accumulator < imm ? imm : accumulator;​ +
-  } +
-+
- +
-double readSensor() { +
-  return constrain(mlx.readObjectTempC(),​ MIN_TEMP, MAX_TEMP);​ +
-+
- +
-ISR(TIMER2_COMPA_vect){ +
-  readPending = true; +
-+
- +
-void readSensorAndUpdate() { +
-  bool measureThisState = /*!(PIND & PD5);*/ !digitalRead(5);​  +
-  if (measureThisState) { +
-    measuring = true; +
-    if (!measureLastState) { +
-      resetFilter();​ +
-    } +
-    feedFilter(readSensor());​ +
-  } else { +
-    measuring = false; +
-    bool changeFilterThisState = /*!(PINB & PB1)*/ !digitalRead(9);​ +
-    if (changeFilterThisState && !changeFilterLastState) { +
-      currentFilter = getNextFilter();​ +
-      resetFilter();​ +
-      feedFilter(readSensor());​ +
-    } +
-    changeFilterLastState = changeFilterThisState;​ +
-  } +
-  measureLastState = measureThisState;​ +
-+
- +
-/** +
- * Format: -56.22  +
- ​* ​         74.78 +
- ​* ​        ​313.01 +
- * 6 chars length plus 2 spaces after, always fill 8! +
- */ +
-void formatTemp(double temp, char * loc) { +
-  int cursor = 0; +
-  if (temp < 0) { +
-    loc[cursor++] = '​-';​ +
-    temp = -temp; +
-  } +
-   +
-  int temp100 = ((int)(temp * 100)) % 100; +
-  int temp1 = (int)(temp);​  +
- +
-  if (temp1 / 100) { +
-    loc[cursor++] = '​0'​ + (temp1 / 100); +
-    temp1 = temp1 % 100; +
-  } +
- +
-  if (temp1 / 10) { +
-    loc[cursor++] = '​0'​ + (temp1 / 10); +
-    temp1 = temp1 % 10; +
-  } +
- +
-  loc[cursor++] = '​0'​ + temp1; +
-  loc[cursor++] = '​.';​ +
-  loc[cursor++] = '​0'​ + (temp100 / 10); +
-  loc[cursor++] = '​0'​ + (temp100 % 10); +
- +
-  while (cursor != 8) { +
-    loc[cursor++] = ' '; +
-  } +
-+
- +
-void writeDisplay() { +
-  formatTemp(immediate,​ line2); +
-  if (currentFilter != FILTER_CUR) { +
-    formatTemp(accumulator,​ line2 + 10); +
-    if (currentFilter == FILTER_MAX) { +
-      line1[10] = '​M';​ line1[11] = '​A';​ line1[12] = '​X';​ +
-    } +
-    if (currentFilter == FILTER_MIN) { +
-      line1[10] = '​M';​ line1[11] = '​I';​ line1[12] = '​N';​ +
-    } +
-  } else { +
-    line1[10] = line1[11] = line1[12] = ' '; +
-    line2[8] = line2[9] = line2[10] = line2[11] = line2[12] = line2[13] = line2[14] = line2[15] = ' '; +
-  } +
-  if (measuring) { +
-    if (measuringStage == 0) line1[8] = 1; +
-    if (measuringStage == 1) line1[8] = 2; +
-    if (measuringStage == 2) line1[8] = 3; +
-    if (measuringStage == 3) line1[8] = 4; +
-    if (measuringStage == 3) measuringStage = 0; +
-    else measuringStage = measuringStage + 1; +
-  } else { +
-    line1[8] = ' '; +
-  } +
-  line1[16] = line2[16] = 0; +
-  // write lines +
-  lcd.setCursor(0,​ 0); +
-  lcd.print(line1);​ +
-  lcd.setCursor(0,​ 1); +
-  lcd.print(line2);​ +
-+
- +
-void setup() { +
-  DDRD |= (PD5 | PD6 | PD2); +
-  DDRB |= (PB1); +
-  pinMode(6, INPUT_PULLUP);​ +
-  pinMode(5, INPUT_PULLUP);​ +
-  Serial.begin(9600);​ +
-  mlx.begin();​ +
-  Wire.setClock(100000);​ +
-  lcd.init();​ +
-  lcd.init();​ +
-  lcd.backlight();​ +
-  lcd.createChar(1,​ stage1); +
-  lcd.createChar(2,​ stage2); +
-  lcd.createChar(3,​ stage3); +
-  lcd.createChar(4,​ stage4);+
  
-  cli(); +Pentru că senzorul de temperatură este interfațat pe I2C, și comunicația pe I2C are nevoie ca interrupt-urile să fie pornite, nu pot face citirea senzorului direct în interrupt-ul de timer. 
-  ​TCCR2A = 0; +În loc, interrupt-ul setează un flag global. Bucla principală verifică constant acest flag, și dacă este setat, îl elimină și face o citire a senzorului.
-  TCCR2B = 0; +
-  TCNT2  = 0; +
-  OCR2A = 249; +
-  TCCR2B |= (1 << WGM21); +
-  TCCR2B |= (1 << CS22) | (0 << CS21) | (0 << CS20); +
-  TIMSK2 |= (1 << OCIE2A); +
-  sei(); +
-}+
  
 +Afișarea la display se face de 10 ori pe secundă. În mod ideal, afișarea s-ar putea face mai des, dar refresh rate-ul display-ului nu permite (durează ~70ms ca un pixel să-și schimbe starea).
  
 +Filtrele sunt evaluate odată cu refresh-ul senzorului. Dacă se cere schimbarea filtrului, înainte de citire, se resetează datele de acumulare si e schimbată funcția de filtru.
  
-void loop() { +===== Rezultatul Obținut ===== 
-  long current ​millis(); +Am obținut un dispozitiv care poate măsura temperatura în timp real și care poate afișa maximul și minimul temperaturii dintr-un loc.\\ 
-  if (current - lastRead >100) { +{{:​pm:​prj2021:​apredescu:​imagine1_stanica_ovidiu.jpeg?​600|}} 
-    writeDisplay();​ +{{:​pm:​prj2021:​apredescu:​imagine_4_stanica_ovidiu.jpeg?​600|}
-    lastRead ​current; +{{:​pm:​prj2021:​apredescu:​imagine_2_stanica_ovidiu.jpeg?​600|}
-  } +{{:​pm:​prj2021:​apredescu:​imagine_3_stanica_ovidiu.jpeg?​600|}}
-  if (readPending) ​+
-    ​readPending = false; +
-    readSensorAndUpdate();​ +
-  ​+
-+
-</​code>​+
  
-===== Rezultatul Obtinut ​=====+===== Concluzii ​===== 
 +În urma realizării acestui proiect, am observat cât de ușor și de distractiv este să creezi proiecte folositoare folosindu-mă de arduino.
  
-===== Downloads ​===== +===== Download ​===== 
-[[https://​ocw.cs.pub.ro/​courses/​pm/prj2021/apredescu/pistol-de-masurare-temperatura?​do=export_pdf|Link pdf]]+<note tip> 
 +Arhiva conține o poză cu proiectul, schema bloc, schema electrică și codul sursă al proiectului:​  
 +{{:pm:prj2021:apredescu:​resurse_stanica_ovidiu.zip|Arhivă Resurse}} 
 +</note>
  
 +===== Jurnal =====
 +2021/04/25 - Creare pagină wiki\\
 +2021/05/16 - Creare schemă bloc și actualizare pagină wiki\\
 +2021/06/01 - Finalizare parte hardware și software a proiectului + creare schemă electrică\\
 +2021/06/02 - Finalizare pagină wiki
  
 ===== Bibliografie/​Resurse ===== ===== Bibliografie/​Resurse =====
-[[https://​ocw.cs.pub.ro/​courses/​pm/​prj2021/​apredescu/​pistol-de-masurare-temperatura|Link proiect]]+[[https://​ocw.cs.pub.ro/​courses/​pm/​prj2021/​apredescu/​pistol-de-masurare-temperatura?​do=export_pdf|Link pdf]]\\ 
 +[[https://​ocw.cs.pub.ro/​courses/​pm/​prj2021/​apredescu/​pistol-de-masurare-temperatura|Link proiect]]\\ 
 +https://​www.youtube.com/​watch?​v=xAeO1ZQtwKc - Link cu video demo\\ 
 +https://​app.diagrams.net/​ - Program folosit pentru schema bloc\\ 
 +https://​www.kicad.org/​download/​ - Program folosit pentru schema electrică
  
pm/prj2021/apredescu/pistol-de-masurare-temperatura.1622569534.txt.gz · Last modified: 2021/06/01 20:45 by ovidiu.stanica
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0