Did you know...
|
|
The hysteresis mode is used for controling a digital output
based on a high and low limit. Hysteresis control
is when a controller changes output states only when a gvien
input goes below the low limit, or goes
above the high limit. This method of control is
frequently used when the input is highly responsive to the
output, or when the input may fluxuate rapidly above and below a
single setpoint.
The best known use of hysteresis control is the common household thermostat.
A furnace is turned on when the room temperature drops below a
set point. It is turned off when the room temperature rises some
fixed number of degrees above the set point.

If a simpler control is used (turn the furnace on below the set
point, and off above the setpoint) then the furnace may rapidly
turn itself on and off (short cycling) as the temperature in the
room varies between slightly above and slightly below the set
point. This sort of operation tends to be inefficient, hard on
equipment, and irritating to humans. This operation can be caused
when desired by setting the high and low limits of the hysteresis
controller right next to each other.
The hysteresis mode outputs a 0 or a 1 in its public data to
represent whether the output is in the low limit state or the
high limit state. The public data does not indicate the value of
the output pin.
The initialization of the hysteresis mode requires two
packets::
| Byte # |
Byte Value |
Description |
| 0 |
200 |
Configure pin, First Message |
| 1 |
pin# |
Physical Pin number |
| 2 |
5 |
Channel mode = CHANNEL_MODE_HYSTERESIS |
| 3 |
Low Limit MSB |
(Low Limit) / 256 |
| 4 |
Low Limit LSB |
(Low Limit) modulo 256 |
| 5 |
Hysteresis Mode |
0: High and low limits are absolute values
1: High and low limits are releative to Low Limit Pin |
| 6 |
Low Limit Pin |
Pin from which to read low limit (if not equal to
255) |
| 7 |
High Limit Pin |
Pin from which to read high limit (if not equal to
255) |
| Byte # |
Byte Value |
Description |
| 0 |
201 |
Configure pin, Second Message |
| 1 |
pin# |
Physical Pin number |
| 2 |
5 |
Channel mode = CHANNEL_MODE_HYSTERESIS |
| 3 |
High Limit MSB |
(High Limit) / 256 |
| 4 |
High Limit LSB |
(High Limit) modulo 256 |
| 5 |
Pin Output Settings |
This field is a bit field: Bits 0x03
Action to take when the input is <= the low limit
0 = pin low, 1 = pin high, 2 = pin High-Z
Bits 0x0C
Action to take when the input is >= the high limit
0 = pin low, 1 = pin high, 2 = pin High-Z
Bit 0x10
State to assume if limit pins are invalid or if low limit
>= high limit
0 = assume the low state (bits 0x03)
1 = assume the high state (bits 0xC0)
Bit 0x20
State to assume at initialization if the input is between
the low and high limits
0 = assume the low state (bits 0x03)
1 = assume the high state (bits 0xC0)
|
| 6 |
Input pin |
Pin whose output will be compared against the limits |
| 7 |
unused |
|
Hysteresis Example 1:
*************
Problem:
A temperature dependent IC needs to be heated to its operating
temperature when a product is used in cold environment. A small
power resisor is attached to the IC, along with a temperature
sensor on its opposite side. The power resistor is controlled by
a transistor attached to pin 21 which turns on when the pin is
high, and off when the pin is low. The desired temperature range
from the sensor, attached to the A/D at pin 2, is between 0x3500
and 0x4000. Assume that the temperature gradient between the
heater and the sensor is zero.
Solution:
This is a very straightforward example of hysteresis. Turn the
heater on when the temperature is equal or below 0x3500, and turn
it off when the temperature isequal or above 0x4000.
Initializaton commands:
First Command:
200 : Set pin mode
21 : of pin 21
5 : to Hysteresis
0x35 : with a low limit of 0x3500
0x00
0 : using absolute values
255 : Which are fixed (255 means don't use a pin input for
255 : High or Low limits).
Second Command:
201 : Set pin mode
21 : of pin 21
5 : to Hysteresis
0x40 : with a high limit of 0x4000
0x00
0x31 : Low state ( 0x03 bits) is = 1 (on)
: High state ( 0x0C bits) is 0= off
: Set default state to high-limit (1) to turn off heater if
: the limits appear invalid (0x10 bit is set)
: And start in high-limit state so we don't
: turn on the heater at start unless
: we start below minimum temperature (0x20 bit is set)
0x02 : Pin 2 is the temperature measuring pin
0x00 : The last byte of the second message is reserved. Set it to
: zero.
Hysteresis Example 2:
********************
Problem:
The producer creating a TV show about a bunch of people lost on a
mysterious island after a plane crash decides that a running jet
engine in the background of the crash site scene would be really
cool. In order to be extra disturbing, the jet engine should
spool up and slow down periodically. Since real jet engines are
very expensive, an aluminum mock-up powered by an electric motor
will be used. A controller is to be created. This controller will
provide two knobs which will control the minimum and maximum
speeds of the jet engine.
The shaft on the motor has an encoder which provides pulses on
pin number 35 each time the engine spins some number of degrees.
Two potentiometers have been wired to act as voltage dividers and
are attached to A/D's on pins 3 and 4. A reed relay's coil has
been attached to +5v and pin 34. The reed relay then controls the
coil of a larger relay which drives the motor. Energizing the
reed relay causes the jet engine to accelerate.
Assume pin 35 has been configured to provide the time between
pulses as its public data, and that its values compare reasonably
with those of the potentiometers.
Soultion:
Configure pin 34 to go low when the number of ticks provided by
pin 35 is larger than the public data of pin 3, and to go input
(high impedence) when the number of ticks is smaller than the
public data of pin 4. This will allow the director to control the
low speed limit with the pot on pin 3, and the high speed limit
with the pot on pin 4.
Notes:
1. Remember that as the motor goes faster, the public data on pin
35 gets smaller, not bigger.
2. Remember that a low side driver (like we're using on the reed
relay) is set to 0 volts to be active.
3. The values for Low Limit and High Limit in the commands don't
matter, since pins 3 and 4 will be providing these limits.
4. Pin 3 is actually the high limit, and pin 4 is the low limit,
since we're measuring rotational period, not rotational velocity.
Initializaton commands:
First Command:
200 : Set pin mode
34 : of pin 34
5 : to Hysteresis
0x00 : Low limit doesn't matter since the limit will be provided
by a
0x00 : pin
0 : use absolute values
4 : Pin 4 specifies the minimum period
3 : pin 3 specifies the maximum period
Second Command:
201 : Set pin mode
34 : of pin 34
5 : to Hysteresis
0x00 : High limit doesn't matter since the limit will be provided
0x00 : by a pin
0x22 : Low state ( 0x03 bits) is = 2 (High impedence)
: High state ( 0x0C bits) is = 0 ( Low side driver)
: Set default state to Low Limit to turn off the jet
: if the director makes the low limit higher than the
: high limit (0x10 is clear)
: Set the initial state to high-limit (1) to get
: the jet moving right at the start (0x20 is set)
35 : Pin 35 is providing the timing
0x00 : The last byte of the second message is reserved. Set it to
: zero.
Hysteresis Example 3:
************
Problem:
A compressed air tank needs to be pressurized. A pressure sensor
is attached to pin 8. Safe pressures for the tank are between 0
and 0x9000. For proper operation of the tools which use air from
the tank, a pressure of at least 0x7000 must be maintained in the
tank. A compressor can be turned on by setting pin 20 high, or
turned off by setting pin 20 low. When the compressor is on it
will cause the pressure in the tank to rise. A valve is installed
which can release pressure from the tank. This valve is open
(allows air to flow out of the tank) when no current is applied
to it. Current can be applied in order to close the valve by
setting pin 21 high. Current can be removed by setting pin 21
low. Due to ambient pressure changes, it is possible for the
pressure in the tank to rise even if the compressor is turned
off.
Provide a configuration to keep the pressure in the tank in
acceptable limits.
Solution:
There are two outputs which need to be controlled here. The first
is the compressor. We will set it to turn on when the pressure
drops to 0x8000, and turn off when the pressure rises to 0x8800.
This will leave a sufficient margin to make sure we supply
necessary pressure to the tools without exceeding the
specifications of the tank. The pressure release valve should be
activated before the tank's maximum pressure is met. We'll open
the valve at 0x8C00, and close it again after pressure drops to
0x8B00. It is important that the release valve high limit be
above the compressor high limit, or the system would cycle all
the time, the compressor running trying to reach a pressure which
causes the valve to pop open, releasing pressure.
Initializaton commands for compressor:
First Command:
200 : Set pin mode
20 : of pin 20
5 : to Hysteresis
0x80 : with a low limit of 0x8000
0x00
0 : using absolute values
255 : Which are fixed (255 means don't use a pin input for
255 : High or Low limits).
Second Command:
201 : Set pin mode
20 : of pin 20
5 : to Hysteresis
0x88 : with a high limit of 0x8800
0x00
0x11 : Low state ( 0x03 bits) is = 1 (on)
: High state ( 0x0C bits) is 0= off
: Set default state to high-limit (1) to turn off compressor
: the limits appear invalid (0x10 bit is set)
: And start in low-limit state so we build up spare pressure
: when we start (0x20 bit is clear)
8 : Pin 8 is the pressure measuring pin
0x00 : The last byte of the second message is reserved. Set it to
: zero.
Initializaton commands for valve:
First Command:
200 : Set pin mode
21 : of pin 21
5 : to Hysteresis
0x8B : with a low limit of 0x8B00
0x00
0 : using absolute values
255 : Which are fixed (255 means don't use a pin input for
255 : High or Low limits).
Second Command:
201 : Set pin mode
21 : of pin 21
5 : to Hysteresis
0x8C : with a high limit of 0x8C00
0x00
0x11 : Low state ( 0x03 bits) is = 1 (on) (valve closed)
: High state ( 0x0C bits) is 0= off (valve open)
: Set default state to high-limit (1) to open valve if
: the limits appear invalid (0x10 bit is set)
: And start in low-limit state so we build up pressure
: when we start (0x20 bit is clear) = valve closed
8 : Pin 8 is the pressure measuring pin
0x00 : The last byte of the second message is reserved. Set it to
: zero.
Pin Mode Source Code
The following code is what creates the pin mode for this function inside of the Wombat. You don't need to know this to use the pin mode, but some people find it interesting. See the SDK for some insight into how pin modes work. Hold your mouse over various words and variables for definitions.
#include "types.h"
#include "utilities.h"
#include "global_data.h"
#pragma code APPLICATION
#pragma romdata APPLICATION_DATA
#define HYSTERESIS_MODE_LIMITS 0
#define HYSTERESIS_MODE_MOVING_TARGET 1
uint8 hysteresis_set_pin(void);
void init_hysteresis(void)
{
uint8 temp;
if (rxbuffer[0] == CONFIGURE_CHANNEL_MODE_0)
{
tp.hysteresis.lowlimit = RXBUFFER16(3);
tp.hysteresis.mode = rxbuffer[5] & 0x03;
tp.hysteresis.lowcommandpin = map_pin(rxbuffer[6]);
tp.hysteresis.highcommandpin = map_pin(rxbuffer[7]);
tp.hysteresis.commandpin = 255;
}
else if (rxbuffer[0] == CONFIGURE_CHANNEL_MODE_1)
{
tp.hysteresis.highlimit = RXBUFFER16(3);
tp.hysteresis.lowaction = rxbuffer[5] & 0x03;
rxbuffer[5] >>= 2;
tp.hysteresis.highaction = rxbuffer[5] & 0x03;
rxbuffer[5] >>= 2;
tp.hysteresis.defaultaction = rxbuffer[5] & 0x01;
rxbuffer[5] >>= 1;
tp.hysteresis.commandpin = map_pin(rxbuffer[6]);
temp = hysteresis_set_pin();
//printf ("Set pin result %d\n",temp);
if ( temp == 2)
{
if (rxbuffer[5] & 0x01)
{
//printf ("Initialize high action, inbetween\n");
vpin_set(tp.hysteresis.highaction);
tp.generic.buffer = 1;
tp.hysteresis.currentstate = 1;
}
else
{
//printf ("Initialize low action, inbetween\n");
vpin_set(tp.hysteresis.lowaction);
tp.generic.buffer = 0;
tp.hysteresis.currentstate = 0;
}
}
else if (temp == 1)
{
//printf("Initialize active below low\n");
vpin_set(tp.hysteresis.highaction);
tp.generic.buffer = 1;
tp.hysteresis.currentstate = 1;
}
else
{
//printf("Initialize active above high\n");
vpin_set(tp.hysteresis.lowaction);
tp.generic.buffer = 0;
tp.hysteresis.currentstate = 0;
}
}
}
uint8 hysteresis_set_pin(void)
{
if (tp.hysteresis.commandpin == 255)
{
//printf ("Hysteresis command pin undefined.\n");
return 2;
}
tp2.hysteresis.input = get_buffer(tp.hysteresis.commandpin);
//printf ("Hysteresis input %d\n", tp2.hysteresis.input);
//Calculate low and high limits
if (tp.hysteresis.mode == HYSTERESIS_MODE_LIMITS)
{
if (tp.hysteresis.highcommandpin == 255 )
{
tp2.hysteresis.highlimit = tp.hysteresis.highlimit; }
else
{
tp2.hysteresis.highlimit = get_buffer(tp.hysteresis.highcommandpin);
}
if (tp.hysteresis.lowcommandpin == 255 )
{
tp2.hysteresis.lowlimit = tp.hysteresis.lowlimit; }
else
{
tp2.hysteresis.lowlimit = get_buffer(tp.hysteresis.lowcommandpin);
}
}
else if (tp.hysteresis.mode = HYSTERESIS_MODE_MOVING_TARGET)
{
if (tp.hysteresis.lowcommandpin != 255)
{
//printf ("Using relative limits...\n");
//printf ("Low limit is...%d\n",get_buffer(tp.hysteresis.lowcommandpin));
tp2.hysteresis.highlimit =
tp2.hysteresis.lowlimit =
get_buffer(tp.hysteresis.lowcommandpin);
tp2.hysteresis.temp16 = tp2.hysteresis.highlimit + tp.hysteresis.highlimit;
if (tp2.hysteresis.temp16 < tp2.hysteresis.highlimit)
{
tp2.hysteresis.highlimit = 0xFFFF;
}
else
{
tp2.hysteresis.highlimit = tp2.hysteresis.temp16;
}
tp2.hysteresis.temp16 = tp2.hysteresis.lowlimit - tp.hysteresis.lowlimit;
if (tp2.hysteresis.temp16 > tp2.hysteresis.lowlimit)
{
tp2.hysteresis.lowlimit = 0x0000;
}
else
{
tp2.hysteresis.lowlimit = tp2.hysteresis.temp16;
}
}
else
{
tp2.hysteresis.lowlimit = 0x0000;
tp2.hysteresis.highlimit = 0x0000;
}
}
//printf ("Hysteresis low limit %d, Hysteresis high limit %d\n", tp2.hysteresis.lowlimit, tp2.hysteresis.highlimit);
//Set the pin
if (tp2.hysteresis.lowlimit >= tp2.hysteresis.highlimit)
{
if(tp.hysteresis.defaultaction )
{
vpin_set(tp.hysteresis.highaction);
tp.generic.buffer = 1;
tp.hysteresis.currentstate = 1;
executive_settings.buffer_dirty = 1;
return (1);
}
else
{
vpin_set(tp.hysteresis.lowaction);
tp.generic.buffer = 0;
tp.hysteresis.currentstate = 0;
executive_settings.buffer_dirty = 1;
return (0);
}
}
else if (tp2.hysteresis.input >= tp2.hysteresis.highlimit && tp.hysteresis.currentstate == 0)
{
vpin_set(tp.hysteresis.highaction);
tp.generic.buffer = 1;
tp.hysteresis.currentstate = 1;
executive_settings.buffer_dirty = 1;
return (1);
}
else if (tp2.hysteresis.input <= tp2.hysteresis.lowlimit && tp.hysteresis.currentstate == 1)
{
vpin_set(tp.hysteresis.lowaction);
tp.generic.buffer = 0;
tp.hysteresis.currentstate = 0;
executive_settings.buffer_dirty = 1;
return (0);
}
return (2);
}
void update_hysteresis(void)
{
hysteresis_set_pin();
//printf ("Pin setting %d before update\n",vpin_read());
//printf ("Set pin result %d\n",hysteresis_set_pin());
//printf ("Pin setting %d after update\n",vpin_read());
}
#ifndef COMPILING_FIRMWARE
#ifdef TEST_HYSTERESIS
int main(void)
{
int final_result = 0;
int test = 0;
int pin = 20;
int input_pin = 21;
int low_limit_pin = 255;
int high_limit_pin = 255;
int low;
int high;
system_init();
printf("Test %d: Normal mode, absolute low 2000, absolute high 3000\n",test);
low = 2000;
high = 3000;
set_buffer(map_pin(input_pin),2500);
rxbuffer[0] = CONFIGURE_CHANNEL_MODE_0;
rxbuffer[1] = pin;
rxbuffer[2] = PIN_MODE_HYSTERESIS;
rxbuffer[3] = low / 256;
rxbuffer[4] = low % 256;
rxbuffer[5] = 0; // 0 - Absolute value 1- High relative to low
rxbuffer[6] = low_limit_pin; // Low not based on pin
rxbuffer[7] = low_limit_pin; // High not based on pin
process_rxbuffer();
rxbuffer[0] = CONFIGURE_CHANNEL_MODE_1;
rxbuffer[1] = pin;
rxbuffer[2] = PIN_MODE_HYSTERESIS;
rxbuffer[3] = high / 256;
rxbuffer[4] = high % 256;
rxbuffer[5] = 1 + (0 << 2) + ( 0 << 4 ) + ( 0 << 5);
// Low = go high, High = go low, Low if illegal, start with
// low action
rxbuffer[6] = input_pin;
rxbuffer[7] = 0x55; //unused
process_rxbuffer();
if (!read_pin(map_pin(pin)))
{
//Should be on
printf("Error, test %d. Pin did not initialize on\n",test);
final_result = 1;
}
set_buffer(map_pin(input_pin),2500);
process_pins();
if (!read_pin(map_pin(pin)))
{
//Should be on
printf("Error, test %d. Pin shoudl be on (1)\n",test);
}
test++;
printf("Test %d: Normal mode, absolute low 2000, absolute high 3000, input 2000 from 2500\n",test);
set_buffer(map_pin(input_pin),2000);
process_pins();
if (!read_pin(map_pin(pin)))
{
//Should be on
printf("Error, test %d. Pin should be on (2)\n",test);
}
test++;
printf("Test %d: Normal mode, absolute low 2000, absolute high 3000, input 3000 from 2000\n",test);
set_buffer(map_pin(input_pin),3000);
process_pins();
if (read_pin(map_pin(pin)))
{
//Should be off
printf("Error, test %d. Pin should be off (3)\n",test);
}
++test;
printf("Test %d: repeat in relative mode, 2000, + 1000\n",test);
low = 0 ;
high = 1000;
low_limit_pin = 3;
set_mode(map_pin(low_limit_pin),PIN_MODE_CONTROLLED);
set_buffer(map_pin(input_pin),2500);
set_buffer(map_pin(low_limit_pin),2000);
rxbuffer[0] = CONFIGURE_CHANNEL_MODE_0;
rxbuffer[1] = pin;
rxbuffer[2] = PIN_MODE_HYSTERESIS;
rxbuffer[3] = low / 256;
rxbuffer[4] = low % 256;
rxbuffer[5] = 1; // 0 - Absolute value 1- High relative to low
rxbuffer[6] = low_limit_pin; // Low not based on pin
rxbuffer[7] = high_limit_pin; // High not based on pin
process_rxbuffer();
rxbuffer[0] = CONFIGURE_CHANNEL_MODE_1;
rxbuffer[1] = pin;
rxbuffer[2] = PIN_MODE_HYSTERESIS;
rxbuffer[3] = high / 256;
rxbuffer[4] = high % 256;
rxbuffer[5] = 1 + (0 << 2) + ( 0 << 4 ) + ( 0 << 5);
// Low = go high, High = go low, Low if illegal, start low action
rxbuffer[6] = input_pin;
rxbuffer[7] = 0x55; //unused
process_rxbuffer();
if (!read_pin(map_pin(pin)))
{
//Should be on
printf("Error, test %d. Pin did not initialize on\n",test);
final_result = 1;
}
process_pins();
if (!read_pin(map_pin(pin)))
{
//Should be on
printf("Error, test %d. Pin shoudl be on (1)\n",test);
}
test++;
printf("Test %d: Normal mode, absolute low 2000, absolute high 3000, input 2000 from 2500\n",test);
set_buffer(map_pin(input_pin),2000);
process_pins();
if (!read_pin(map_pin(pin)))
{
//Should be on
printf("Error, test %d. Pin should be on (2)\n",test);
}
test++;
printf("Test %d: Normal mode, absolute low 2000, absolute high 3000, input 3000 from 2000\n",test);
set_buffer(map_pin(input_pin),3000);
process_pins();
if (read_pin(map_pin(pin)))
{
//Should be off
printf("Error, test %d. Pin should be off (3)\n",test);
}
return(final_result);
}
#endif
#endif
|
|