Quantcast
Channel: MEL PICBASIC Forum
Viewing all articles
Browse latest Browse all 4793

PID thermostat Issue

$
0
0
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.

Viewing all articles
Browse latest Browse all 4793