Schema bloc
Elementul principal al sistemului de achiziţie a temperaturii este senzorul LM335. Circuitul de adaptare este format din amplificatoare operaţionale, necesare pentru a amplifica nivelul semnalului furnizat de traductor, şi un convertor analog-digital, care furnizează intrarea circulitului de prelucrare.
Circuitul de prelucrare electronică este reprezentat demicrocontrollerul AtMega128, programarea acestuia fiind descrisă mai jos.
Fiecare bloc component va fi descris în continuare.
Sistemul de achiziţie a temperaturii
Senzorul LM335 este folosit în configuraţie de senzor calibrat. In schemă, senzorul LM335 se poate echivala cu o diodă Zener.
Rezistenţa R5 stabilizează curentul prin senzor la o valoare de 1 mA. Tensiunea pe această diodă este dependentă de temperatură. Potenţiometrul R7 este folosit pentru calibrarea tensiunii de ieşire la 25oC: 2,98V. Ea se modifică cu 10mV/grad.
Circuitul are o impedanţă dinamică mai mică de 1Ω şi funcţionează între 0.45mA si 5mA fără degradări ale perfomanţelor. Calibrat, LM335 are o eroare mai mică de 1oC la o variaţie a temperaturii de 100oC (tipic 0.5oC). Spre deosebire de alţi senzori de temperatură, LM335 are o ieşire liniară în tensiune.
Circuitul de adaptare cu traductorul
Traductorul folosit, LM335 are o panta de 10mV/oK, iar pentru intervalul cerut (0oC si 100oC ) tensiunile de iesire vor avea valorile +2.732V la 0oC si 3.732V la 100oC => excursia de tensiune va fi de 1V.
Circuitul de mai sus are rolul de a mari excursia tensiunii de la iesire de la 1V la 5V pentru a ne putea folosi de intreaga rezolutie a ADC-ului intern al microcontrolerului a carui intrare analogica ia valori intre 0...5V, pentru
Din acestea rezulta ca amplificarea acestui adaptor trebuie sa fie A=ΔUf/ΔUi=5/1=5 pe fiecare grad celsius.
Amplificarea este: A=(R3+Rv2)/R2
R6≈R3+Rv2. Pentru R2=10kΩ avem:
R3+Rv2=50k rezulta ca R3=45K, iar Rv2=5K
Se alege R6=50k.
Circuitul de mai sus are rolul de a mari excursia tensiunii de la iesire de la 1V la 5V pentru a ne putea folosi de intreaga rezolutie a ADC-ului intern al microcontrolerului a carui intrare analogica ia valori intre 0...5V, pentru
Din acestea rezulta ca amplificarea acestui adaptor trebuie sa fie A=ΔUf/ΔUi=5/1=5 pe fiecare grad celsius.
Amplificarea este: A=(R3+Rv2)/R2
R6≈R3+Rv2. Pentru R2=10kΩ avem:
R3+Rv2=50k rezulta ca R3=45K, iar Rv2=5K
Se alege R6=50k.
Circuitul de prelucrare electronică
Se foloseşte microcontrolerul AtMega128, produs de Atmel. Acest microcontroler lucrează pe 8 biţi şi are o memorie de 128 KB.
Alte caracteristici ale microcontrollerului:
- 4KB memorie EEPROM
- 4KB SRAM intern
- Două timere pe 8 biţi
- Convertor analog-digital integrat pe 10 biţi, cu 8 canale
- Selectare a frecvenţei de ceas prin software
- 53 de linii de input/output programabile
Microcontrolerul funcţionează la o tensiune cuprinsă între 4,5 şi 5,5 V, la o frecvenţă de până la 16MHz.
Configuraţia pinilor folosiţi este următoarea:
Iesirea circuitului de adaptare cu traductorul, se va conecta pe pinul 62, adica pe canalul 0 al convertorului analog – digital (ADC0).
Butoanele pentru setarea temperaturii de referinta de catre utilizator se vor conecta pe pinii 47 (PA4) pentru ridicarea referintei cu un grad, si 48 (PA5) pentru coborarea acesteia cu un grad.
Iesirea pentru releul de declansare a agregatului de incalzire si ledul de semnalare a acestui releu sunt pe pinul 49 (PA2), iar racirea se comanda pe pinul 50(PA3).
Este posibil ca, pentru activarea releului,s emnalul furnizat de mcirocontroller să nu fie suficient de mare. In acest caz, ieşirea poate fi conectată la un AO cu reacţie negativă sau la un tranzistor.
Ledurile de semnalare a modului de afisare temperature setata / temperature reala sunt conectate pe pinul 0 (PA0) respectiv pinul 1 (PA1).
Driverele de LCD se conecteaza la microcontroler pe portul E si portul D (PD0-3 (MSB), PE4-7, PE0-3 (LSB)).
Afişajul
Cele 3 afisoare TIL321P sunt controlate de catre 3 drivere HCF4543F:
Tabela de adevar pentru driver:
Afisorul TIL321P:
Tabelul următor prezintă legătura dintre tensiunea de ieşire a senzorului LM335 (Ui), tensiunea de iesire a circuitului de adaptare a traductorului (Uf), numarul treptei de esantionare a ADC-ului intern al microcontrolerului (Te), numarul aproximat al treptei de esantionare (Nr Te) şi temperatura afişată (T).
T(ºC)
|
Ui
|
Uf
|
Te
|
Nr Te
|
Nr binar
|
0
|
2,732
|
0
|
0
|
0
|
00000000
|
5
|
2,782
|
0,25
|
12,67327
|
13
|
00001101
|
10
|
2,832
|
0,5
|
25,34653
|
25
|
00011001
|
15
|
2,882
|
0,75
|
38,0198
|
38
|
00100110
|
20
|
2,932
|
1
|
50,69307
|
51
|
00110011
|
25
|
2,982
|
1,25
|
63,36634
|
63
|
00111111
|
26
|
2,992
|
1,3
|
65,90099
|
66
|
01000010
|
30
|
3,032
|
1,5
|
76,0396
|
76
|
01001100
|
35
|
3,082
|
1,75
|
88,71287
|
89
|
01011001
|
40
|
3,132
|
2
|
101,3861
|
101
|
01100101
|
45
|
3,182
|
2,25
|
114,0594
|
114
|
01110010
|
50
|
3,232
|
2,5
|
126,7327
|
127
|
01111111
|
55
|
3,282
|
2,75
|
139,4059
|
139
|
10001011
|
60
|
3,332
|
3
|
152,0792
|
152
|
10011000
|
65
|
3,382
|
3,25
|
164,7525
|
165
|
10100101
|
70
|
3,432
|
3,5
|
177,4257
|
177
|
10110001
|
75
|
3,482
|
3,75
|
190,099
|
190
|
10111110
|
80
|
3,532
|
4
|
202,7723
|
203
|
11001011
|
85
|
3,582
|
4,25
|
215,4455
|
215
|
11010111
|
90
|
3,632
|
4,5
|
228,1188
|
228
|
11100100
|
95
|
3,682
|
4,75
|
240,7921
|
241
|
11110001
|
100
|
3,732
|
5
|
253,4653
|
253
|
11111101
|
ADCul intern are urmatoarele caracteristici:
-eroare totala de ±2 LSB,
-rezolutia este de 10biti,
-timpul de conversie este de 13-260µs.
ADC-ul primeste pe intrarea CH1(ADC0) o tensiune VinÎ(0..5V) si este alimentat la Vref=5V.
Cod la 0V: 0000 0000 (00H)
Cod la 5V: 1111 1111 (FFH)
Precizia necesare este de 8 biti, deci vom citi doar ADCL ceea ce inseamna 256 de valori reprezentabile. Noi avem 101 de valori adica rezolutia acestui convertor este de aproximativ 0.394oC/bit:
Rezolutia=(1/256)*Ui=(1/256)*5V=0.01953V≈19.53V/bit
Rezolutia=(1/256)*T =(1/256)*101oC≈0.394oC/bit
ADC-ul are o intrerupere proprie care este chemata atunci cand se termina o conversie, si care seteaza registrul “intrare” cu acea valoare. Astfel programul ia intotdeauna ultima valoare esantionata de catre ADC.
Codul pentru programarea microcontrolerului este:
#include "m128def.inc"
.DSEG
.def intrare=R27
.def flg=R29
.def comp=R28
.def z1 = R22
.def z2 = R23
.def temp = R16
.def temp1 = R17
.def temp2 = R18
.def t_conv = R19
.def masura = R20
.def t_set=R21
.def unu=R22
.cseg
.org $000
rjmp RESET
.org $0020 // vector de intrerupere pt overflow a timer0
rjmp tc0i
.org $002A // vector de intrerupere pt terminarea conversiei ADC
rjmp ADC_ISR
.CSEG
tc0i:
in temp, SREG ; salvez continutul SREG
mov ZL, z1
mov ZH, z2
adiw ZL,0x1 ; incrementez contorul
mov z1, ZL
mov z2, ZH
out SREG,temp ; setez continutul SREG la val anterioara
reti
RESET:
cli ; dezactivare intreruperi
ldi temp,0x05 ; Initiez Timer/Counter 0 Prescaler
out TCCR0,temp ; to Timer 0 Control Register.
; Fiecare tick are 256 µs.
ldi t_set,33
ldi TEMP,low(RAMEND) ; setez locatia de memorie pt stiva
out SPL,TEMP
ldi TEMP, high(RAMEND)
out SPH, TEMP
ldi temp,0xCF ; configurare pini iesire/intrare
out DDRA, Temp ; aplic configuratia
ldi r16, 0
out ADMUX, r16 ; selectez canalul 0 in ADMUX
ldi r16, 0b11101101 ; selectez: ADC Enable, Start Conversion,
; Free-Running Mode, write
; zero to ADC Int flag, enable int,
; prescaler: 101 for XTAL/32
out ADCSR, r16 ; pun setarule in registrul ADC-ului
rcall stop_timer ; nu pornesc timerul/opresc dc e deja pornit
sei ; activez toate intreruperile
sbi PORTA,1 ; setez pe temp reala
ldi temp, 0x00
rcall start
rjmp Loop
start_timer:
cli
ldi z1,0
ldi temp,$02 ; setez Bitul 1
out TIMSK,temp ; in Timer Interupt Mask Register pt a
; dezactiva intreruperile timer0
sei
ret
stop_timer:
cli
ldi temp,$00 ; resetez Bitul 1
out TIMSK,temp ; in Timer Interupt Mask Register pt a
; dezactiva intreruperile timer0
sei
ret
Loop: ; Loop Label
rcall Ia_temp;
rcall set_temp
rcall mas_temp ; verifica dc
rcall Setare_lcd
rjmp Loop
mas_temp:
in temp, TIMSK
cpi temp, 0x0 // merge timerul?
breq fin2
mov t_conv, t_set // se va afisa t_set
mov ZL, z1
mov ZH, z2
subi ZH, 0x4C
brne fin3
subi ZL, 0x4B // au trecut 5 sec? 256us * 19531 = 5 s brne fin3
rcall stop_timer
cbi PORTA,0 // aprind ledul de T_real
sbi PORTA,1
fin2: mov t_conv, masura // se va afisa masura
fin3: ret
set_temp:
IN temp,PORTA ; ce buton s-a apasat? bitul 4 up, 5 down
bst temp,4
brts creste
bst temp,5
brts scade
fin1:
ret
creste:
cbi PORTA,1
sbi PORTA,0 // aprind ledul de setare temp
inc t_set
rcall start_timer;
rjmp fin1
scade:
cbi PORTA,1
sbi PORTA,0 // aprind ledul de setare temp
dec t_set
rcall start_timer
rjmp fin1
compara:
mov temp, t_set
ldi flg,1
rcall start ; converteste t_set intr-un nr pt comparatie
cp intrare, temp ; decide incalzirea/racirea
brlo incalzire
brlt incalzire
cp temp, intrare
brlo racire
brlt racire
cbi PORTA,3 ; sting ambele leduri (incalzire/racire)
cbi PORTA,2
endcompara:
ret
incalzire:
cbi PORTA, 3 ; aprind ledul de incalzire
sbi PORTA, 2
rjmp endcompara
racire:
cbi PORTA, 2 ; aprind ledul de racire
sbi PORTA, 3
rjmp endcompara
Ia_temp:
ldi temp, 83 // doar pt simulare
mov intrare, temp
ldi flg,0
rcall start // convertesc intrarea de la adc in o temp
mov masura, temp
rcall compara
ret
Setare_lcd:
call BIN2BCD // intoarce in temp2 valoarea BCD a unui nr
// binar [0,255] si in unu cifra sutelor
out PORTE, temp2
out PORTD, unu
ret
#include "math.asm"
#include "rutine.asm"
ADC_ISR:
push r16
in r16, SREG
push r16
push r17
in r16, ADCL
in r17, ADCH
lsr r17
ror r16
lsr r17
ror r16
mov intrare, r15
com r16
mov r15, r16
pop r17
pop r16
out SREG, r16
pop r16 reti
Fisierul “rutine.asm”:
.cseg
BIN2BCD:
ldi temp,0x8
ldi unu, 0
mov temp1, t_conv
ldi temp2,0x0
BK: lsl temp2
brcs UN
brcc UN1
BK1:lsl temp1
brcc ET
inc temp2 // daca am carry la lsl atunci il transfer
// in registru
ET: cpi temp,0x1
breq FIN
call TEST
call TEST2
dec temp
rjmp BK
FIN:
clr temp // sterg temp
ret
TEST:
push temp
ldi temp, 0xF
and temp,temp2 // pun in temp primii 4 biti ai masurii
cpi temp,0x5 // compar acesti biti cu 5
brsh et2 // daca >=5 atunci sar la et2
et3:pop temp
ret
et2:inc temp // adaug 3 la nr
inc temp
inc temp
andi temp2, 0xF0 // sterg primii 4 biti ai masurii
add temp2,temp // ii inlocuiesc cu temp
rjmp et3
TEST2:
push temp
ldi temp, 0xF0
and temp,temp2 // pun in temp primii 4 biti ai masurii
lsr temp // mut la dreapta cu 4
lsr temp
lsr temp
lsr temp
cpi temp,0x5 // compar acesti biti cu 5
brsh et21 // daca >=5 atunci sar la et2
et31:pop temp
ret
et21:inc temp // adaug 3 la nr
inc temp
inc temp
andi temp2, 0x0F // sterg cei 4 biti ai masurii
lsl temp // pun la loc cei 4 biti mutati anterior
lsl temp
lsl temp
lsl temp
or temp2,temp // ii inlocuiesc cu temp
rjmp et31
UN: inc unu
rjmp bk1
UN1: lsl unu
rjmp bk1
Fisierul “math.asm”:
;***** Subroutine Register Variables
.def drem16uL=r14
.def drem16uH=r15
.def dres16uL=r16
.def dres16uH=r17
.def dd16uL =r16
.def dd16uH =r17
.def dv16uL =r18
.def dv16uH =r19
.def dcnt16u =r20
.def count = r21
//se face conversia round(x*0,394)=temperatura sau round(temp/0,394)=x
//unde x este intrarea adc-ului
start:
push r0
push r1
push r14
push r15
push r17
push r18
push r19
push r20
push r21
push r22
push ZH
push ZL
push r27
mov mc16uL, temp
ldi mc16uH,0x0
cpi flg, 0x1
breq conv0
ldi mp16uL, low(394)
ldi mp16uH, high(394)
rjmp conv1
conv0:
ldi mp16uL, low(1000)
ldi mp16uH, high(1000)
conv1:
rcall mpy16u
back:
lsr m16u3
ror m16u2
ror m16u1
ror m16u0
mov dd16uL,m16u0
mov dd16uH,m16u1
cpi flg, 0x1
breq conv2
ldi dv16uL,low(1000)
ldi dv16uH,high(1000)
rjmp conv3
conv2:
ldi dv16uL,low(394)
ldi dv16uH,high(394)
conv3: rcall div16u
again:
lsl drem16uL //inm cat cu 2
lsl drem16uH
lsl dres16uL
lsl dres16uH
ldi count, 0xA
mov ZH,drem16uH
mov ZL,drem16uL
no:
sbiw ZH:ZL,0x32
dec count
brne no
sbiw ZH:ZL, 0
brlt end1
cpi flg, 0x1
breq end
ldi count, 0x1e
mov ZH,drem16uH
mov ZL,drem16uL
no1:
sbiw ZH:ZL,0x32
dec count
brne no1
sbiw ZH:ZL, 0
brlt end
inc dres16uL
end:inc dres16uL
end1:
mov temp,dres16uL
pop r27
pop ZL
pop ZH
pop r22
pop r21
pop r20
pop r19
pop r18
pop r17
pop r15
pop r14
pop r1
pop r0
ret
;***** Subroutine Register Variables
.def mc16uL =r16 ;multiplicand low byte
.def mc16uH =r17 ;multiplicand high byte
.def mp16uL =r18 ;multiplier low byte
.def mp16uH =r19 ;multiplier high byte
.def m16u0 =r18 ;result byte 0 (LSB)
.def m16u1 =r19 ;result byte 1
.def m16u2 =r20 ;result byte 2
.def m16u3 =r21 ;result byte 3 (MSB)
.def mcnt16u =r22 ;loop counter
;***** Code
mpy16u:
clr m16u3 ;clear 2 highest bytes of result
clr m16u2
ldi mcnt16u,16 ;init loop counter
lsr mp16uH
ror mp16uL
m16u_1:
brcc noad8 ;if bit 0 of multiplier set
add m16u2,mc16uL ;add multiplicand Low to byte 2 of res
adc m16u3,mc16uH ;add multiplicand high to byte 3 of res
noad8:ror m16u3 ;shift right result byte 3
ror m16u2 ;rotate right result byte 2
ror m16u1 ;rotate result byte 1 and multiplier High
ror m16u0 ;rotate result byte 0 and multiplier Low
dec mcnt16u ;decrement loop counter
brne m16u_1 ;if not done, loop more
ret
div16u:
clr drem16uL ;clear remainder Low byte
sub drem16uH,drem16uH;clear remainder High byte and carry
ldi dcnt16u,17 ;init loop counter
d16u_1:
rol dd16uL ;shift left dividend
rol dd16uH
dec dcnt16u ;decrement counter
brne d16u_2 ;if done
ret ; return
d16u_2:
rol drem16uL ;shift dividend into remainder
rol drem16uH
sub drem16uL,dv16uL ;remainder = remainder - divisor
sbc drem16uH,dv16uH ;
brcc d16u_3 ;if result negative
add drem16uL,dv16uL ; restore remainder
adc drem16uH,dv16uH
clc ; clear carry to be shifted into result
rjmp d16u_1 ;else
d16u_3:
sec ; set carry to be shifted into result
rjmp d16u_1
BIN2BCD:
ldi temp,0x8
ldi unu, 0
mov temp1, t_conv
ldi temp2,0x0
BK: lsl temp2
brcs UN
brcc UN1
BK1:lsl temp1
brcc ET
inc temp2 // daca am carry la lsl atunci il transfer
// in registru
ET: cpi temp,0x1
breq FIN
call TEST
call TEST2
dec temp
rjmp BK
FIN:
clr temp // sterg temp
ret
TEST:
push temp
ldi temp, 0xF
and temp,temp2 // pun in temp primii 4 biti ai masurii
cpi temp,0x5 // compar acesti biti cu 5
brsh et2 // daca >=5 atunci sar la et2
et3:pop temp
ret
et2:inc temp // adaug 3 la nr
inc temp
inc temp
andi temp2, 0xF0 // sterg primii 4 biti ai masurii
add temp2,temp // ii inlocuiesc cu temp
rjmp et3
TEST2:
push temp
ldi temp, 0xF0
and temp,temp2 // pun in temp primii 4 biti ai masurii
lsr temp // mut la dreapta cu 4
lsr temp
lsr temp
lsr temp
cpi temp,0x5 // compar acesti biti cu 5
brsh et21 // daca >=5 atunci sar la et2
et31:pop temp
ret
et21:inc temp // adaug 3 la nr
inc temp
inc temp
andi temp2, 0x0F // sterg cei 4 biti ai masurii
lsl temp // pun la loc cei 4 biti mutati anterior
lsl temp
lsl temp
lsl temp
or temp2,temp // ii inlocuiesc cu temp
rjmp et31
UN: inc unu
rjmp bk1
UN1: lsl unu
rjmp bk1
Fisierul “math.asm”:
;***** Subroutine Register Variables
.def drem16uL=r14
.def drem16uH=r15
.def dres16uL=r16
.def dres16uH=r17
.def dd16uL =r16
.def dd16uH =r17
.def dv16uL =r18
.def dv16uH =r19
.def dcnt16u =r20
.def count = r21
//se face conversia round(x*0,394)=temperatura sau round(temp/0,394)=x
//unde x este intrarea adc-ului
start:
push r0
push r1
push r14
push r15
push r17
push r18
push r19
push r20
push r21
push r22
push ZH
push ZL
push r27
mov mc16uL, temp
ldi mc16uH,0x0
cpi flg, 0x1
breq conv0
ldi mp16uL, low(394)
ldi mp16uH, high(394)
rjmp conv1
conv0:
ldi mp16uL, low(1000)
ldi mp16uH, high(1000)
conv1:
rcall mpy16u
back:
lsr m16u3
ror m16u2
ror m16u1
ror m16u0
mov dd16uL,m16u0
mov dd16uH,m16u1
cpi flg, 0x1
breq conv2
ldi dv16uL,low(1000)
ldi dv16uH,high(1000)
rjmp conv3
conv2:
ldi dv16uL,low(394)
ldi dv16uH,high(394)
conv3: rcall div16u
again:
lsl drem16uL //inm cat cu 2
lsl drem16uH
lsl dres16uL
lsl dres16uH
ldi count, 0xA
mov ZH,drem16uH
mov ZL,drem16uL
no:
sbiw ZH:ZL,0x32
dec count
brne no
sbiw ZH:ZL, 0
brlt end1
cpi flg, 0x1
breq end
ldi count, 0x1e
mov ZH,drem16uH
mov ZL,drem16uL
no1:
sbiw ZH:ZL,0x32
dec count
brne no1
sbiw ZH:ZL, 0
brlt end
inc dres16uL
end:inc dres16uL
end1:
mov temp,dres16uL
pop r27
pop ZL
pop ZH
pop r22
pop r21
pop r20
pop r19
pop r18
pop r17
pop r15
pop r14
pop r1
pop r0
ret
;***** Subroutine Register Variables
.def mc16uL =r16 ;multiplicand low byte
.def mc16uH =r17 ;multiplicand high byte
.def mp16uL =r18 ;multiplier low byte
.def mp16uH =r19 ;multiplier high byte
.def m16u0 =r18 ;result byte 0 (LSB)
.def m16u1 =r19 ;result byte 1
.def m16u2 =r20 ;result byte 2
.def m16u3 =r21 ;result byte 3 (MSB)
.def mcnt16u =r22 ;loop counter
;***** Code
mpy16u:
clr m16u3 ;clear 2 highest bytes of result
clr m16u2
ldi mcnt16u,16 ;init loop counter
lsr mp16uH
ror mp16uL
m16u_1:
brcc noad8 ;if bit 0 of multiplier set
add m16u2,mc16uL ;add multiplicand Low to byte 2 of res
adc m16u3,mc16uH ;add multiplicand high to byte 3 of res
noad8:ror m16u3 ;shift right result byte 3
ror m16u2 ;rotate right result byte 2
ror m16u1 ;rotate result byte 1 and multiplier High
ror m16u0 ;rotate result byte 0 and multiplier Low
dec mcnt16u ;decrement loop counter
brne m16u_1 ;if not done, loop more
ret
div16u:
clr drem16uL ;clear remainder Low byte
sub drem16uH,drem16uH;clear remainder High byte and carry
ldi dcnt16u,17 ;init loop counter
d16u_1:
rol dd16uL ;shift left dividend
rol dd16uH
dec dcnt16u ;decrement counter
brne d16u_2 ;if done
ret ; return
d16u_2:
rol drem16uL ;shift dividend into remainder
rol drem16uH
sub drem16uL,dv16uL ;remainder = remainder - divisor
sbc drem16uH,dv16uH ;
brcc d16u_3 ;if result negative
add drem16uL,dv16uL ; restore remainder
adc drem16uH,dv16uH
clc ; clear carry to be shifted into result
rjmp d16u_1 ;else
d16u_3:
sec ; set carry to be shifted into result
rjmp d16u_1
0 comentarii:
Trimiteți un comentariu