;*****************************************************************************
;       8051- Programm fuer ATMEL Flash- Mikrocontroller AT89S53
;       Projekt: T4- Modul 		Version: V1.0
;	ASM-Software:			Version: V0.4
;       Autor: Andreas Hoeger
;
;       Datum: 16.07.2000
;       --> zusätzlich aendern: Headertext weiter unten im Code "ORG ...."
;
;	Timing ausgelegt fuer Systemtakt mit 16 MHz Quarz
;
;*****************************************************************************

        $MOD51                          ; use 8051 predefined symbols
        $SYMBOLS                        ; append symbol table to listing

	;****** Compilerschalter *********************************************

TESTLED			EQU	1	; 1=einbinden, 0=weglassen

LCD_RS_2143547		EQU	1	; 1=einbinden, 0=weglassen

;*****************************************************************************

        DSEG

	;****** 00h bis 1Fh = Registerbaenke 0 bis 3 *************************
	;****** 20h bis 2Fh = bitadressierbarer Bereich **********************

       	ORG     20h			
BITS:   DS      1      		; Merker- Bits

TAST_R:	DS	1		; Von IC2 (Tastatur) eingelesenes Byte
IN_R:	DS	1		; Von IC6 (Digital I/O) eingelesenes Byte

CAN_SR:	DS	1		; CAN- Statusregister
CAN_IR:	DS	1		; CAN- Interruptregister

	;****** 30h bis 3Fh = Allzweckbytes **********************************

CNT0:	DS	1		; Counter- Byte 0
CNT1:	DS	1		; Counter- Byte 1
CNT2: 	DS	1		; Counter- Byte 2

	;****** 40h bis 4Fh = CAN- Buffer ************************************

CAN_I1:	DS	1		; CAN Botschaft Identifier Byte 1
CAN_I2:	DS	1		; CAN Botschaft Identifier Byte 1
CAN_D0:	DS	1		; CAN Botschaft Datenbyte 0
CAN_D1:	DS	1		; CAN Botschaft Datenbyte 1
CAN_D2:	DS	1		; CAN Botschaft Datenbyte 2
CAN_D3:	DS	1		; CAN Botschaft Datenbyte 3
CAN_D4:	DS	1		; CAN Botschaft Datenbyte 4
CAN_D5:	DS	1		; CAN Botschaft Datenbyte 5
CAN_D6:	DS	1		; CAN Botschaft Datenbyte 6
CAN_D7:	DS	1		; CAN Botschaft Datenbyte 7
	
CAN_ADR:	DS	1	; CAN Adresse fuer Read Byte/ Write Byte
CAN_DAT: 	DS	1	; CAN Daten fuer Read Byte/ Write Byte

	;****** 50h bis 5Fh = Zwischenspeicherplatz für eine EEPROM- Page ****

	ORG	50h
EEBUFF:	DS	PSIZE		; Eine Page (16 Bytes) Buffer fuer EEPROM

	;****** 60h bis 7Fh = Stack ******************************************

        ORG     60h
STACK:  DS      20h                     ; Stack definieren von 60h bis 80h

	;****** ab 80h oberer RAM Bereich parallel zu SFRs *******************
	;****** --> beachte Adressierungsart, sie wählt den Bereich **********

	;****** Definitionen Allzweck- Speicherbits **************************

BIT00	BIT	BITS.0
BIT01   BIT     BITS.1                 
BIT02   BIT     BITS.2                 
BIT03   BIT     BITS.3                 
BIT04   BIT     BITS.4                 
BIT05   BIT     BITS.5                 
BIT06   BIT     BITS.6
BIT07   BIT     BITS.7     
	
	;****** Definitionen fuer I2C- Bus (EEPROM, DS1621) ******************

SCL	BIT	p3.1			; serial clock
SDA	BIT	p3.0			; serial data

PSIZE	EQU	16			; Pagesize bei AT24C04 EEPROM
EESIZE	EQU	512			; Anzahl Bytes bei AT24C04 EEPROM
EEADDR	EQU	0A0H			; EEPROM Device-Address (1010 00XX)

DSADDR	EQU	90H			; DS1621 Device-Address (1001_000X)

	;****** Definitionen fuer CAN- Controller ****************************

CAN_ALE	BIT	p3.4			; ALE / AS
CAN_CS	BIT	p3.5			; CS/
CAN_RD	BIT	p3.6			; RD/E
CAN_WR	BIT	p3.7			; WR/

CAN_ADR_CR	EQU	00H		; Adresse Control Register (CR) 
CAN_ADR_CMR	EQU	01H		; Adresse Command Register (CMR)
CAN_ADR_SR	EQU	02H		; Adresse Status Register (SR)
CAN_ADR_IR	EQU	03H		; Adresse Interrupt Register (IR)
CAN_ADR_ACR	EQU	04H		; Adresse Acceptance Code (ACR)
CAN_ADR_AMR	EQU	05H		; Adresse Acceptance Mask (AMR)
CAN_ADR_BTR0	EQU	06H		; Adresse Bus Timing Reg 0 (BTR0)
CAN_ADR_BTR1	EQU	07H		; Adresse Bus Timing Reg 1 (BTR1)
CAN_ADR_OCR	EQU	08H		; Adresse Output Control (OCR)

CAN_ADR_I1_TX	EQU	0AH		; Adresse Ident High Byte (send)
CAN_ADR_I2_TX	EQU	0BH		; Adresse Ident Low Byte (send)
CAN_ADR_D0_TX	EQU	0CH		; Basisadresse 8 Datenbytes (send)

CAN_ADR_I1_RX	EQU	14H		; Adresse Ident High Byte (receive)
CAN_ADR_I2_RX	EQU	15H		; Adresse Ident Low Byte (receive)
CAN_ADR_D0_RX	EQU	16H		; Basisadresse 8 Datenbytes (receive)

CAN_ADR_CDR	EQU	1FH		; Adresse Clock Divider Register (CDR)

CAN_INI_CR	EQU	01H		; Initwert CAN Controllregister
CAN_INI_CMR	EQU	00H		; Initwert CAN Commandregister
CAN_INI_BTR0	EQU	80H		; Initwert CAN Bus Timing Register 0
CAN_INI_BTR1	EQU	49H		; Initwert CAN Bus Timing Register 1
CAN_INI_ACR	EQU	00H		; Initwert CAN Acceptance Code
CAN_INI_AMR	EQU	0FFH		; Initwert CAN Acceptance Mask
;CAN_INI_OC	EQU			; Initwert CAN Output Control Register
CAN_INI_CDR	EQU	40H		; Initwert CAN Clock Divider Register	

	;****** Definitionen fuer LCD ****************************************

DB4		BIT	p2.0		; 4-Bit-Datenbus LSB
DB5		BIT	p2.1		; 4-Bit-Datenbus
DB6		BIT	p2.2		; 4-Bit-Datenbus
DB7		BIT	p2.3		; 4-Bit-Datenbus MSB

LCD_E		BIT	p2.4		; LCD enable
LCD_RW		BIT	p2.5		; LCD read/write
LCD_RS		BIT	p2.6		; LCD register select

LCD_IX		EQU	83H		; LCD- Init Befehl 1,2 und 3
LCD_I4		EQU	82H		; LCD- Init Befehl 4
LCD_I5		EQU	82H		; LCD- Init Befehl 5
LCD_I5A		EQU	8CH		; LCD- Init Befehl 5a
LCD_I6		EQU	80H		; LCD- Init Befehl 6
LCD_I6A		EQU	88H		; LCD- Init Befehl 6a
LCD_I7		EQU	80H		; LCD- Init Befehl 7
LCD_I7A		EQU	8FH		; LCD- Init Befehl 7a
LCD_I8		EQU	80H		; LCD- Init Befehl 8
LCD_I8A		EQU	86H		; LCD- Init Befehl 8a

RS_MASK		EQU	01000000b	; Setze RS

	;****** Definitionen fuer digital Inputs *****************************

DIG_SH		BIT	p1.0		; digital I/O, Shift/Load Schiebereg.
DIG_CLK		BIT	p1.1		; digital I/O, Schiebetakt
DIG_QH2		BIT	p1.2		; digital I/O, Eingang von IC2
DIG_QH6		BIT	p1.3		; digital I/O, Eingang von IC6

	;****** Definitionen fuer SPI ****************************************

SPI_SS		BIT	p1.4		; SPI, SS/
MOSI		BIT	p1.5		; SPI, MOSI (Dateneingang)
MISO		BIT	p1.6		; SPI, MISO (Datenausgang)
SPI_CLK		BIT	p1.7		; SPI, serial clock

	;****** Definitionen allgemein ***************************************

LED		BIT	p2.7		; Leuchtdiode (LED an=LOW, aus=HIGH)

HIGH_MASK	EQU	00001111b	; High nibble wegmaskieren


;*****************************************************************************
        
        CSEG

        ;*********************************************************************
        ; Interrupt- Vectortabelle
        ;*********************************************************************

        ORG     0000h				;power on / reset vector
        jmp     on_reset

	ORG	0003h				;external interrupt 0 vector
	reti

        ORG     000Bh                           ;timer 0 overflow vector
	reti
        
	ORG     0013h                           ;external interrupt 1 vector
	reti

        ORG     001Bh                           ;timer 1 overflow vector
	reti

        org     0023h                           ;serial I/O interrupt vector
	reti                          

        ORG     002Bh                           ;timer 2 overflow vector
	reti

	ORG	0033h				;?? reserved ??
	reti

        ;*********************************************************************
        ORG     00E0H				; lesbare Kennung 
        DB      'T4-Modul V1.0   '		; ASCII- Text ins HEX- File
        DB      'Hoeger_7/00_V004'		; eintragen
        ;*********************************************************************

        ;*********************************************************************
        ; Beginn Anwendungs- Programmcode
        ;*********************************************************************
        
        ORG     0100H

on_reset:  

	;****** min. 500 ms Wartezeit wegen Errata-Sheet *********************
	;****** ISP sonst ab dem zweiten mal blockiert ***********************

errata: mov	CNT0,#15H		; ca. 3 Sekunden
err2:	nop
	mov	CNT1,#0FFH
err3:	nop
	mov	CNT2,#0FFH
err4:	nop	
	djnz	CNT2,err4
	djnz	CNT1,err3
	djnz	CNT0,err2
			
	;****** START  System-Initialisierung ********************************

        mov     IE,#00H			; Interrupts nicht freigeben

	mov	8EH,#01H		; Bit 0 von SFR 8Eh setzen, damit
					; ALE- Pin nicht auf 1/6 osz-freq. schwingt

	mov     SP,#STACK		; Stackpointer auf Stackbereich setzen

        mov     R0,#00H			; Register loeschen
        mov     R1,#00H
        mov     R2,#00H                  
        mov     R3,#00H                 
        mov     R4,#00H
        mov     R5,#00H                 
        mov     R6,#00H 
	mov	R7,#00H                

        mov     BITS,#00H		; Merkerbits loeschen

	;****** Parallelports initialisieren (1=Eingang 0=Ausgang) ***********

        mov	P0,#00H		; Port 0 an CAN- Controller
				; P0.0 bis P0.7 = AD- Bus
				; alle OUTPUT = 0 (Grundzustand)

	mov     P1,#0CH		; Port 1 digital inputs / SPI
				; P1.0 = SH/LD 	= Bit DIG_SH 	= OUTPUT = 0
				; P1.1 = CLK   	= Bit DIG_CLK	= OUTPUT = 0
				; P1.2 = QH(IC2)= Bit DIG_QH2	= INPUT  = 1
				; P1.3 = QH(IC6)= Bit DIG_QH6	= INPUT  = 1
				; P1.4 = SS/	= Bit SPI_SS	= OUTPUT = 0
				; P1.5 = MOSI	= Bit MOSI	= OUTPUT = 0
				; P1.6 = MISO   = Bit MISO	= OUTPUT = 0
				; P1.7 = SCK	= Bit SPI_CLK	= OUTPUT = 0

	mov	P2,#00H		; Port 2 LCD und LED
				; P2.0 = DB4 	= Bit DB4 	= OUTPUT = 0
				; P2.1 = DB5   	= Bit DB5	= OUTPUT = 0
				; P2.2 = DB6	= Bit DB6	= OUTPUT = 0
				; P2.3 = DB7	= Bit DB7	= OUTPUT = 0
				; P2.4 = E	= Bit LCD_E	= OUTPUT = 0
				; P2.5 = R/W	= Bit LCD_RW	= OUTPUT = 0
				; P2.6 = RS     = Bit LCD_RS	= OUTPUT = 0
				; P2.7 = LED	= Bit LED	= OUTPUT = 0

        mov     P3,#0CH		; Port 3 CAN-Steuerltg. und I2C-Bus
				; P3.0 = SDA 	= Bit SDA 	= OUTPUT = 0
				; P3.1 = SCL   	= Bit SCL	= OUTPUT = 0
				; P3.2 = INT/	= Bit ---	= INPUT  = 1
				; P3.3 = N.C.	= Bit ---	= INPUT  = 1
				; P3.4 = ALE	= Bit CAN_ALE	= OUTPUT = 0
				; P3.5 = CS/	= Bit CAN_CS	= OUTPUT = 0
				; P3.6 = RD/    = Bit CAN_RD	= OUTPUT = 0
				; P3.7 = WR/	= Bit CAN_WR	= OUTPUT = 0
	
	;****** Init I2C- Bus ************************************************
	
	setb	SDA		; Grundzustand I2C-Bus = HIGH
	setb	SCL		; Grundzustand I2C-Bus = HIGH

	;****** Init Schieberegister (digital Input) *************************
	
	clr	DIG_CLK		; Grundzustand CLK = LOW
	setb	DIG_SH		; Grundzustand SH/LD = HIGH

	;****** Init CAN Controller Steuerleitungen **************************
	
	setb	CAN_WR		; Grundzustand WR/ = HIGH
	setb	CAN_RD		; Grundzustand RD/ = HIGH
	setb	CAN_CS		; Grundzustand CD/ = HIGH
	clr	CAN_ALE		; Grundzustand ALE = LOW

	;****** Init LCD- Modul **********************************************

	call	ini_lcd			

	;****** Init CAN- Controller *****************************************

	call	ini_can

	;****** 


;	mov	DPTR,#MSG001
;	call	print_lcd


	; Text auf LCD anzeigen







	; hier kommt das richtig gute programm hin






;	;****** START Blink- LED abhaengig *********************************** 
;
;blink:	call	io_shift		; Eingänge einlesen
;	jb	TAST_R.0,x01
;	mov	CNT0,#60H
;	jmp	loop0
;x01:	mov	CNT0,#0FFH		; Pulsdauer FF/FF = 150 ms
;loop0:	nop				; Pulsdauer C0/FF = 115 ms
;	mov	CNT1,#0FFH		; Pulsdauer 90/FF =  80 ms
;loop1:	nop				; Pulsdauer 60/FF =  55 ms
;	djnz	CNT1,loop1		; Pulsdauer 33/FF =  30 ms
;	djnz	CNT0,loop0		; Pulsdauer 11/FF =  10 ms
;					; Pulsdauer 10/1A =   1 ms
;	cpl	LED
;	jmp	blink			; LED toggeln



	IF TESTLED

	;****** START Blink- LED ********************************************* 

blink:	mov	CNT0,#0FFH		; Pulsdauer FF/FF = 150 ms
loop0:	nop				; Pulsdauer C0/FF = 115 ms
	mov	CNT1,#0FFH		; Pulsdauer 90/FF =  80 ms
loop1:	nop				; Pulsdauer 60/FF =  55 ms
	djnz	CNT1,loop1		; Pulsdauer 33/FF =  30 ms
	djnz	CNT0,loop0		; Pulsdauer 11/FF =  10 ms
					; Pulsdauer 10/1A =   1 ms
	cpl	LED
	jmp	blink			; LED toggeln

	;****** ENDE Blink-LED ***********************************************


;	;****** START Test der Zeitschleifen *********************************
;
;test:	call	zehn_ms
;	cpl	LED
;	jmp	test

	;****** ENDE Test der Zeitschleifen **********************************

	ENDIF

;*****************************************************************************


	IF LCD_RS_2143547		;  nur wenn LCD- Modul von RS

        ;*********************************************************************
        ; Unterprogramm Initialisierung LCD- Modul RS 214-3547
        ;*********************************************************************

ini_lcd:	
	mov	A,#01H			; LSB setzen, andere loeschen 
	mov	C,ACC.1			; Carry loeschen und damit
	mov	LCD_E,C			; strobe loeschen

	call	zehn_ms			; Wartezeit > 15 ms
	call	zehn_ms			;	

	;****** 1. bis 3. Befehl LCD Init ************************************

	mov	A,#LCD_IX		; Befehl LCD Init 1 bis 3
	call	lcd_out			; Portausgabe mit enable

	call	zehn_ms			; Wartezeit > 4.1 ms	

	mov	A,#LCD_IX		; Befehl LCD Init 1 bis 3
	call	lcd_out			; Portausgabe mit enable

	call	ein_ms			; Wartezeit > 100us
	
	mov	A,#LCD_IX		; Befehl LCD Init 1 bis 3
	call	lcd_out			; Portausgabe mit enable

	call	zehn_ms			; Wartezeit > 4.1 ms	

	;******	4. Befehl LCD Init *******************************************
	
	mov	A,#LCD_I4		
	call	lcd_out			; setze 4-Bit-Mode

	call	us_50			; Wartezeit > 40 us

	;******	5. Befehl LCD Init *******************************************
	
	mov	A,#LCD_I5		
	call	lcd_out			; setze Matrixformat 5*8 oder 5*11

	mov	A,#LCD_I5A		
	call	lcd_out			

	call	us_50			; Wartezeit > 40 us

	;******	6. Befehl LCD Init *******************************************
	
	mov	A,#LCD_I6		
	call	lcd_out			; setze display off, cursor off
					; setze blink off

	mov	A,#LCD_I6A		
	call	lcd_out			

	call	us_50			; Wartezeit > 40 us


	;******	7. Befehl LCD Init *******************************************
	
	mov	A,#LCD_I7		
	call	lcd_out			; setze display on, cursor on & blink

	mov	A,#LCD_I7A		
	call	lcd_out			

	call	us_50			; Wartezeit > 40 us

	;******	8. Befehl LCD Init *******************************************
	
	mov	A,#LCD_I8		
	call	lcd_out			; cursor move right, no shift

	mov	A,#LCD_I8A		
	call	lcd_out			

	call	us_50			; Wartezeit > 40 us

	ret

	ENDIF				; ENDIF LCD_RS_2143547

        ;*********************************************************************
        ; Unterprogramm fuer Byteausgabe an LCD-Port
        ;*********************************************************************

lcd_out:
	mov	P2,A			; Befehl in A auf Port ausgeben
	call	ein_ms			; Einschwing-Wartezeit
	setb	LCD_E			; strobe setzen
	call	ein_ms			; Mindestwartezeit 450 ns
	clr	LCD_E			; strobe loeschen

	ret

        ;*********************************************************************
        ; Unterprogramme fuer Textausgabe auf LCD- Anzeige
        ;*********************************************************************
	; Ausgabe einer kompletten Textzeile
	; DPTR muss vorher auf den Text gesetzt werden: mov DPTR,#TEXTx
	
print_lcd:
	mov	A,#0			; Akku loeschen
	movc	A,@A+DPTR		; einen Buchstaben holen
	inc	DPTR
	cjne	A,#16,pr_1		; Ende der Textzeile ?
	sjmp	pr_2

pr_1:	
	call	char_out		; An LCD senden
	sjmp	print_lcd
pr_2:
	ret

        ;*********************************************************************
	; Ausgabe eines Buchstabens im 4-Bit-Mode: 
	; zuerst high nibble, dann low nibble ausgeben
	; Ausgabe erfolgt jedoch ueber LSBs des Ports !

char_out:
	push	acc			; Byte sichern
	
	swap	a			
	anl	a,#HIGH_MASK		; obere Bits loeschen
	orl	a,#RS_MASK		; setze RS=1 (high = dataregister)
	call	lcd_out			; High nibble ausgeben (in LSBs!)

	pop	acc			
	anl	a,#HIGH_MASK
	orl	a,#RS_MASK		; setze RS=1 (high = dataregister)
	call	lcd_out			; Low nibble ausgeben (in LSBs!)

	call	us_50			; Wartezeit > 40 us bis
					; naechster Buchstabe weil LCD
					; im Write-Only-Mode ohne Busy Flag
	ret

        ;*********************************************************************
        ; Unterprogramm fuer Initialisierung CAN-Controller
        ;*********************************************************************

ini_can:
	mov	CAN_ADR,#CAN_ADR_CR	; Control Register init
	mov	CAN_DAT,#CAN_INI_CR	
	call	can_write

	mov	CAN_ADR,#CAN_ADR_CMR	; Command Register init
	mov	CAN_DAT,#CAN_INI_CMR	
	call	can_write
	
	mov	CAN_ADR,#CAN_ADR_BTR0	; BTR0 Register init
	mov	CAN_DAT,#CAN_INI_BTR0	
	call	can_write
	mov	CAN_ADR,#CAN_ADR_BTR1	; BTR1 Register init
	mov	CAN_DAT,#CAN_INI_BTR1	
	call	can_write

	mov	CAN_ADR,#CAN_ADR_ACR	; Acceptance Code init
	mov	CAN_DAT,#CAN_INI_ACR	
	call	can_write
	mov	CAN_ADR,#CAN_ADR_AMR	; Acceptance Mask init
	mov	CAN_DAT,#CAN_INI_AMR	
	call	can_write

	mov	CAN_ADR,#CAN_ADR_CDR	; Clock Divider init
	mov	CAN_DAT,#CAN_INI_CDR	
	call	can_write



	; output control register ??? (--> einfach lassen wie es is)

	; hier noch freischlten in CR
	ret

        ;*********************************************************************
        ; Unterprogramm fuer CAN-Controller: READ BYTE
        ;*********************************************************************

can_read:
	; erwarteter Grundzustand: 	ALE=low und RD/ WR/ CS/=high
	;				A/D- Bus (Port 0) = OUTPUT
	; Uebergabewerte:		Adresse in CAN_ADR
	;				erhaltene Daten in CAN_DAT
	
	setb	CAN_ALE			; ALE vorbereitend nach HIGH
	nop
	mov	P0,CAN_ADR		; Adresse auf AD-Bus legen
	nop
	clr	CAN_ALE			; fallende Flanke ALE
	nop
	clr	CAN_CS			; CS/ aktivieren fuer CAN Controller
	clr	CAN_RD			; RD/ aktivieren
	nop
	mov	P0,#0FFH		; Port 0 = INPUT
	nop
	nop	
	mov	CAN_DAT,P0		; Daten uebernehmen
	nop
	setb	CAN_RD
	setb	CAN_CS
	nop
	mov	P0,#00H			; Port 0 = OUTPUT (Grundzustand)
	
	; zurueck mit eingelesenen Daten in CAN_DAT	

	ret
        
	;*********************************************************************
        ; Unterprogramm fuer CAN-Controller: WRITE BYTE
        ;*********************************************************************

can_write:
	; erwarteter Grundzustand: 	ALE=low und RD/ WR/ CS/=high
	;				A/D- Bus (Port 0) = OUTPUT
	; Uebergabewerte:		Adresse in CAN_ADR
	;				Daten (bzw. Befehl) in CAN_DAT
	
	setb	CAN_ALE			; ALE vorbereitend nach HIGH
	nop
	mov	P0,CAN_ADR		; Adresse auf AD-Bus legen
	nop
	clr	CAN_ALE			; fallende Flanke ALE
	nop
	clr	CAN_CS			; CS/ aktivieren fuer CAN Controller
	clr	CAN_WR			; WR/ aktivieren
	nop
	mov	P0,CAN_DAT		; Daten auf AD-Bus legen
	nop
	nop
	setb	CAN_WR
	nop
	setb	CAN_CS
	nop

	ret
        
        ;*********************************************************************
        ; Unterprogramm zum Einlesen der Schieberegister
        ;*********************************************************************

io_shift:	
	; Schiebt ein Byte vom 74165 herein, MSB first (Bit Nr. H).
	; Eingang / Ausgang ist bereits definiert.
	; DIG_CLK wird low erwartet und kehrt low zurueck.
	; DIG_SH wird high erwartet und kehrt high zurueck.
	; Erhaltenes Byte von IC2 (Tastatur) wird in TAST_R zurueckgegeben.
	; Erhaltenes Byte von IC6 (Dig. Input) wird in IN_R zurueckgegeben.

	push	ACC
	mov	CNT0,#8		; Anzahl Bits pro Byte

	clr	DIG_SH		; DIG_SH auf low, Daten parallel laden
	nop			
	nop			
	setb	DIG_SH		; DIG_SH auf high, geladene Daten schieben
	nop
	nop
x00:	setb	DIG_CLK		; steigende Flanke Takt
	nop			
	nop			
	mov	A,TAST_R	
	mov	C,DIG_QH2	; input Bit von IC2
	rlc	A
	mov	TAST_R,a
		
	mov	A,IN_R 
	mov	C,DIG_QH6	; input Bit von IC6
	rlc	A
	mov	IN_R,a

	clr	DIG_CLK		; Taktpuls beenden
	nop
	nop
	djnz	CNT0,x00

	pop	ACC
	ret
        
	;*********************************************************************
        ; Unterprogramm Zeitschleife 0.05 ms (50 us fuer LCD)
        ;*********************************************************************

us_50:
	mov	R0,#42H
wait4:	nop
	djnz	R0,wait4
	
	ret			

        ;*********************************************************************
        ; Unterprogramm Zeitschleife 1 ms
        ;*********************************************************************

ein_ms:	nop
	mov	R0,#10H
wait0:	nop
	mov	R1,#1AH
wait1:	nop
	djnz	R1,wait1
	djnz	R0,wait0
	
	ret			

        ;*********************************************************************
        ; Unterprogramm Zeitschleife 10 ms
        ;*********************************************************************

zehn_ms:nop
	mov	R0,#11h
wait2:	nop
	mov	R1,#0FFh
wait3:	nop
	djnz	R1,wait3
	djnz	R0,wait2
	
	ret			

        ;*********************************************************************
        ; Unterprogramme fuer I2C- Bus
        ;*********************************************************************

write_byte:

	; AT24Cxx Byte Write function.
	; Called with programmable address in A, byte address in
	; register pair ADDR_HI:ADDR_LO, data in register XDATA.
	; Does not wait for write cycle to complete.
	; Returns CY set to indicate that the bus is not available
	; or that the addressed device failed to acknowledge.
	; Destroys A.

		call	start
		jc	x49		; abort if bus not available

		rl	a		; programmable address to bits 3:1
		orl	a, #EEADDR	; add fixed address
		clr	acc.0		; specify write operation
		call	shout		; send device address
		jc	x48		; abort if no acknowledge

;		mov	a, addr_hi	; send high byte of address
		call	shout		;
		jc	x48		; abort if no acknowledge

;		mov	a, addr_lo	; send low byte of address
		call	shout		;
		jc	x48		; abort if no acknowledge

;		mov	a, zdata	; get data
		call	shout		; send data
		jc	x48		; abort if no acknowledge

		clr	c		; clear error flag
	x48:
		call	stop
	x49:
		ret


read_current:

	; AT24Cxx Current Address Read function.
	; Called with programmable address in A. Returns data in A.
	; Returns CY set to indicate that the bus is not available
	; or that the addressed device failed to acknowledge.

		call	start
		jc	x45		; abort if bus not available

		rl	a		; programmable address to bits 3:1
		orl	a, #EEADDR	; add fixed address
		setb	acc.0		; specify read operation
		call	shout		; send device address
		jc	x44		; abort if no acknowledge

		call	shin		; receive data byte
		call	NAK		; do not acknowledge byte
		clr	c		; clear error flag
	x44:
		call	stop
	x45:
		ret


read_random:

	; AT24Cxx Random Read function.
	; Called with programmable address in A, byte address in
	; register pair ADDR_HI:ADDR_LO. Returns data in A.
	; Returns CY set to indicate that the bus is not available
	; or that the addressed device failed to acknowledge.

		push	b
		mov	b, a		; save copy of programmable address

		; Send dummy write command to set internal address.

		call	start
		jc	x47		; abort if bus not available

		rl	a		; programmable address to bits 3:1
		orl	a, #EEADDR	; add fixed address
		clr	acc.0		; specify write operation
		call	shout		; send device address
		jc	x46		; abort if no acknowledge

;		mov	a, addr_hi	; send high byte of address
		call	shout		;
		jc	x46		; abort if no acknowledge

;		mov	a, addr_lo	; send low byte of address
		call	shout		;
		jc	x46		; abort if no acknowledge

		; Call Current Address Read function.

		mov	a, b		; get programmable address
		call	read_current
		jmp	x47		; exit
	x46:
		call	stop
	x47:
		pop	b
		ret


start:

	; Send START, defined as high-to-low SDA with SCL high.
	; Return with SCL, SDA low.
	; Returns CY set if bus is not available.

		setb	SDA
		setb	SCL

		; Verify bus available.

		jnb	SDA, x40	; jump if not high
		jnb	SCL, x40	; jump if not high

		nop			; enforce setup delay and cycle delay
		clr	SDA
		nop			; enforce hold delay
		nop			;
		nop			;
		nop			;
		nop			;
		clr	SCL

		clr	c		; clear error flag
		jmp	x41
	x40:
		setb	c		; set error flag
	x41:
		ret


stop:

	; Send STOP, defined as low-to-high SDA with SCL high.
	; SCL expected low on entry. Return with SCL, SDA high.

		clr	SDA
		nop			; enforce SCL low and data setup
		nop
		setb	SCL
		nop			; enforce setup delay
		nop			;
		nop			;
		nop			;
		nop			;
		setb	SDA
		ret

shout:

	; Shift out a byte to the AT24Cxx, most significant bit first.
	; SCL, SDA expected low on entry. Return with SCL low.
	; Called with data to send in A.
	; Returns CY set to indicate failure by slave to acknowledge.
	; Destroys A.

		push	b
		mov	b, #8		; bit counter
	x42:
		rlc	a		; move bit into CY
		mov	SDA, c		; output bit
		nop			; enforce SCL low and data setup
		setb	SCL		; raise clock
		nop			; enforce SCL high
		nop			;
		nop			;
		nop			;
		clr	SCL		; drop clock
		djnz	b, x42		; next bit

		setb	SDA		; release SDA for ACK
		nop			; enforce SCL low and tAA
		nop			;
		setb	SCL		; raise ACK clock
		nop			; enforce SCL high
		nop			;
		nop			;
		nop			;
		mov	c, SDA		; get ACK bit
		clr	SCL		; drop ACK clock

		pop	b
		ret


shin:

	; Shift in a byte from the AT24Cxx, most significant bit first.
	; SCL expected low on entry. Return with SCL low.
	; Returns received data byte in A.

		setb	SDA		; make SDA an input

		push	b
		mov	b, #8		; bit count
	x43:
		nop			; enforce SCL low and data setup
		nop			;
		nop			;
		setb	SCL		; raise clock
		nop			; enforce SCL high
		nop			;
		mov	c, SDA		; input bit
		rlc	a		; move bit into byte
		clr	SCL		; drop clock
		djnz	b, x43		; next bit

		pop	b
		ret


ACK:

	; Clock out an acknowledge bit (low).
	; SCL expected low on entry. Return with SCL, SDA low.

		clr	SDA		; ACK bit
		nop			; enforce SCL low and data setup
		nop			;
		setb	SCL		; raise clock
		nop			; enforce SCL high
		nop			;
		nop			;
		nop			;
		clr	SCL		; drop clock
		ret


NAK:

	; Clock out a negative acknowledge bit (high).
	; SCL expected low on entry. Return with SCL low, SDA high.

		setb	SDA		; NAK bit
		nop			; enforce SCL low and data setup
		nop			;
		setb	SCL		; raise clock
		nop			; enforce SCL high
		nop			;
		nop			;
		nop			;
		clr	SCL		; drop clock
		ret




;*****************************************************************************
;*****************************************************************************


        ;*********************************************************************
        ; Datensatzdefinition
        ;*********************************************************************
	; Botschaftsendemarke = 16 weil das kein darstellbares Zeichen ist

        ORG     1000H           


MSG001:	DB	' Hello, World. ',16

	;DB     '(000.0000.0000.000000.00.0000.0',00000000B,0DH,0AH


;*****************************************************************************
; ENDE DES GESAMTEN QUELLTEXTES
;*****************************************************************************

        END

