Detalii Senzor de Temperatură

Introducere
Prezentarea de mai jos e destul vastă. Pentru o înţelegere mai uşoară am împărţit totul în mai multe capitole:
  1. Transmiterea temperaturii
  2. Prelucrarea temperaturii
  3. Afişarea temperaturii Nokia 3310
  4. Afişarea temperaturii Nokia 1100 
 Transmiterea Temperaturii
 Senzorul de temperatură DS18B20 (sau DS18S20) folosit  este unul digital. Asta înseamnă că temperatura ambientală va fi convertită de senzor într-o valoare digitală şi va fi transmisă în format digital. Pentru pornirea senzorului, începerea conversiei şi transmisia temperaturii sunt necesare o serie de comenzi pe care sensorul le recunoaşte. Transmisia acestor comenzi se face printr-un singur fir (1 wire communication) în mod bidirecţional.
Acesti tip de comunicare se bazează pe o legatură de tipul Master-Slave (Stăpân-Sclav). În cazul meu, Masterul îl reprezintă microcontroller-ul ATtiny13, iar Slaveul îl reprezintă senzorul de temperatură DS18B20.
Asta înseamnă că începerea comunicării va fi întotdeauna iniţiată de Master, indiferent dacă Masterul vrea să transmită ceva sau dacă Slave-ul vrea să transmită ceva. Cu alte cuvinte Masterul va zice fie "Eu vorbesc acum", fie "Eu ascult acum", iar Slaveul se va supune. 
Transiterea comenzilor se face printr-o înşiruire de biţi, dar care vor avea o formă puţin diferită în cazul protocolului 1-Wire. Astfel, transmiterea unui bit de "0" se va face printr-un impuls negativ lung, iar transmiterea unui bit de "1" se va face printr-un impuls negativ scurt. 
 
Puţin mai detaliat, dacă Masterul vrea să transmită "0" atunci el va iniţia transmisia unui bit printr-un front căzător, de la "1" la "0", după care va aştepta o durată aproxinativ egală cu durata maximă de transmisie a unui bit. Slaveul va citi valoarea aproximativ la mijlocul duratei de transmisie a unui bit, atunci când aceasta va fi "0".
În cazul în care Masterul transmite "1", după iniţierea comunicării, prin frontul căzător, masterul va trece imediat în starea "1". Astfel, în momentul în care Slaveul citeşte valoarea, aceasta va fi "1".
 
Pentru recepţia datelor, Masterul trebuie să iniţieze comunicarea printr-un front căzător, după care trebuie să treacă imediat în modul HiZ (înaltă impedanţă), adică trebuie să configureze portul legat la senzor ca şi intrare. Făcând asta, controlul asupra valorii bitului care se transmite rămâne la Slave.
 
Astfel, Masterul va citi "0" atunci când Slaveul ţine linia de date în "0" pe toată durata transmisie unui bit.
 
În celălalt caz, Masterul citşte "1", dacă Slaveul lasă linia de date să ajngă în "1", imediat după ce comunicarea a fost iniţiată.
 
Pentru acest montaj, m-am limitat la a implementa doar trei comenzi: Reset (Repornire), Write (Scriere) şi Read (Citire). Reset-ul e necesar pentru a pune în funcţiune senzorul şi pentru a-i schimba starea internă. Acesta se realizează printr-un impuls negativ de o durată mai lungă pe linia de date a senzorului. Imediat după încetarea resetului şi revenirea liniei de date la valoarea "1", senzorul îşi va face simţită prezenţa prin iniţierea unui impuls negativ scurt. Astfel Masterul va şti că Slaveul e prezent. Pentru mai multe detalii se poate studia foaia de catalog a senzorului, codul ataşat sau internetul. :-)
Mai jos se poate vedea schema logică transmisia, respectiv recepţia datelor prin protocolul 1-Wire:
Prelucrarea Temperaturii
Senzorul de temperatura folosit are o fineţe foarte mare (0.006 grade pentru 18B20 şi 0.5 grade pentru 18S20) şi o precizie de ±0.5 grade. Pentru mine e important să ştiu valoarea temperaturii în numere întregi, aşa că am ales să ignor valorile subunitare. Senzorul are o plajă de valori cuprinsă între -55 grade şi +127 grade, din care eu voi folosi doar intervalul [-55, +99], având în vedere că valoare temperaturii va fi afişată pe două cifre.
Pentru a avea cât mai multe indicii atunci când apare o defecţiune, am ales să adaug la prelucratea temperaturii o serie de mesaje cu câte o semnificaţie distinctă. Am luat următoarele cazuri posibile şi am încercat să le identific prin programul microcontrollerului:
  1. Cablul ce duce la senzor e întrerupt "-88"
  2. Linia de date face scurt la masă "-99"
  3. Linia de date face scurt la plus "-88"
  4. Contact rezistiv la masă pe linia de date "0"
Toate aceste situaţii pot fi identificate de către microcontroller, iar acesta va afişa un mesaj corespunzător astfel încât să-mi dau seama cât mai repede ce s-a întamplat.
Astfel, dacă cablul ce duce la senzor e întrerupt sau dacă face scurt la plus, pe linia de date nu va apărea impulsul de prezentă al senzorului după reset. În aces caz pe ecran se va afişa "-88".
Dacă linia face scurt la masă, atunci linia de date nu va reveni la "1" după terminarea resetului, caz în care pe ecran se va afişa "-99".
În cazul în care există un contact rezistiv la masă pe linia de date, valoarea afişată la pornirea senzorlui va fi întotdeauna "0". Pentru a nu confunda o defecţiune cu o temperatură ambientală de zero grade se va verifica temperatura afişată la pornirea senzorului, când temperatura va fi implicit "85". Dacă la pornire, prima valoare afişată pe ercan e "0", atunci pe linia de date este un defect.
Poleiul apare atunci când temperatura aerului este sub 4 grade, astfel în care temperatura scade sub 4 grade, aprind un led roşu de avertisment, care va colora întreg ecranul.
Schema logică a afişării prelucrării temperaturii se poate vedeam mai jos:


Afişarea temperaturii Nokia 3310
Pentru afişarea temperaturii, cerinţele mele au fost următoarele:
  • cifrele să fie cât mai mari
  • programul să fie cât mai mic
  • să fiu atenţionat atunci când poate apărea poleiul 
E foarte important ca atunci când eşti la volan să îţi foloseşi atenţia doar la condus. De acee am vrut ca cifrele afişate să fie cât se poate de mari astfel ca printr-o simplă privire (ocheadă) să pot vedea temperatura de afară. Pentru asta am folosit două tipuri de ecrane, unul din ele de la un Nokia 3310, iar celălalt de la un Nokia 1100. În cele ce urmează o să prezint algoritmul de afişare a cifrelor folosind un ecran de Nokia 3310.
Ecranul de Nokia 3310 are o rezoluţie de 84 x 48 pixeli. Fiecare pixel reprezintă un bit din memoria RAM internă a ecranului. Implicit ecranul e împărţit în blocuri de 6 x 8 pixeli. Astfel ecranul va avea 6 linii compuse din câte 14 blocuri fiecare.
 
Fiecare coloană dintr-un bloc reprezintă câte un octet din memoria internă a ecranului. Astfel fiecare bit din acel octet reprezintă un pixel din acea linie din bloc.
Ca şi exemplu, pentru a putea afişa litera "N" va fi nevoie de următorii octeţi:
Pentru a putea desena cifre am ales să mă folosesc de patru tipuri de blocuri fiecare având un conţinut aparte. Astfel, pentru a putea desena cifre ma voi folosi de blocuri pline, blocuri goale şi blocuri pe jumătate pline sau pe jumătate goale. Fiecare astfel de bloc este numerotat de la 0 la 3 în funcţie de conţinutul celor două jumătăţi din care este format. Cele două jumătăţi le-am privit ca două cifre dintr-un număr binar.
Cu aceste patru tipuri de blocuri, pe care le-am numit pattern-uri (forme), am început să construiesc nişte segmente, fiecare fiind format din câte 4 blocuri (pattern-uri). Fiecarui segment i-am ataşat un număr format din indecşii patternurilor folosite in acel segment. Am ales 8 segmente cu care voi putea construi orice cifră de la 0 la 9.
Am pus toate segmentele într-un tabel astfel încât să le pot folosi mai uşor.
Pentru a obţine o cifră e nevoie de patru astfel de segmente. În exemplul de mai jos am folosit 4 segmente pentru a obţine cifra "3". Segmentele folosite au fost cuplate câte două, astfel că am putut să stochez în doi octeţi indecşii segmentelor folosite. Astfel putem ataşa fiecărei cifre doi octeţi care să conţină indecşii segmentelor folosite.
 
Pentru cifra "3" avem nevoie de doi octeţi (0x40 şi 0x23) pentru a şti indicii segmentelor din care e compusă cifra. Odată aflaţi indicii segmentelor, se pot afla indicii blocurilor folosite din fiecare segment şi, implicit, patternurile din fiecare bloc. În mod similar se vor putea obţine toate cifrele de la 0 la 9.
Toate aceste date se vor putea stoca pe doar 32 octeţi (4 patternuri, 8 segmente şi 2x10 cifre).

Dacă fiecare cifră e compusă din 4x4 blocuri, atunci dimensiunea în pixeli a acesteia ar fi 24 x 32 pixeli. Se poate observa că cifrele astfel obţinute vor ocupa mare parte din ecran.
Mai jos se poate vedea schema logică pentru afişarea unei cifre pe ecran:
Afişarea temperaturii Nokia 1100 
A trebuit să fac doi senzori, unul pentru mine şi pentru tatăl meu. Din păcate, însă n-am avut două ecrane de nokia 3310, ci doar încă unul de nokia 1100. Iniţial mi-am zis că nu pot fi aşa de mari diferenţe deoarece, din exterior cele două ecrane păreau aproape identice. După o studiere rapidă a foilor de catalog ale celor două ecrane am văzut diferenţe mari.
Pentru început comenzile pentru iniţializarea şi calibrarea ecranului diferă nu doar ca şi coduri, ci şi ca şi număr.
Apoi rezoluţia celor două ecrane diferă, cel de nokia 1100 fiind mai mare (96 x 65 pixeli). Asta înseamnă că dacă aş afişa cifrele folosite pe Nokia 3310, pe ecranul de nokia 1100, ele ar arata astfel:
Pentru a rezolva această problemă, adică să fac ca cifrele să pară la fel de mari şi pe ecranul de nokia 1100 m-am folosit de acelaşi algoritm ca cel pentru nokia 3310, doar cu "setări" diferite.
Astfel, am împărţit ecranul în blocuri de 8x8 pixeli.
Fiecare cifra am construit-o din 4x6 blocuri, astfel obţinând o creştere a dimensiunii cifrei cu 50% faţă de dimensiunea cifrei folosită pe nokia 3310. Comparativ, cifra afişată pe ecranul de nokia 1100 este mult mai mare (32 x 48 pixeli), ca şi număr de pixeli faţă de cea afişată pe ecranul de nokia 3310 (24 x 32 pixeli).
Am redus numărul de patternuri folosite în blocurile de pe ecran. Astfel am ales să folosesc doar două tipuri de blocuri (blocuri pline şi blocuri goale), fiecare primind un indice 0 (gol) sau 1 (plin).
În continuare am construit 8 segmente, fiecare compus din două rânduri de câte 4 blocuri. Fiecare bloc este stocat pe câte un bit din octetul ataşat fiecărui segment.
Astfel obţinem următorul tabel de segmente.
Ca şi exemplu, pentru a construi cifra "4" o să fie nevoie de următoarele segmente: 1, 4 şi 3. Dat fiind că pentru fiecare segment am alocat 4 biţi, o să fie nevoie de un octet şi jumătate pentru a avea toată informaţia legată construirea unei cifre. Cel mai comod pentru mine a fost să folosesc tot doi octeţi pentru fiecare cifră, cu patru biţi de umplutură la al doilea octet ataşat cifrei.
În mod similar putem afla compoziţia celorlalte cifre.
Se observă că de data asta va fi nevoie de 30 octeţi pentru a stoca toate cifrele de la 0 la 9 (2 patternuri, 8 segmente şi 2x10 cifre). Algoritmul de afişare al cifrelor rămâne neschimbat pentru cele două ecrane, doar configuraţiile vor fi altele (dimensiunea blocurilor, numărul de segmente per cifră, numărul de blocuri per segment, numărul de blocuri per linie, etc).
Din considerente strict legate de reducerea dimensiunii codului am ales să stochez toate datele legate de cifre în EEPROM-ul intern al microcontrollerului (care are o dimensiune de 64 octeţi).
Pentru a reduce consumul de stivă a microcontrollerului (care are 64 octeţi de RAM) am ales să scriu cod cu cât mai puţine funcţii, astfel că programul principal conţine şi partea de driver pentru comunicarea cu senzorul.
Pentru detalii legate de cum se realizează comunicarea cu senzorul de temperatură, se pot citi specificaţiile senzorului (DS18S20 sau DS18B20) şi se pot căuta informaţii pe internet. Asta e tot... :-)

6 comentarii:

  1. Vroiam sa te intreb ...... ceva legat de ,,,,cum identific niste senzori de la masina in ecu sau mai bine spus in epromul 28f800bb

    RăspundețiȘtergere
  2. Vroiam sa te intreb ...... ceva legat de ,,,,cum identific niste senzori de la masina in ecu sau mai bine spus in epromul 28f800bb

    RăspundețiȘtergere
    Răspunsuri
    1. Salut Valentin,
      Îți sugerez să cauți în cartea tehnică a mașinii ce tip de senzori sunt folosiți sau să întrebi pe oricare din forum-urile pasionaților de automobile.
      Cu siguranță vei obține informația dorită.
      Numai bine!

      Ștergere
  3. Imi pare rau ca nu am mai scris si nu amm fost atent ,iti multumesc pentru raspuns

    RăspundețiȘtergere
  4. Imi pare rau ca nu am mai scris si nu amm fost atent ,iti multumesc pentru raspuns

    RăspundețiȘtergere