;*************************************************************** ; USE ONLY A 87C51FA MICROCONTROLLER! ; IT USES THE TIMER 2 FOR BAUD RATE GENERATOR ;*************************************************************** ; ;*************************************************************** ; SYSTEM EQUATES ;*************************************************************** ; ; EVENTS - USED DURING MASTER MODE AS AN EVENT ; .EQU START_DAYBREAK, 0 .EQU ZONE2_OFF, 5 .EQU ZONE3_OFF, 10 .EQU START_DAY, 15 .EQU START_SUNSET, 50 .EQU ZONE1_ON, 60 .EQU START_NIGHT, 65 .EQU ZONE2_ON, 70 .EQU ZONE3_ON, 75 .EQU ZONE1_OFF, 95 ; .EQU TMIN, 2 .EQU TMAX, 100 - TMIN .EQU UP_VALUE, TMIN .EQU DOWN_VALUE, TMAX ; .EQU OFF, 0 .EQU ON, 1 ; ; BAUD RATE VALUES - COPY IN RCAP2H AND RCAP2L ; BR = OSC_FREQ / (32 * (65536 - (RCAP2H,RCAP2L))) ; .EQU BR300H, 254 .EQU BR300L, 95 .EQU BR600H, 255 .EQU BR600L, 48 .EQU BR1200H, 255 .EQU BR1200L, 152 .EQU BR2400H, 255 .EQU BR2400L, 204 .EQU B4800RH, 255 .EQU BR4800L, 230 .EQU BR9600H, 255 .EQU BR9600L, 243 ; ; COMMANDS ; .EQU CHA_OFF, 0 .EQU CHA_ON, 1 .EQU SET_SCALE, 2 .EQU DAYBREAK_ON, 3 .EQU DAY_ON, 4 .EQU SUNSET_ON, 5 .EQU NIGHT_ON, 6 .EQU FIRE_ON, 7 ; .EQU DELAY_VALUE, 16 ; about 100 us (3*16) .EQU COMP_DELAY, 48 ; about 300 us ; ; DIMMER STATES - USED ONLY TO VARY THE LIGTH LEVEL ; .EQU DIMMER_OFF, 0 .EQU DAYBREAK_STATE, 1 .EQU DAY_STATE, 2 .EQU SUNSET_STATE, 3 .EQU NIGHT_STATE, 4 ; .EQU FLASH_TICK_MAX, 50 ; flash frequency = 1 Hz ; .EQU PUMP_ON_MAX, 5 ; pump on time = 5 min .EQU PUMP_MAX, 7 ; pump cycle = 7 min ; ; STOP STATES ; .EQU GOING_STATE, 0 .EQU GO_STATE, 1 .EQU STOPPING_STATE, 2 .EQU STOPPED_STATE, 3 ; .EQU TCON2, 0c8h ; ; INITIALIZATION REGISTER VALUES ; .EQU SP_VALUE, 08h .EQU IP_VALUE, 00000010b .EQU IE_VALUE, 10001010b .EQU P0_VALUE, 01000001b ; day on, pump on .EQU P1_VALUE, 11111111b .EQU P2_VALUE, 10111111b ; led on .EQU P3_VALUE, 11111111b .EQU SCON_VALUE, 01010000b ; MODE 1 - 8 BITS - RX EN - POLLING .EQU TCON_VALUE, 00000000b .EQU TCON2_VALUE, 00110100b ; TIMER 2 AS BAUD RATE GENERATOR .EQU TMOD_VALUE, 00000000b .EQU PCON_VALUE, 10000000b ; ;**************************************************************** ; OPERATION POINTS ;**************************************************************** ; .FLAG PUMP, P0.0 .FLAG ZONE1, P0.1 .FLAG ZONE2, P0.2 .FLAG ZONE3, P0.3 .FLAG NIGHT, P0.4 .FLAG SUNSET, P0.5 .FLAG DAY, P0.6 .FLAG DAYBREAK, P0.7 ; .FLAG MASTER, P1.7 .FLAG MAINS, P2.2 .FLAG TX_EN, P2.3 .FLAG STOP, P2.4 .FLAG TEST, P2.5 .FLAG LED, P2.6 ; ;**************************************************************** ; VARIABLES ;**************************************************************** ; .EQU dimmer_status, 25H ; dimmer state .EQU dimmer_ticks, 26H ; number dimmer ticks .EQU steps, 27H ; number of steps .EQU percent, 28H ; daylight cycle percent .EQU scale, 29H ; time scale ; .EQU pump_ticks, 2AH ; pump ticks .EQU pump_sec, 2BH ; elapsed seconds .EQU pump_min, 2CH ; elapsed minutes ; .EQU t0val, 2DH ; timer 0 value .EQU t1val, 2EH ; timer 1 value ; .EQU flash, 2FH ; flash status .EQU led_status, 30H ; led status .EQU flash_ticks, 31H ; flash ticks ; .EQU stop_status, 32H ; stop button status .EQU value, 33H ; value passed by host ; .EQU random, 34H ; random byte .EQU rand_ch, 35H ; random channel (fire on) ; .EQU flags, 20H ; .FLAG rand_flag, flags.0 ; ;*************************************************************** ; PROGRAM SEGMENT DECLARATION ;*************************************************************** ; .ORG 00H ; ; ;*************************************************************** ; PROGRAM START ;*************************************************************** ; start: ljmp init ; power up ; .ORG 03H ; int 0 ljmp ex_int0 ; .ORG 0X0B ; timer 0 interrupt - system tick ljmp tim0 ; .ORG 13H ; int 1 ljmp ex_int1 ; .ORG 1BH ; timer 1 interrupt ljmp tim1 ; .ORG 23H ; serial interface interrupt ljmp serial ; ; they are not used ; ex_int0: ex_int1: serial: reti ; ;********************************************************** ; INITIALIZATION ;********************************************************** ; .ORG 40H ; ;********************************************************** ; PROCESSOR REGISTERS INITIALIZATION ;********************************************************** ; init: mov SP,#SP_VALUE ; main program start mov P0,#P0_VALUE mov P1,#P1_VALUE mov P2,#P2_VALUE mov P3,#P3_VALUE mov PCON,#PCON_VALUE mov TCON,#TCON_VALUE mov TCON2,#TCON2_VALUE mov RCAP2H,#BR1200H mov RCAP2L,#BR1200L mov TMOD,#TMOD_VALUE mov IP,#IP_VALUE mov IE,#IE_VALUE mov SCON,#SCON_VALUE ; ; ;*************************************************************** ; VARIABLES INITIALIZATION ;*************************************************************** ; mov dimmer_status,#DIMMER_OFF mov dimmer_ticks,#0 mov steps,#0 mov percent,#30 lcall get_scale mov pump_ticks,#0 mov pump_sec,#0 mov pump_min,#0 mov t0val,#0 mov t1val,#0 mov flash,#OFF mov led_status,#ON mov flash_ticks,#0 mov stop_status,#GO_STATE setb rand_flag mov a,#0 mov rand_ch,a jb MASTER,main_loop clr rand_flag ; ;********************************************************** ; MAIN LOOP SYNCHRONIZATION ;********************************************************** ; ;main_sync: jb MAINS,main_sync ; jb MAINS,main_sync ; jb MAINS,main_sync ; ;********************************************************** ; MAIN LOOP ;********************************************************** ; main_loop: jnb MAINS,main_loop ; wait for flag high jnb MAINS,main_loop ; and filter jnb MAINS,main_loop ; mov B,#COMP_DELAY ; delay for negative main_dloop: djnz B,main_dloop ; slope compensation lcall trigger lcall scheduler lcall rand8 ; main_loop1: jb MAINS,main_loop1 ; wait for flag low jb MAINS,main_loop1 ; and filter jb MAINS,main_loop1 ; lcall trigger lcall scheduler lcall rand8 ; ljmp main_loop ; ;*************************************************************** ; ZERO CROSSING TRIGGER - IT STARTS THE TIMERS IF DIMMER NOT OFF ;*************************************************************** ; trigger: mov A,dimmer_status cjne A,#DIMMER_OFF,trigger1 ; clr TR0 clr TR1 clr TF0 clr TF1 ; ret ; trigger1: clr EA ; disable interrupts mov TL0,#0 mov TL1,#0 ; mov A,#100 subb A,t0val cpl A inc A mov TH0,A ; load timer 0 ; mov A,#100 subb A,t1val cpl A inc A mov TH1,A ; load timer 1 ; clr TF0 clr TF1 ; setb TR0 ; start timer 0 ; setb TR1 ; start timer 1 ; setb EA ; enable interrupts ; ret ; ;*************************************************************** ; JOB SCHEDULER ;*************************************************************** ; scheduler: lcall dimmer_handler jnb MASTER,slave_sch ; ; MASTER MODE lcall flash_handler ; lcall pump_handler lcall get_scale lcall get_keys ; ; SLAVE MODE ; slave_sch: ret ; ;*************************************************************** ; DIMMER HANDLER ;*************************************************************** ; dimmer_handler: mov A,flash cjne A,#ON,dimmer_hand1 ret ; dimmer_hand1: inc dimmer_ticks jb MASTER,dimmer_hand2 lcall check_ser ; only valid for slave mode dimmer_hand2: mov A,dimmer_ticks cjne A,scale,dimmer_h_end ; mov dimmer_ticks,#0 lcall new_step ; check for light level variation ; jnb MASTER,dimmer_h_end ; inc steps mov A,steps cjne A,#20,dimmer_h_end mov steps,#0 ; inc percent mov A,percent cjne A,#100,dimmer_hand3 ; mov percent,#0 ; dimmer_hand3: lcall events ; check for a new event ; dimmer_h_end: ret ; ;*************************************************************** ; EVENTS REQUESTED BY HOST COMMAND ;*************************************************************** ; check_ser: jnb RI,check_end ; if no byte rec return clr RI ; clear flag mov A,SBUF mov B,#16 div AB mov value,B cjne A,#FIRE_ON+1,check_ser1 ; check command check_ser1: jc exec check_end: ret ; exec: mov B,#3 mul AB mov DPTR,#command_table jmp @A+DPTR ; command_table: ljmp do_choff ljmp do_chon ljmp do_setscale ljmp do_daybreak ljmp do_day ljmp do_sunset ljmp do_night ljmp do_rand ; ; ;*************************************************************** ; CHANNEL OFF ;*************************************************************** ; do_choff: mov A,value ; check value cjne A,#8,do_choff1 do_choff1: jc do_choff2 ret ; do_choff2: cjne a,rand_ch,do_choff3 clr rand_flag do_choff3: mov dptr,#choff_table movc A,@A+DPTR anl P0,A ret ; choff_table: .BYTE 11111110b .BYTE 11111101b .BYTE 11111011b .BYTE 11110111b .BYTE 11101111b .BYTE 11011111b .BYTE 10111111b .BYTE 01111111b ; ;*************************************************************** ; CHANNEL ON ;*************************************************************** ; do_chon: mov A,value ; check value cjne A,#8,do_chon1 do_chon1: jc do_chon2 ret ; do_chon2: cjne A,rand_ch,do_chon3 clr rand_flag do_chon3: mov DPTR,#chon_table movc A,@A+DPTR orl P0,A ret ; chon_table: .BYTE 00000001b .BYTE 00000010b .BYTE 00000100b .BYTE 00001000b .BYTE 00010000b .BYTE 00100000b .BYTE 01000000b .BYTE 10000000b ; ;*************************************************************** ; SET SCALE ;*************************************************************** ; do_setscale: mov A,value ; check value inc A mov B,#2 mul AB ; mov scale,A ; ret ; ;*************************************************************** ; DO DAYBREAK ;*************************************************************** ; do_daybreak: mov dimmer_status,#DAYBREAK_STATE mov t0val,#UP_VALUE ; increase daybreak mov t1val,#DOWN_VALUE ; decrease night clr DAYBREAK setb NIGHT mov dimmer_ticks,#0 ret ; ;*************************************************************** ; DO DAY ;*************************************************************** ; do_day: mov dimmer_status,#DAY_STATE mov t0val,#DOWN_VALUE ; decrease daybreak mov t1val,#UP_VALUE ; increase day setb DAYBREAK clr DAY mov dimmer_ticks,#0 ret ; ;*************************************************************** ; DO SUNSET ;*************************************************************** ; do_sunset: mov dimmer_status,#SUNSET_STATE mov t0val,#UP_VALUE ; increase sunset mov t1val,#DOWN_VALUE ; decrease day clr SUNSET setb DAY mov dimmer_ticks,#0 ret ; ;*************************************************************** ; DO NIGHT ;*************************************************************** ; do_night: mov dimmer_status,#NIGHT_STATE mov t0val,#DOWN_VALUE ; decrease sunset mov t1val,#UP_VALUE ; increase night setb SUNSET clr NIGHT mov dimmer_ticks,#0 ret ; ;*************************************************************** ; DO RAND ;*************************************************************** ; do_rand: mov a,value cjne a,#8,do_rand1 do_rand1: jc do_rand2 ret do_rand2: setb rand_flag mov rand_ch,a ret ; ;*************************************************************** ; EVENTS DURING THE DAYLIGHT CYCLE ;*************************************************************** ; events: mov A,percent cjne A,#START_DAYBREAK,z2off_check ; mov dimmer_status,#DAYBREAK_STATE mov t0val,#UP_VALUE ; increase daybreak mov t1val,#DOWN_VALUE ; decrease night clr DAYBREAK setb NIGHT ret ; z2off_check: cjne A,#ZONE2_OFF,z3off_check ; clr ZONE2 ; zone2 off ret ; z3off_check: cjne A,#ZONE3_OFF,day_check ; clr ZONE3 ; zone3 off ret ; day_check: cjne A,#START_DAY,sunset_check ; mov dimmer_status,#DAY_STATE ; start day mov t0val,#DOWN_VALUE ; decrease daybreak mov t1val,#UP_VALUE ; increase day setb DAYBREAK clr DAY ret ; sunset_check: cjne A,#START_SUNSET,z1on_check ; mov dimmer_status,#SUNSET_STATE ; start sunset mov t0val,#UP_VALUE ; increase sunset mov t1val,#DOWN_VALUE ; decrease day setb DAY clr SUNSET ret z1on_check: cjne A,#ZONE1_ON,night_check ; setb ZONE1 ; zone1 on ret ; night_check: cjne A,#START_NIGHT,z2on_check ; mov dimmer_status,#NIGHT_STATE ; start night mov t0val,#DOWN_VALUE ; decrease sunset mov t1val,#UP_VALUE ; increase night setb SUNSET clr NIGHT ret z2on_check: cjne A,#ZONE2_ON,z3on_check ; setb ZONE2 ; zone2 on ret ; z3on_check: cjne A,#ZONE3_ON,z1off_check ; setb ZONE3 ; zone3 on ret ; z1off_check: cjne A,#ZONE1_OFF,events_end ; clr ZONE1 ; zone1 off ; events_end: ret ; ;*************************************************************** ; NEW STEP - INCR/DECR LIGTH(txval) AND STOP THE VARIATION AT THE ; END - (dimmer_status = DIMMER_OFF) ;*************************************************************** ; new_step: mov A,dimmer_status ; mov B,#3 mul AB mov DPTR,#step_table jmp @A+DPTR ; step_table: ljmp step_off ljmp step_daybreak ljmp step_day ljmp step_sunset ljmp step_night ; step_daybreak: dec t1val inc t0val mov A,t0val cjne A,#TMAX,step_daybreak1 ; mov dimmer_status,#DIMMER_OFF setb DAYBREAK ; daybreak on clr DAY clr SUNSET clr NIGHT ; step_daybreak1: ret ; step_day: dec t0val inc t1val mov A,t1val cjne A,#TMAX,step_day1 ; mov dimmer_status,#DIMMER_OFF setb DAY ; day on clr DAYBREAK clr SUNSET clr NIGHT ; step_day1: ret ; step_sunset: dec t1val inc t0val mov A,t0val cjne A,#TMAX,step_sunset1 ; mov dimmer_status,#DIMMER_OFF setb SUNSET ; sunset on clr DAYBREAK clr DAY clr NIGHT ; step_sunset1: ret ; step_night: dec t0val inc t1val mov A,t1val cjne A,#TMAX,step_night1 ; mov dimmer_status,#DIMMER_OFF setb NIGHT ; night on clr DAYBREAK clr DAY clr SUNSET ; step_night1: step_off: ret ; ;*************************************************************** ; FLASH HANDLER ;*************************************************************** ; flash_handler: mov A,flash cjne A,#ON,flash_off ; inc flash_ticks mov A,flash_ticks cjne A,#FLASH_TICK_MAX,flash_off ; mov flash_ticks,#0 mov A,led_status cjne A,#ON,led_off ; led_on: mov led_status,#OFF setb LED ; led off ret ; led_off: mov led_status,#ON clr LED ; led on ; flash_off: ret ; ;*************************************************************** ; PUMP HANDLER ;*************************************************************** ; pump_handler: inc pump_ticks mov A,pump_ticks cjne A,#100,pump_end ; mov pump_ticks,#0 inc pump_sec mov A,pump_sec cjne A,#60,pump_end ; mov pump_sec,#0 inc pump_min mov A,pump_min cjne A,#PUMP_MAX,pump_check ; mov pump_min,#0 setb PUMP ; pump on ret ; pump_check: cjne A,#PUMP_ON_MAX,pump_end clr PUMP ; pump off ; pump_end: ret ; ;*************************************************************** ; GET KEYS ;*************************************************************** ; get_keys: jb TEST,get_keys1 ; mov A,P0 push ACC ; save dimmer channel status mov P0,#11111111b ; all channel on ; test_on: jnb TEST,test_on pop ACC ; restore dimmer status mov P0,A ; ret ; get_keys1: mov A,stop_status ; mov B,#3 mul AB mov DPTR,#stop_table jmp @A+DPTR ; stop_table: ljmp going ljmp go ljmp stopping ljmp stopped ; going: jnb STOP,key_end mov stop_status,#GO_STATE mov flash,#OFF mov flash_ticks,#0 clr LED ; led on ret ; go: jb STOP,key_end mov stop_status,#STOPPING_STATE mov flash,#ON ret ; stopping: jnb STOP,key_end mov stop_status,#STOPPED_STATE mov flash,#ON ret ; stopped: jb STOP,key_end mov stop_status,#GOING_STATE mov flash,#OFF mov flash_ticks,#0 mov flash,#ON ; key_end: ret ; ;*************************************************************** ; GET TIME SCALE FROM ROTARY SWITCH ;*************************************************************** ; scale_table: .BYTE 2 ; 40 sec .BYTE 4 ; 80 sec .BYTE 6 ; 120 sec .BYTE 8 ; 160 sec .BYTE 10 ; 200 sec .BYTE 12 ; 240 sec .BYTE 14 ; 280 sec .BYTE 16 ; 320 sec .BYTE 18 ; 360 sec .BYTE 20 ; 400 sec ; get_scale: jnb MASTER,get_scale_end ; mov A,P2 ; rrc A ; jc get_scale1 ; ; mov scale,#8 ; ljmp get_scale4 ; ;get_scale1: rrc A ; jc get_scale2 ; ; mov scale,#9 ; ljmp get_scale4 ; get_scale2: mov A,P1 rlc A mov B,#7 scale_loop: rlc A jc get_scale3 ; mov scale,B dec scale ljmp get_scale4 ; get_scale3: djnz B,scale_loop ; mov scale,#0 ; get_scale4: mov DPTR,#scale_table mov A,scale movc A,@A+DPTR mov scale,A ; get_scale_end: ret ; ;*************************************************************** ; TIMER 0 INTERRUPT ;*************************************************************** ; tim0: push ACC ; save registers a push B ; b push DPH ; save dp push DPL ; clr TF0 ; clear int flag clr TR0 ; stop timer 0 mov A,dimmer_status ; mov B,#3 mul AB mov DPTR,#t0_table jmp @A+DPTR ; t0_table: ljmp t0_off ljmp t0_daybreak ljmp t0_day ljmp t0_sunset ljmp t0_night ; t0_daybreak: t0_day : setb DAYBREAK ; negative trigger pulse lcall delay clr DAYBREAK ; ljmp t0_off ; t0_sunset: t0_night: setb SUNSET ; negative trigger pulse lcall delay clr SUNSET ; t0_off: pop DPL ; restore dp pop DPH pop B ; restore b pop ACC ; restore a ; reti ; ;*************************************************************** ; TIMER 1 INTERRUPT ;*************************************************************** ; tim1: push ACC ; save registers a push B ; b push DPH push DPL ; clr TF1 ; clear int flag clr TR1 ; stop timer 0 mov A,dimmer_status ; mov B,#3 mul AB mov DPTR,#t1_table jmp @A+DPTR ; t1_table: ljmp t1_off ljmp t1_daybreak ljmp t1_day ljmp t1_sunset ljmp t1_night ; t1_sunset: t1_day: setb DAY ; negative trigger pulse lcall delay clr DAY ; ljmp t1_off ; t1_daybreak: t1_night: setb NIGHT ; negative trigger pulse lcall delay clr NIGHT ; t1_off: pop DPL ; restore dp pop DPH pop B ; restore b pop ACC ; restore a ; reti ; return from interrupt ; ;*************************************************************** ; TRIGGER PULSE WIDTH DELAY ;*************************************************************** ; delay: mov B,#DELAY_VALUE delay_loop: djnz B,delay_loop ret ; ;*************************************************************** ; RANDOM8 ;*************************************************************** ; rand8: jnb rand_flag,rand8_ex mov A,random jnz rand8b cpl A mov random,A rand8b: anl A,#10111000b mov C,P mov A,random rrc A mov random,A jc set8 reset8: mov A,rand_ch ljmp do_choff3 set8: mov A,rand_ch ljmp do_chon3 ; rand8_ex: ret ; ;*************************************************************** ; PROGRAM END ;*************************************************************** ; .END