[Assembler] System przerwań Intel 8051

0

Witam, mam program napisany, który ładuje do pamięci kody cyfr i za pomocą klawiatury sprzętowej cyfry te są wyświetlane na wyświetlaczu. Problem w tym, że po wciśnięciu klawisza program dalej chodzi, a chciałbym to zrobić za pomocą systemu przerwań. Tak, żeby po wciśnięciu klawisza zostało wykonane przerwanie. Jedyny problem to taki ;), że nie umiem i nie wiem jak ten system przerwań działa na 8051... czy jest tu ktoś kto mógłby mnie naprowadzić co gdzie i jak?

Kod programu:

mov 11h, #11111001b
mov 12h, #10100100b
mov 13h, #10110000b
mov 14h, #10011001b
mov 15h, #10010010b
mov 16h, #10000010b
mov 17h, #11111000b
mov 18h, #10000000b
mov 19h, #10010000b
mov 1Ah, #0xbf
mov 1Bh, #11000000B
mov 1ch, #0x7f
start:

	MOV R0, #0x11	
    
    ; scan row0
	SETB P0.0	
	CLR P0.3	
	CALL colScan	
	JB F0, finish
	
    ; scan row1
	SETB P0.3	
	CLR P0.2	
	CALL colScan	
	JB F0, finish

	; scan row2
	SETB P0.2		
	CLR P0.1		
	CALL colScan	
	JB F0, finish
		
	; scan row3
	SETB P0.1		
	CLR P0.0	
	CALL colScan
	JB F0, finish	
			


	JMP start	
				
finish:
    MOV P1, @r0
    MOV P0, #0xFF
    CLR F0
	JMP start	

; column-scan subroutine
colScan:
	JNB P0.6, gotKey
	INC R0			
	JNB P0.5, gotKey
	INC R0		
	JNB P0.4, gotKey	
	INC R0		
	RET			
gotKey:
	SETB F0		
	RET		
	

Screen symulatora na którym pracuje:

user image

0

Masz tutaj przykład jak to zrobić http://www.computersciencelab.com/8051ExampleProgram.htm

0

dzieki, ale i tak z tego nie wiele rozumiem... wiem, że trzeba do odpowiedniego rejestru wysłać adres przerwania wiem, że to musi być przerwanie od INT1/P3.3 czyli adres będzie 0x13 tylko co dalej? Jak ma wyglądać instrukcja przerwania? I jak z niej wychodzić, czy w ogóle się z niej wychodzi?

poniżej daje link do screena z architekturą symulatora na którym pracuje. Jakbyś mi mógł trochę więcej powiedzieć coś naprowadzić byłbym bardzo wdzięczny

user image

0

Normalnie mniej więcej kod tak powinien wyglądać:

 
         ORG   0x13       ; the ISV for the EXT 1 interrupt is 0x0013
EXT1INT: LJMP  function ; tutaj w tym miejscu powinna być funkcja przerwania, ale w praktyce daje się skok do innej funkcji

... tutaj jakiś twój kod

function: 
tutaj kod dla przerwania, a na końcu dajemy
reti ; jest to powrót do miejsca w kodzie który był ostatnio wykonywany, a następiło przerwanie
0

no właśnie, ale jaki ten kod przerwania. Co w nim powinno się znajdować? Może banalne pytania, ale w ogóle tego nie rozumiem.

0

No do przerwania INT1 masz podłączoną de facto klawiaturę a więc w funkcji przerwania powinno się odczytać klawisz wciśnięty, ale równie dobrze możesz zrobić co innego. Nie rozumiem w czym masz problem...

1

Dla klawiatury: zezwalasz na przerwanie INT1, oraz ogólnie zezwalasz na przyjmowanie przerwań.
Aby przerwanie wystąpiło, na jednym z wejść bramki AND sterowanej z portów P0.4, P0.5, P0.6 powinien pojawić się sygnał niski, zatem już wiesz, że stan jałowy portów P0.4, P0.5, P0.6 jest stanem wysokim. Wymuszenie stanu niskiego zostaw dla keypada; w tym celu, jednorazowo, podczas inicjacji/reset ustaw porty P0.0 ... P0.3 w stan niski. Wciśnięcie przycisku na keypadzie spowoduje zwarcie jednego wejścia bramki AND do stanu niskiego, oraz zgłoszenie przerwania.

Prawdę mówiąc, ta bramka wcale nie jest potrzebna. W ZX-Spectrum matrycowa klawiatura jest sprawdzana co 20ms, tutaj też można tak zrobić. Timer zgłaszający przerwanie masz, w jego obsłudze sterujesz multiplekserem LED i nic nie stoi na przeszkodzie, by tam dodpisać podprogram odczytywania klawiatury, co 20ms, lub rzadziej.

Odczyt Twojej klawiatury polega na przesuwaniu logicznego zera w jednej kolumnie matrycy i odczytaniu stanu drugiej kolumny, dla każdej pozycji zera w pierwszej kolumnie. Odczytanie zerowego bitu jest równoznaczne ze zwarciem na przecięciu pozycji zerowego bitu, a pozycją przesuwanego zera.

Przykład dla klawiszy 1,2,3:

  1. pozostawiam zero TYLKO na wierszu z przyciskami 1,2,3: orl P0,00000111b (zakładając, że poprzednio był tam stan jałowy ****0000b)
  2. odczytuję stan portu P0 do jakiegoś rejestru Rn. Jeżeli odczytany bit Rn.4 jest wyzerowany, to klawisz 3 jest wciśnięty - ten z kolumny podłączonej do P0.4. Podobnie dla dwóch pozostałych kolumn: if Rn.5=0 then key "2" is down; if Rn.6=0 then key "1" is down.

Sprawdzenie następnej kolumny różni się tylko podpunktem 1. Zamiast rozkazu ORL, wstawiam SETB P0.3 oraz CLR P0.2 (klawisze 456), wymuszany stan portu P0 to ****1011b, potem ponownie odczyt stanu P0 - odczyt stanu klawiszy 456. Kolejny rząd klawiszy 789 wymaga przesunięcia stanu niskiego na P0.1 ... potem klawisze *0#, i ostatecznie ustawienie stanu jałowego: wyzerowanie P0.0...P0.3.

Pisząc obsługę przerwań, nie zapomnij zapisać stanu rejestów które modyfikujesz i jednoczeście używasz w innych funkcjach, które mogą zostać przerwane, oraz flag (m.in. C,Z,O,P) jeżeli się zmieniają. Zamiast PUSH-ować wiele razy, możesz podmienić bank rejestrów Rn na jeden z trzech dodatkowych, dzięki czemu jedną instrukcją (np. XRL) "zapisujesz" stan ośmiu rejestru R0-R7. Nie powiem Ci który pseudo-rejestr odpowiada za aktywny bank rejestrów, bo ściągę zostawiłem prawie 1000km stąd. Wracając z podprogramu przerwania musisz odtworzyć stan rejestrów i flag (np. ponowne XRL na rejestrze banku rejestrów), ewentualnie kilka rozkazów POP w odwrotnej kolejności jak PUSH, wyzerowanie flagi "pending interupt", o ile taka istnieje, dla przerwania INT1 (modyfikując stanami logicznymi na kolumnach matrycy możesz nieumyślnie złosić przerwanie poprzez tą zbyteczną bramkę AND) oraz powrót instrukcją reti.

Problem przerwania w przerwaniu nie jest aż tak poważny, o ile go wykryjesz. Procesor obsługując przerwanie int1, może przyjąć kolejne przewranie int1 (zapamiętać, że wystąpiło), ale uruchomi je dopiero, gdy aktualnie aktywny podprogram obsługi tego przerwania powróci. Grozi to zapętleniem (niech ktoś sprostuje, jeżeli się mylę). Wyłączając przerwanie int1 na czas manipulacji portami, które mogą wywołać sprzętowe przerwanie int1, rozwiązuje problem.

1 użytkowników online, w tym zalogowanych: 0, gości: 1