Assembler - RFID-Zugangskontrolle

From XennisWiki
Jump to: navigation, search

Programmierung des Mikrocontrollers Atmel AVR - ATmega 16.

Zum besseren Verständnis des Programms der Programmablaufplan: File:Assembler - RFID-Zugangskontrolle PAP.pdf

; TGI - Versuch 11
; RFID-Zugangskontrolle

.include "m16def.inc"

; ##### benutzerdefinierte Registerdefinitionen #####
.def	Temp		= R16
.def	Counter		= R17
.def	Maske		= R18
.def	Temp2		= R19
; ##### Ende benutzerdefinierte Registerdefinitionen #####

; ##### benutzerdefinierte Konstanten #####
.equ	Vergleichswert	= 76
.equ	MaskePB2	= (1<<PB2)			; Eingangsmaske (Enstspricht 0b00000100)
; ##### Ende benutzerdefinierte Konstanten #####

.dseg
.org	0x0060

; ##### benutzerdefinierte Variablen #####
RFIDRawData:	.byte	11				; Die 11 Zeile der Tabelle speichern
RFIDData:	.byte	5				; Kartendaten nach Paritätsprüfung
							; Jeweils zwei Datenblöcke (z.B. D00-D03 und D10-D13) werden in einem Byte gespeichert
; ##### Ende benutzerdefinierte Variablen #####

.cseg
;.org	0x0000
;jmp	init
.org	0x002a						; Vorgegebene Startadresse


; Drei Kartennummern (AUSGEDACHTE ZAHLEN!)
Authorised: .db 1,    	9,	173, 	89,  	156, \
		23,	123,	23,	0,	1, \
		1,	9,	173,	58,	49
;0109ad3a31.sti: 1,	9,	173,	058,	049
;0109ad280e.sti: 1,	9,	173,	040,	014
;0109ad599c.sti: 1	9,	173,	089,	156

; ##### Initialisierung #####
init:
	; Stackpointer initialisieren
	ldi	Temp,		high(RAMEND)
	out	SPH,		Temp
	ldi	Temp,		low(RAMEND)
	out	SPL,		Temp
	; Portdefinitionen
	ldi	Temp,		1			; PORTB (Eingaben und Ausgaben)
	out	DDRB,		Temp				; PB0 (Ausgabe): SHD, Shutdown
	ldi	Temp,		5				; PB2 (Eingabe): OUT, Daten
	out	PORTB, 		Temp

	; RFIDRawData und RFIDData löschen?

	; Display initialisieren
	call	lcd_init

	; RFID-Empfänger anschalten
	ldi	Temp,		4			; 100 => PB0=0
	out	PORTB,		Temp			; Shutdown-Pin auf Low legen

; ##### Hauptprogrammm #####
.def	CounterRFIDData		= R23
.def	CounterAuthorised	= R24

main:
	; Unterprogramme aufrufen
	call	Synchronise
	call	DetectHeader
	call	ReadCardInformation
	call	CheckParity				; Bei Erfolg wird in Temp(R16) eine 1 zurückgegeben
	; Überprüfen, ob Übertragung erfolgreich war
	cpi	Temp,	1				; Überprüfen, ob Übertragung erfolgreich war (d.h. Temp=1)
	brne	main					; War Übertragung nicht erfolgreich (d.h. Z=0) => fange von vorne an

; Gelesene Kartennummer mit gespeicherten vergleichen
	ldi	ZL,		low(Authorised*2)	; Z-Pointer, da der Befehl "lpm" nur mit diesem geht
	ldi	ZH,		high(Authorised*2)	; "*2" da Authorised vom Typ "Word"

	ldi	CounterAuthorised,	3		; Da 3 Kartennummer vorgegeben sind

; Vergleicht die gespeicherte Nummer nacheinander mit den drei vorgegeben Nummern
vergleicheNaechsteNummer:
	ldi	CounterRFIDData,	5		; 5 gepspeicherte Daten RFIDData
	ldi	YL,		low(RFIDData)
	ldi	YH,		high(RFIDData)

; Vergleicht zuerst das erste Byte der empfangen Nummer mit dem ersten Byte der vorgegeben Nummer,
; Stimmen dieser überein, werden das zweite Byte der empfangenen mit der vorgegebnen verglichen, usw.
; (von 1...5, "CounterRFIDData" zählt hierbei die Durchläufe der Schleife herunter)
; Stimmen die Nummern an einer Byte-Stelle nicht überein => springe aus Schleife zu "nummernNichtGleich"
vergleicheNummern:
	lpm	Temp,		Z+			; Lade vorgegebene Kartennummer Authorised(j)
	ld	Temp2,		Y+			; Lade empfangene Kartennummer RFIDData(i)

	cp	Temp,		Temp2			; Nummer Authorised(j) mit Nummer RFIDData(i) vergleichen
	brne	nummernNichtGleich			; Sind die Nummer nicht gleich (d.h. Z=0) => springe

	dec	CounterRFIDData
	breq	callAccessGranted			; Ist Counter = 0 (d.h. Z=1) => rufe "AccessGranted" auf
	jmp	vergleicheNummern			; Da Counter != 0 => vergleiche die nächste Nummer
; Das Byte der Nummer stimmt nicht mit dem Byte der anderen überen. Vergleiche die empfangene Nummer
; mit der nächsten vorgegeben Nummer
nummernNichtGleich:
	dec	CounterRFIDData

	clr	Temp
	add	ZL,		CounterRFIDData		; Authorised(j+CounterRFIDData)
	adc	ZH,		Temp

	dec	CounterAuthorised
	breq	callAccessDenied			; Ist Counter = 0 (d.h. Z=1) => rufe "AccessDenied" auf

	jmp	vergleicheNaechsteNummer

; Kartennummer wurde akzeptiert => rufe "AccessGranted" auf
callAccessGranted:
	call	AccessGranted
	jmp	main

; Kartennummer wurde nich akzeptiert => rufe "AccessDenied" auf
callAccessDenied:
	call	AccessDenied
	jmp	main

; #####################################################################
; ##### Benutzerdefinierte Unterprogramme #####
			
; # Synchronise
; # ---------
; # Synchronisiere auf eine 01-Folge
; # I: -
; # O: -
Synchronise:
	push	Temp
	push	Counter
	push	Maske

	ldi	Maske,		MaskePB2		; Maske für Pin B2 laden

; Warte solange PB2=0 (Warte auf steigende Flanke)
s_wait:
	clr	Counter
	in	Temp,		PINB			; PIN B einlesen
	and	Temp,		Maske
	breq	s_wait					; Ist PB2=0 (d.h. Z=1) => wiederhole

; Inkrementiere Zähler solange PB2=1 (Warte auf fallende Flanke)
s_incCounter:
	inc	Counter					; Inkrementiere Zähler
	in	Temp,		PINB
	and	Temp,		Maske
	brne	s_incCounter				; Ist PB2=1 (d.h. Z=0) => wiederhole

; Vergleiche den gemessenen Wert mit dem Vergleichswert (Zähler auswerten)
	cpi	Counter,	Vergleichswert
	brlo	s_wait					; Ist der Counter < Vergleichswert => Springe an Anfang

	pop	Maske
	pop	Counter
	pop	Temp
	ret

; # TriggerRising
; # ---------
; # Triggert auf eine steigende Flanke
; # I: -
; # O: R16 = empfangenes Zeichen
TriggerRising:
	push	Counter
	push	Maske

	ldi	Maske,		MaskePB2
	clr	Counter

; Inkrementiere Zähler solange PB2=0 (Warte auf steigende Flanke)
tr_incCounter:
	inc	Counter
	in	Temp,		PINB
	and	Temp,		Maske
	breq	tr_incCounter				; Ist PB2=0 (d.h. Z=1) => wiederhole

; Vergleiche den gemessenen Wert mit dem Vergleichswert
tr_compare:
	ldi	Temp,		0			; Rückgabeparameter des Programms, wird ggf. später dann auf 1 gesetzt
	cpi	Counter,	Vergleichswert
	brsh	tr_end					; Ist Counter >= Vergleichswert => springe ans Ende

; Warte solange PB2=0 (Warte auf fallende Flanke)
tr_warteAufFallendeFlanke:
	in	Temp,		PINB
	and	Temp,		Maske
	brne	tr_warteAufFallendeFlanke		; Ist PB2=1 (d.h. Z=0) => wiederhole
	ldi	Temp,		1			; Rückgabeparameter des Programms

tr_end:
	pop	Maske
	pop	Counter
	ret

; # TriggerFalling
; # ---------
; # Triggert auf fallende Flanke
; # I: -
; # O: R16 = empfangenes Zeichen
TriggerFalling:
	push	Counter
	push	Maske

	ldi	Maske,		MaskePB2
	clr	Counter

; Inkrementiere Zähler solange PB2=1 (Warte auf fallende Flanke)
tf_incCounter:
	inc	Counter
	in	Temp,		PINB
	and	Temp,		Maske
	brne	tf_incCounter				; Ist PB2=1 => wiederhole

; Vergleiche den gemessenen Wert mit dem Vergleichswert
tf_compare:
	ldi	Temp,		1			; Rückgabeparameter des Programms, Wird ggf. später dann auf 1 gesetzt
	cpi	Counter,	Vergleichswert
	brsh	tf_end					; Ist Counter >= Vergleichswert => springe ans Ende

; Warte solange PB2=0 (Warte auf fallende Flanke)
tf_warteAufSteigendeFlanke:
	in	Temp,		PINB
	and	Temp,		Maske
	breq	tf_warteAufSteigendeFlanke		; Ist PB2=0 (d.h. Z=1) => wiederhole
	ldi	Temp,		0			; Rückgabeparameter des Programms

tf_end:
	pop	Maske
	pop	Counter
	ret

; # DetectHeader
; # ---------
; # Detektiert den Header "1.1111.1111"
; # I: -
; # O: -
DetectHeader:
	push	Temp
	push	Counter
	push	Maske

	ldi	Temp,		1
	ldi	Maske,		MaskePB2

; Initialisiert Schleife
dh_init:
	ldi	Counter,	9			; Zähler auf 9 initialisieren, da der Header aus 9 Einsen besteht
	cpi	Temp,		1			; Empfangenes Zeichen, Rückgabe von "TriggerRising" und "TriggerFalling"
	breq	dh_callTriggerRising			; Ist empfangenes Zeichen=1 (Z=1) => rufe "TriggerRising" auf
	call	TriggerFalling				; Ist empfangenes Zeichen=0 (Z=0) => rufe "TriggerFalling" auf
	jmp	dh_zaehleEinsen
	
; Ruft das Unterprogramm "TriggerRising" auf
dh_callTriggerRising:
	call	TriggerRising

; Zählt, ob an PIN B2 nacheinander 9 Einsen anliefen 
dh_zaehleEinsen:
	cpi	Temp,		0			; Überprüfen, ob eine 0 als Zeichen empfangen wurde
	breq	dh_init					; Wurde eine 0 als Zeichen empfangen (d.h. Z=1) => fange von vorne an

	dec	Counter					; Dekrementiere Schleifenzähler
	brne	dh_callTriggerRising			; Counter!=0 (d.h. Z=0) => wiederhole schleife
							; 1 Wurde gelesen
; Ende
	pop	Maske
	pop	Counter
	pop	Temp
	ret

; # ReadCardInformation
; # ---------
; # Liest die Daten der Karte
; # I: -
; # O: -
.def	CounterRow 	= R20
.def	RowRawData	= R21
ReadCardInformation:
	push	Temp
	push	CounterRow				; Zählt die 11 Zeilen der Tabelle
	push	Counter					; "CounterBit", zählt in diesem Programm die Bits
	push	RowRawData				; Speichert nach und nach jedes gelesene Zeichen einer Zeile
	push	ZL
	push	ZH

	ldi	ZL,		low(RFIDRawData)
	ldi	ZH,		high(RFIDRawData)
	ldi	Temp,		1			; Wird nach "DetectHeader" aufgerufen, d.h. letztes Zeichen war eine 1
	ldi	CounterRow,	11			; 11 Zeilen müssen eingelesen werden (2 Kundennr. + 8 Datenzeilen + 1 Spaltenparitätszeile)

; Initialisierung, wenn eine neue Zeile eingelesen wird
ri_naechsteZeileLesen:
	clr	RowRawData				; Da nun neue Zeile eingelesen wird => lösche RowRawData
	ldi	Counter,	5			; 5 Bits (Zeichen) müssen pro Zeile eingelesenen werden (4 Datenbits + 1 Paritätsbit)

; Nächstes empfangenes Zeichen lesen
ri_naechstesZeichenLesen:
	cpi	Temp,		0			; Überprüfen, ob eine 0 als Zeichen empfangen wurde
	breq	ri_callTriggerFalling			; Wurde eine 0 als Zeichen empfangen (d.h. Z=1) => rufe "TriggerFalling" auf
	call	TriggerRising				; Wurde eine 1 als Zeichen empfangen (d.h. Z=0) => rufe "TriggerRising" auf
	jmp	ri_end

; Unterprogramm "TriggerFalling" aufrufen
ri_callTriggerFalling:
	call	TriggerFalling

; Empfangenes Zeichen speicher, ggf. eine Zeile weiter springen
ri_end:
	lsl	RowRawData				; Logischer Linksshift
	add	RowRawData,	Temp			; Empfangenes Zeichen speichern

	dec	Counter					; Ein Bit wurde eingelesen
	brne	ri_naechstesZeichenLesen		; Wurde noch nicht das letzte Bit der Zeile gelesen (d.h. Z=0) => lese nächstes Zeichen ein

	st	Z+,		RowRawData		; Speicher die Daten in "RFIDRawData" und setze Z-Pinter eins weiter, um nächste Zeile dort speichern zu können

	dec	CounterRow				; Eine Zeile wurde komplett eingelesen
	brne	ri_naechsteZeileLesen			; Wurden noch nicht alle Zeilen eingelesen (d.h. Z=0) => lese nächste Zeile ein

; Ende
	pop	ZH					; Alle Zeilen wurden eingelesen
	pop	ZL						
	pop	RowRawData
	pop	Counter
	pop	CounterRow
	pop	Temp
	ret

; ##### Ende benutzerdefinierte Unterprogramme #####


; ###########################################################################

; ##### Vorgegebene Unterprogramme #####

; Vorgegebenes Unterprogramm "lcd_init"
; Initialisiert das Display
lcd_init:
	nop
	ret

; Vorgegebenes Unterprogramm "AccessGranted"
; Zeigt im Display die Kartennummer und Zutrittsgenehmigung an
AccessGranted:
	nop
	ret

; Vorgegebenes Unterprogramm "AccessDenied"
; Verbietet den Zutritt
AccessDenied:
	nop
	ret

; Vorgegebenes Unterprogramm "CheckParity"
; Liest die Daten von den gespeicherten Rohdaten, überprüft die Parität
; und speichert die Kartendaten unter "RFIDData".
; I: -
; O: R16 = Übertragung war erfolgreich (=1, sonst 0)
CheckParity:
	nop
	ret