Proportional Control


Senior Member
This snippet comes from code I did for a Fuel Vaporizer. The Picaxe controls an "EGR Valve" to keep the temperature at about 450F inside a heat exchanger. I modified this code for general use by removing the specific temperature sensor stuff and replaced it with a Pot to simulate a temperature sensor.

I would not recommend using a DS18B20 for accurate proportional temperature control because the sampling rate is too slow. We used a K type thermocouple along with an Adafruit Max31855 Thermocouple Amplifier in our project. The sample rate was 10 samples per second in the final code, but I think that 5 samples per second should work fine for most applications.

'Proportional Control algorithm / code by for HOT Gas Valve in Fuel Vaporizer System

'With modification of the constants , this can also be used for general proportional control .

'Non-Engineering terms were used for variables to 'hopefully make the code and
'process more understandable 'for non-engineers. 

'Attach a 10K Pot to pin c.1 to simulate a temperature sensor

#Picaxe 20M2
[COLOR="#008000"]'#terminal 4800[/COLOR]

symbol gain      =  10[COLOR="#008000"] ' Determines Proportional band
                       ' With a gain of 10 the P Band will be from 400F to 500F
                       ' Increase gain to narrow the band [/COLOR]
symbol bias      = 500[COLOR="#008000"] ' Power Level at nominal operating condition (Assuming 50 percent power)[/COLOR]
symbol set_point = 450 [COLOR="#008000"]' Set Point value [/COLOR]
symbol adc_val       = w0
symbol process_value = w1[COLOR="#008000"] ' Process Value (temperature)[/COLOR]
symbol error_value   = w2 [COLOR="#008000"]' difference between SV & PV[/COLOR]
symbol power_level   = w3[COLOR="#008000"] ' Range is 0 to 1000 for 0 to 100 percent[/COLOR]
symbol temp_var      = w4[COLOR="#008000"] ' General Purpose Variable for intermediate math[/COLOR]


pwmout pwmdiv16, b.1, 249, 0 

      readadc10 c.1,ADC_Val 
      process_value = ADC_Val / 4 + 300  [COLOR="#008000"]'Scale ADC to Temperature Range [/COLOR]

     if process_value <= set_point then 
         error_value = set_point - process_value
         power_level = gain * error_value + bias Max 1000
         pwmduty b.1,power_level 
    elseif process_value >  set_point then
         error_value = process_value - set_point
         temp_var = gain * error_value max bias 
         power_level = bias - temp_var 
         pwmduty b.1,power_level 

Last edited:


New Member
Could you post the Max31855 interface code.
How do you handle the 32 bit word from the Max31855?



Senior Member

I've pushed that link through Google translate and fixed the Syntax errors in the code, mainly spaces in $ A1 numbers and BREAK for (presumably) PAUSE, and pasted below. Can't guarantee that the code will give the correct results though. ;) The Adafruit link is: (in English).

I would expect reduction or 32 bits to 16 bit data should be quite easy (the resolution of the sensor won't be any better than that), but I have submitted various "32-bit" calculation routines in the "Code Snippets" section of the forum, should they be needed.


Having to make a programmer-regulator for a ceramic furnace, I was interested in an amplifier with cold junction correction intended for type K probes (-200 to 1250 ° C)
It's the MAX31855 Doc here

It can be found in an easier to use form
It is thus interfaced under voltage of 5V.
The connection with the µC is made by SPI serial link.
The data is contained in a 32-bit set.

In order to use it with Picaxes not equipped with the shiftin function, the bit-banging solution is used here.
Given the app, although detected, negative temperatures (in addition to 2) are not displayed, nor are the decimals.

The reading is done in the form of twice 16bits in b1 b0 and b3 b2 thus making it possible to recover the sign bits of the probe and ambient temperature, as well as the fault bits:
open probe connection
short circuit probe with Gnd
short circuit probe with Vcc (not used here)

Attached is the program part concerning the temperature reading:

'' Thermocouple amplifier K Max31855K -
'V01-Use for positive T
'' Probe fault detection
'PieM 20140511
'' ELCD204BLB Series Display

#picaxe 14M2

'*********** symbols ***************************

symbol clk = C.0 'clock
symbol dat = pinC.1 'data
symbol Cs = C.2 'chip select
symbol Aff = C.4 'Out serial display

symbol countx = b10 'counter
symbol V_fr = w0 'var temperature cold junction
symbol V_ch = w1 'var temperature thermocouple
symbol T_fr = w2 'temperature cold junction
symbol T_ch = w3 'temperature thermocouple

'******** Home ********************************
gosub FAC 'display erase

serout Aff, T4800, ($A1,6,0, $A2, "HELLO", 0)
serout Aff, T4800, ($A1,2,3, $A2, "Soft ThermoK-V01", 0)
pause 3000
gosub FAC
Low Cs
V_ch = 0 'BITS transfer 31 to 16 MSB first
for countx = 0 to 15;
V_ch = V_ch * 2 + dat 'shift << 1 and write bit data
pulsout clk, 1 'pulse clock
next countx

V_fr = 0
for countx = 0 to 15 'Transfer BITS 15 to 0 MSB First [was compt]
V_fr = V_fr * 2 + dat;
pulsout clk, 1
next countx
high Cs

T_fr = V_fr * 2/512 'temp fr in deg C (shifts: << 1 and >> 9)
T_ch = V_ch * 2/32 'temp ch in deg C (shifts: << 1 and >> 5)

'negative temperature detection: no display.
if bit15 = 1 or bit31 = 1then
serout Aff, T4800, ($A1,0,0, $A2, "Temp negative!", 0): pause 1000

'' temperature display
serout Aff, T4800, ($A1,0,0, $A2, "Thermosonde:", # T_ch, 223, "C", 0)
serout Aff, T4800, ($A1,0,1, $A2, "T. Ambiant:", # T_fr, 223, "C", 0)

b0 = b0 * 16 '4 left shifts to eliminate the MSBs.
if b0> 0 then 'detection of fault bits on probe
gosub decod_def: endif 'decoding and display

serout Aff, T4800, ($A3, $01)
serout Aff, T4800, ($A3, $0C)
pause 150  ; [was break]
gosub FAC

if bit4 = 1 then
serout Aff, T4800, ($A1,0,0, $A2, "Open circuit!", 0): endif 'open circuit
if bit5 = 1 then
serout Aff, T4800, ($A1,0,3, $A2, "Court Circuit Gnd!", 0): endif 'CC with Gnd

pause 1000
gosub FAC
Cheers, Alan.


Hi Allen,

You beat me to it, I'd found this post and had started to the same but got called onto something else. I will go through it and see how I get on integrating into my project over on the other thread.

Can I ask,

'negative temperature detection: no display. if bit15 = 1 or bit31 = 1then serout Aff, T4800, ($A1,0,0, $A2, "Temp negative!", 0): pause 1000 endif
if bit4 = 1 then serout Aff, T4800, ($A1,0,0, $A2, "Open circuit!", 0): endif 'open circuit if bit5 = 1 then serout Aff, T4800, ($A1,0,3, $A2, "Court Circuit Gnd!", 0): endif 'CC with Gnd
Where do/are the "bits" coming from and how??

Last edited: