Summary of STEAM GENERATOR using PIC16F873
This article details a DIY steam generator controller for residential steam showers, managed by a PIC16F873 microcontroller. The system automates water filling, heating, and draining while monitoring thermal and level sensors to handle six specific error conditions. It features push-button controls for high/low steam rates and extendable cycles, utilizing a 3000W heating element and copper piping construction.
Parts used in the Steam Generator Controller:
- PIC16F873 Microcontroller
- 4-inch Copper Pipe Tank
- Silver Soldered End Caps
- 3000W Heating Element
- Stainless Steel Bolts
- Pre-existing Relay Card
- 220V to 24V Transformer
- Solid State Relay (SSR)
- Cooling Fan
- 1/4-inch Flexible Copper Tubing
- DS1820 Temperature Sensor
- Push Buttons (Switches)
Introduction
This program is a steam generator controller that is intended for use in a residential steam shower. It controls water inlet and drain valves, power to the heating element, and various level and thermal sensors.
Features
Push button automated control of the steam shower. High and low steam rates, extendable cycles, error conditions are sensed and handled.
Specifications
- Power: 220VAC, 3000W
- Time to boil: 6 minutes
- Added time to preheat steam room: 10 minutes
- Steam cycle: 20 minutes, plus additional 20 minute cycles if requested
- Steam level: Full steam, low steam
- Time to cool and drain: 20 minutes, typical
- Error conditions: six
Construction
This project works quite well but has not passed the prototype stage yet. (It’s still built on a wooden platform!)
The tank is a 4″ copper pipe with end caps. It is silver soldered to withstand heat. The replacable 3000W heating element extends inward through one end of the tank. Stainless bolts are used. The relay card is a pre-existing unit that I had in my collection. The 220/24V transformer, solid state relay, cooling fan are below the relay card. The “U” shaped 1/4″ flexible copper tubing alongside the tank is for preheating the incoming water so that it doesn’t squelch the steam when the inlet water valve opens.
Code:
/****************************************************************
STEAMGEN07.C
This is a steam generator.
WORKING CODE
ERRORS - count the number of quick flashes
1 - not drained at beginning
2 - not filled within time limit during initial fill cycle
3 - not filled within time limit during rinse cycle
4 - not filled to limit during heating within time limit
5 - over temperature during preheat or soak cycles
6 - under temperature after preheat cycle
LED FLASH
SLOW - filling, preheating, draining
SOLID - soak mode
FAST - stop and wait (warn) period
---------
+5--20-|Vdd C0|-11--- Heat-A relay
| C1|-12--- Heat-B relay
Gnd--08-|Vss C2|-13--- Heat - SSR
Gnd--19-|Vss C3|-14--- Fill
4MHz--10-|Xtal C4|-15--- Drain
--09-|Xtal |
| | PROGRAMMING CONNECTOR
| B7|-28--DATA
| B6|-27--CLK
| MCLR|-01--MCLR
| | GND
| 16F876 |
| |
Level --21-|B0 C5|-16-- LED1
Sw1 --22-|B1 C6|-17-- LED2
Sw2 --23-|B2 B4|-25-- LED RETURNS
DS1820 --03-|A1 B3|-24-- BEEPER
| B5|-26-- COOLING FAN
---------
**********************************************************/
#include < 16F876.H >
#include < jonsinc.h >
#fuses XT, NOPROTECT, PUT, NOWDT, BROWNOUT, NOLVP, NOCPD, NOWRT
#define RELAY_HEAT_A PIN_C0
#define RELAY_HEAT_B PIN_C1
#define RELAY_SSR PIN_C2
#define RELAY_FILL PIN_C3
#define RELAY_DRAIN PIN_C4
#define LED_1 PIN_C5
#define LED_2 PIN_C6
#define SWITCH_LEVEL PIN_B0
#define SWITCH_1 PIN_B1
#define SWITCH_2 PIN_B2
#define BEEPER PIN_B3
#define LED_RETURN PIN_B4
#define DS1820_DATA_PIN PIN_A1
#define FAN PIN_B5
//============================
#define PERCENT_100 4
#define PERCENT_75 3
#define PERCENT_50 2
#define PERCENT_25 1
#define PERCENT_0 0
#define LED_FLASH_NONE 0
#define LED_FLASH_SLOW 1
#define LED_FLASH_FAST 2
#define LED_INIT_FLASH_COUNT 16
#define MINIMUM_INTERVAL 1
#define HIGH_STEAM 1
#define LOW_STEAM 2
//============================
#define STATE_START 0
#define STATE_INITIAL_CHECKS 1
#define STATE_READ_SWITCHES 2
#define STATE_FILL 3
#define STATE_PREHEAT 4
#define STATE_SOAK 5
#define STATE_WARN 6
#define STATE_DRAIN 7
#define STATE_ERROR 9
//============================
#define ERROR_NONE 0
#define ERROR_NOT_DRAINED 1
#define ERROR_NOT_FILLED_DURING_FILL 2
#define ERROR_NOT_FILLED_DURING_RINSE 3
#define ERROR_FILL_ABSENCE 4
#define ERROR_OVERTEMP 5
#define ERROR_UNDERTEMP 6
//============================
// times in seconds
#define TIME_FILL_LIMIT 240
#define TIME_DRAIN 160
#define TIME_PREBOIL 360
#define TIME_PREHEAT_SHOWER 600
#define TIME_SOAK_MODE 1200
#define TIME_STOP_AND_WAIT 130
#define TIME_FILL_ABSENCE 300
#define TIME_TEMPERATURE_MEAS 10
// times in mS
#define TIME_ADD_WATER_INCR 1000
#define TIME_ADD_WATER_DELAY 100
#define TIME_DRAIN_COOL_FILL 10000
#define TIME_INITIAL_OVERFILL 3000
// times in uS
#define BEEPER_PERIOD_DELAY 518
// number of cycles for beeper
#define BEEP_CYCLES 500
//============================
// DS1820 temperature sensor
#define DS1820_SKIP_ROM 0xCC
#define DS1820_READ_SCRATCHPAD 0xBE
#define DS1820_CONVERT_T 0x44
// temperature in degrees C
#define TEMPERATURE_DRAIN_LIMIT 65
#define TEMPERATURE_OVER 105
#define TEMPERATURE_UNDER 90
//============================
#use delay ( clock=6000000 )
#use standard_io ( A )
#use standard_io ( B )
#use standard_io ( C )
void CheckSwitches ( void );
void AddWaterIfNecessary ( void );
void FlashErrorCode ( cError );
void AllRelaysOff ( void );
void Beep ( char cCount );
void SetHeaterPower ( char cLevel );
char ReadTemperature ( void );
void ResetDS1820 ( void );
void WriteDS1820 ( void );
void ReadDS1820 ( void );
void WaitForConversion ( void );
static char cInterruptCount;
static long iSecondCount, iFillOvertimeCount;
static char cSwitch1Count, cSwitch1on;
static char cSwitch2Count, cSwitch2on;
static char cError, cState, cMode, cOff, cResetCount;
static char cLedFlash, cLedOn, cSSRon, cSSRcount, cDebugMode;
static char cPower, cDutyCycleCount, cDutyCycleState;
static char cShiftBit,cDataOut, cTemperatureSecondCount;
static long iDataIn;
//*************************************************************************
#int_rtcc
void TimerInterrupt ( void ) // 21.760mS tick, 46 interrupts per second
{
// ONE-SECOND TICK
if ( cInterruptCount++ == 47 ) // a little more than one second so flashes divide evenly
{
cInterruptCount = 0; // restart interrupt count
iSecondCount++; // increment second count
cTemperatureSecondCount++; // increment temperature second count
iFillOvertimeCount++; // increment overtime count
}
// SOLID STATE RELAY POWER CYCLING
if ( cDutyCycleCount++ >= 4 ) // is it 84mS yet? (sets the overall duty cycle granularity)
{
cDutyCycleCount = 0; // reset
if ( cDutyCycleState == cPower ) // is heat cycle done yet?
{
output_low ( RELAY_SSR ); // turn solid state relay off
}
else
{
if ( cDutyCycleState == 0 ) // if first state
{
output_high ( RELAY_SSR ); // turn solid state relay on
}
}
if ( cDutyCycleState++ >= 3 ) // increment state
{
cDutyCycleState = 0; // reset
}
}
// LED FLASH/SOLID CONTROL
switch ( cLedFlash )
{
case LED_FLASH_NONE:
{
cLedOn = YES;
break;
}
case LED_FLASH_SLOW:
{
if ( ( cInterruptCount % 24 ) == 0 )
{
cLedOn ^= 1;
}
break;
}
case LED_FLASH_FAST:
{
if ( ( cInterruptCount % 8 ) == 0 )
{
cLedOn ^= 1;
}
break;
}
}
if ( cLedOn == YES )
{
output_low ( LED_RETURN ); // LED on
}
else
{
output_high ( LED_RETURN ); // LED off
}
// SWITCH 1 SENSE
if ( input ( SWITCH_1 ) == LOW ) // if pressed
{
if ( cSwitch1Count++ >= 92 ) // increment count
{
cSwitch1Count = 92; // prevent wrap, limit to highest needed
}
}
else // when button is released
{
if ( cSwitch1Count >= 92 ) // if was pressed for two seconds
{
cOff = YES; // signal OFF
}
else
{
if ( cSwitch1Count >= 2 ) // else if was pressed momentarily
{
cSwitch1on = YES; // signal normal press
}
}
cSwitch1Count = 0; // switch up, restart
}
// SWITCH 2 SENSE
if ( input ( SWITCH_2 ) == LOW ) // if pressed
{
if ( cSwitch2Count++ >= 92 ) // increment count
{
cSwitch2Count = 92; // prevent wrap, limit to highest needed
}
}
else // when button is released
{
if ( cSwitch2Count >= 92 ) // if was pressed for two seconds
{
cOff = YES; // signal OFF
}
else
{
if ( cSwitch2Count >= 2 ) // else if was pressed momentarily
{
cSwitch2on = YES; // signal normal press
}
}
cSwitch2Count = 0; // switch up, restart
}
// RESET (PRESS BOTH SWITCHES SIMULTANEOUSLY)
if ( ( input ( SWITCH_1 ) == LOW ) && ( input ( SWITCH_2 ) == LOW ) ) // if pressed for three seconds
{
if ( cResetCount++ >= 143 ) // increment count
{
cResetCount = 143; // cap it
}
}
else // when button is released
{
if ( cResetCount >= 143 ) // if was pressed for five seconds
{
reset_cpu();
}
cResetCount = 0; // switch up, restart
}
}
//****************************************************************************
For more detail: STEAM GENERATOR using PIC16F873
- What is the primary function of this program?
The program controls water inlet and drain valves, power to the heating element, and various level and thermal sensors for a residential steam shower. - How long does it take to boil water?
The time to boil is 6 minutes. - Can the steam cycle be extended?
Yes, the standard 20-minute steam cycle can be extended with additional 20-minute cycles if requested. - What are the two available steam levels?
The system supports Full steam and low steam levels. - How many error conditions does the system sense?
The system senses and handles six specific error conditions. - Does the project include a preheating feature for incoming water?
Yes, a U-shaped flexible copper tubing preheats incoming water to prevent it from squelching the steam. - What happens if the temperature exceeds limits during preheat?
An over-temperature error condition is triggered if the temperature goes above 105 degrees C during preheat or soak cycles. - How do you reset the CPU manually?
Pressing both Switch 1 and Switch 2 simultaneously for five seconds resets the CPU. - What indicates a stop and wait warning period?
A fast LED flash indicates a stop and wait warning period.

