Several years ago, Darrel (god rest his soul) and Henrik helped me no end in developing a 4 channel controller for my reptiles. I've used this code as a basis to develop simplified version, and to see if I can use a DTH11 sensor to incorporate humidity readout. Here is what I've got
Code:
'*******************************************************************************
' Set Config - 18F2520
'*******************************************************************************
ASM
__CONFIG _CONFIG1H, _OSC_HS_1H
__CONFIG _CONFIG2L, _PWRT_ON_2L
__CONFIG _CONFIG2H, _WDT_ON_2H & _WDTPS_512_2H
__CONFIG _CONFIG3H, _MCLRE_ON_3H & _LPT1OSC_OFF_3H & _PBADEN_OFF_3H
__CONFIG _CONFIG4L, _LVP_OFF_4L & _XINST_OFF_4L
ENDASM
'*******************************************************************************
' LCD (20 x 4) set up
'*******************************************************************************
DEFINE LCD_DREG PORTB ' LCD Data port
DEFINE LCD_DBIT 0 ' starting Data bit (0 or 4)
DEFINE LCD_EREG PORTB ' LCD Enable port
DEFINE LCD_EBIT 5 ' Enable bit (on EasyPIC 5 LCD)
DEFINE LCD_RSREG PORTB ' LCD Register Select port
DEFINE LCD_RSBIT 4 ' Register Select bit (on EasyPIC 5 LCD)
DEFINE LCD_BITS 4 ' LCD bus size (4 or 8 bits)
DEFINE LCD_LINES 4 ' number of lines on LCD
DEFINE LCD_COMMANDUS 2000 ' Command delay time in us
DEFINE LCD_DATAUS 50 ' Data delay time in us
'*******************************************************************************
' Defines Statements
'*******************************************************************************
DEFINE OSC 20 ' 18F4520 / 18F2520, 20mhz crystal
clear
'*******************************************************************************
'Analog and Comparator settings
'*******************************************************************************
ADCON0 = %00000000 'AD converter module disabled
ADCON1 = %00001111 'All Digital
ADCON2 = %00000000
CMCON = 7 'Disable Comparators
'*******************************************************************************
'Pins & Ports
'*******************************************************************************
TempSensor1 VAR PORTA.5 ' Pin assigned to Sensor (EasyPIC5)
HeaterOut1 VAR PORTA.4 ' Output
'*******************************************************************************
'Interrupts
'*******************************************************************************
DEFINE WRITE_INT 1
INCLUDE "DT_INTS-18.bas" ; DT's Base Interrupt System
ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler TMR1_INT, HeaterDrive, ASM, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM
T1CON = %00000001 ; free-running, 1:4 prescaler
@ INT_ENABLE TMR1_INT ; enable Timer1 interrupts
'*******************************************************************************
'DS18B20 Defines
'*******************************************************************************
DEFINE DS1820_DECIMALS 1 ' 1
DEFINE DS1820_VERIFYCRC YES ' NO
DEFINE DS18B20_ONLY YES ' NO
INCLUDE "DT18x20.pbp" ' Include DT18x20 module
'*******************************************************************************
'Inc PID routine
'*******************************************************************************
INCLUDE "incPID.pbp" ' Include the PID routine.
'*******************************************************************************
'Varibles
'*******************************************************************************
TempWD VAR WORD ' temporary WORD variable
FlashStar VAR BIT
GIE VAR INTCON.7
spMode1 VAR BYTE
SetPoint1 VAR WORD[1]
Temperatures VAR WORD
HeatCycle VAR BYTE BANK0 SYSTEM
HeaterDrives VAR BYTE[4] BANK0 SYSTEM
HeatDrive1 VAR HeaterDrives[0]
SensorActive VAR BIT
ChannelPWR VAR BIT
'*******************************************************************************
'EEPROM data
'*******************************************************************************
EE_spMode1 DATA 0 ' 0=Manual mode, temp is set by Pot.
EE_SetPoint1 DATA WORD 250 ' 25.0 deg. after programming if not in manual mode
EE_pid_Kp1 DATA WORD $0700 ' PID constants $0700, $0080, $0200
EE_pid_Ki1 DATA WORD $0080
EE_pid_Kd1 DATA WORD $0200
EE_pid_Ti1 DATA 8 ' Update I-term every 8th call to PID
EE_pid_I_Clamp1 DATA 250 ' Clamp I-term to max ±100
EE_pid_Out_Clamp1 DATA WORD 255 ' Clamp the final output to 255
EE_CH1PWR DATA 1
READ EE_spMode1, spMode1
READ EE_SetPoint1, WORD SetPoint1
READ EE_pid_Kp1, WORD pid_Kp
READ EE_pid_Ki1, WORD pid_Ki
READ EE_pid_Kd1, WORD pid_Kd
READ EE_pid_Ti1, pid_Ti
READ EE_pid_I_Clamp1, pid_I_Clamp
READ EE_pid_Out_Clamp1, WORD pid_Out_Clamp
read EE_CH1PWR, ChannelPWR
'*******************************************************************************
'Initialization
'*******************************************************************************
LCDOUT $FE,1:FLAGS=0:PAUSE 250:LCDOUT $FE,1:PAUSE 250 ' Initialize LCD
@ DS1820_Select _TempSensor1 ; Select the DS18x20 pin
@ DS1820_Resolution 12 ; Set # of bits in resolution
LOW HeaterOut1 ; set heater pin to Output
'*******************************************************************************
'Main Program
'*******************************************************************************
Main:
@ DS1820_Convert ; start a temperature conversion
@ DS1820_Stat ; check the sensors status
; enable interrupts after 1-wire
PAUSEUS 20
GIE = 1 ; disable interrupts before 1-wire
@ DS1820_Read ; get the temperature result
@ DS1820_Stat
GIE = 1
IF DS1820_Error = 0 THEN ; if there were no errors
LCDOUT $FE,$80 ; line 1, col 0
TempWD = TempC : GOSUB TempToLCD ; display TempC
'TempWd = TempC
pid_Error = SetPoint1 - TempC
TempWD = pid_Error ; Display the error value
Gosub PID
IF pid_Out.15 THEN pid_Out = 0 ; only keep positive values
HeatDrive1 = pid_Out
ELSE ;--- Error reading Sensor --------
gosub senserror
ENDIF
GOTO Main
'*******************************************************************************
'Interrupt
'*******************************************************************************
ASM
HeaterDrive
incf HeatCycle,F ; HeatCycle
movf _HeatDrive1,W ; HeatDrive1
subwf HeatCycle,w
btfsc STATUS,C
bcf _HeaterOut1
btfss STATUS,C
bsf _HeaterOut1
INT_RETURN
ENDASM
'*******************************************************************************
'Display Temp
'*******************************************************************************
TempToLCD:
IF TempWD.15 THEN LCDOUT "-" ; if negative, display minus sign
TempWD = ABS(TempWD) ; get the positive value
LCDOUT DEC TempWD/DS1820_DIG ; Display the Integer portion
@ if (DS1820_DECIMALS > 0) ; if using decimals
LCDOUT "." ; display decimal point
TempWD = TempWD//DS1820_DIG ; get decimal portion
@ if (DS1820_DECIMALS > 1) ; with DECIMALS=2, next DIG is 1
LCDOUT DEC1 TempWD DIG 1
@ endif
@ if (DS1820_DECIMALS >= 1) ; with DECIMALS=1, next DIG is 0
LCDOUT DEC1 TempWD DIG 0
@ endif
@ endif
RETURN
'*******************************************************************************
'Sensor Error
'*******************************************************************************
senserror:
LCDOUT $FE,1,"Sensor Error"
HeatDrive1 = 0
pause 1000
LCDOUT $FE,1," "
return
The only issue I have with this code is that unlike the 4 channel version (which has been keeping my vivariums at a stable temperature for the past 4 years) is that it jumps out to the sensor error routine to often for my liking. Other than that it behaves just like the 4ch version and maintains a stable temperature around the set point. Any suggestions as to reduce the frequency that it detects a miss-read would be welcome.
OK now on to the second part.
I've used this code below to read the DTH11 sensor and display the results on an LCD
Code:
ASM
__CONFIG _CONFIG1H, _OSC_HS_1H
__CONFIG _CONFIG2L, _PWRT_ON_2L
__CONFIG _CONFIG2H, _WDT_ON_2H & _WDTPS_512_2H
__CONFIG _CONFIG3H, _MCLRE_ON_3H & _LPT1OSC_OFF_3H & _PBADEN_OFF_3H
__CONFIG _CONFIG4L, _LVP_OFF_4L & _XINST_OFF_4L
ENDASM
'*******************************************************************************
' LCD (20 x 4) set up
'*******************************************************************************
DEFINE LCD_DREG PORTB ' LCD Data port
DEFINE LCD_DBIT 0 ' starting Data bit (0 or 4)
DEFINE LCD_EREG PORTB ' LCD Enable port
DEFINE LCD_EBIT 5 ' Enable bit (on EasyPIC 5 LCD)
DEFINE LCD_RSREG PORTB ' LCD Register Select port
DEFINE LCD_RSBIT 4 ' Register Select bit (on EasyPIC 5 LCD)
DEFINE LCD_BITS 4 ' LCD bus size (4 or 8 bits)
DEFINE LCD_LINES 4 ' number of lines on LCD
DEFINE LCD_COMMANDUS 2000 ' Command delay time in us
DEFINE LCD_DATAUS 50 ' Data delay time in us
'*******************************************************************************
' Defines Statements
'*******************************************************************************
DEFINE OSC 20 ' 18F4520 / 18F2520, 20mhz crystal
ADCON1 = $0F
clear
'*******************************************************************************
'Analog and Comparator settings
'*******************************************************************************
ADCON0 = %00000000 'AD converter module disabled
ADCON1 = %00001111 'All Digital
ADCON2 = %00000000
CMCON = 7 'Disable Comparators
'*******************************************************************************
'Port and Register settings (interrupts)
'*******************************************************************************
TRISA = %00010111
TRISB = %00000011
T0CON = %11000111
T1CON = %00000001 ; free-running, 1:1 prescaler
TMR1H = %11111111
TMR1L = %11111011
'*******************************************************************************
LCDOUT $FE,1:FLAGS=0:PAUSE 250:LCDOUT $FE,1:PAUSE 250 ' Initialize LCD
'*******************************************************************************
dht var byte[32]
humidite var byte
haut var byte
bas var byte
temp var byte
x var byte
dht11 var portA.5
'*******************************************************************************
start:
TRISA.5 = 0 '
high dht11
pause 2000 ' wait 2 sec
low dht11 : pause 18' send 20ms low
high dht11 : pauseus 30 ' send 40us hi
TRISA.5 = 0
PulsIn PORTA.5, 1, haut
if haut < 15 then goto start
for x = 31 to 0 step-1
PulsIn PORTA.5, 1, dht[x] ' 1
next x
For x = 31 to 0 step-1
if dht(x)>=9 and dht(x)<=21 then dht(x)=0 'if pulsewidth between 20 and 40uS then read as '0'
if dht(x)>=29 and dht(x)<=41 then dht(x)=1 'if pulsewidth between 60 and 80uS then read as '1'
next x
humidite=dht[31]*128+dht[30]*64+dht[29]*32+dht[28]*16+dht[27]*8+dht[26]*4+dht[25]*2+dht[24]*1
temp=dht[15]*128+ dht[14]*64+dht[13]*32+dht[12]*16+dht[11]*8+dht[10]*4+dht[9]*2+dht[8]*1
lcdout $FE,1
lcdout $FE,$C0,"Humidite = ",#humidite,"% "
lcdout $FE,$80,"Temperature = ",#temp,$DF,"C"
goto start
The part I'm stumped with is how to use the data from the DTH11 to replace that of the 18B20. If I read the data sheet for the DHT11 once triggered to send data, it sends a 40 bit serial data which includes 8 bit temperature and 8 bit humidity (presumably bits 8-15 for temp and bits 24 to 31 for humidity by the code high-lighted). The data sheet for the 18B20 states that you can set the resolution for temp to digital conversion between 9 and 12 bits, but I'm sure it sends the actual temperature value as 2 x 8 bit bytes ??
Constructive comments welcome.
Bookmarks