6-Channel Realtime Controller

Wichit Sirichote, kswichit@kmitl.ac.th
Build a 6-channel realtime controller with builtin clock display and keys for time settings.

I like the open collector buffer chip, 7407 very much. It has 6-channel TTL input and 6-channel NPN output. The output driver has maximum sink current of 30mA at 30V. I used it in many microcontroller projects. The 7407 chip provides simple driver from microcontroller port to the high power circuit easily.

 

This new simple design of the realtime controller also uses the 7407 the same as my old version. I have added 7-segment display and 4-button for clock settings. The controller has 6-channel with open collector output. The controller has no battery for clock backup. Instead it will be set up manually. On power up reset, all output bits will be disabled. After clock has been set, the output and clock will be functioning. The controller is useful for controlling home appliances with the solid-state relay.

Below diagram shows how to use solid-state relay to control home appliances. Each device will be controlled using time settings, says the air-conditioner for 22:00-5:30.

Hardware

The controller chip is AT89S52, 8-kB Flash 8051 compatible microcontroller. The display is 4-digit seven segment LED, LDS2481AS. Output is 6-channel using 7407 buffer chip. The output is open collector designed for connecting the solid-state relay directly. Port0 with 10k pullup resistor drives the segment of the LED display.

P3.4 to P3.7 drives the common cathode pins. The key switches, SW1-SW4 use the common pins for key press detection. KEYIN line is input bit at P3.2. Key press will be detected when a given key has been pressed. SW5 is extra key used for turning on one output bit. I used it for turning on the air conditioner manually. U4 is optional EEPROM prepared for future design. It may be used for programming the scheduler by user.

Figure 1: Hardware schematic (click to enlarge).

Software

The firmware was written using c language. The source code was compiled with Mikro-C for 8051 version 2.2. The main code is forever loop scanning display and key switches. Realtime clock is generated by timer0, 10ms interrupt. The clock is updated every one second. The program is scanning every one minute. Each program consists of three bytes. The first two byes is HR:MM and the third one is output control byte.

After reset, running state will be 0, the clock and output will be disabled. When any key has been pressed, running state will be 1, clock and output will be functioning.


/*
   6-channel Realtime controller with clock display and keys
   MikroC for 8051 V2.2
   Copyright (C) 2015 Wichit Sirichote, wichit.sirichote@gmail.com
   MCU: 89S52
   Output: open collector 7407       
 */
char code convert[10] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7c,0x07,0x7f,0x67};
   char buffer[4]; // display buffer
   char i,j;
   char min_key;
   char hour_key;
   char pressed;
   char command;
   char sec10,sec,min,hour;
   char blink_tick;
   char blink;
   char state; // state =0 turn off all outputs
   // state =1 normal clock running, initiate when any keys were pressed
   
   char temp;
 
void cout(char n);
   void print_time();
 
/*
   / air.pgm
   / activates four devices by time setting
   / '1' is on and '0' is off
   / OUTPUT [1...8]
   / output 1 is a SSR controlled 12,000btu air conditioner
   / output 2 is a 7W night lamp at bed
   / output 3 is a 10W lamp at bedroom's door
   / output 4 is a 20W fluorescent at kitchen
   / output 5 reserved
   / output 6 high current 12Vdc solenoid driver
   / output 7 reserved
   / output 8 reserved
/line day time output 1...8
   :01 24 1900 0 0 1 1 0 0 0 0 / on lamp at bedroom door and kitchen
   :02 24 2000 0 1 1 1 1 0 0 0 / also bed lamp, and fan
   :03 24 2200 1 0 1 1 1 0 0 0 / off bed lamp, on air conditioner
   :04 24 2230 1 0 0 0 1 0 0 0 / off door lamp
   :05 24 2310 1 0 0 0 0 0 0 0 / off fan
   :06 24 0530 0 0 0 0 1 0 0 0 / off air-conditioner and on fan again
   :07 24 0600 0 0 0 0 0 0 0 0 / off all
   :00
   */
char pgm[]={ 19,0, 0x30, 20,0,0x78,22,0,0xb8,22,30,0x88,23,10,0x80,5,30,0x08,6,0,0x00};
 
void scan_pgm()
   {
   for(i=0; i<7; i++)
   {
   if(hour == pgm[i*3] && min == pgm[(i*3)+1]) // check time for output
   {temp = ~pgm[(i*3)+2]; // write output byte to P2
   P2 = temp>>2; // shift to P2.0-P2.5
   }
   }
   }
 
 
 
void scan()
   {
   P0=buffer[0];
   P3=~0x10;
   if((P3&8)==0) hour_key=0;
   else hour_key=1;
 
 Delay_ms(1);
   P3=0xff;
 P0=buffer[1];
   P3=~0x20;
   if((P3&8)==0) min_key=0;
   else min_key=1;
 Delay_ms(1);
   P3=0xff;
 
 P0=buffer[2]; //|0x80;
   P3=~0x40;
   Delay_ms(1);
   P3=0xff;
 
 P0=buffer[3];
   P3=~0x80;
   Delay_ms(1);
   P3=0xff;
   
   if(P3_2_bit==0) P2_0_bit=0; // turn AC on if P3.2 was pressed
 }
 void release_key()
   {
   if((min_key&&hour_key)==1) pressed=0;
   }
 void set_hour()
   {
   if((hour_key==0) && (pressed==0))
   {
   if(++hour >=24)hour =0;
   print_time();
   pressed=1;
   state=1;
   }
   }
 void set_min()
   {
   if((min_key==0) && (pressed==0))
   {
 sec =0;
   if(++min>59) min =0;
   print_time();
   pressed=1;
   state=1;
 }
   }
 
 void initUART()
   {
   SCON = 0x52; /* SCON: mode 1, 8-bit UART, enable rcvr */
   PCON = 0x80; // SMOD =1
   TMOD = 0x21; /* TMOD: timer 1, mode 2, 8-bit reload */
   TH1 = 0xfe; /* TH1: reload value for 9600 baud */
   TR1_bit = 1; /* TR1: timer 1 run */
   }
 char cin_ready()
   {
   if(RI_bit)
   {
   RI_bit=0; // clear when set
   return SBUF;
   }
   else
   return 0xff;
   }
 char cin()
   {
   while(RI_bit==0)
   continue;
   RI_bit=0;
   return SBUF;
   }
 void cout(char n)
   {
   while(TI_bit==0) continue;
   TI_bit=0;
   SBUF = n;
   }
 
 // receive HH:MM from RTC chip
   // format is \rHH:MM
   void get_time()
   {
 if(cin_ready()==0x0d)
   {
   buffer[3]= convert[cin()-0x30];
   buffer[2]= convert[cin()-0x30];
   cin(); // dummy read for colon
   buffer[1]= convert[cin()-0x30];
   buffer[0]= convert[cin()-0x30];
   }
   }
   
   void print_time()
   {
   buffer[0]= convert[min%10];
   buffer[1]= convert[min/10];
   buffer[2]= convert[hour%10]|0x80;
   buffer[3]= convert[hour/10];
   if(buffer[3]== 0x3F) buffer[3]=0; // turn off zero
   
   }
   
   void time()
   {
   if(++sec10==100)
   {
   sec10 =0;
   //P3 ^= 0x80;
   print_time(); // print time every second
   blink=1;
 if ( ++sec >= 60)
   {
   sec = 0;
   scan_pgm(); // scan program every minute
   if ( ++min >= 60)
   {
   min = 0;
 if ( ++hour >= 24)
   hour = 0;
   }
   }
   }
}
void Timer0InterruptHandler() org IVT_ADDR_ET0
   {
   TH0 |= 0xdc; // reload timer 0 for 10ms tick 0xDC00 with 11.0592MHz
 time(); // update realtime clock
   if(blink)
   {
   if(++blink_tick >50)
   {
   blink=0;
   blink_tick=0;
   buffer[2]&= ~0x80;
   }
   }
 }
 
void main() {
 EA_bit = 0;
   ET0_bit = 1; // or IE |= 0x82; /* set bit EA and Timer0 enable */
 SCON = 0x52; // 8-bit UART mode
   TMOD = 0x21; // timer 1 mode 2 auto reload
   TH1= 0xfe; // 9600 8n1 with 3.579545MHz XTAL
   PCON = 0x80; //smod = 1
   TR1_bit = 1;
   TR0_bit = 1; // run timer0 and timer1
 hour = 8; // when reset set current time to 8:00
   min = 0;
   sec = 0;
   state=0;
   buffer[0]=0x40;
   buffer[1]=0x40;
   buffer[2]=0x40;
   buffer[3]=0x40;
   
   initUART();
   pressed=0;
 
 while(1)
   {
   
   switch(state)
   {
   case 0:
   P2 =0xFF; // turn output off all bits
   
   scan();
   set_hour();
   set_min();
   release_key();
   break;
   
   case 1:
   EA_bit = 1; // run clock
   scan();
   set_hour();
   set_min();
   release_key();
   break;
   
   }
   }
   }
 
Source code listing.

PCB

I made the controller's PCB by using laser printer. The PCB pattern of the bottom layer was transferred from the printed paper to the PCB with ironing. The PCB is single side layer. For some lines that cannot route, I used small wire to connect it. The DXF file is available for the correct size.

Seven segment LED

The display is four digits multiplex connection LED. It is small, so we can drive it using 8051 port directly. The brightness is quite nice for bedroom.

Sample board

To test program settings, we can have six LED with cathode pin for each LED tied to the output bit. A small 1k resistor is used to limit the current from +12V adapter tied to the common anode pins. We may adjust HR and MM to 19:00, the output will activated at 19:01.

For daytime, we may have a red color filter to make nice readings.

PARTS LIST

Semiconductors

D1 1N4007, Silicon rectifier diode
U1 7407, 6-channel open collector buffer
U2 AT89S52, 8-bit microcontroller
U3 LDS2481AS, 7-segment LED
U4 24C16B, EEPROM (optional)
U5 LM7805/TO, +5V regulator

Resistors (all resistors are 1/4W +/-5%)

R1 10k

Capacitors

C3,C1 30pF disc ceramic capacitor
C2 10uF electrolytic capacitor
C4 100nF multilayer capacitor or disc ceramic
C5 100uF electrolytic capacitor
C6 1000uF 16V, electrolytic capacitor
C7 0.1uF disc ceramic capacitor

Additional parts

SW1,SW2,SW3,SW4 12x12mm tact switch
SW5 AC_ON 6x6mm tact switch
JA1 terminal
J1 DC input jack
Y1 11.0592MHz crystal

 

Using solid-state relay for AC load switching

The output for each channel is capable of driving the solid-state directly. The load can be AC load with a proper current driving capacity. The example one is OMRON G3MB-202PL, 2A @240VAC. Wiring for the control signal to the relay is only two wires, +12V and the output from 7407 driver.

We can use it for switching the LED light bulb with simple method. Have the old technology 5W light bulb parallels to the LED light bulb.

For the heavy load, we can use bigger size solid-relay.

Download

Schematic, source code, HEX file, PCB DXF file, 7407 datasheet , LDS2481AS datasheet



<
12 November 2016