Keine Angst vor Assembler

Status
Für weitere Antworten geschlossen.
Fertig Code Teil 3

Hi
Nun ja, dies Initialisierung ist nicht in allen Teilen zwingend. Auch die Routinen, die nun aufgezeigt sind, müssen so nicht in eure Programme und es ist auch möglich, das der ein oder andere Fehlerteufel noch vorhanden ist. Lediglich die Kommunikation mit dem PC und die Timer 1 und 2 Routinen sind getestet und laufen...
Code:
; *****************************************************************************
; *                 Programmblöcke  vom Hauptprogramm                         *
; *****************************************************************************


;********************************************************************
;*                 Berechnen der Laufzeit.                          *
;* Für 100 Taktzyklen wird 1 zum Wert in Zykl1 addiert, Bei 100     *
;* in Zykl_1 zählt Zykl_1 +1  und Zykl_1 beginnt von 0              *
;* Eine Min- Max Berechnung kann hier erweitert werden              *
;********************************************************************


Laufzeit:
	LDS	S_Merker, Zykl_1		; Laufzeitzähler setzen
	STS	Zykl_Zeit_1, S_Merker
	LDS	S_Merker, Zykl_2
	STS	Zykl_Zeit_2, S_Merker		; Zykl_Zeit_1 u.2 in OpenEye auslesen
	STS	Zykl_1, S_Merker
	STS	Zykl_2, S_Merker
RET

;---------------------------- Eingänge lesen -----------------------------------------
Read_IO:

RET

;****************************************************
;*                Kanalselektion                    *
;****************************************************                                              
Read_IO_M:	
		LDI	ZH,High(Neu_Input_A)
		LDI	ZL,Low(Neu_Input_A)	
		LDI	Cnt_Reg, 0b11111011	; 1. Kanal beschalten
		RCall	Read_IO_Kanal
		LDI	ZH,High(Neu_Input_B)
		LDI	ZL,Low(Neu_Input_B)	
		LDI	Cnt_Reg, 0b11110111	; 2. Kanal beschalten
		RCall	Read_IO_Kanal
		LDI	ZH,High(Neu_Input_C)
		LDI	ZL,Low(Neu_Input_C)	
		LDI	Cnt_Reg, 0b11101111	; 3. Kanal beschalten
		RCall	Read_IO_Kanal
		LDI	ZH,High(Neu_Input_D)
		LDI	ZL,Low(Neu_Input_D)	
		LDI	Cnt_Reg, 0b11011111	; 4. Kanal beschalten
		RCall	Read_IO_Kanal
RET

;***************************************************************
;*        Kanal Eingänge einlesen und in Variable ablegen      *
;***************************************************************                                              
Read_IO_Kanal:	
		In 	S_Merker, PortC		; zuerst Port C lesen 
		ORI	S_Merker, 0b00111100	; alle Ausgabebits auf 1 setzen
		AND	S_Merker, Tab_Cnt	; nur Kanal-Bit auf 0 ziehen
		OUT	PortC, S_Merker		; Taster des selektierten Kanals aktiv
		In 	S_Merker, PortC		; Port C in Register S_Merker schreiben
				;Nun blenden wir unerwünschte Bits aus
		ANDI	S_Merker, 0b00000011	; Nur Bit 0-1 sind für uns interessant.
		In 	T_Merker, PortD		; Port D in Register T_Merker schreiben
				;Nun blenden wir unerwünschte Bits aus
		ANDI	S_Merker, 0b11111100	; Nur Bit 0-1 sind für uns interessant.
		OR 	S_Merker, T_Merker	; führen die Eingänge zusammen
		ST	Z, S_Merker		; und legen neuen Wert in Variable ab
RET


; ******************************************************************
; *  Kanalweise prüfen der Eingänge inclusive der Flankenauswertung           *
; *  ****************************************************************
Chk_IO_Change_M:
	LDI	ZH,High(Neu_Input_A)		; Variablenadressen  Kanal A
	LDI	ZL,Low(Neu_Input_A)	
	LDI	XH,High(IO_Change_Bit_A)
	LDI	XL,Low(IO_Change_Bit_A)
	RCall	Chk_IO_Chg_Kanal		; Auswertung
	LDI	ZH,High(Neu_Input_B)		; Variablenadressen  Kanal A
	LDI	ZL,Low(Neu_Input_B)	
	LDI	XH,High(IO_Change_Bit_B)
	LDI	XL,Low(IO_Change_Bit_B)
	RCall	Chk_IO_Chg_Kanal		; Auswertung
	LDI	ZH,High(Neu_Input_C)		; Variablenadressen  Kanal C
	LDI	ZL,Low(Neu_Input_C)	
	LDI	XH,High(IO_Change_Bit_C)
	LDI	XL,Low(IO_Change_Bit_C)
	RCall	Chk_IO_Chg_Kanal		; Auswertung
	LDI	ZH,High(Neu_Input_D)		; Variablenadressen  Kanal D
	LDI	ZL,Low(Neu_Input_D)	
	LDI	XH,High(IO_Change_Bit_D)
	LDI	XL,Low(IO_Change_Bit_D)
	RCall	Chk_IO_Chg_Kanal		; Auswertung

RET
 

; ********************************************************************
; *  Es wird geprüft, ob eine Änderung eines  Einganges aufgetreten ist und        *
; *  das Ergebnis  in Die Variable IO_Change_Bit eingetragen.  Im Programm   *
; *  wird dieses Bit nach der  Bearbeitung gelöscht                                                   *
; *  ******************************************************************
Chk_IO_Chg_Kanal:
	LD	S_Merker, Z+		; Reg. S_Merker mit neuem Wert laden
	LD	T_Merker, Z		; das letzte gelesene Byte holen
	EOR	T_Merker, S_Merker	; S_Merker ist nicht verändert, 
	BREQ 	End_Chk_Chg_Kanal	; Reg. T_Merker ist 0 , keine Änderung
	ST	X, T_Merker		; Bits ablegen, die sich geändert haben
	RCall	Chk_To_Low		; Aufruf der Prüfung Wechsel von 1 nach 0
	RCall	Chk_to_High		; Aufruf der Prüfung Wechsel von 0 nach 1
	ST	Z, S_Merker		; Unterprogramme dürfen Register nicht verändern
End_Chk_Chg_Kanal: 
RET



;---------------------------- seriellen Empfang prüfen ----------------------------
Chk_RS232_Empf:	; Lese serielles Interface
	LDS	S_Merker, Write_Pos
	LDS	T_Merker, Read_Pos
	CP	T_Merker, S_Merker
	BREQ 	End_Chk_Empf
	LDI	ZH,High(Ring_Buf)
	LDI	ZL,Low(Ring_Buf)		; Adresszeiger auf Ringbuffer
	INC	T_Merker			; Lesezeiger erhöhen
	CPI	T_Merker,	20		; Lesezeiger Grenze ?
	BRLO	Read_Val			; unter Grenze, dann Empfang abholen
	CLR	T_Merker			; Temp auf 0 setzen
Read_Val:	
	STS	Read_Pos, T_Merker
	ADD	ZL, T_Merker			; Adresse kann größer als 1 Byte werden 
	ADC	ZH, Zero			; daher Addition mit Übertrag
	LD	Work_Reg, Z			; Empfang abholen
	STS	Erste_Variable, Work_Reg	
	RCall	Chk_RS232_Bef
	
End_Chk_Empf:		
	CLR	Work_Reg
RET

;-------------------- Eingänge auf Änderung testen -----------------------------

; ***********************************************************************
; * -------------------- Eingänge auf Änderung testen ----------------- *
; *  Es wird geprüft, ob eine Änderung eines Einganges aufgetreten ist  *
; *  und das Ergebnis in Die Variable IO_Change_Bit eingetragen         *
; *  Im Programm wird dieses Bit nach der Bearbeitung gelöscht.         *
; ***********************************************************************
Chk_IO_Change:
	LDS 	S_Merker, Neu_Input_A		; Reg. S_Merker mit neuem Wert laden
	LDS	T_Merker, old_Input_A		; das letzte gelesene Byte holen
	EOR	T_Merker, S_Merker		; S_Merker ist nicht verändert, 
	BREQ 	End_Chk_Change			; Reg. T_Merker ist 0 , keine Änderung
	STS	IO_Change_Bit_A, T_Merker	; Bits ablegen, die sich geändert haben
	RCall	Chk_To_Low			; Aufruf der Prüfung Wechsel von 1 nach 0
	RCall	Chk_to_High			; Aufruf der Prüfung Wechsel von 0 nach 1
	STS	Old_Input_A, S_Merker		; Unterprogramme dürfen S_Merker nicht verändern
End_Chk_Change: 

RET

;-------------------- Ereignisbehandlung Eingänge -----------------------------
Chk_Signal_Flag:

RET

;********************************************************************
;*              Auswerten der Zeitereignisse                        *
;*        das ist keine ISR, daher auch kein  Push und POP          *
;*    Soll ein Timer sofort erfasst werden, zum Bsp. Stoppuhr,dann  *
;*    ist die Routine direkt in der Timer-ISR aufzurufen            *
;* Dies hier ist nur ein Beispiel, wie mit Controlbits gearbeitet   *
;* werden kann. Die Verzögerung bewegt sich in wenigen ms           *
;********************************************************************

Chk_Timer_Flag:				
	LDS	Event_Reg, Timer_Flag
	TST	Event_Reg
	BREQ	End_TimeFlg
	Mov	Ablage, Event_Reg
	LDI	Temp, 0b00000001
	AND	Ablage, Temp
	TST	Ablage
	BREQ	Chk_TimeFlg_ms10
			;Aufruf Routine für ms-Auftrag, dieser Aufruf besser direkt in Timer-ISR
	LDI	Temp, 0b11111110			; Timerflag löschen
	And	Event_Reg, Temp
	
Chk_TimeFlg_ms10:
	Mov	Ablage, Event_Reg
	LDI	Temp, 0b00000010
	AND	Ablage, Temp
	TST	Ablage
	BREQ	Chk_TimeFlg_ms100
			;Aufruf Routine für 10ms-Auftrag
	LDI	Temp, 0b11111101			; Timerflag löschen
	And	Event_Reg,Temp

Chk_TimeFlg_ms100:
	Mov	Ablage, Event_Reg
	LDI	Temp, 0b00000100
	AND	Ablage, Temp
	TST	Ablage
	BREQ	Chk_TimeFlg_sek
	; --------------			;Aufruf Routine für 100ms-Auftrag
	LDI	Temp, 0b11111011		; Timerflag löschen
	And	Event_Reg, Temp
	
Chk_TimeFlg_sek:
	Mov	Ablage, Event_Reg
	LDI	Temp, 0b00001000
	AND	Ablage, Temp
	TST	Ablage
	BREQ	Chk_TimeFlg_min
	; --------------			;Aufruf Routine für Sekunden-Auftrag
	;RCall	Toggle_PrtD5			; Aufruf für Testzwecke freigeben, kommt nicht aus ISR
	LDI	Temp, 0b11110111		; Timerflag löschen
	AND	Event_Reg, Temp
	
Chk_TimeFlg_min:
	Mov	Ablage, Event_Reg
	LDI	Temp, 0b00010000
	AND	Ablage, Temp
	TST	Ablage
	BREQ	Chk_TimeFlg_std
	; --------------			;Aufruf Routine für min-Auftrag
	
	LDI	Temp, 0b11101111		; Timerflag löschen
	AND	Event_Reg, Temp
	
Chk_TimeFlg_std:
	Mov	Ablage, Event_Reg
	LDI	Temp, 0b00100000
	AND	Ablage, Temp
	TST	Ablage
	BREQ	Chk_TimeFlg_tag
	; --------------			;Aufruf Routine für Stds-Auftrag
	LDI	Temp, 0b11011111		; Timerflag löschen
	AND	Event_Reg, Temp
	
Chk_TimeFlg_Tag:
	Mov	Ablage, Event_Reg
	LDI	Temp, 0b01000001
	AND	Ablage, Temp
	TST	Ablage
	BREQ	Chk_TimeFlg_wo
	; --------------			;Aufruf Routine für Tag-Auftrag
	LDI	Temp, 0b10111111		; Timerflag löschen
	AND	Event_Reg, Temp
	
Chk_TimeFlg_wo:
	Mov	Ablage, Event_Reg
	LDI	Temp, 0b10000000			
	AND	Ablage, Temp
	TST	Ablage
	BREQ	End_TimeFlg
	; --------------			;Aufruf Routine für Woches-Auftrag
	LDI	Temp, 0b01111111		; Timerflag löschen
	AND	Event_Reg, Temp

End_TimeFlg:
	STS	Timer_Flag, Event_Reg		; und Timerflags zurückschreiben
RET


;********************************************************************
;*              Auswerten Zeitereigniss Sekunde                     *
;*        das ist keine ISR, daher auch kein  Push und POP          *
;********************************************************************
Toggle_PrtD5:						
	LDS	S_Merker, Ausgabebyte
	LDI 	Temp,0b00100000
	EOR	S_Merker, Temp
	STS	Ausgabebyte, S_Merker
RET

;--------------------------------- Ausgabe an RS 232 -----------------------------
Write_UART:	

RET	

; **********************************************************************************
; * ----------------------------- Ausgabe an IO-Ports -----------------------------*
; *               Beachte, nur Bit 5 und 6 sollen verändert wertden.               *
; *                       Alle anderen Bits bleiben unverändert                    *
; **********************************************************************************
Write_IO:
	In	S_Merker, PortD		; Wert in Register Port D lesen
	
	LDS	T_Merker, Ausgabebyte	; Bearbeitetes Ausgabebyte holen
	ANDI	S_Merker, 0b10011111	; Nur Bits ändern, die Ausgegeben werden
	OR	T_Merker, S_Merker	; Mit eier Oder - Funktion Ausgabebits setzen
	Out 	PortD, T_Merker		; und in das Ausgaberegister Port D schreiben

RET
 
Fertig Code Teil 4

Hi
Ich hoffe, der Rest passt jetzt hier hinein. Wer dieses Programm testen will, sollte beachten, ich habe eine Baudrate von 19200 bei 8 Mhz eingesetzt. Diese Einstellung gehört dann in OpenEye und der Befehl zum Übertragen der Variablen ist "V" oder "v".
Code:
; *********************************************************************************
; *                 Programmblöcke  der  Untertprogramme                          *
; *********************************************************************************

; ************************************************************************************
; *  Es wird geprüft, ob die Änderung von 1 nach 0  erfolgt ist und das Ergebnis     *
; *  in die Variable  Change_To_Low eingetragen.  Im Programm wird dieses  Bit       *
; *  nach der Bearbeitung gelöscht und löst nur eine einmalige  Bearbeitung   aus.   *
; ************************************************************************************
Chk_To_Low:
	Push	Temp			; diese Registerinhalte werden noch gebraucht
	Push	Merker
	LDS	Temp, 	Old_Input	; Eine alte 1 und die Änderung ergeben eine 1
 	And	Merker, Temp 	
	LDS	Temp, 	Change_To_Low	; nur Änderungen eintragen, andere Bits
	Or	Merker, Temp		; müssen ihren Wert erhalten
	STS	Change_To_Low, Merker
	POP	Merker
	POP	temp
RET		

; *************************************************************************************
; *  Es wird geprüft, ob die Änderung von 0 nach 1  erfolgt ist und das Ergebnis      *
; *  in die Variable Change_To_ High eingetragen.  Im Programm wird dieses  Bit       *
; *  nach der Bearbeitung gelöscht und löst nur eine einmalige  Bearbeitung   aus.    *
; *************************************************************************************
Chk_To_High:
	Push	Temp			; diese Registerinhalte werden noch gebraucht
	Push	Merker
	LDS	Temp, 	neu_Input	; Eine neue 1 und die Änderung ergeben eine 1
 	And	Merker, Temp 	
	LDS	Temp, 	Change_To_High	; nur Änderungen eintragen, andere Bits
	Or	Merker, Temp		; müssen ihren Wert erhalten
	STS	Change_To_High, Merker
	POP	Merker
	POP	temp
RET	

; *****************************************************************************
; *  Prüfung Änderung von 1 nach 0 , Ergebnis steht in   Change_To_ High_x    *
; *****************************************************************************
 
Chk_To_Low_M:				;Multi....
	Push	S_Merker		; diese Registerinhalte werden noch gebraucht
	Push	T_Merker
	LD	S_Merker, Z		; Z zeigt bereits auf diese Variable
 	And	T_Merker, S_Merker	; in T_Merker sind die veränderten Bits
	Push 	ZH			; Z wird aber noch gebraucht
	Push 	ZL				
	LDI	Temp, 11		; 11 Adressen Differenz zu Change_To_Low_x
	ADD	ZL, Temp		; Z berechnen 
	ADC	ZH, Zero		; und Addition mit Übertrag
	LD	S_Merker, Z		; nur Änderungen eintragen, andere Bits
	Or	T_Merker, S_Merker	; müssen ihren Wert erhalten
	ST	Z, T_Merker		; und zurückschreiben
	POP	ZL			; Registerinhalte wieder herstellen
	POP	ZH
	POP	T_Merker
	POP	S_Merker
RET		

; *****************************************************************************
; *  Prüfung Änderung von 0 nach 1 , Ergebnis steht in   Change_To_ High_x    *
; *****************************************************************************
Chk_To_High_M:				;Multi....
	Push	S_Merker		; diese Registerinhalte werden noch gebraucht
	Push	T_Merker
	And	T_Merker, S_Merker	; Eine neue 1 und die Änderung ergeben eine 1
	Push 	ZH			; Z wird aber noch gebraucht 
	Push 	ZL				
	LDI	Temp, 12		; 12 Adressen Differenz zu Change_To_High_x
	LD	S_Merker, Z		; nur Änderungen eintragen, andere Bits
	Or	T_Merker, S_Merker	; müssen ihren Wert erhalten
	ST	Z, T_Merker
	POP	ZL			; Registerinhalte wieder herstellen
	POP	ZH
	POP	T_Merker
	POP	S_Merker
RET	
 



; ***********************************************************************************
; *  Es wird geprüft, ob Befehle bereits erkannt  wurden, die weitere Daten         *
; *  erforderlich machen.  Diese Information ist in der Variablen  Bef_Control      *
; *  abgelegt . Erst wenn klar ist, dies ist ein neuer Befehl,  wird er decodiert.  *
; *  Je nach Ergebnis ist auch  Bef_Control verändert                               *
; ***********************************************************************************
Chk_RS232_Bef :
;	LDS	Merker, Bef_Control	; Befehlscontrollregister laden
;	ANDI	Merker, 0b00001000	; Bit für 3 Byte Befehl prüfen
;	BREQ	Chk_Two_Byte		; kein 3 Byte-Befehl, prüfe 2 Byte
;	RCall 	Three_Block		; bearbeite 3 Byte-Befehl
;	RJmp 	Chk_RS232_Bef_End		
Chk_Two_Byte:
;	LDS	Merker, Bef_Control	; Befehlscontrollregister laden
;	ANDI	Merker, 0b00000100	; Bit für 3 Byte Befehl prüfen
;	BREQ	Chk_One_Byte		; kein 2 Byte-Befehl, prüfe Befehl
;	RCall 	Two_Block		; Bearbeite 2 Byte Befehl
;	RJmp 	Chk_RS232_Bef_End 
Chk_One_Byte:

		
	RCall	Chk_Order
Chk_RS232_Bef_End : RET


; *************************************************************************************
; *  Es wird geprüft, wie viele Bytes bearbeitet wurden. Der Zähler ist in der        *
; *  Variablen  Bef_Cnt abgelegt.  Dieser Wert hoch gezählt und dient gleichzeitig    *
; *  als Offset.  In Value_Dir ist der Kanal hinterlegt, für den  die Werte bestimmt  *
; *  sind.                                                                            *
; *************************************************************************************
Two_Block:

RET

; *************************************************************************************
; *  Es wird geprüft, wie viele Bytes bearbeitet wurden. Der Zähler ist in der        *
; *  Variablen  Bef_Cnt abgelegt.  Dieser Wert hoch gezählt und dient gleichzeitig    *
; *  als Offset.  In Value_Dir ist der Kanal hinterlegt, für den  die Werte bestimmt  *
; *  sind.                                                                            *
; *************************************************************************************

Three_Block:
	LDS	S_Merker, Value_Dir	; Kanaladresse laden
	LDI	ZH,High(Kanal_0)
	LDI	ZL,Low(Kanal_0)		; Adresszeiger auf 1. Kanal
	ADD	ZL, S_Merker		; Adresse kann größer als 1 Byte werden 
	ADC	ZH, Zero		; daher Addition mit Übertrag
	LDS	S_Merker, Bef_Cnt	; Bytenummer laden
	ADD	ZL, S_Merker		; Adresse kann größer als 1 Byte werden 
	ADC	ZH, Zero		; daher Addition mit Übertrag
	ST	Z, Work_Reg		; Information im Kanalbereich ablegen
	INC	S_Merker		; Bytezähler erhöhen
	CPI	S_Merker, 3		; Abfrage, ob Bytezahl erreicht
	BRLO	Three_Block_End		; und beenden
	LDS	S_Merker, Bef_Control
	ANDI	S_Merker, 0b11110111	; Bit für 3 Bytebefehl löschen
	STS	Bef_Control, S_Merker	; und Controlflags zurückschreiben
	CLR	S_Merker		; Merker Löschen
Three_Block_End:
        STS	Bef_Cnt, S_Merker	; Bef_Cnt zurückschreiben 
RET

; ****************************************************************************************
; *  Es wird geprüft, wie viele Bytes bearbeitet wurden. Die Vorgabezahl der zu          *
; *  empfangenen Bytes liegt in Cnt_Soll.  Der Zähler ist in der  Variablen  Bef_Cnt     *
; *  abgelegt.  Dieser Wert wird  hoch gezählt und dient gleichzeitig als Offset         *
; *  In Value_Dir ist der Kanal hinterlegt, für den  die Werte bestimmt sind.            *
; ****************************************************************************************
Multi_Block:
	LDS	Merker, Value_Dir	; Kanaladresse laden
	LDI	ZH,High(Kanal_0)
	LDI	ZL,Low(Kanal_0)		; Adresszeiger auf 1. Kanal
	ADD	ZL,Merker		; Adresse kann größer als 1 Byte werden 
	ADC	ZH, Zero		; daher Addition mit Übertrag
	LDS	Merker, Bef_Cnt		; Bytenummer laden
	ADD	ZL, Merker		; Adresse kann größer als 1 Byte werden 
	ADC	ZH, Zero		; daher Addition mit Übertrag
	ST	Z, Work_Reg		; Information im Kanalbereich ablegen
	INC	Merker			; Bytezähler erhöhen
	LDS 	Temp, Cnt_Soll		; Anzahl der erwarteten Bytes
	CP	Merker, Temp		; Abfrage, ob Bytezahl erreicht
	BRLO	Multi_Block_End		; und beenden
	LDS	Merker, Bef_Control
	ANDI	Merker,0b11110111	; Bit für 3 Bytebefehl löschen
	STS	Bef_Control, Merker	; und Controlflags zurückschreiben
	CLR	Merker			; Reg_x Löschen
	STS	Cnt_Soll, Merker	; Reg_x gleich zum Reset der Vorgabe nutzen
Multi_Block_End:
	STS	Bef_Cnt, Merker		; Bef_Cnt zurückschreiben 
RET
; ************************************************************************************
; *                 Auswahl Befehle vom Empfang über RS 232,                         *
; ************************************************************************************
Chk_Order:
	CPI	Work_Reg, 'M'		; Multibytebefehl ?
	BRNE 	CHK_Ag			; sonst weiter mit Testen auf "A"
	;RCall 	Multi_Block		; Aufruf Unterprogramm
	RJMP 	Chk_Order_End	 
CHK_Ag:
	CPI	Work_Reg, 'A'		; Relais A einschalten ?
	BRNE 	CHK_ak			; sonst weiter mit Testen auf "a"
	RCall 	Set_Relais_A		; Aufruf Unterprogramm
	RJMP 	Chk_Order_End		 
CHK_ak:
	CPI	Work_Reg, 'a'		; Relais A ausschalten ?
	BRNE 	CHK_Bg			; sonst weiter mit Testen auf "B"
	RCall 	Set_Relais_A		; Aufruf Unterprogramm
	RJMP 	Chk_Order_End		 
CHK_Bg:
	CPI	Work_Reg, 'B'		; Relais B einschalten ?
	BRNE 	CHK_bk			; sonst weiter mit Testen auf "b"
	RCall 	Set_Relais_B		; Aufruf Unterprogramm
	RJMP 	Chk_Order_End	 
CHK_bk:
	CPI	Work_Reg, 'b'		; Relais B einschalten ?
	BRNE 	CHK_Vg			; sonst weiter mit Testen auf "V"
	RCall 	Set_Relais_B		; Aufruf Unterprogramm
	RJMP 	Chk_Order_End	 
CHK_Vg: 
	CPI	Work_Reg, 'V'		; Werte empangen, z. B. Parameter ?
	BRNE 	CHK_vk			; sonst weiter mit Testen auf "R"
	RCall 	Send_Value		; Aufruf Unterprogramm
	RJMP 	Chk_Order_End	 
CHK_vk:
	CPI	Work_Reg, 'v'		; Werte angefordert ?
	BRNE 	Chk_Order_End		; sonst ende
	RCall 	Send_Value		; Aufruf Unterprogramm
	
Chk_Order_End:
	CLR	Work_Reg
Ret

;------------------------ Setzen von Bits in Ausgabebyte --------------------------
Set_Relais_A:
RET

;------------------------ Setzen von Bits in Ausgabebyte --------------------------
Set_Relais_B:
RET

;------------------------ Laden von Eingängen --------------------------
Set_Multi_Byte:
	LDS	Merker, Value_Dir	; Kanaladresse laden
	LDI	ZH,High(Kanal_0)
	LDI	ZL,Low(Kanal_0)		; Adresszeiger auf 1. Kanal
	ADD	ZL, Merker		; Adresse kann größer als 1 Byte werden 
	ADC	ZH, Zero		; daher Addition mit Übertrag
	LDS	Merker, Bef_Cnt		; Bytenummer laden
	ADD	ZL, Merker		; Adresse kann größer als 1 Byte werden 
	ADC	ZH, Zero		; daher Addition mit Übertrag
	ST	Z, Work_Reg		; Information im Kanalbereich ablegen
	INC	Merker			; Bytezähler erhöhen
	LDS 	Temp, Cnt_Soll		; Anzahl der erwarteten Bytes
	CP	Merker, Temp		; Abfrage, ob Bytezahl erreicht
	BRLO	Multi_Byte_End		; und beenden
	LDS	Merker, Bef_Control
	ANDI	Merker,0b11110111	; Bit für 3 Bytebefehl löschen
	STS	Bef_Control, Merker	; und Controlflags zurückschreiben
	CLR	Merker			; Reg_x Löschen
	STS	Cnt_Soll, Merker	; Reg_x gleich zum Reset der Vorgabe nutzen
Multi_Byte_End:
	STS	Bef_Cnt, Merker		; Bef_Cnt zurückschreiben 

RET

Set_Value:
RET
 
leider noch ein 5. Teil

Hat nicht geklappt, war wohl doch zuviel. Daher hier nun der wirklich letzte Abschnitt:

Code:
; ***************************************************************************
; * Senderoutine an den PC in. Da wir verschiedene Inhalte beachten müssen, *
; * werden wir auch  diesen  Daten eine Kennung verpassen.   Der Kopf wird  *
; *  mit "VALUE" gesendet.   Das zu sendende Byte  wird in einem Register   *
; * Send_Byte der Routine Ser_Out übergeben                                 *
; ***************************************************************************

Send_Value:
	LDI	Send_Byte, 'V'		; Telegramm-Kopf
	rcall   SerOut			
	LDI	Send_Byte, 'A'
	rcall   SerOut			
	LDI	Send_Byte, 'L'
	rcall   SerOut			
	LDI	Send_Byte, 'U'
	rcall   SerOut			
	LDI	Send_Byte, 'E'
	rcall   SerOut			
	LDI	ZH,High(Erste_Variable)
	LDI	ZL,Low(Erste_Variable)	; Adresszeiger auf 1. Variable
	LDI	Cnt_Reg, 40		; Anzahl zu sendender Bytes
Loop_Send:
	LD	Send_Byte, Z+		; Lade inhalt der Adresse von Z und erhöhe Z
	RCall   SerOut			; Senderoutine aufrufen
	DEC	Cnt_Reg			; Bytezähler runterzählen
	BRNE	Loop_Send		; Wenn nicht 0 dann weiter senden
RET
			
; ************************************************
; * Sendeanstoss der UART Schnittstelle RS 232   *
; * Übergabewert in Register Send_Byte           *
;*************************************************

SerOut:	
	SBIS	UCSRA,UDRE		; Warten Freigabe UDR 
	RJMP	SerOut
   	OUT	UDR, Send_Byte
RET                                 

;*************************************************************************
;*                  Interrupt Programmteile                              *
;*************************************************************************

; **************************************************************
; *  Der Timer 0 wird zur Laufzeitberechnung benutzt und       *
; *  löst den Interrupt bei Überlauf aus. Der Vorteiler ist 1  *
; **************************************************************
isrTimer0:				; Sprungmarke aus der Interrupt Vector Tabelle
	;Push	Temp			; Register 1 sichern
	;In	Temp, SREG		; Statusregister holen
	;Push	Temp			; und auf Stack sichern
	;Push	S_Merker
	;LDS	S_Merker, Zykl_1
	;Inc	S_Merker		; entspricht bei 16 MHz einer Zeit von 16 µs
	;CPI	S_Merker, 100
	;BRLO	Set_Zykl_1		; wenn < 100 dann ablegen und weiter
	;Clr	S_Merker
	;STS	Zykl_1, S_Merker
	;LDS	S_Merker, Zykl_2
	;Inc	S_Merker
	;STS	Zykl_2, S_Merker
	;RJmp	isrTimer0_End

;Set_Zykl_1:
	;STS	Zykl_1, S_Merker
	
;isrTimer0_End:

	;POP	S_Merker
	;POP	Temp			; und auf Stack sichern
	;OUT	SREG,Temp		; Statusregister holen
	;POP	Temp			; und auf Stack sichern
RETI
;---------------- Timer 0 ist nicht in Betrieb -------------------


;*************************************************************************
;*                      ---Timer 1 Interrupt ------                      *
;* beachte, die unteren Register haben keine direkte Wertzuweisung für   *
;* Vergleiche und Verknüpfungen, daher braucht es ein weiteres Register  *
;*************************************************************************
isrTimer1:				; Sprungmarke aus der Interrupt Vector Tabelle
	Push	Temp			; Register 1 sichern
	In	Temp, SREG		; Statusregister holen
	Push	Temp			; und auf Stack sichern
	Push	S_Merker		; 2. register sichern
	LDI	Temp, 10		; hier werden die Vergleichswerte geladen
	LDS	S_Merker, Timer_Flag
	ORI	S_Merker, 0b00000001
	STS	Timer_Flag , S_Merker
	Inc	ms0
	CP	ms0, Temp		; direkter Vergleich mit CPI mit diesem Register nicht möglich
	BRLO 	Sprung			; die Distanz wird zu Groß, um das Ziel mit 1 Sprung zu erreichen
	CLR	ms0
	LDS	S_Merker, Timer_Flag
	ORI	S_Merker, 0b00000010
	STS	Timer_Flag , S_Merker
	INC	ms1
	CP	ms1, Temp		
	BRLO 	End_ISR_Timer
	CLR	ms1
	LDS	S_Merker, Timer_Flag
	ORI	S_Merker, 0b00000100
	STS	Timer_Flag , S_Merker
	INC	ms2
	CP	ms2, Temp		
	BRLO 	End_ISR_Timer
	CLR	ms2
	LDS	S_Merker, Timer_Flag
	ORI	S_Merker, 0b00001000
	STS	Timer_Flag , S_Merker
	;RCALL	Toggle_PrtD5		; Sekundenblinker für Test freigeben. Kommt aus ISR.
	LDI	Temp, 60		; daher verwendete Register beachten, evtl. sichern!
	INC	Sekunde
	CP	Sekunde, Temp		
	BRLO 	End_ISR_Timer
	CLR	Sekunde
	LDS	S_Merker, Timer_Flag
	ORI	S_Merker, 0b00010000
	STS	Timer_Flag , S_Merker
	INC	Minute
	CP	Minute, Temp		
	BRLO 	End_ISR_Timer
	CLR	Minute
	LDS	S_Merker, Timer_Flag
	ORI	S_Merker, 0b00100000
	STS	Timer_Flag , S_Merker
	LDI	Temp, 24
	INC	Stunde
	CP	Stunde, Temp		
Sprung:
	BRLO 	End_ISR_Timer
	CLR	Stunde
	LDS	S_Merker, Timer_Flag
	ORI	S_Merker, 0b01000000
	STS	Timer_Flag , S_Merker
	LDI	Temp, 7
	INC	Tag
	CP	Tag, Temp		
	BRLO 	End_ISR_Timer
	CLR	Tag
	LDS	S_Merker, Timer_Flag
	ORI	S_Merker, 0b10000000
	STS	Timer_Flag , S_Merker
	
	INC	Woche

End_ISR_Timer:
	Pop	S_Merker		; Register in umgekehrter Reihenfolge aktualisieren
	POP	Temp			; Statusregister 
	Out	SREG, Temp		; zurückschreiben
	POP	Temp			; Register 1 aktualisieren
RETI

; **************************************************************
; *  Der Timer 2 wird zur Laufzeitberechnung benutzt und       *
; *  löst den Interrupt bei Vergleich aus. Der Vorteiler ist 1 *
; **************************************************************
isrTimer2:		  		; Sprungmarke aus der Interrupt Vector Tabelle
	Push	Temp			; Register 1 sichern
	In	Temp, SREG		; Statusregister holen
	Push	Temp			; und auf Stack sichern
	Push	S_Merker
	LDS	S_Merker, Zykl_1
	Inc	S_Merker		; entspricht bei 16 MHz einer Zeit von 16 µs
	CPI	S_Merker, 100
	BRLO	Set_Zykl_nxt0		; wenn < 100 dann ablegen und weiter
	ClR	S_Merker
	STS	Zykl_1, S_Merker
	LDS	S_Merker, Zykl_2
	Inc	S_Merker
	STS	Zykl_2, S_Merker
	RJmp	isrTimer2_End

Set_Zykl_nxt0:
	STS	Zykl_1, S_Merker

	
isrTimer2_End:
	
	POP	S_Merker
	POP	Temp			; und auf Stack sichern
	OUT	SREG,Temp		; Statusregister holen
	POP	Temp			; und auf Stack sichern
RETI

; **************************************************************
; *  der UART Interrupt wird beim Empfang  ausgelöst.          *
; *  Der empfangene Wert wird in den  Ringbuffer eingetragen.  *
; * Ringbuffer eingetragen.                                    *
; **************************************************************

Int_RXc:
	PUSH	Temp			; temp auf dem Stack sichern
	PUSH	ZH
	PUSH	ZL
	IN	Temp, SREG		; SREG sichern    
	PUSH	Temp
	PUSH	S_Merker
	PUSH	Work_Reg
	LDS	Temp, Write_Pos		; Write_Pos = Schreibzeiger Ringpuffer
	LDI	ZH,High(Ring_Buf)
	LDI	ZL,Low(Ring_Buf)	; Adresszeiger auf Ringbuffer
	INC	Temp			; Schreibzeiger erhöhen
	CPI	Temp,	20		; Schreibzeiger Grenze ?
	BRLO	Eintrag			; unter Grenze, dann Empfang eintragen
	CLR	Temp			; Temp auf 0 setzen
Eintrag:	
	STS	Write_Pos, Temp
	ADD	ZL, Temp		; Adresse kann größer als 1 Byte werden 
	ADC	ZH, Zero		; daher Addition mit Übertrag
	IN	Work_Reg, UDR		; UART Daten lesen, Work_Reg ist Reserviert
	ST	Z, Work_Reg		; Empfang aus UART  in Puffer schreiben
	POP	Work_Reg
	POP	S_Merker
	POP	temp 
	OUT	sreg, temp		; SREG wiederherstellen
	POP	ZL
	POP	ZH
	POP	temp			; temp wiederherstellen    
RETI

Ich hoffe, ihr habt euren Spaß damit.
Gruß oldmax
 
Assembler !!

Halo OLDMAX,

eigentlich stehe ich ganz auf deiner Seite... Assembler ist der Grundstein der Mikrokontroller-Programmierung....

Leider, oder Gott sei Dank, geht es auch einfacher--- Nicht für dich und (für mich auch) ..

Die Kontroller in einer Hochsprache zu programmeiren, ist einfach, einfacher, auch wenn mann nicht bis zum Kern der Sache vordringen kann..
--Als super-Oldi habe ich einfach keine Zeit mich mit dem -Assembler-gewurstel auseinander zu setzen.. Meine Assembler-kenntnis hilt mir unwahrscheinlich, mich mit einer Hochsprache (C, Processing) auseinander zu setzen........Für die AVR-s kann ich nur ARDUINO vorsclagen.....

Wolfgang.
 
Hi Wolfgang
Dieser Beitrag sollte als abgeschlossen betrachtet werden. Ich möchte hier jetzt keine Grundsatzdiskussion anschließen, ob Assembler oder eine Hochsprache. Aus vielen anderen Threads weiß ich, das dies auch Dauerläufer werden können. Jeder ist von "seiner" Lieblingssprache überzeugt. Dieser Beitrag ist eben darum geschrieben, um zu zeigen, das ein Controller auch nur Elektronik ist. Und du sagst es ja auch, das sich keine andere Sprache so nah an der Hardware bewegt. Es war mein Ziel, dies im Umgang mit Assembler offenzulegen. Vielleicht hat es auch einigen geholfen, unverständliches Verhalten eines Controllers zu erkennen und zu deuten. Wenn also eine Grundsatzdiskussion erwünscht wird, bitte, dann in einem neuen Thread. Hier bleibt es bei "keine Angst vor Assembler"
Gruß oldmax
 
Status
Für weitere Antworten geschlossen.

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)