The Bud Toaster - (currently: Model 14, version 3)

Hippie Dickie

The Herbal Cube
Manufacturer
i guess i sound proud, but i really am just thoroughly enjoying this project. i've found out a lot of interesting (to me at least) engineering stuff and, working alone all day, i'd like to share with someones. you know, for what it's worth.

i think the world could use another great vaporizer.
 

Qbit

cannabanana
Hippie Dickie said:
i guess i sound proud, but i really am just thoroughly enjoying this project. i've found out a lot of interesting (to me at least) engineering stuff and, working alone all day, i'd like to share with someones. you know, for what it's worth.

i think the world could use another great vaporizer.
Hehe, of course - I was just having a joke. ;) Just take care you don't vaporize Alderaan.
 
Qbit,

Bubar

Well-Known Member
Did you take off the pictures? I was trying to look at your circuit diagram and it appears to no longer be there.
 
Bubar,

Hippie Dickie

The Herbal Cube
Manufacturer
Sorry about that. ImageShack got hacked and so i removed the images so the hack message wouldn't appear. Here is the circuit diagram again:


PLEASE REFER TO POST #1 FOR MOST UP-TO-DATE SCHEMATIC



i undeleted all the images i have stored (about 36) on ImageShack. So they are all available there.

Lost power for multi-hours yesterday which kept me off the internet all night.

i forgot to include the 0.1uf capacitor on the power supply lead to the MAX6675, but it doesn't seem to matter. i'll probably add it to the pcb when i remember to do it and i'm ordering parts.

i think i finally see how to complete the enclosure in a way that allows swappable batteries. the current operating prototype has soldered in batteries, and that's not as convenient in daily operation as i had imagined it would be. so i'm (working on) implementing that today.
 
Hippie Dickie,

Hippie Dickie

The Herbal Cube
Manufacturer
i think i've found a safe, reliable way to place the thermocouple against the oven tube to get a consistent reading.

The thermocouple has 0.010" bare wire leads. i slide some 22 ga teflon over the leads as insulation. but the tip itself is still a bare wire, and boy, based on personal experience, that wire can conduct a bodacious amount of current if the tip shorts against the coil.

the tip is sandwiched between two pieces of mica, and a metal clip wraps around the mica like a strap.

Here is the side view:

picture.php


Here is a view through the oven tube directly at the thermocouple probe tip:

picture.php


P.S. gosh! ImageShack should be called ImageSucks, imho.
 

Bubar

Well-Known Member
For insulating the thermocouple you might also try mineral oil? IDK if it will stand the temps, but it is conductive thermally, but not electrically.

How do you get such a nice clean cut on your glassware?

Also, do you find that resistors on your max6675 lines help? I don't use any and it still works fine.
 
Bubar,

Hippie Dickie

The Herbal Cube
Manufacturer
i think the mineral oil would start to smoke at vape temps -- the coil/glass gets above 450F. i find physical contact to be satisfactory. i just want repeatability of measurement.

i made a jig to hold the 6" test tube horizontal against a glass cutting head. i'll take a photo next time i think about it.

Procedure: i heat the area to be scored with a BIC, rotate about 10 to 20 times against the cutting head, BIC the score for about 30 seconds, wipe the score with a damp cloth and wrap the score, and snap the glass in the cloth. Then polish the edge as necessary. then BIC the edge to try to anneal the edge and heal any stress fractures. i have some glass working stuff in the lab.

i didn't notice any difference with adding the resisters to the MAX, but maybe limiting current will extend battery / component life.
 
Hippie Dickie,

Hippie Dickie

The Herbal Cube
Manufacturer
i'm in the middle of building the next version of the current prototype - hopefully this unit will work and be a birthday present.

Here are the new PCBs:

picture.php


and the back of the largest one:

picture.php


This is new copperclad board - not from Radio Shack and certified lead free. It has been a bitch to get the pattern imprinted on the copper. (and believe me, after 30+ years, i know about bitches). the first 4 attempts were utter failures. then i tried some Brasso to clean the copper surface and i got at least some toner to stick -- enough so i could fill in the voids by hand with a Sharpie.

The focus this time is on removable batteries that can be charged individually outside the Bud Toaster. Having soldered in batteries, while very reliable, is just not convenient. This totally changes the physical configuration, with the vape itself being reduced in size to 2.5" wide, by 2" deep, by 1.75" high.

Here are two batteries with Deans connectors installed and protected by electrical tape and "Dip-It" (the stuff that makes rubberized handles on hand tools).

picture.php


The batteries will be next to each other, with the connectors stacked to plug into the back of the largest PCB.

This is how they will be placed side-by-side:

picture.php


Soldering iron is hot, it's time to populate the PCBs.
 

Hippie Dickie

The Herbal Cube
Manufacturer
Now the boards are populated ...

picture.php


and the power cell plugs ...

picture.php


Now to enclose it all up. i'm still changing things around (in my mind and in CAD) but i think i've got a viable approach now.
 

Squeeky

Well-Known Member
WOW Hippie you have come a long way. I used to follow your threads on vaporinfo. You are the one that really got me into attempting a DIY. It served me well for roughly a year. THANK YOU! I'm looking at purchasing a Launch Box, but may wait to see what you come up with this time :)

God Speed!
 
Squeeky,

Hippie Dickie

The Herbal Cube
Manufacturer
Thanks for your comments, Squeeky. i'm glad you got some good vapage out of my earlier design.

i think i have finally come up with a workable scheme for enclosing this prototype. i can even recycle some stainless that didn't quite work out for an earlier configuration. i've got a stack of work to do this weekend but i simply MUST finish this version.
 
Hippie Dickie,

Bubar

Well-Known Member
Do you think you can explain more in depth about your temperature control algorithm? I have been trying to use vanilla PID control, but getting the gains tuned has not worked out well at all. My temperature is drifting by almost 10C!
 
Bubar,

Hippie Dickie

The Herbal Cube
Manufacturer
Here's the algorithm that sets the duty cycle each tick*. Heavily commented.

The algorithm works on the error between the temperature of the coil (COILTEMP - measured every 3 ticks) and the desired setpoint temperature (SETPOINT).

i think the algorithm description is in an earlier post. if i get time today i'll check and repost it here.
There are some other subroutines that are called in sequence to calculate the error and the change in the error -- and that set flags to indicate whether the COILTEMP is above or below SETPOINT, and whether the error is increasing or decreasing, and accelerating or decelerating. The previous value for all these variables is also used (xOLD).

* tick = 100 msec. one of the timers is the ticker.

;==================
;Calculate the new DUTYCYCLE value
;vTrip set if COILTEMP > COILTEMPtrip
;SPERROR = |SETPOINT(f) - COILTEMP(W)|
;SPERRORold = previous SPERROR
; vAbove set if COILTEMP > SETPOINT
; vBelow set if COILTEMP < SETPOINT
;SPERRORchg = |SPERROR - SPERRORold|
; vInc set if SPERROR > SPERRORold
; vDec set if SPERROR < SPERRORold
;SPERRORchg2 = previous SPERRORchg
; vAccel set if SPERRORchg > SPERRORchg2
; vDecel set if SPERRORchg < SPERRORchg2
;DUTYCYCLEsp: calculated value to maintain COILTEMP = SETPOINT
;DUTYCYCLEnew: 10-bit value to load into PWM duty cycle register
;------------------
CalcDCnew:
;clear new value flag
bcf vPWM,vDCnew ;set flag if new value calculated

;------------------
;quick exit if holding a DC setting
case_DCcnt:
movf DCcnt ;move to self to test for zero
btfsc ZERO ;not ZERO, count pending
goto case_not_vTrip ;no count pending, do calc
decfsz DCcnt ;count the tick
return ;not done yet, wait another tick

;------------------
;case ~vTrip - COILTEMP below COILTEMPtrip, set to MAX
case_not_vTrip:
btfsc vCOILTEMP,vTrip
goto case_vTrip

;turn on maximum warp speed
;??? bsf vSTATE,vStart
goto calcDC_max

;------------------
case_vTrip:
;if max current then kill current
btfss vPWM,vDCmax
goto case_vStart

btfss vSTATE,vStart ;Start-up mode? ...
goto calcDC_sp ;... No, DCnew = DCsp
goto calcDC_zero ;... Yes, kill current to force peak

;------------------
case_vStart:
;if vStart then ...
btfss vSTATE,vStart
goto case_vAbove

;... test for peak above SETPOINT
btfss vCOILTEMP,vAbove
goto case_vStart_1
btfss vCOILTEMP,vDec
return ;wait for it

;... decrease COILTEMPtrip by SPERROR/2
call AdjCOILTEMPtrip
call eePutCOILTEMPtrip

;... clear vStart
bcf vSTATE,vStart

;... kill current
goto case_vAbove

case_vStart_1:
;... assume vBelow, test for peak
btfss vCOILTEMP,vInc
return ;wait for it

;... increase COILTEMPtrip by SPERROR/2
call AdjCOILTEMPtrip
call eePutCOILTEMPtrip

;... clear vStart
bcf vSTATE,vStart

;... turn on current
goto case_vBelow

;------------------
;case vAbove
case_vAbove:
btfss vCOILTEMP,vAbove
goto case_vBelow

;if now(vInc) then ...
btfss vCOILTEMP,vInc
goto case_vA_1

;decrease DCsp by (SPERROR/8 + 1)
movlw .3
call WeqFcnERRORbyW ;W = (total error)/8 + 1
call SubWfromDUTYCYCLEsp
call UpdateDCspIneePROM

case_vA_1:
;cut back to 50%
btfss vCOILTEMP,vAccel ;Accel? ...
goto calcDC_half ;... No, DCnew = DCsp/2
goto calcDC_zero ;... Yes, kill current

;------------------
;case vBelow (and after vStart)
case_vBelow:
;test for at SETPOINT
btfss vCOILTEMP,vBelow
goto calcDC_sp ;at SETPOINT! set DCnew = DCsp

;case DCmax ...
btfsc vPWM,vDCmax
goto calcDC_sp ;DCnew = DCsp after vTrip

case_vB_1:
;case vInc & vDecel ...
btfss vCOILTEMP,vInc
goto case_vB_2
btfss vCOILTEMP,vDecel
goto case_vB_2

;... wait
call IncDUTYCYCLEsp
goto calcDC_sp ;DCnew = DCsp

case_vB_2:
;case vInc & vAccel ...
btfss vCOILTEMP,vInc
goto case_vB_3
btfss vCOILTEMP,vAccel
goto case_vB_2a

;... increase DCsp
movlw .3
call WeqFcnERRORbyW ;W = (total error)/8 + 1
call AddWtoDUTYCYCLEsp
call UpdateDCspIneePROM

case_vB_2a: ;... kick up current by f(error, change in error)
btfss vCOILTEMPold,vAccel
goto calcDC_2x ;DCnew = DCsp*2
goto calcDC_max ;two vAccel in row
case_vB_3:
;case vDec & vDecel ...
btfss vCOILTEMP,vDec
goto case_vB_4
btfss vCOILTEMP,vDecel
goto case_vB_4

;... wait
goto calcDC_sp

case_vB_4:
;case vDec & vAccel ...
btfss vCOILTEMP,vDec
goto case_vB_5
btfss vCOILTEMP,vAccel
goto case_vB_5

;... decrease DCsp
movlw .3
call WeqFcnERRORbyW ;W = (total error)/8 + 1
call SubWfromDUTYCYCLEsp
call UpdateDCspIneePROM
goto calcDC_sp

case_vB_5:
;case else (missing vflag)... set DCnew = DCsp
goto calcDC_sp

;------------------
calcDC_2x: ;set DUTYCYCLEnew = DUTYCYCLEsp*2
banksel DUTYCYCLEnew
movf DUTYCYCLEsp,W
movwf DUTYCYCLEnew
movf DUTYCYCLEsp+1,W
movwf DUTYCYCLEnew+1
bcf CARRY
rlf DUTYCYCLEnew
rlf DUTYCYCLEnew+1
bcf vPWM,vDCzero
bcf vPWM,vDCmax
bsf vPWM,vDCsp
bsf vPWM,vDCnew
return

calcDC_half: ;set DUTYCYCLEnew = DUTYCYCLEsp/2
banksel DUTYCYCLEnew
movf DUTYCYCLEsp,W
movwf DUTYCYCLEnew
movf DUTYCYCLEsp+1,W
movwf DUTYCYCLEnew+1
bcf CARRY
rrf DUTYCYCLEnew+1
rrf DUTYCYCLEnew
bcf vPWM,vDCzero
bcf vPWM,vDCmax
bsf vPWM,vDCsp
bsf vPWM,vDCnew
return

calcDC_sp: ;set DUTYCYCLEnew = DUTYCYCLEsp
banksel DUTYCYCLEnew
movf DUTYCYCLEsp,W
movwf DUTYCYCLEnew
movf DUTYCYCLEsp+1,W
movwf DUTYCYCLEnew+1
bcf vPWM,vDCzero
bcf vPWM,vDCmax
bsf vPWM,vDCsp
bsf vPWM,vDCnew
return
;------------------
calcDC_max: ;set DUTYCYCLEnew to DUTYCYCLEmax
banksel DUTYCYCLEnew
movlw cDCMAXlo
movwf DUTYCYCLEnew
movlw cDCMAXhi
movwf DUTYCYCLEnew+1
bcf vPWM,vDCzero
bsf vPWM,vDCmax
bcf vPWM,vDCsp
bsf vPWM,vDCnew
return
;------------------
calcDC_zero: ;set DUTYCYCLEnew to zero
banksel DUTYCYCLEnew
clrf DUTYCYCLEnew
clrf DUTYCYCLEnew+1
bsf vPWM,vDCzero
bcf vPWM,vDCmax
bcf vPWM,vDCsp
bsf vPWM,vDCnew
return

;==================
 
Hippie Dickie,

Hippie Dickie

The Herbal Cube
Manufacturer
i see stability and i see temp swings of 2C to 5C. But there is much room for improvement in this algorithm. i'm still fudging the math with an ad hoc adjustment. i think i should be measuring the area under the error curve (if you get what i'm driving at) and use that area value to anticipate the change in temperature caused by the change in duty cycle value.
 
Hippie Dickie,

Hippie Dickie

The Herbal Cube
Manufacturer
This will help understand some of the variables in the algorithm:

;*********************************
;***** data registers: $20 .. $7F
;*********************************
ORG 0x0020

;Coil Temperature readings
;store lo-byte, followed by hi-byte
COILTEMP EQU 0x20 ;.. 0x2F
constant vNoSensor=2 ;bit set if sensor missing
constant cCOILTEMPstart=0x20
constant cCOILTEMPend=0x2F

;*********************************
;0x70..0x7F (0xF0..0xFF) mapped in both banks
;*********************************
ORG 0x0070
vSTATE EQU 0x70 ;vaporizer state
constant vTick=0 ;set on Heartbeat interrupt
constant vWait=1
constant vRun=2
constant vLEDact=3 ;LED is ACTIVE (1)
constant vLEDon=4 ;LED is ON (set) / OFF (clear)
constant vPause=5 ;wait for BTN idle
constant vStart=6 ;starting from below TRIP
constant vError=7

vSENSOR EQU 0x71 ;sensor state
constant vBtn=0 ;Button (AtoD) reading ready
constant vBtn1=1 ;TOP
constant vBtn2=2 ;MIDDLE
constant vBtn3=3 ;BOTTOM
constant vBtnON=4 ;Button press active
constant vTypeK=7 ;K-Thermocouple reading ready

vCOILTEMP EQU 0x72 ;coil temperature state
constant vAbove=0 ;COILTEMP is above SETPOINT
constant vBelow=1 ;COILTEMP is below SETPOINT
constant vInc=2 ;error is increasing
constant vDec=3 ;error is decreasing
constant vAccel=4 ;change in error is increasing
constant vDecel=5 ;change in error is decreasing
constant vTrip=6 ;COILTEMP is above COILTEMPtrip

vPWM EQU 0x73 ;pulse width modulator state
constant vPWMon=0 ;PWM is active
constant vDCmax=1 ;Duty Cycle at max value
constant vDCzero=2 ;Duty Cycle at zero
constant vDCsp=3 ;Duty Cycle at setpoint value
constant vDCnew=7 ;new Duty Cycle value ready

vCOILTEMPold EQU 0x74 ;previous COILTEMP status
vSENSORold EQU 0x75 ;previous tick sensor reading
BTNVALUE EQU 0x76 ;lo value from AtoD reading
;BTNVALUE+1 EQU 0x77 ;hi value from AtoD reading
constant cBTNVALUEadr=0x76
COILTEMPptr EQU 0x78 ;pointer to most recent coil temperature value
eeCOILTEMPptr EQU 0x79 ;pointer to last saved MAX6675 reading
eeDUTYCYCLEptr EQU 0x7A ;buffer of DUTYCYCLEsp values
DCcnt EQU 0x7B ;ticks to hold dutycycle value
LOOPcnt EQU 0x7C ;loop counter (ReadCOILTEMP)
BTN3delay EQU 0x7D ;20 ticks (2 seconds)
BTNcount EQU 0x7D ;count ticks same button held
FLASHdelay EQU 0x7E ;ticks until LED flashes start
COILTEMPdelay EQU 0x7F ;ticks until next temp reading (0..3)

;*********************************
;***** data registers: $A0 .. $BF
;*********************************
ORG 0x00A0
SETPOINT EQU 0xA0 ;0xA0..0xA1 temperature set point
;SETPOINT+1 EQU 0xA1
constant cSETPOINTadr=0xA0
SPERROR EQU 0xA2 ;setpoint error lo
;SPERROR+1 EQU 0xA3 ;setpoint error hi
constant cSPERRORadr=0xA2
SPERRORold EQU 0xA4 ;previous setpoint error
;SPERRORold+1 EQU 0xA5
SPERRORchg EQU 0xA6 ;setpoint error old - setpoint error
;SPERRORchg+1 EQU 0xA7
SPERRORchg2 EQU 0xA8 ;previous setpoint error change
;SPERRORchg2+1 EQU 0xA9

;COILTEMP TRIP - maximum temperature for duty cycle = DCMAX
COILTEMPtrip EQU 0xAA
;COILTEMPtrip+1 EQU 0xAB
constant cCOILTEMPtrip=0xAA

;free EQU 0xAC
;free EQU 0xAD
;free EQU 0xAE
;free EQU 0xAF

ORG 0x00B0
DUTYCYCLEsp EQU 0xB0
;DUTYCYCLEsp+1 EQU 0xB1
constant cDUTYCYCLEsp=0xB0
DUTYCYCLEnew EQU 0xB2
;DUTYCYCLEnew+1 EQU 0xB3
constant cDUTYCYCLEnew=0xB2
FLASHdelay0 EQU 0xB4
FLASHcount0 EQU 0xB5
RUNTIME EQU 0xB6 ;ticks until shutdown
;RUNTIME+1 EQU 0xB7
LEDcnt EQU 0xB8 ;ticks remaining for this LED state
FLASHcnt EQU 0xB9 ;number of LED on/off sequences
DUTYCYCLEcnt EQU 0xBA ;save DCsp in eePROM if stable this many ticks
WORKVAR EQU 0xBB ;working register (lo)
;WORKVAR+1 EQU 0xBC ;working register (hi)
W_temp EQU 0xBD ;variable used for context saving
STATUS_temp EQU 0xBE ;variable used for context saving
vSHUTDOWN EQU 0xBF ;vaporizer error
; constant vBattery=0
; constant vTooHot=1
; constant vNoSensor=2
; constant vMaxRunTime=3
 
Hippie Dickie,

Hippie Dickie

The Herbal Cube
Manufacturer
Here is the top of the program code and the interrupt handler. This may be kind of hard to understand because i use macros extensively to make the intent of the algorithm more readable.

;***** RESET *****
ORG 0x0000 ;reset vector location
goto main ;go to beginning of program
;*********************

;***** INTERRUPT *****
ORG 0x0004 ;interrupt vector location
;*********************

Save_W_STATUS

If_Heartbeat_Interrupt THEN ;else, dismiss the interrupt

Stop_Heartbeat
Clear_Heartbeat_Interrupt_Flag

Read_Button ;check for button press

If_vRun THEN
Reset_Watchdog ;restart 250 msec WDT
Read_Coil_Temperature ;every 3rd tick
;tests for TOO HOT and MISSING SENSOR

intr_done:
Start_Heartbeat
Set_vSTATE vTick ;set the heartbeat flag

intr_exit:
Restore_W_STATUS
retfie

;******************
;end of interrupt
;******************
 
Hippie Dickie,

skippymcware

Well-Known Member
Hippie,

What mosfet are you using? I am slowly making sense of your circuit, but don't see that component labelled anywhere. Also, is it possible that you have the pins labelled wrong for the L78L33 on your circuit diagram? Lastly, what are those resistors between the max6675 and the 12f683? Are they just to limit the current?

[EDIT: Question answered via email. Thank you.]

Thanks,
-skippy
 
skippymcware,

Hippie Dickie

The Herbal Cube
Manufacturer
Thank-you for noticing the error on the voltage regulator pins. i can't count how many times i've looked at the data sheets and diagram and never noticed the error. i think it was a copy error from the 5v regulator i started with.

Here is the parts list:

Parts List

Item Manufacturer ID
12F683 579-PIC12F683-E/SN
LE45AB 497-1530-1-ND
MAX6675 700-MAX6675ISA
MOSFET 512-FDB8832
15 Ohm Resistor 660-RK73H1JTTD15R0F
220 Ohm Resistor 660-RK73H1JTTD2200F
1K Ohm Resistor 660-RK73H1JTTD1001F
2K Ohm Resistor 660-RK73H1JTTD2001F
3.9K Ohm Resistor 660-RK73H1JTTD3901F
10uf Capacitor 399-4925-1-ND
0.1uf Capacitor 80-C0603C104J3R
Red LED APTD3216SRCPRV
Green LED APTD3216CGCK
Blue LED APTD3216PBC/A
SPST Switch 101-0264-EV
K-type Thermocouple EW-08419-02
Digital Thermometer custom China part
Battery LR44
Nichrome-80 16ga
PTFE 28awg .013"
PCB
A123Systems ANR26650M1
Charger (6A) CH-LFP32V6A
Deans Male Plug L5HGL912
Deans Female Socket L5KX3806
Deans 16ga wire LXWUR7
Wire mesh sleeve
1/8" dia x 2" extruded acrylic rod
Dip-It
Tweezers
Toothpicks
Wood Disc
Wood Block
Case
Tube 15mm x 38mm custom India part
Vial 12mm x 38mm custom India part
Tube 12mm x 100mm custom India part
solder
flux

(Updated 11/4/10 -- Sorry for the formatting ... FC is throwing away tabs.)

The MOSFET (Q2 at bottom of diagram, connecting to pin 5 of the 12F683) is Fairchild. i just sized it for a decent input voltage range (0 to 30 vdc) and robust current handling (40A) -- i'm figuring 18 volt deWalt power pack at the high end, with 1/2 ohm of resistance, so i need at least 36A current handling capacity.

All the resistors are current limiters. The 12F683 input/output pins can't sink or source more than 90ma total, so the lines to the MAX and the MOSFET are limited. The LEDs need current limit or they will burn out. Disclaimer: i'm not a hardware designer, so this is all a guess from looking at other circuits - i'm an EE by degree only. Fortunately it's working well enough that i stopped studying the topic.

re: LEDs - these are 3.3v LEDs getting 20 ma of current.

re: MAX - it only wants 1.5ma max so adding a second one shouldn't be a problem.

Hope that helps.
 
Hippie Dickie,

skippymcware

Well-Known Member
B1, B2, B3 tactile switch RK73H1JTTD2001F

Not that I desperately need the part number of your tactile switches, but I figured I should point out that one of these things is just like the other... and shouldn't be.

Thanks again for all your help,
-skippy
 
skippymcware,

Hippie Dickie

The Herbal Cube
Manufacturer
Let me try to explain the dutycycle algorithm in English.

First i'll provide some context for the algorithm:

The PIC handles temperature control via its built-in PWM. The PWM (pulse width modulator) functions as a current control, switching the current on and off. There is a "frequency" and a "dutycycle" that control the PWM. Frequency is somewhat arbitrary -- in this case i set it to 1000 cycles per second. The "dutycycle" is a 10-bit value that gets loaded into the PWM register, and it functions like a dimmer switch. It specifies how much of each frequency cycle is supplying current to the heater coil : 0 is no current, 1023 is full current for the entire cycle, and a value in between is the fraction of the cycle that the current is ON, in 1/10 % steps. Pretty cool.

i have the PWM configured to run at maximum frequency (with respect to the 4 MHz PIC system clock). My goal was to make sure the audio sound from the switching of the PWM is not audible. Evidently i have failed in this goal -- although i can't hear it (except very rarely), other people say it is very noticable (the sound may prevent teenagers from using this vape! - a built-in underage restricter!), and it certainly annoys the cats.

Here is the basic scenario for a cold start-up sequence:
Load the bud into the vial
Insert vial into oven
Apply battery power to the vape (BLUE led comes on)

(GREEN led flashes 3 times every 5 seconds to remind you the vape is powered)

Hold BUTTON3 for 2 seconds: GREEN led goes to ON until button is released.

Release BUTTON3 - PIC initializes and enters the main loop.

The 7 minute count-down timer starts running.

Every 100 msec (a "tick"), the clock interrupts the main loop to:
--- read the COILTEMP (only every third tick),
--- test for a BUTTON press, and
--- reset the Watch Dog Timer.

(The interrupt code is listed in post #91.)

(It always grates on me that Neo is called a "program writer" by Mr. Rineheart, his manager (as if!). Coder, hacker, programmer, software engineer, even "weenie", would all be more "natural" to my ear. Oh well.)

If for whatever reason the WDT is not reset within 1/4 second, the vape shuts off.

In the main loop, we're waiting for the clock tick.
When the clock interrupt returns to the main loop,

1 - check if maximum run time (7 minutes) has elapsed,
and if so, shut off (damn distracted stoners!)

2 - check for a button press and takes the appropriate action
- Button 1, increase SETPOINT by 10F;
- Button 3, decrease SETPOINT by 10F;
- Button 2, use current COILTEMP as the new SETPOINT.

3 - update the duty cycle value

4 - turn ON the GREEN led if COILTEMP is within 0.5F of SETPOINT

end loop

Anyway, here is a chart i used to think about the algorithm that calculates the next value to load into the dutycycle register:
picture.php


i had a conceptual breakthrough when i changed the focus of the algorithm from trying to maintain COILTEMP at a SETPOINT temperature, to making the error between COILTEMP and SETPOINT be zero. It's the same thing of course (right?), but it shifted my thinking enough to break through writers block and get the algorithm finished in Feb 2009.
 

Hippie Dickie

The Herbal Cube
Manufacturer
Now, referring to that chart,
-- the x axis is time, with time increasing to the right, and
-- the y axis is temperature, with higher temperature going up

i consider three temperature regions:

(1) from cold start to a "trip" temperature
(2) from "trip" to "setpoint"
(3) above "setpoint"

In region (1), the dutycycle is at maximum (DCmax).

There are two cases for region (2):

(2a) start up
When COILTEMP exceeds COILTEMPtrip, the dutycycle is set to zero (DCzero).
Then it stays at DCzero and waits for the temperature to peak (COILTEMPpeak).
Then it clears the "Start up" flag

(2b) running
(see below)

(3) above "setpoint"
This is the easy case: set dutycycle to DCzero!

The algorithm is biased to not let the temperature run away. These batteries are such outrageous current sources that the heater can hit 1000F within 2 minutes at full current.

So, region (2b) is the complicated case. i identify 4 cases of temperature activity in this region:

("error" here refers to the difference between COILTEMP and SETPOINT)

(2b1) vInc & vDecel
The error is increasing, but the increase in error is decelerating

(2b2) vInc & vAccel
The error is increasing, and the increase in error is accelerating

(2b3) vDec & vAccel
The error is decreasing, and the decrease in error is accelerating (i.e. beware of overshoot)

(2b4) vDec & vDecel
The error is decreasing, but the decrease in error is decelerating.

So the algorithm looks at the error and the change in error, both for this tick and the previous tick. And it adjusts the dutycycle value based on the size of the error

The goal is to get a dutycycle value that maintains the SETPOINT by balancing out the loss of heat from air flow and trichome vapor extraction, and the build-up of heat from an enclosed space and residual heat storage of the physical components.

Other points:
The temperature response of the coil is asymetric:
-- heats up at 10F per second (DCmax), and
-- cools at 2F (DCzero).

The algorithm adjusts the COILTEMPtrip by half the error between SETPOINT and peak COILTEMP during the initial startup action.

The code in post #88 is my latest version of this algorithm. Still somewhat ad hoc in terms of setting the dutycycle value. i'm guessing i need to actually calculate the area under the error curve to nail the error to zero. i see incredible temperature stability (+/- 1 F) as it is, so i'm utterly convinced i can achieve absolute temperature control.
 
Hippie Dickie,

skippymcware

Well-Known Member
Hmm. That will be very useful once I get down to writing code. That is still a ways away, though.
 
skippymcware,

Hippie Dickie

The Herbal Cube
Manufacturer
Thanks for catching the error in the tactile switch part number - post has been edited.
 
Hippie Dickie,

Hippie Dickie

The Herbal Cube
Manufacturer
Here is the code for the main loop - again, i like to use macros for readability, but that hides a lot of the action:

;***********************
;While (TRUE) DO
;***********************
;loop runs once per tick
vape_run:

;wait for next heartbeat tick
Wait_vSTATE vTick
Clear_vSTATE vTick

;check run time and exit
If_Maximum_Run_Time Error_Shutdown

run_BTN:
;check for button press
If_BUTTON_Adjust_SETPOINT

run_DC:
;set DutyCycle as f(SETPOINT, COILTEMP)
Update_Duty_Cycle

run_LED:
;activate LED if COILTEMP at SETPOINT
Signal_SETPOINT

;processing done - wait for next tick
goto vape_run

;*********
; WEND
;*********
 
Hippie Dickie,

Hippie Dickie

The Herbal Cube
Manufacturer
Almost have this next version put together:

picture.php


picture.php


lousy fit-n-trim, i know, but at least the pieces fit inside the enclosure.

my major problem with "fit" is bending the stainless steel (vertical walls) accurately, so when i cut the cherry for the top and the bottom pieces to be 2" by 2.5", it is a cleaner fit.

i want the top and bottom pieces to be just proud of the leather that wraps the stainless.

and, gosh, making an enclosure is a major pain in the ass. my round version was much, much, much easier to fabricate ... but i can't figure out (yet) how to get the pcb and buttons and leds and digital thermometer to fit in that shape.
 
Top Bottom