;
This example application is intended
to illustrate some of the
;
features of Venom-SC.
;
;
The program controls an oven's
temperature using a thermistor
;
to sense temperature and a digital
output to turn a heater
;
on and off.
;
There is a keypad and LCD
for a user interface.
;
;
The oven temperature must not
change rapidly, so there
;
is a ramp-up and ramp-down
feature.
;
;
This code will run on a
VM-1 and Application Board 5802
;
- though we don't supply the
thermistor.
;
;
Features illustrated:
;
* MAKE to create objects
;
* START to create a new
task (multi-tasking)
;
* PRINT for LCD control
;
* #define for
macros/constants.
;**************
PROGRAM INIT AND MAIN PROCEDURES
************
;State
machine states
#define
COLD 0
#define
WARMING 1
#define
AT_TEMP 2
#define
COOLING 3
;Timing
constants: all times are in
milliseconds
#define
KEY_LOOP_TIME 60
#define
BUZZ_TIME 20
#define
CONTROL_LOOP_TIME 1000
#define
BANNER_TIME 1000
;
The initialisation procedure, called by
startup
;
TO
init
target_temp := 50
;Oven's final target
temperature
actual_temp
:= 0 ;Oven's
actual temperature
ramp_temp
:= 0 ;Oven's
slow-rising target temperature
on_flag
:= FALSE ;Signal
to the oven state-machine
oven_state
:= COLD ;State of the oven
state-machine
MAKE
lcd alphalcd(20,2,0)
;The User I/F output
device [20x2 on the VM-1 Expansion
Bus]
MAKE
kpd keypad(0,496)
;The User I/F input
device [4x4 on the 2nd
I2CBus]
key_buff
:= kpd.InputBuffer(2,15)
MAKE
heater Digital(128)
;The heater control
[Digital on the 1st I2CBus]
MAKE
buzzer Digital(129)
;Audible warning output.
MAKE
thermistor_in Analogue (47)
;The temperature input
[Analogue on the VM-1]
END
;
The main program entry, called by
startup after init
;
TO
main
START
control_task ;The task
controlling the oven
user_interface_loop
;The task doing the
User I/F (not started as a
task - as we use this
one!)
END
;***************
USER I/F TASK PROCEDURES
***************
;This
is the menu structure for the
application...
;
TO
user_interface_loop
banner
FOREVER
;a simple menu structure
that goes round a loop of
menus.
[
main_menu
set_target_menu
;Put
other menus here...
]
END
;Print
the opening banner on the LCD
at start-up.
;
TO
banner
PRINT
TO lcd, cls,"
Oven Controller",CR
PRINT
TO lcd, "
Verson 1.00"
;12345678901234567890
- LCD character positions
WAIT
BANNER_TIME ;Hold the banner
on for a while.
END
;The
main menu of the Oven Controller.
Displays information
;
and provides access to the other
menu(s)
;
#define
DN_KEY 0
#define
UP_KEY 1
#define
EXIT_KEY 3
TO
main_menu
LOCAL
on_off_string , the_key
;Set
up the Menu text
PRINT
TO lcd, cls,cr,
"Start Stop
Set"
;
0 1 2 3 : The 'soft
keys'
EVERY
KEY_LOOP_TIME
[
kpd.Update
the_key
:= key_buff.Key
IF
the_key >= 0 ;Any
key pressed?
[
SELECT
CASE the_key ;Which
one was it?
CASE
DN_KEY
[
on_flag
:= TRUE ;Tell
the oven control task to go
ON
]
CASE
UP_KEY
[
on_flag
:= FALSE ;Tell
the oven control task to go
OFF
]
CASE
EXIT_KEY
[
BREAK
;Drop out of the
main menu
]
CASE
ELSE
[
buzz_wrong_key
;[Other keys aren't
used]
]
]
IF
((INDEX0 AND
$F) = 0)
OR (the_key >= 0)
;Don't need to update
LCD so often as keypad
[
; - only every 16
times round the loop =
480mS.
IF
on_flag
on_off_string
:= "On "
ELSE
on_off_string
:= "Off"
;Update
the display
PRINT
TO lcd,
HOME,on_off_string,actual_temp:4,"C[",ramp_temp:3,"C][",target_temp:3,"C]"
]
]
END
;The
menu to set the target
temperature.
;
#define
MIN_TEMP 0
#define
MAX_TEMP 100
TO
set_target_menu
LOCAL
old_value := NOT target_temp
;This is used to
know when to update the
display.
;Set
up the Menu text
PRINT
TO lcd, cls,"Set
Temp:",CR
PRINT
TO lcd, "
< C > Done"
;
0 1 2 3 - The 'soft
keys'
EVERY
KEY_LOOP_TIME ;Timed loop
[
kpd
. Update ;Scan
the Keypad
the_key
:= key_buff.Key
IF
the_key >= 0 ;Any
key pressed?
[
SELECT
CASE the_key ;Select
an action for each key
CASE
DN_KEY
[
IF
target_temp > MIN_TEMP
target_temp := target_temp - 1
]
CASE
UP_KEY
[
IF
target_temp < MAX_TEMP
target_temp := target_temp + 1
]
CASE
EXIT_KEY
[
BREAK
;Drop out of this
menu
]
CASE
ELSE
[
buzz_wrong_key
]
]
IF
old_value <> target_temp ;Only
print if value changed.
[
old_value
:= target_temp
PRINT
TO lcd , GOTOXY(3,1),
target_temp:3
]
]
END
;Buzzer
operated when an unused key is
used.
TO
buzz_wrong_key
buzzer.On
WAIT
BUZZ_TIME
buzzer.Off
END
;*****************
CONTROL TASK PROCEDURES ***************
;This
procedure is started as a task
to control the oven
;using
a state machine and a feedback
loop.
;
TO
control_task
EVERY
CONTROL_LOOP_TIME ;Timed
loop
[
state_machine
feedback_control
]
END
;Operate
the heater output depending on the
temperature.
; -
use hysteresis to make sure it's
not turned on or off
;
too often.
;
TO
feedback_control
actual_temp
:= read_temperature
IF
actual_temp < ramp_temp - 1
heater
. On
ELSE
if actual_temp > ramp_temp +
1
heater
. Off
END
;The
oven state machine. This is one
way of doing
;
the ramp.
;The
state machine has 4 states that
are moved between
;
depending on the signals on_flag
(from the user)
;
and ramp_temp vs target_temp.
;
TO
state_machine
SELECT
CASE oven_state
CASE
COLD
[
if
on_flag
oven_state
:= WARMING
]
CASE
WARMING
[
IF
on_flag = 0
oven_state
:= COOLING
ELSE
IF ramp_temp >=
target_temp
oven_state
:= AT_TEMP
ELSE
ramp(1)
]
CASE
AT_TEMP
[
if
on_flag = 0
oven_state
:= COOLING
ELSE
IF ramp_temp <
target_temp
oven_state
:= WARMING
ELSE
IF ramp_temp >
target_temp
oven_state
:= COOLING
]
CASE
COOLING
[
IF
on_flag
oven_state
:= WARMING
ELSE
IF ramp_temp <=
0
oven_state
:= COLD
ELSE
ramp(-1)
]
END
;Ramp
the temperature slowly.
;
TO
ramp (increment)
IF
increment < 0
[
IF ramp_temp > 0
ramp_temp := ramp_temp + increment
]
ELSE
[
IF ramp_temp <
target_temp
ramp_temp := ramp_temp + increment
]
END
;
Read the thermometer input to
generate a temperature.
;
TO
read_temperature
RETURN
temp(thermistor_in . Value)
AS INT
END
;Linearise
a precision thermistor reading
;The
circuit is a simple divider, with
a 10K
;resistor
to 5V. The divided voltage is
with a 10-bit ADC.
;LA
& LB are Constants defining
the Thermistor Curve
;
- calculated from the Thermistor
datasheet to
;
give good matching from 0 -
25C. OTher values
;could
be used for different ranges.
#define
LA_VALUE (-3.7182837)
#define
B_VALUE 3854.6692
#define
BIAS_RES 10000
TO
temp(reading)
LOCAL
resistance
IF
reading = 0 ;avoid
Divide by Zero.
reading
:= 1
;Calculate
the resistance of the
thermistor.
resistance
:= bias_res / (1024 / reading -
1.0)
;Calculate
the temperature in degrees C;
273.15K is 0C.
RETURN
b_value / (LOG resistance -
la_value) - 273.15
END