;Last change: RLH 17 Apr 2006 6:58 pm ;RELAY & DAC CONTROLLER ;------------------------- ;Robert Hunt January 2006 ;Target device 8031 ;Clock speed 11.0592MHz ;No external RAM ;PORT EQUATES *************************************************************************************************** ;Function Address Port Pin Description select0 EQU 90h ;p1.0 1 (Relay & DAC select address bit 0) select1 EQU 91h ;p1.1 2 (Relay & DAC select address bit 1) select2 EQU 92h ;p1.2 3 (Relay & DAC select address bit 2) relay_data EQU 93h ;p1.3 4 (Data to relay addressable latch. 1 closes relay) relay_latch EQU 94h ;p1.4 5 (Latch for relay addressable latch. Active low) dac_data EQU 95h ;p1.5 6 (Data to all DACs) dac_clk EQU 96h ;p1.6 7 (Clock to all DACs) dac_enable EQU 97h ;p1.7 8 (Enable for DAC /CS demux. Active low. 1 sets all /CS high) Rx EQU B0h ;p3.0 10 (Serial i/p from terminal @ 9600) Tx EQU B1h ;p3.1 11 (Serial o/p to terminal @ 9600) spare1 EQU B2h ;p3.2 12 () spare2 EQU B3h ;p3.3 13 () spare3 EQU B4h ;p3.4 14 () spare4 EQU B5h ;p3.5 15 () ;/wr EQU B6h p3.6 16 (External RAM control) ;/rd EQU B7h p3.7 17 (External RAM control) ;CONSTANT EQUATES *********************************************************************************************** nul EQU 00h ;ASCII NUL character bel EQU 07h ;ASCII BEL character bs EQU 08h ;ASCII BS character cr EQU 0Dh ;ASCII CR character lf EQU 0Ah ;ASCII LF character space EQU 20h ;ASCII space character recall EQU '!' ;Character to recall previous command ;BIT EQUATES (Bit addressable segment 20h to 2Fh) *************************************************************** string_mode EQU 00h ;Tx routine mode select. '1'=string, '0'=single value hex_mode EQU 01h ;Tx routine mode select. '1'=display as hex '0'=raw tx_busy EQU 02h ;Indicates serial tx in progress new_rx EQU 03h ;Indicates new command in rx_buffer equal EQU 04h ;Set by 'compare' subroutine enter EQU 05h ;Set to indicate enter key pressed. Not cleared in ISR com_data_mode EQU 06h ;Set to switch from command mode to data mode ISR comment EQU 07h ;Flag used in RX ISR to indicate comment field bs_to_bs_sp_bs EQU 08h ;Flag set if users terminal only sends BS when deleting cr_to_cr_lf EQU 09h ;Flag set if users terminal only sends CR silent_mode_on EQU 0Ah ;Flag set by silent_on routine to turn of Tx ;BYTE EQUATES (user RAM area 30h to 7fh) ************************************************************************ tx_ptr EQU 30h ;Tx data pointer (code byte relative to DPTR) disp_byte EQU 31h ;Byte to send to terminal temp EQU 32h ;Temporary register low_hex EQU 33h ;Low ASCII hex nibble for hex_to_bin procedure high_hex EQU 34h ;High ASCII hex nibble for hex_to_bin procedure rx_buffer EQU 40h;to 4Fh Base address of rx buffer rx_buf_1_left EQU 4Eh ;Last buffer location available for users command rx_buffer_end EQU 4Fh ;End address of rx buffer rx_buffer_over EQU 50h ;End address + 1 of rx buffer rx_buffer2 EQU 50h;to 5Fh Base address of rx buffer 2 (Double buffering) stack_base EQU 60h;to 7Fh Stack ;REGISTER BANK USAGE********************************************************************************************* ;R0 & R1 can be used for relative addressing ;Bank 0 ;R0 Rx buffer 1 pointer \ DOUBLE ;R1 Rx buffer 2 pointer / BUFFERING ;R2 Pointer for Tx ;R3 Used in program loops as a counter ;Bank 1 ;R0 Not used ;R1 Not used ;EXTERNAL RAM ADDRESS MAP *************************************************************************************** ;Contant RAM Base Address Read Command No. Of Bytes block_0 EQU 0000h ;NOT USED 2 block_1 EQU 0003h ;NOT USED 2 ;MACROS (Address labels do not work in macros) ****************************************************************** ;CAUTION: Changing instructions in these macros may invalidate relative jumps. txwait MACRO ;*************************************************************************************************** ;Note: An interrupt request will not be responded to while ;an interrupt of equal priority is still in progress. JNB scon.1,-3 CLR scon.1 ENDM ORG 00h SJMP start ;INTRRUPT VECTORS *********************************************************************************************** ;Source Vector address Function ;IE0 0003h Ext interrupt 0 ;TF0 000Bh Timer 0 overflow ;IE1 0013h Ext interrupt 1 ;TF1 001Bh Timer 1 overflow ;R1+T1 0023h Rx & Tx complete ;TF2+EXF2 002Bh Timer 2 overflow & ext reload ;INTERRUPT JUMPS ************************************************************************************************ ORG 23h LJMP coms_commands ;MAIN PROGRAM *************************************************************************************************** ORG 30h start: MOV SP,#stack_base ;Set stack pointer. (stack uses internal user RAM) LCALL reset main: JBC new_rx,new_command ;If user pressed enter, clear flag & process command LJMP main new_command: CLR equal ;String compare flag JB tx_busy,-3 ;Wait until the tx int routine is idle (it uses DPTR) test_first: MOV DPTR,#rl0_open_cmd ;Data pointer to start of comparison message LCALL compare JNB equal,test_next1 CLR select0 ;\ CLR select1 ; |Select relay 0 CLR select2 ;/ CLR relay_data ;Relay addressable latch line low to open relay 0 CLR relay_latch ;\ SETB relay_latch ;/Pulse relay addressable latch enable line low LJMP main test_next1: MOV DPTR,#rl0_close_cmd ;Data pointer to start of comparison message LCALL compare JNB equal,test_next2 CLR select0 ;\ CLR select1 ; |Select relay 0 CLR select2 ;/ SETB relay_data ;Relay addressable latch line high to close relay 0 CLR relay_latch ;\ SETB relay_latch ;/Pulse relay addressable latch enable line low LJMP main test_next2: MOV DPTR,#rl1_open_cmd ;Data pointer to start of comparison message LCALL compare JNB equal,test_next3 SETB select0 ;\ CLR select1 ; |Select relay 1 CLR select2 ;/ CLR relay_data ;Relay addressable latch line low to open relay 1 CLR relay_latch ;\ SETB relay_latch ;/Pulse relay addressable latch enable line low LJMP main test_next3: MOV DPTR,#rl1_close_cmd ;Data pointer to start of comparison message LCALL compare JNB equal,test_next4 SETB select0 ;\ CLR select1 ; |Select relay 1 CLR select2 ;/ SETB relay_data ;Relay addressable latch line high to close relay 1 CLR relay_latch ;\ SETB relay_latch ;/Pulse relay addressable latch enable line low LJMP main test_next4: MOV DPTR,#rl2_open_cmd ;Data pointer to start of comparison message LCALL compare JNB equal,test_next5 CLR select0 ;\ SETB select1 ; |Select relay 2 CLR select2 ;/ CLR relay_data ;Relay addressable latch line low to open relay 2 CLR relay_latch ;\ SETB relay_latch ;/Pulse relay addressable latch enable line low LJMP main test_next5: MOV DPTR,#rl2_close_cmd ;Data pointer to start of comparison message LCALL compare JNB equal,test_next6 CLR select0 ;\ SETB select1 ; |Select relay 2 CLR select2 ;/ SETB relay_data ;Relay addressable latch line high to close relay 2 CLR relay_latch ;\ SETB relay_latch ;/Pulse relay addressable latch enable line low LJMP main test_next6: MOV DPTR,#rl3_open_cmd ;Data pointer to start of comparison message LCALL compare JNB equal,test_next7 SETB select0 ;\ SETB select1 ; |Select relay 3 CLR select2 ;/ CLR relay_data ;Relay addressable latch line low to open relay 3 CLR relay_latch ;\ SETB relay_latch ;/Pulse relay addressable latch enable line low LJMP main test_next7: MOV DPTR,#rl3_close_cmd ;Data pointer to start of comparison message LCALL compare JNB equal,test_next8 SETB select0 ;\ SETB select1 ; |Select relay 3 CLR select2 ;/ SETB relay_data ;Relay addressable latch line high to close relay 3 CLR relay_latch ;\ SETB relay_latch ;/Pulse relay addressable latch enable line low LJMP main test_next8: MOV DPTR,#rl4_open_cmd ;Data pointer to start of comparison message LCALL compare JNB equal,test_next9 CLR select0 ;\ CLR select1 ; |Select relay 4 SETB select2 ;/ CLR relay_data ;Relay addressable latch line low to open relay 4 CLR relay_latch ;\ SETB relay_latch ;/Pulse relay addressable latch enable line low LJMP main test_next9: MOV DPTR,#rl4_close_cmd ;Data pointer to start of comparison message LCALL compare JNB equal,test_next10 CLR select0 ;\ CLR select1 ; |Select relay 4 SETB select2 ;/ SETB relay_data ;Relay addressable latch line high to close relay 4 CLR relay_latch ;\ SETB relay_latch ;/Pulse relay addressable latch enable line low LJMP main test_next10: MOV DPTR,#rl5_open_cmd ;Data pointer to start of comparison message LCALL compare JNB equal,test_next11 SETB select0 ;\ CLR select1 ; |Select relay 5 SETB select2 ;/ CLR relay_data ;Relay addressable latch line low to open relay 5 CLR relay_latch ;\ SETB relay_latch ;/Pulse relay addressable latch enable line low LJMP main test_next11: MOV DPTR,#rl5_close_cmd ;Data pointer to start of comparison message LCALL compare JNB equal,test_next12 SETB select0 ;\ CLR select1 ; |Select relay 5 SETB select2 ;/ SETB relay_data ;Relay addressable latch line high to close relay 5 CLR relay_latch ;\ SETB relay_latch ;/Pulse relay addressable latch enable line low LJMP main test_next12: MOV DPTR,#rl6_open_cmd ;Data pointer to start of comparison message LCALL compare JNB equal,test_next13 CLR select0 ;\ SETB select1 ; |Select relay 6 SETB select2 ;/ CLR relay_data ;Relay addressable latch line low to open relay 6 CLR relay_latch ;\ SETB relay_latch ;/Pulse relay addressable latch enable line low LJMP main test_next13: MOV DPTR,#rl6_close_cmd ;Data pointer to start of comparison message LCALL compare JNB equal,test_next14 CLR select0 ;\ SETB select1 ; |Select relay 6 SETB select2 ;/ SETB relay_data ;Relay addressable latch line high to close relay 6 CLR relay_latch ;\ SETB relay_latch ;/Pulse relay addressable latch enable line low LJMP main test_next14: MOV DPTR,#rl7_open_cmd ;Data pointer to start of comparison message LCALL compare JNB equal,test_next15 SETB select0 ;\ SETB select1 ; |Select relay 7 SETB select2 ;/ CLR relay_data ;Relay addressable latch line low to open relay 7 CLR relay_latch ;\ SETB relay_latch ;/Pulse relay addressable latch enable line low LJMP main test_next15: MOV DPTR,#rl7_close_cmd ;Data pointer to start of comparison message LCALL compare JNB equal,test_next16 SETB select0 ;\ SETB select1 ; |Select relay 7 SETB select2 ;/ SETB relay_data ;Relay addressable latch line high to close relay 7 CLR relay_latch ;\ SETB relay_latch ;/Pulse relay addressable latch enable line low LJMP main test_next16: MOV DPTR,#dac0_load_cmd ;Data pointer to start of comparison message LCALL compare JNB equal,test_next17 CLR select0 ;\ CLR select1 ; |Select DAC 0 CLR select2 ;/ LCALL dac_load LJMP main test_next17: MOV DPTR,#dac1_load_cmd ;Data pointer to start of comparison message LCALL compare JNB equal,test_next18 SETB select0 ;\ CLR select1 ; |Select DAC 1 CLR select2 ;/ LCALL dac_load LJMP main test_next18: MOV DPTR,#dac2_load_cmd ;Data pointer to start of comparison message LCALL compare JNB equal,test_next19 CLR select0 ;\ SETB select1 ; |Select DAC 2 CLR select2 ;/ LCALL dac_load LJMP main test_next19: MOV DPTR,#dac3_load_cmd ;Data pointer to start of comparison message LCALL compare JNB equal,test_next20 SETB select0 ;\ SETB select1 ; |Select DAC 3 CLR select2 ;/ LCALL dac_load LJMP main test_next20: MOV DPTR,#dac4_load_cmd ;Data pointer to start of comparison message LCALL compare JNB equal,test_next21 CLR select0 ;\ CLR select1 ; |Select DAC 4 SETB select2 ;/ LCALL dac_load LJMP main test_next21: MOV DPTR,#dac5_load_cmd ;Data pointer to start of comparison message LCALL compare JNB equal,test_next22 SETB select0 ;\ CLR select1 ; |Select DAC 5 SETB select2 ;/ LCALL dac_load LJMP main test_next22: MOV DPTR,#dac6_load_cmd ;Data pointer to start of comparison message LCALL compare JNB equal,test_next23 CLR select0 ;\ SETB select1 ; |Select DAC 6 SETB select2 ;/ LCALL dac_load LJMP main test_next23: MOV DPTR,#dac7_load_cmd ;Data pointer to start of comparison message LCALL compare JNB equal,test_next101 SETB select0 ;\ SETB select1 ; |Select DAC 7 SETB select2 ;/ LCALL dac_load LJMP main test_next101: MOV DPTR,#bsexpand_cmd ;Data pointer to start of comparison message LCALL compare JNB equal,test_next102 LCALL bs_expand_on LJMP main test_next102: MOV DPTR,#talk_cmd ;Data pointer to start of comparison message LCALL compare JNB equal,test_next103 LCALL talk_mode LJMP main test_next103: MOV DPTR,#help_cmd ;Data pointer to start of comparison message LCALL compare JNB equal,test_next104 LCALL help LJMP main test_next104: MOV DPTR,#reset_cmd ;Data pointer to start of comparison message LCALL compare JNB equal,test_next105 LJMP start LJMP main test_next105: MOV DPTR,#cr_expoff_cmd ;Data pointer to start of comparison message LCALL compare JNB equal,unknown LJMP cr_expand_off LJMP main unknown: LCALL typo ;Entry does not match any command LJMP main ;INTERRUPT SERVICE ROUTINE - Serial ports. Command entry mode *************************************************** coms_commands: PUSH PSW PUSH A PUSH B PUSH DPL PUSH DPH JNB SCON.1,not_tx ;\Jump to tx if tx complete interrupt flag set AJMP tx ;/ not_tx: JB SCON.0,rx ;\Exit interrupt routine if receive flag not set AJMP end_int ;/ ;RS232 RECEPTION ************************************************************************************************ rx: CLR SCON.0 ;Clear receive interrupt flag JNB new_rx,idle ;\Exit ISR if still processing previous command AJMP end_int ;/ idle: MOV A,SBUF ;Store new key press in Acc CJNE A,#cr,not_cr ;\ If CR key pressed SETB enter ; | Set enter key pressed flag CLR comment ; | Clear the comment flag CJNE R0,#rx_buffer,not_empty1 ; | If user has not typed text do not set new_rx flag SJMP empty ; | and don't send a new prompt yet not_empty1 MOV @R0,#nul ; | mark end of user command, PUSH tx_ptr ;\ MOV DPTR,#silent_cmd ; | MOV R0,#rx_buffer ; | MOV tx_ptr,#0 ; | next_s: MOV A,tx_ptr ; | MOVC A,@A+DPTR ; | If the command is for silent mode, select MOV B,@R0 ; | that mode now to stop Tx of the prompt CJNE A,B,not_silent_cmd ; | and exit the interrupt routine. INC R0 ; | INC tx_ptr ; | JNZ next_s ; | SETB silent_mode_on ; | MOV R0,#rx_buffer ; | POP tx_ptr ; | AJMP end_int ; | not_silent_cmd: POP tx_ptr ;/ SETB new_rx ; | set new command received flag, MOV R0,#rx_buffer ;\ MOV R1,#rx_buffer2 ; | next_copy: MOV A,@R0 ; | DOUBLE BUFFER COPY MOV @R1,A ; | INC R0 ; | Copy Rx buffer 1 to Rx buffer 2 INC R1 ; | CJNE R0,#rx_buffer_over,next_copy ;/ MOV R0,#rx_buffer ; | reset rx buffer pointer MOV R1,#rx_buffer2 ; | reset rx buffer 2 pointer AJMP end_int ; | and exit interrupt routine. empty: JNB silent_mode_on,no_tx1 ; | Exit ISR if silent mode is on AJMP end_int ; | no_tx1: JNB tx_busy,no_tx2 ; | exit ISR if tx is already in progress, AJMP end_int ; | no_tx2: MOV SBUF,#cr ; | send CR, txwait ; | wait until serial tx is complete, MOV SBUF,#lf ; | send LF, txwait ; | wait until serial tx is complete MOV SBUF,#'-' ; | send '-', txwait ; | wait until serial tx is complete, MOV SBUF,#'>' ; | send '>', txwait ; | wait until serial tx is complete AJMP end_int ;/ and exit interrupt routine. not_cr: JNB comment,not_comment2 ;\ AJMP end_int ;/ Exit if a comment field is in progress. not_comment2: CJNE A,#';',not_semicolon ;\ If a semicolon has been sent it is the SETB comment ; | start of a comment. The comment will end AJMP end_int ;/ with a CR. not_semicolon: CJNE A,#bs,not_bs ;\ If BS key pressed, CJNE R0,#rx_buffer,not_empty2 ; | check if rx buffer empty. AJMP end_int ; | If so, prevent rx buffer underflow. not_empty2: DEC R0 ; | Decrement rx buffer pointer, JNB silent_mode_on,no_tx3 ; | Exit ISR if silent mode is on AJMP end_int ; | no_tx3: JNB tx_busy,no_tx4 ; | exit ISR if tx is already in progress, AJMP end_int ; | no_tx4: MOV SBUF,#bs ; | backspace cursor, txwait ; | wait until serial tx is complete, JB bs_to_bs_sp_bs,space_bs ; | Continue if terminal only sends a BS AJMP end_int ; | End if terminal sends BS,SP,BS space_bs MOV SBUF,#space ; | delete character at cursor, txwait ; | wait until serial tx is complete MOV SBUF,#bs ; | backspace cursor, txwait ; | wait until serial tx is complete, AJMP end_int ;/ and exit interrupt routine. not_bs: JB A.5,greater1fh ;\ JB A.6,greater1fh ; | Exit ISR if any other JB A.7,greater1fh ; | control character sent. AJMP end_int ;/ greater1fh: CJNE A,#lf,not_lf ;\ Exit ISR if LF sent. Otherwise command AJMP end_int ;/ LOAD PID cr/lf could write a lf to RAM. not_lf: CJNE R0,#rx_buf_1_left,not_full ;Check if rx buffer is full. AJMP end_int not_full: CJNE R0,#rx_buffer,not_recall ;Check if rx buffer was empty. CJNE A,#recall,not_recall ;Check if recall key was pressed. MOV B,R1 ;\ buffer_recall: MOV R0,#rx_buffer ; | MOV R1,#rx_buffer2 ; | next_rcopy: MOV A,@R1 ; | DOUBLE BUFFER REVERSE COPY MOV @R0,A ; | INC R0 ; | Copy Rx buffer 2 to Rx buffer 1 INC R1 ; | CJNE R0,#rx_buffer_over,next_rcopy ; | MOV R1,B ;/ MOV R0,#rx_buffer ;\ next_char: JB silent_mode_on,silent_recall ; | Exit ISR if silent mode is on JNB tx_busy,no_tx5 ; | SJMP silent_recall ; | Recall previous no_tx5: MOV SBUF,@R0 ; | user command txwait ; | to display silent_recall: INC R0 ; | CJNE @R0,#nul,next_char ;/ SJMP end_int not_recall: MOV @R0,A ;Store new key press in rx buffer INC R0 ;Point to next buffer location JB silent_mode_on,end_int ;Exit ISR if silent mode is on JB tx_busy,end_int ;Check if tx is already in progress MOV SBUF,A ;Echo users key press txwait ;Wait until serial transmission is complete SJMP end_int ;RS232 TRANSMISSION ********************************************************************************************* tx: CLR SCON.1 ;clear transmit complete int flag JB silent_mode_on,mes_end ;Exit ISR if silent mode is on JB string_mode,display_string JB hex_mode,display_hex ;BYTE MODE TRANSMISSION ***************************************************************************************** ;Take byte in disp_byte and send to display. MOV SBUF,disp_byte ;Send digit txwait ;Wait until serial transmission is complete SJMP end_int ;HEX MODE TRANSMISSION ****************************************************************************************** ;Take byte in disp_byte and send it as ASCII hex display_hex: MOV A,disp_byte ANL A,#F0h ;\ SWAP A ;/ Isolate the most significant nibble ADD A,#30h MOV B,A CLR C ;\ SUBB A,#3Ah ; | Test if the digit is greater than 9 MOV A,B ; | JC h_less_than_f ;/ ADD A,#07h h_less_than_f: MOV SBUF,A ;Send digit to display txwait ;Wait until serial transmission is complete MOV A,disp_byte ANL A,#0Fh ;Isolate the least significant nibble ADD A,#30h MOV B,A CLR C ;\ SUBB A,#3Ah ; | Test if the digit is greater than 9 MOV A,B ; | JC l_less_than_f ;/ ADD A,#07h l_less_than_f: MOV SBUF,A ;Send digit to display txwait ;Wait until serial transmission is complete SJMP end_int ;STRING MODE TRANSMISSION *************************************************************************************** display_string: SETB tx_busy ;Set busy flag. MOV A,tx_ptr ;ACC points to message relative to DPTR INC tx_ptr ;Increment for next character MOVC A,@A+DPTR JZ mes_end ;Exit if end of message (ACC=0) MOV SBUF,A ;Send character SJMP end_int mes_end: CLR tx_busy ;Clear busy flag end_int: POP DPH POP DPL POP B POP A POP PSW RETI ;PROCEDURE - Compare command string ***************************************************************************** ;DPTR should be preloaded to point to the library command. not_equal should be precleared compare: MOV tx_ptr,#0 MOV R1,#rx_buffer2 ;Start address of input buffer to R1 next: MOV A,tx_ptr ;ACC points to command relative to DPTR MOVC A,@A+DPTR ;Character of library command to ACC CJNE A,#'?',chr_test ;Test for don't care character INC R1 ;\? in command so increment pointers INC tx_ptr ;/and skip compare JNZ next ;If not at the end of the command, test next char SETB equal ;Was at end of command SJMP end_sub chr_test: MOV B,@R1 ;Character from input buffer to B reg CJNE A,B,end_sub ;Compare character of test message with typed message INC R1 ;\ INC tx_ptr ;/Increment pointers JNZ next ;If not at the end of the test message test next character SETB equal end_sub: RET ;PROCEDURE - Convert ASCII hex to binary ************************************************************************ ;Takes ASCII hex from high_hex and low_hex and returns the binary result in ACC hex_to_bin: MOV A,high_hex ;\ ADD A,#194 ;| JC a_to_f1 ;| MOV A,high_hex ;| CLR C ;|Convert high nibble and multiply by 16 SUBB A,#48 ;|to give the correct magnitude. SJMP low_nibble ;| a_to_f1: MOV A,high_hex ;| CLR C ;| SUBB A,#55 ;| low_nibble: MOV B,#16 ;/ MUL AB ;ACC now has high nibble with correct magnitude MOV B,A ;Temporarily store high nibble in B reg MOV A,low_hex ;\ ADD A,#194 ;| JC a_to_f2 ;| MOV A,low_hex ;| CLR C ;|Convert the low nibble SUBB A,#48 ;| SJMP end_conv ;| a_to_f2: MOV A,low_hex ;| CLR C ;| SUBB A,#55 ;/ end_conv: ADD A,B ;ACC now contains the binary result RET ;PROCEDURE - Load a DAC with the last four ASCII hex characters of the latest instruction received ************** ;The compare procedure must have been called so that R1 points one place after the received instruction. ;Value in dac_select determins which DAC is loaded. dac_select should be pre-loaded. dac_load: MOV R1,#rx_buffer2 ;Start address of input buffer to R1 INC R1 INC R1 INC R1 INC R1 INC R1 ;Now points to MS nibble MOV high_hex,@R1 INC R1 ;Now points to LS nibble MOV low_hex,@R1 LCALL hex_to_bin ;High byte returned in ACC CLR dac_enable ;Enable selected DAC MOV R3,#8 ;Loop counter shift_out_h: RLC A ;Shift out MSB first MOV dac_data,C ;Data to DAC SETB dac_clk ;\Pulse the DAC clock line CLR dac_clk ;/Rising edge clock DJNZ R3,shift_out_h ;Repeat until all 8 bits have been shifted out INC R1 ;\ MOV high_hex,@R1 ;| INC R1 ;| MOV low_hex,@R1 ;| LCALL hex_to_bin ;| CLR dac_enable ;|Convert and shift out the low byte MOV R3,#8 ;|Same as the routine above shift_out_l: RLC A ;| MOV dac_data,C ;| SETB dac_clk ;| CLR dac_clk ;| DJNZ R3,shift_out_l ;/ SETB dac_enable ;Enable line high - DAC updates. RET ;PROCEDURE - Power up reset ************************************************************************************* reset: MOV IE,#00h ;Disable all interrupts SETB Rx ;Configure as an input pin CLR select0 ;\ CLR select1 ; |Relay / DAC select to known state CLR select2 ;/ CLR relay_data ;Relay latch data line to known state SETB relay_latch ;Disable relay latch (memory mode) SETB dac_enable ;Disable DACs CLR dac_clk ;DAC clock line low CLR PSW.3 ;\ CLR PSW.4 ;/Select register bank 0 MOV TMOD,#21h ;Timer 0 mode 1. Timer 1, 8 bit auto reload (mode 2) MOV TH1,#FDh ;Load timer 1 for 9600 baud. (Timer rate ck/12) MOV SCON,#70h ;8 bit UART, baud rate from timer 1, rx enabled MOV TCON,#40h ;Run timer 1. Disable timer 0 CLR com_data_mode ;Select command mode serial ports ISR CLR silent_mode_on ;Flag used to allow high speed control from a file CLR new_rx ;Clear new command received flag CLR enter ;Clear enter key pressed flag CLR bs_to_bs_sp_bs ;Flag set if users terminal only sends BS when deleting SETB cr_to_cr_lf ;Flag set if users terminal only sends CR CLR tx_busy ;Clear tx busy flag MOV R0,#rx_buffer ;Reset rx buffer pointer MOV @R0,#nul ;Mark rx buffer as empty MOV R1,#rx_buffer2 ;Reset rx buffer 2 pointer MOV @R1,#nul ;Mark rx buffer 2 as empty CLR comment ;Flag used in RX ISR to indicate comment field MOV IP,#0 ;Configure interrupt priority. Note: An interrupt ;request will not be responded to while an interrupt ;of equal priority is still in progress CLR hex_mode ;Set single byte mode to display raw byte in ISR MOV IE,#90h ;Serial port interrupts on JB tx_busy,-3 ;Wait until the tx int routine is idle SETB string_mode ;Select string tx mode in int routine MOV DPTR,#reset_message ;Data pointer to start of message MOV tx_ptr,#0 ;Reset message pointer to start of message SETB SCON.1 ;Initiate serial tx interrupt RET ;PROCEDURE - Send help text ************************************************************************************* help: JB tx_busy,-3 ;Wait until the tx int routine is idle SETB string_mode ;Select string tx mode in int routine MOV DPTR,#help_message1a ;Data pointer to start of message MOV tx_ptr,#0 ;Reset message pointer to start of message SETB SCON.1 ;Initiate serial tx interrupt NOP ;Allow time for interrupt to occur JB tx_busy,-3 ;Wait until the tx int routine is idle SETB string_mode ;Select string tx mode in int routine MOV DPTR,#help_message2a ;Data pointer to start of message MOV tx_ptr,#0 ;Reset message pointer to start of message SETB SCON.1 ;Initiate serial tx interrupt NOP ;Allow time for interrupt to occur JB tx_busy,-3 ;Wait until the tx int routine is idle SETB string_mode ;Select string tx mode in int routine MOV DPTR,#help_message3a ;Data pointer to start of message MOV tx_ptr,#0 ;Reset message pointer to start of message SETB SCON.1 ;Initiate serial tx interrupt NOP ;Allow time for interrupt to occur JB tx_busy,-3 ;Wait until the tx int routine is idle SETB string_mode ;Select string tx mode in int routine MOV DPTR,#help_message4a ;Data pointer to start of message MOV tx_ptr,#0 ;Reset message pointer to start of message SETB SCON.1 ;Initiate serial tx interrupt NOP ;Allow time for interrupt to occur JB tx_busy,-3 ;Wait until the tx int routine is idle SETB string_mode ;Select string tx mode in int routine MOV DPTR,#help_message5a ;Data pointer to start of message MOV tx_ptr,#0 ;Reset message pointer to start of message SETB SCON.1 ;Initiate serial tx interrupt CLR enter ;Clear enter key pressed flag wait_for_enter: JNB enter,wait_for_enter ;If user pressed enter, clear flag & continue JB tx_busy,-3 ;Wait until the tx int routine is idle SETB string_mode ;Select string tx mode in int routine MOV DPTR,#help_message1b ;Data pointer to start of message MOV tx_ptr,#0 ;Reset message pointer to start of message SETB SCON.1 ;Initiate serial tx interrupt NOP ;Allow time for interrupt to occur JB tx_busy,-3 ;Wait until the tx int routine is idle SETB string_mode ;Select string tx mode in int routine MOV DPTR,#help_message2b ;Data pointer to start of message MOV tx_ptr,#0 ;Reset message pointer to start of message SETB SCON.1 ;Initiate serial tx interrupt NOP ;Allow time for interrupt to occur JB tx_busy,-3 ;Wait until the tx int routine is idle SETB string_mode ;Select string tx mode in int routine MOV DPTR,#help_message3b ;Data pointer to start of message MOV tx_ptr,#0 ;Reset message pointer to start of message SETB SCON.1 ;Initiate serial tx interrupt NOP ;Allow time for interrupt to occur JB tx_busy,-3 ;Wait until the tx int routine is idle SETB string_mode ;Select string tx mode in int routine MOV DPTR,#help_message4b ;Data pointer to start of message MOV tx_ptr,#0 ;Reset message pointer to start of message SETB SCON.1 ;Initiate serial tx interrupt CLR enter ;Clear enter key pressed flag wait_for_entr1: JNB enter,wait_for_entr1 ;If user pressed enter, clear flag & continue JB tx_busy,-3 ;Wait until the tx int routine is idle SETB string_mode ;Select string tx mode in int routine MOV DPTR,#help_message1c ;Data pointer to start of message MOV tx_ptr,#0 ;Reset message pointer to start of message SETB SCON.1 ;Initiate serial tx interrupt NOP ;Allow time for interrupt to occur JB tx_busy,-3 ;Wait until the tx int routine is idle SETB string_mode ;Select string tx mode in int routine MOV DPTR,#help_message2c ;Data pointer to start of message MOV tx_ptr,#0 ;Reset message pointer to start of message SETB SCON.1 ;Initiate serial tx interrupt NOP ;Allow time for interrupt to occur JB tx_busy,-3 ;Wait until the tx int routine is idle SETB string_mode ;Select string tx mode in int routine MOV DPTR,#help_message3c ;Data pointer to start of message MOV tx_ptr,#0 ;Reset message pointer to start of message SETB SCON.1 ;Initiate serial tx interrupt NOP ;Allow time for interrupt to occur JB tx_busy,-3 ;Wait until the tx int routine is idle SETB string_mode ;Select string tx mode in int routine MOV DPTR,#help_message4c ;Data pointer to start of message MOV tx_ptr,#0 ;Reset message pointer to start of message SETB SCON.1 ;Initiate serial tx interrupt NOP ;Allow time for interrupt to occur JB tx_busy,-3 ;Wait until the tx int routine is idle SETB string_mode ;Select string tx mode in int routine MOV DPTR,#help_message5c ;Data pointer to start of message MOV tx_ptr,#0 ;Reset message pointer to start of message SETB SCON.1 ;Initiate serial tx interrupt RET ;PROCEDURE - Send unrecognised command error message ************************************************************ typo: JB tx_busy,-3 ;Wait until the tx int routine is idle SETB string_mode ;Select string tx mode in int routine MOV DPTR,#typo_message ;Data pointer to start of message MOV tx_ptr,#0 ;Reset message pointer to start of message SETB SCON.1 ;Initiate serial tx interrupt RET ;PROCEDURE - Enable conversion of BS to BS,SP,BS **************************************************************** bs_expand_on: SETB bs_to_bs_sp_bs ;Flag set (users terminal only sends BS when deleting) JB tx_busy,-3 ;Wait until the tx int routine is idle SETB string_mode ;Select string tx mode in int routine MOV DPTR,#bs_expand_msg ;Data pointer to start of message MOV tx_ptr,#0 ;Reset message pointer to start of message SETB SCON.1 ;Initiate serial tx interrupt RET ;PROCEDURE - Turn Tx back on ************************************************************************************ talk_mode: CLR silent_mode_on ;Flag cleared JB tx_busy,-3 ;Wait until the tx int routine is idle SETB string_mode ;Select string tx mode in int routine MOV DPTR,#prompt ;Data pointer to start of message MOV tx_ptr,#0 ;Reset message pointer to start of message SETB SCON.1 ;Initiate serial tx interrupt RET ;PROCEDURE - Disable conversion of CR to CR,LF ****************************************************************** cr_expand_off: CLR bs_to_bs_sp_bs ;Flag cleared (users terminal sends CR,LF JB tx_busy,-3 ;Wait until the tx int routine is idle SETB string_mode ;Select string tx mode in int routine MOV DPTR,#cr_expoff_msg ;Data pointer to start of message MOV tx_ptr,#0 ;Reset message pointer to start of message SETB SCON.1 ;Initiate serial tx interrupt RET ;MESSAGE STORE - Note messages can not be longer than 256 bytes ************************************************* reset_message: db cr,lf,cr,lf,'RELAY & DAC CONTROLLER',cr,lf db 'ROBERT HUNT JANUARY 2006',cr,lf,cr,lf db 'Type HELP for help.' db bel,cr,lf,cr,lf,'->',nul help_message1a: db cr,lf,cr,lf,'RELAY & DAC CONTROLLER HELP',cr,lf db '---------------------------',cr,lf,cr,lf db 'INTRODUCTION',cr,lf,cr,lf,nul help_message2a: db 'This unit is designed for use as general purpose Automatic Test Equipment',cr,lf db '(ATE). It can be used with Windows Terminal or an equivalent terminal',cr,lf db 'emulation program. This mode of operation is mainly only of interest for',cr,lf,nul help_message3a: db 'test purposes. Its full power and flexability is realised when it is driven',cr,lf db 'by a computer program. Combinimg this unit with a multimeter with GPIB or',cr,lf db 'other communication capability gives a cheap and flexable ATE system.',cr,lf,cr,lf,nul help_message4a: db 'This unit contains 8 double pole clean contacts and 8 16 bit DAC outputs.',cr,lf db 'Each of the 8 contact pairs can be opened and closed with simple ASCII',cr,lf db 'commands. The DACs are unipolar. Each can be loaded with a 4 character',cr,lf,nul help_message5a: db 'ASCII hex word from 0000 to FFFF.',cr,lf,cr,lf db ' PRESS ENTER TO CONTINUE',cr,lf,nul help_message1b: db bs,bs,'COMMUNICATION SETTINGS',cr,lf,cr,lf db 'Terminal emulation: VT-100',cr,lf db 'Local echo: off',cr,lf,nul help_message2b: db 'CR->CR/LF: off',cr,lf db 'Baud rate: 9600',cr,lf db 'Data bits: 8',cr,lf db 'Stop bits: 1',cr,lf db 'Parity: none',cr,lf db 'Flow control: none',cr,lf db 'Caps Lock: on',cr,lf,cr,lf,nul help_message3b: db 'COMMANDS',cr,lf,cr,lf db 'HELP Displays this help text.',cr,lf db 'RESET Restarts the relay and DAC controller.',cr,lf,nul help_message4b: db 'RLn OPEN Where n is from 0 to 7, opens the associated relay contact',cr,lf db ' pair.',cr,lf,cr,lf db ' PRESS ENTER TO CONTINUE',cr,lf,nul help_message1c: db bs,bs,'RLn CLOSE Where n is from 0 to 7, closes the associated relay contact.',cr,lf db ' pair.',cr,lf db 'DACn hhhh Where n is from 0 to 7, loads the associated DAC with value hhhh.',cr,lf,nul help_message2c: db ' hhhh must be an ASCII hexadecimal value from 0000 to FFFF and',cr,lf db ' must always consist of 4 characters. A value of 0000 sets the',cr,lf db ' output to 0V. FFFF sets it to full scale.',cr,lf,nul help_message3c: db 'BS EXP ON If your terminal only sends one BS character type BSEXPAND to',cr,lf db ' enable the expansion of BS to BS, SP, BS.',cr,lf,nul db 'CR EXP OFF Windows 3.1 Terminal removes LFs during text file transmission.',cr,lf,nul help_message4c: db ' If your terminal program does not do this, use this command.',cr,lf db 'SILENT Turns off character echo and all messages.',cr,lf db 'TALK Turns on character echo and all messages.',cr,lf,nul help_message5c: db ' Delete a character which has been typed.',cr,lf db ' Executes a command.',cr,lf db '<',recall,'> Recalls the previous command.',cr,lf db cr,lf,'->',nul typo_message: db bel,cr,lf,'< UNRECOGNISED COMMAND >',cr,lf,cr,lf,'->',nul prompt: db cr,lf,cr,lf,'->',nul bs_expand_msg: db cr,lf,'< BS EXPANSION IS ON >',cr,lf,cr,lf,'->',nul cr_expoff_msg: db cr,lf,'< CR EXPANSION IS OFF >',cr,lf,cr,lf,'->',nul ;COMMAND STORE ************************************************************************************************** ;Question marks are don't cares. Compare will pass whatever they are. help_cmd: db 'HELP',nul reset_cmd: db 'RESET',nul rl0_open_cmd: db 'RL0 OPEN',nul rl0_close_cmd: db 'RL0 CLOSE',nul rl1_open_cmd: db 'RL1 OPEN',nul rl1_close_cmd: db 'RL1 CLOSE',nul rl2_open_cmd: db 'RL2 OPEN',nul rl2_close_cmd: db 'RL2 CLOSE',nul rl3_open_cmd: db 'RL3 OPEN',nul rl3_close_cmd: db 'RL3 CLOSE',nul rl4_open_cmd: db 'RL4 OPEN',nul rl4_close_cmd: db 'RL4 CLOSE',nul rl5_open_cmd: db 'RL5 OPEN',nul rl5_close_cmd: db 'RL5 CLOSE',nul rl6_open_cmd: db 'RL6 OPEN',nul rl6_close_cmd: db 'RL6 CLOSE',nul rl7_open_cmd: db 'RL7 OPEN',nul rl7_close_cmd: db 'RL7 CLOSE',nul dac0_load_cmd: db 'DAC0 ????',nul dac1_load_cmd: db 'DAC1 ????',nul dac2_load_cmd: db 'DAC2 ????',nul dac3_load_cmd: db 'DAC3 ????',nul dac4_load_cmd: db 'DAC4 ????',nul dac5_load_cmd: db 'DAC5 ????',nul dac6_load_cmd: db 'DAC6 ????',nul dac7_load_cmd: db 'DAC7 ????',nul bsexpand_cmd: db 'BSEXPAND',nul silent_cmd: db 'SILENT',nul talk_cmd: db 'TALK',nul cr_expoff_cmd: db 'CREXPAND OFF',nul ;END ***********************************************************************************************************