* MORSE CODE TEACHING PROGRAM * * COPYRIGHT (C) 1978, HOWARD CUNNINGHAM, WAYNE DOWNER. * COPYRIGHT (C) 1980, HOWARD CUNNINGHAM, WAYNE DOWNER. * * THIS PROGRAM WILL INSTRUCT A STUDENT IN RECEIVING * INTERNATIONAL MORSE CODE. IT IS EXPECTED THAT * A STUDENT WITH NO PRIOR EXPERIANCE WILL BE ABLE TO * COPY CODE AT A RATE OF EIGHT TO TEN WORDS PER * MINUTE AFTER ONLY SIX SESSIONS WITH THE PROGRAM. * * FOR A COMPLETE DISCUSSION REFER TO "A FULLY AUTOMATIC * MORSE CODE TEACHING MACHINE", HOWARD CUNNINGHAM, * QST, NEWINGTON, CONN (MAY 1977). * REVISION HISTORY * * 07/15/78 INITIAL VERSION ADAPTED FROM EARLY * 6800 VERSION, HOWARD CUNNINGHAM. * 07/17/78 SERIAL IO DRIVERS, WAYNE DOWNER. * 07/24/78 DOUBLE WEIGHT RESPONSES IF GOOD AVERAGE * ADDED, HOWARD CUNNINGHAM. * 10/10/78 LOWER CASE CONVERTED TO UPPER CASE ON * INPUT, HOWARD CUNNINGHAM. * 01/22/80 CORRECTED: MORSE CHARACTER FOR "SIX" AND CONSTANT * FOR DETERMINING WHEN THE FULL ALPHABET HAS BEEN * REACHED, WAYNE DOWNER. * 02/03/80 ADDED PARALLEL ASCII OUT AND A CORRECT RESPONCE * INPUT, WAYNE DOWNER. * 02/22/80 CONVERTED PARALLEL ASCII OUT TO 5X7 MATRIX * SCAN, CORRECTED: RESPONCE WAIT LOCKUP,CHARACTER * SELECT LOCKUP, AND PAUSE FOR ROOM ECHO, * WAYNE DOWNER. SPC 4 * ASSEMBLY CONSTANTS FREQ EQU 333 CYCLES PER MSEC WPM EQU 15 SENDING SPEED R2 EQU 2 POINTER TO R2 REGISTER SPC 4 * REGISTER ASSIGNMENTS * * BANK 0 * * R0 (SCRATCH) * R1 STACK POINTER (POST DECREMENT ON PUSH) * R2 RESPONSE WAIT TIME IN SEC/50 * R3 PRINT COLUMNS REMAINING BEFORE END OF LINE * R4 MAJOR SPINNER * R5 SELECTED LETTER * R6 NUMBER OF LETTERS IN CURRENT ALPHABET * R7 (SCRATCH) * * BANK 1 * * R0 SERIAL BIT COUNTER * R1 ASCII ASSEMBLY * R2 BAUD RATE * R3-R7 (UNAVAILABLE) SPC 4 ORG 0 RAM BSS 8 BANK 0 REGISTERS BSS 15 STACK AREA STACK BSS 1 TEMPORARY STACK BSS 3 BANK 1 REGISTERS ERROR BSS 37 ERROR RATE FUNCTION PAG * RESTART VECTOR LOCATION * ORG 0 JMP TEACH * INPUT BUFFER FULL VECTOR LOCATION * ORG $03 * NOT PRESENTLY USED * INTERRUPT SERVICE ROUTINE FOR SERIAL INPUT * ORG $07 TIME.INT SEL RB1 XCH A,R0 SAVE A JNZ NOT.STRT MOV A,R1 ONE AND A HALF BIT DELAY STRT T MOV T,A MOV A,#$08 XCH A,R0 RESTORE A RETR NOT.STRT XCH A,R2 ONE BIT DELAY STRT T MOV T,A XCH A,R2 XCH A,R0 RESTORE A XCH A,R1 SAVE A CLR C JNT1 ZERO.IN CPL C ZERO.IN RRC A DJNZ R0,NOT.DONE XCH A,R1 RESTORE A CPL F1 DIS TCNTI RETR NOT.DONE XCH A,R1 RETR * BAUD RATE DETECT SUBROUTINE * SER.RATE SEL RB1 CLR F1 MOV R0,#$08 STOP TCNT CLR A MOV T,A SET-UP TIMER MARKING STRT T JT1 MARKING WAIT FOR START STRT.BIT JNT1 STRT.BIT STRT T MOV A,T MASSAGE COUNTER VALUE CPL A INC A MOV R2,A STORE ONE BIT DELAY CLR C SET-UP A HALF BIT DELAY CPL C RRC A MOV T,A EN TCNTI READ REST OF CHAR RETR * SERIAL INPUT ENABLING SUBROUTINE * GET.SER MOV @R1,A SEL RB1 CLR F1 MOV A,R2 CALC ONE AND A HALF BIT CLR C DELAY CONSTANT CPL C RRC A ADD A,R2 MOV R1,A STORE CONSTANT IN R1 CLR A MOV R0,A CPL A STRT CNT EN TCNTI ENABLE START BIT DETECT MOV T,A SEL RB0 MOV A,@R1 RETR * INPUT RETRIEVING SUBROUTINE * READ.SER SEL RB1 MOV A,R1 MOVE SERIAL INPUT TO A ANL A,#%01111111 JB6 ALPHA RETR ALPHA ANL A,#%11011111 RETR * INIT LINE LENGTH AND RETRIEVE GRAPH INC VALUE * INIT.COL MOV @R1,A SAVE A IN A,P2 SWAP A RLC A ANL A,#$06 ADD A,#COL.LEN ADD TABLE BASE ADDR MOV R3,A MOVP A,@A GET LINE LENGTH XCH A,R3 INC A MOVP A,@A GET GRAPH INCREMENT XCH A,@R1 RESTORE A RETR COL.LEN BSS 0 LINE LENGTH AND GRAPH INC TABLE BYTE 14+6,-255/14-1 BYTE 30+6,-255/30-1 BYTE 62+6,-255/62-1 BYTE 78+6,-255/78-1 * CARRIAGE RETURN / LINEFEED SUBROUTINE * RETURN CALL INIT.COL MOV @R1,A DEC R1 SAVE A MOV A,#$0D CARRIAGE RETURN CALL OUT.SER MOV A,#$0A LINEFEED CALL OUT.SER CLR A CALL OUT.SER 4 X NULL CALL OUT.SER CALL OUT.SER CALL OUT.SER INC R1 MOV A,@R1 RESTORE A RETR * SERIAL OUTPUT SUBROUTINE * OUT.SER DIS TCNTI SEL RB1 MOV R0,#$0B INIT BIT COUNTER CLR C JTF STRT.T JMP STRT.T NEXT.BIT JNC OUT.ZERO NEXT BIT 1? ORL P2,#$80 YES JMP SET.NEXT OUT.ZERO ANL P2,#$7F NO SET.NEXT CPL C TWEEK FOR STOP BIT RRC A SET-UP NEXT BIT WAIT.1 JTF STRT.T WAIT FOR TIMER FLAG JMP WAIT.1 STRT.T XCH A,R2 SET ONE BIT DELAY STRT T MOV T,A XCH A,R2 DJNZ R0,NEXT.BIT CHECK FOR STOP BIT RLC A XCH A,R2 CLR C RLC A MOV T,A SET TWO BIT DELAY RRC A XCH A,R2 RESTORE ORIG A CPL A WAIT.2 JTF DONE WAIT FOR END OF STOP BITS JMP WAIT.2 DONE SEL RB0 CHECK FOR LAST CHAR DJNZ R3,END JMP RETURN END RETR PAG ORG $100 * MAIN PROGRAM TEACH * * ENTRY TO TEACH IS VIA POWER UP RESET. * THE GENERAL STRUCTURE IS AS FOLLOWS: * * REPEAT * SELECT LETTER * REPEAT * SEND LETTER * REPEAT * ACCEPT RESPONSE * UNTIL CORRECT OR TIME OUT * DISPLAY LETTER * UNTIL CORRECT * EVALUATE PERFORMANCE * UNTIL POWER OFF TEACH CALL PRESET TEA1 MOV R1,#STACK JNT0 TEA1.5 CALL GRAPH TEA1.5 MOV R5,#0 BLANK THE DISPLAY TEA2 MOV A,R4 XCH A,R5 CLR F0 CLEAR ERROR FLAG TEA3 CPL A OUTL P1,A MOV R0,#250 PAUSE FOR ROOM ECHO CALL WAIT CALL SEND ORL P1,#%11111111 DISABLE THE DISPLAY MOV A,#' SPACE CALL OUT.SER * WAIT FOR RESPONSE OR TIMEOUT MOV A,R2 START TIMEOUT TIMER CALL SPI.5 INIT SPINNER TEA3.5 CALL GET.SER ENABLE INPUT TEA4 MOV R7,#20*FREQ/42 TEA5 CALL SPINNER KILL 20 MSEC CALL SPINNER CALL SPINNER CALL SPINNER DJNZ R7,TEA5 JNT0 TEA6.5 IF "CORRECT" BUTTON JF1 TEA6 IF RESPONSE DEC A COUNT RESPONSE TIME JNZ TEA4 DIS TCNTI CLR F0 SET ERROR FLAG CPL F0 JMP TEA8 * TEST RESPONSE TEA6 DIS TCNTI MOV @R1,A SAVE COUNT DEC R1 CALL READ.SER SET RESPONSE ADD A,#-13 SENSE RETURN JZ TEA1 IF GRAPH ADD A,#13 MOV @R1,A SAVE RESPONSE CALL ASCII SET ASCII FOR CORRECT LETTER CPL A INC A ADD A,@R1 INC R1 JZ TEA7 IF CORRECT RESPONSE MOV A,@R1 JMP TEA3.5 TEA6.5 DIS TCNTI MOV @R1,A CPL F1 TEA7 MOV A,@R1 * ADJUST SENDING RATE TEA8 CPL A COMPUTE NEW SPEED INC A ADD A,R2 ADD A,#4 BIAS OUT UNDERFLOW RLC A JNC TEA9 IF NO OVERFLOW MOV A,#255 TEA9 MOV R0,#R2 AVERAGE WITH OLD RATE CALL WEIGHT * PRINT CORRECT RESPONSE CALL ASCII CALL OUT.SER JF1 TEA10 MOV A,R5 SETUP THE PRIOR DISPLAY JMP TEA3 IF HERE BY TIMEOUT TEA10 CALL GRADE JMP TEA2 SPC 4 * SUBROUTINE SPINNER * * SPINNER SIMULATES A WEIGHTED SPINNER (RANDOM NUMBER * GENERATOR) BY ADVANCING A CHARACTER POINTER THROUGH * THE ERROR RATE TABLE. THE SPINNER SPINS WHILE WAITING * FOR USER RESPONSES. * USES R0. MEAN EXECUTION TIME IS 10 CYCLES. SPINNER DJNZ R0,SPI2 SPI.5 DJNZ R4,SPI1 XCH A,R4 SET SPINNER BACK AT BEGINNING MOV A,R6 XCH A,R4 SPI1 MOV @R1,A MOV A,R4 ADD A,#ERROR MOV R0,A MOV A,@R0 MOV R0,A INC R0 MOV A,@R1 SPI2 RET SPC 4 * SUBROUTINE PRESET * * PRESET INITIALIZES REGISTERS AND MEMORY PRESET MOV R1,#STACK SEL RB1 MOV R2,#-208/96 INIT TO 4800 BAUD SEL RB0 JNT0 NOTERM CALL SER.RATE NOTERM MOV R2,#3*50 GIVE AT 3 SECONDS CALL INIT.COL MOV R4,#1 SPINNER MOV R0,#ERROR+36 RESET ERROR RATES MOV R7,#36 PRE1 MOV @R0,#255 WORST CASE RATE DEC R0 DJNZ R7,PRE1 MOV @R0,#255/3 INITIAL AVERAGE RATE MOV R6,#4 NUM IS 4 LETTERS RET SPC 4 * SUBROUTINE SEND * * SEND GENERATES MORSE CODE FOR THE CHARACTER * REFERENCED BY R5. ON EXIT A, R0 AND R7 * ARE DESTROIED. SEND MOV A,R5 GET MORSE ADD A,#MORSE&%11111111 MOVP A,@A SEN1 CLR C RRC A GET NEXT ELEMENT JZ SEN3 IF FINISHED JNC SEN2 CALL DIT SEND DASH CALL DIT SEN2 CALL DIT SEND DIT CALL PAUSE JMP SEN1 SEN3 RET MORSE BSS 1 BYTE %11011,%100011,%10011,%1011 BYTE %111111,%101111,%100111,%1111 BYTE %111110,%11110,%10110,%1110 BYTE %10010,%1010,%110,%111 BYTE %100001,%10001,%11001,%1001 BYTE %11101,%10101,%1101,%101 BYTE %111100,%111000,%10100,%1100 BYTE %110000,%100000,%11000,%10000 BYTE %1000,%100,%11,%10 SPC 4 * SUBROUTINE PAUSE, WAIT * * EXECUTION IS DELAYED ONE DIT TIME (OR R0 MSEC). * ON EXIT R0 AND R7 ARE ZERO. PAUSE MOV R0,#1200/WPM WAIT MOV R7,#FREQ/2-15 COMPENSATED FOR SCANCHAR CALL SCANCHAR WAI1 DJNZ R7,WAI1 DJNZ R0,WAIT RET SPC 4 * SUBROUTINE DIT * * A 1 KHZ SQUARE WAVE IS GENERATED ON THE OUTPUT * PORT FOR ONE DIT TIME. * ON EXIT R0 AND R7 ARE ZERO. DIT MOV R0,#1200/WPM DIT1 ANL P2,#%10111111 MOV R7,#FREQ/4-15 COMPENSATED FOR SCANCHAR CALL SCANCHAR DIT2 DJNZ R7,DIT2 ORL P2,#%01000000 MOV R7,#FREQ/4 DIT3 DJNZ R7,DIT3 DJNZ R0,DIT1 RET SPC 4 ORG $200 * SUBROUTINE ASCII * * ON EXIT A IS ASCII FOR CHARACTER REFERENCED * BY R5. ALL OTHER REGISTERS ARE PRESERVED. ASCII MOV A,R5 ADD A,#ASCTAB&%11111111 MOVP A,@A RET ASCTAB ASCII "%" ASCII "Q7ZG098O1JPWLRAM6BXDYCKN23FU45VHSITE" SPC 4 * SUBROUTINE WEIGHT * * COMPUTES A MOVING WEIGHTED AVERAGE AS FOLLOWS: * * (R0) = .875 * (R0) + .125 * A * * ON EXIT ALL REGISTERS ARE PRESERVED. (R1) IS * USED. WEIGHT MOV @R1,A ADD A,@R0 RRC A (A+B)/2 ADD A,@R0 RRC A ((A+B)/2+B)/2 ADD A,@R0 RRC A (((A+B)/2+B)/2+B)/2 MOV @R0,A MOV A,@R1 RET SPC 4 * SUBROUTINE GRADE * * THE INDIVIDUAL AND TOTAL ERROR RATES ARE * ADJUSTED. IF RATES ARE SUFICIENTLY LOW, * A NEW CHARACTER IS ADDED. ON ENTRY F0 IS SET * IF A CORRECT RESPONSE OCCURED THE FIRST TRY. GRADE MOV A,#255 JF0 GRA1 CPL A GRA1 MOV R0,#ERROR CALL WEIGHT ADJUST TOTAL MOV A,@R0 XCH A,R0 ADD A,R5 XCH A,R0 ADD A,#-256*10/100 MOV A,@R1 JC GRA1.5 CALL WEIGHT GRA1.5 CALL WEIGHT ADJUST INDIVIDUAL MOV R0,#ERROR MOV A,R6 MOV R7,A INC R7 MOV A,#-256*30/100 30 PERCENT OVERALL GRA2 ADD A,@R0 JC GRA3 IF BAD ERROR RATE INC R0 MOV A,#-256*40/100 40 PERCENT INDIVIDUAL DJNZ R7,GRA2 INC R6 ADD NEW LETTER MOV A,R6 ADD A,#-37 JNZ GRA3 IF MORE LETTERS LEFT DEC R6 GRA3 RET SPC 4 * SUBROUTINE GRAPH * * THE ERROR RATE FUNCTION IS DISPLAYED AS * A BAR GRAPH. USES R0, R5 AND R7. GRAPH MOV A,R6 MOV R5,A INC R5 GRF1 CALL RETURN NEXT BAR DEC R5 CALL ASCII INC R5 GET LABEL CALL OUT.SER MOV A,#' CALL OUT.SER MOV A,R5 ADD A,#ERROR-1 MOV R0,A MOV A,@R0 MOV R0,A (R0) = STAR COUNTER MOV A,#'* CALL INIT.COL ((R1)) = INCREMENT PER STAR GRF2 XCH A,R0 ADD A,@R1 XCH A,R0 JNC GRF2.5 IF THIS LINE FINISHED CALL OUT.SER JMP GRF2 GRF2.5 DJNZ R5,GRF1 LOOP FOR ALL CHARACTERS CALL GET.SER GRF3 JF1 GRF4 JNT0 GRF4 JMP GRF3 GRF4 CALL RETURN RET SPC 4 * SUBROUTINE SCANCHAR * * SCANCHAR OUTPUTS THE NEXT DISPLAY COLUMN. * ON EXIT R0 AND R1 (BANK 1) ARE DISTROYED. ORG $300 SCANCHAR MOV @R1,A SAVE A SEL RB1 IN A,P1 CPL A JB7 SCAN1 IF SCAN ENABLED MOV R1,A RL A RL A ADD A,R1 ADD A,#COLTAB&%11111111 MOV R1,A CLR A SCAN1 DEC R1 RR A ANL A,#%00001111 JNZ SCAN2 MOV A,R1 ADD A,#5 MOV R1,A MOV A,#%00010000 SCAN2 MOV R0,A MOV A,R1 MOVP A,@A OUTL P1,A OUTPUT COL DATA MOVD P4,A WITH STROBE MOV A,R0 XRL A,#%01111111 OUTL P1,A ENABLE COLUMN SEL RB0 MOV A,@R1 RESTORE A RETR * DISPLAY COLUMN TABLE COLTAB BYTE %11111111,%11111111,%11111111,%11111111,%11111111 "BLANK" BYTE %11000001,%10111110,%10111010,%10111101,%11000010 Q BYTE %10111111,%10111000,%10110111,%10101111,%10011111 7 BYTE %10111100,%10111010,%10110110,%10101110,%10011110 Z BYTE %11000001,%10111110,%10111110,%10110110,%11010000 G BYTE %11000001,%10111010,%10110110,%10101110,%11000001 0 BYTE %11001110,%10110110,%10110110,%10110101,%11000011 9 BYTE %11001001,%10110110,%10110110,%10110110,%11001001 8 BYTE %11000001,%10111110,%10111110,%10111110,%11000001 O BYTE %11101110,%11011110,%10000000,%11111110,%11111110 1 BYTE %11111001,%11111110,%10111110,%10000001,%10111111 J BYTE %10000000,%10110111,%10110111,%10110111,%11001111 P BYTE %10000000,%11111101,%11110011,%11111101,%10000000 W BYTE %10000000,%11111110,%11111110,%11111110,%11111110 L BYTE %10000000,%10110111,%10110011,%10110101,%11001110 R BYTE %11000000,%10110111,%10110111,%10110111,%11000000 A BYTE %10000000,%11011111,%11100111,%11011111,%10000000 M BYTE %11100001,%11010110,%10110110,%10110110,%10111001 6 BYTE %10000000,%10110110,%10110110,%10110110,%11001001 B BYTE %10011100,%11101011,%11110111,%11101011,%10011100 X BYTE %10000000,%10111110,%10111110,%11011101,%11100011 D BYTE %10001111,%11110111,%11110000,%11110111,%10001111 Y BYTE %11000001,%10111110,%10111110,%10111110,%11011101 C BYTE %10000000,%11110111,%11101011,%11011101,%10111110 K BYTE %10000000,%11001111,%11110111,%11111001,%10000000 N BYTE %11011100,%10111010,%10111010,%10110110,%11001110 2 BYTE %10111110,%10111110,%10110110,%10101010,%11011101 3 BYTE %10000000,%10110111,%10110111,%10110111,%10111111 F BYTE %10000001,%11111110,%11111110,%11111110,%10000001 U BYTE %11110011,%11101011,%11011011,%10000000,%11111011 4 BYTE %10001101,%10101110,%10101110,%10101110,%10110001 5 BYTE %10001111,%11110011,%11111100,%11110011,%10001111 V BYTE %10000000,%11110111,%11110111,%11110111,%10000000 H BYTE %11001110,%10110110,%10110110,%10110110,%10111001 S BYTE %11111111,%10111110,%10000000,%10111110,%11111111 I BYTE %10111111,%10111111,%10000000,%10111111,%10111111 T BYTE %10000000,%10110110,%10110110,%10110110,%10111110 E SPC 4 END