; ******************************************************
; * SCHRITT: Dieses Programm steuert 2 Schrittmotoren  *
; * Die Drehzahl der beiden Motoren empfaengt MIDI8031 *
; * ueber MIDI (was sonst), dazu dient das Steuer-     *
; * programm in GFA-Basic: SCHRITT.TXT.                *
; ******************************************************

	.registers reg51.inc

; *** Variablen Internes RAM, oberhalb BITFELD***
	.var_org $30		; Variablen-PC setzen

speed0: .ds.b 1			; -64..0..64 Motorgeschw. Motor 0
nach0:	.ds.b 1			; Nachkommastellen
pos0:	.ds.b 1			; Motormosition (0..3)
speed1:	.ds.b 1			; dto. Motor 1
nach1:	.ds.b 1			; dto.
pos1:	.ds.b 1			; dto.
awert:	.ds.b 1			; Hilfsvariable 
stack:					; Ab hier das restliche RAM fuer den Stack

; *** Code: Ab hier beginnt das eigentliche Programm ***

	.text_org $8000

; *** 'Interruptbereich' wie EPROM ab Adresse 0 ***
		ljmp go			; Interruptbereich ueberspringen
int0:	reti			; Nicht verwendet...
		.ds.b 7
timer0:	ljmp steppen	; zum steppen springen
		.ds.b 5
int1:	reti			; int0/1, timer1, serial
		.ds.b 7			; werden in diesem Programm
timer1:	reti			; nicht verwendet. Der Programm-
		.ds.b 7			; kopf zeigt lediglich, was mit
serial:	reti			; MIDI8031 moglich waere.
		.ds.b 7

; *** Hier startet das eigentliche Programm ***

; * Initialisierungen: Variablen & Interrupts
go:
	mov sp,#stack		; Wichtig!!! Stack einrichten
	
 	setb TCON.4			; TR0 Timer 0 laeuft
	anl TMOD,#%11111100	; Mode-Bits ausblenden
	orl TMOD,#%11		; M0=3: Interruptfrq. etwa 3.9KHz
	setb IE.7			; Gennerell Interrupts zulassen
	setb IE.1			; T0 Interrupt Ein
	setb IP.1			; TO Interrupt Hohe Prioritaet

	mov speed0,#1		; Motor1: Speed -64..0..64 (hier vorw.)
	mov nach0,#0		; 		  Nachkommastellen
	mov pos0,#0			; 		  Motor1 an Position 0!
	mov speed1,#-1		; Motor2: (hier rueckwaerts)
	mov nach1,#0		;
	mov pos1,#0			;

; * Warteschleife: Abwechelnd werden MIDI-Bytes an speed0/1 verteilt.
	clr IE.4			; Seriellen Interrupt verbieten
	clr SCON.0			; Serieller Buffer loeschen
loop:
	cpl P3.5			; Anzeigen ueber LED
	jnb SCON.0,!		; RI=1 abwarten
	clr SCON.0			; quittieren
	mov speed0,SBUF		; Byte an speed0
	jnb SCON.0,!
	clr SCON.0		
	mov speed1,SBUF		; Byte an speed1
	sjmp loop

; *** Stepper-Interrupt, wird mit 3.9 kHz aufgerufen ***
steppen:
	push ACC			; Akku retten
	push PSW
; * Step-Routine fuer Motor 0 *
	mov A,nach0			; Addieren
	add A,speed0		; des Steps
	mov nach0,A			; und Abspeichern...
	jnb PSW.2,nstep0	; Overflow-Flag testen
	mov awert,#1		; Hilfsv: Vorwaerts
	jb ACC.7,vor0		; >$80: Vorwaerts ist ok
	mov awert,#-1		; sonst Hilfs Rueckwaerts!
vor0:
	mov A,pos0			; Position 0 holen
	add A,awert			; 1 Step vor/zurueck
	anl A,#%0011		; 4 Steps fuer Motor 0
	mov pos0,A			; Neue Position merken
nstep0:

; * Step-Routine fuer Motor 1 *
	mov A,nach1			; wie Motor 0
	add A,speed1		; ...
	mov nach1,A	
	jnb PSW.2,nstep1
	mov awert,#4		; Vorw. in 4-er Schritten
	jb ACC.7,vor1
	mov awert,#-4		; sonst 4 Rueckwaerts!
vor1:
	mov A,pos1			; Position 1 holen
	add A,awert
	anl A,#%1100		; 4 Steps fuer M. 1 (0,4,8,12)
	mov pos1,A
nstep1:

; * Ausgaenge schalten in Abh. von pos0/1 *
	mov A,pos0			; 0..3 Step 1
	add A,pos1			; 0..15 Step 4
	add	A,#pot-h1		; Adressdifferez zur Tab.
	movc A,@A+pc		; Indiziert aus Tabelle holen
h1:	mov P1,A			; Bitmuster am Port ausgeben

	pop PSW
	pop ACC				; Akku restaurieren
	reti				; Interrupt fertig!

; * Positionstabelle Tabelle fuer 16 Motorstrommoeglichkeiten *
pot:
	.dc.b $AA,$A9,$A5,$A6,$9A,$99,$95,$96
	.dc.b $5A,$59,$55,$56,$6A,$69,$65,$66
	
