AngoLinux

Gioco di riflessi

- A cura del Prof. Stefano Salvi -


Introduciamo un poco di complicazione.

Il testo dell'esercizio è il seguente:

Scrivere un programma Assembler per 8051 che implementi un piccolo gioco dei riflessi.
  • Un LED acceso scorre sulla barra dei LED rossi, verso sinistra.
  • Se il giocatore preme il pulsante verde più a destra mentre è acceso il LED rosso più a sinistra, vince una partita.
  • Quando il giocatore vince una partita, i LED rossi lampeggiano tre volte ed il punto viene accumulato in un conteggio binario visualizzato sui LED gialli.
  • Premendo il secondo tasto da destra, il gioco si azzera.
Utilizzare una subroutine che esegua un ritardo.

NOTE:

  • I LED sono connessi all'alimentazione positiva, quindi un livello logico 0 sull'uscita accende il LED, mentre un livello 1 lo spegne.
  • I bottoni sono connessi a massa, quindi quando un bottone è premuto leggeremo 0 sul corrispondente ingresso, mentre leggeremo 0 se è rilasciato.
  • I LED sono disposti dal bit 0 al bit 7, quindi una rotazione a destra sposta la configurazione a sinistra.
  • Per ulteriroi informazioni sulla programmazione del PPI della scheda GPC-F2, fare riferimento alla pagina Hardware e mappa di memoria della scheda del Manuale d'uso del programma PCMon.

Una possibile soluzione è la seguente:
;giokino.asm
;Stefano Salvi - 17/8/02
;
;Questo programma e' un gioco che aumenta il punteggio nei led gialli ogni volta 
;che si preme 
;il pulsante e e' contemporaneamente acceso l'ultimo led rosso. Quando vinco 
;lampeggiano tutti i led per 3 volte. 
;Imposto la porta di controllo con la porta a e c bassa di output e c alta di 
;input.
;inizializzo un contatore e guardo se quando premo il tasto il mio contatore e' a 
;p1 e allora faccio illuminare 3 volte i led e intanto faccio incrementare il 
;contatore giallo. 
;
; I LED rossi sono connessi alla porta A del PPI.
; I LED gialli sono connessi alla porta C 0..3 del PPI
; I Bottoni verdi sono connessi alla porta C 4..7 del PPI
; Il port A del PPI e' all'indirizzo 0FA00H nella memoria XDATA.
; Il port C del PPI e' all'indirizzo 0FA02H nella memoria XDATA.
; Il port di Controllo del PPI e' all'indirizzo 0FA03H nella memoria XDATA.
; La programmazione del PPI sara' la seguente:
; 1xxx xxxx Programmo port
; x00x xxxx Port A -> modo 0
; xxx0 xxxx Port A -> output
; xxxx 1xxx Port C Hi -> input
; xxxx x0xx Port B -> modo 0
; xxxx xx1x Port B -> input
; xxxx xxx0 Port C Lo -> output
; ---------
; 1000 0010
;
 
.org 8050h
; Definisco alcune costanti utili:
.equ	PPIPORTA, 0FA00h	; Port A del PPI
.equ	PPIPORTC, 0FA02h	; Port C del PPI
.equ	PPICTL, 0FA03h		; Port di controllo del PPI

.equ	novince, 0		; Variabile BIT che indica stato vecchio tasto

	sjmp	main		; salta le subroutine e va al programma principale

;----------------------- routine di ritardo ------------------------------------
; Ritardo di circa 0,2 secondi
;  Con il quarzo a 1059200 Hz, l'8051 esegue 921600 cicli al secondo
;  Se voglio 5 lampeggi al secondo, devo avere un ritardo di 184320 cicli.
;  Ipotizzando di avere un' 'operazione base' di 4 cicli, 240 ripetizioni di
;  questa operazione porteranno ad impiegare 240*4 = 960 cicli totali.
;  Se ora ripeteremo qesto ritardo base per 192 volte, otterremo 960*192=184320
;  cicli int otale (non contando i 4 cicli aggiuntivi per ripetere il ritardo
;  base, pari a 192*4=768)
; Ingresso:
;	nessuno
; Uscita:
;	nessuna
; Usa:
;	r0,r1
delay:
	mov	R1,#192 ; 192 ripetizioni di un ritardo base
lp2:                           ; Ciclo Esterno
	mov	R0,#240 ; 200 ripetizioni di piccolo ritardo (2 nop)
lp3:                           ; Ciclo Interno
	nop                   ; operazione nulla - circa un micorsecondo (uS)
	djnz	R0,lp3     ; Ripete 'nop' (ci mette circa altri 2 uS)
	djnz	R1,lp2     ; ripete il ritardo precedente (200 * 3 -> 600 uS)
;
	ret

;---------------------------------------------------------------------------
; main program 
;---------------------------------------------------------------------------
main:
;----------------------inizializzazioni----------------------------------------	
	mov	sp,#8Fh		; Imposta lo stack per la chiamata a 'delay'	
; Programmo port, Port A -> modo 0, Port A -> output, Port C Hi -> input,
; Port B -> modo 0, Port B -> input, Port C Lo -> output
	mov	a,#10001010b	;imposto porta di controllo
	mov	dptr,#PPICTL
	movx	@dptr,a
	
	mov	a,#1111b    	;imposta porta led gialli-verdi
	mov	dptr,#PPIPORTC
	movx	@dptr,a
	
	mov	r2,#01111111b	; Configurazione dei LED - 0 -> Acceso, 1 -> Spento
	mov	dptr,#PPIPORTA	; Porta LED rossi
	mov	a,r2		; recupera configurazione LED
	movx	@dptr,a		; La invia ai LED
        mov	r5,#0           ; Contatore Punteggi
;
mainlp:
;
; Attende il ritardo necessario ed aggiorna la configurazione dei LED 
;
	acall	delay           ; chiama routine di ritardo
; 
; Elaborazione alla fine, prima di cambiare visualizzazione     
;
; Test del tasto di 'reset Gioco'
;
	mov	dptr,#PPIPORTC	; bit 4-7 -> tasti
	movx    a,@dptr		; Legge porta
	jnb	acc.6,main	; Settimo tasto premuto -> reset gioco
;
;
;----------------------------------------------------------------------------
; Il tasto deve essere premuto quando l'ultimo LED rosso e' acceso.
; Per evitare che, tenendo il tasto premuto, si vinca, quando e' acceso il
; penultimo LED rosso, controllo che il tasto sia rialsciato.
; Solo se il tasto era rilasciato, trovandolo premuto con l'ultimo LED, conto il punto
;
	cjne	r2,#11111101b,testLed7
;
; E' acceso il penultimo LED:
; Se il tasto e' gia' premuto, setta il FLAG
;
	mov	dptr,#PPIPORTC 	; porta pulsanti
	movx	a,@dptr		; legge il pulsante
	clr	novince		; azzera il 'flag'
	jb	acc.7,fineMain	; bit7=1 -> pulsante rialsciato
	setb	novince		; pulsante gia premuto -> setto flag
	sjmp	fineMain	; prosegue
;
testLed7:
	cjne	r2,#11111110b,fineMain
;
; E' acceso l'ultimo LED
;
	jb	novince,fineMain; pulsante premuto da prima: risultato non valido
	mov	dptr,#PPIPORTC	; porta pulsanti
	movx	a,@dptr		; legge il pulsante
	jb	acc.7,fineMain	; Pulsante del gioco non premuto, nessun punto
;
; pulsante premuto -> vincita!!
;
	inc 	r5		; contatore vittorie
	mov	dptr,#PPIPORTC	; Port LED gialli
	mov	a,r5		; copia la configurazione
	anl	a,#0fh		; Elimina i bit in eccesso (4 LED)
	cpl	a		; Inverte configurazione (0 -> Acceso, 1 -> spento)
	movx	@dptr,a		; Manda sui LED

	mov	dptr,#PPIPORTA	; porta led rossi
	mov 	a,#00000000
	mov	r3,#6		; sei inversioni -> tre lampeggi
vinciloop:
	movx	@dptr,a		; manda codice sui LED
        acall   delay		; Pausa per visualizzare i LED
	cpl	a               ; cambia da acceso (0) a spento (1) o viceversa tutti i LED
	djnz	r3,vinciloop
;
; Fine codice vincita
;
fineMain:
;
; Calcola la nuova configurazione e la visualizza
;
	mov	dptr,#PPIPORTA	; porta led rossi
	mov	a,r2		; configurazione memorizzata
	rr	a          	; Ruota la configurazione (Bit 0 va in Bit 7)
	movx	@dptr,a		; la manda sui LED
	mov	r2,a		; Rimette nel registro la configurazione aggiornata
;
	sjmp 	mainlp		; loop


.end

Il sorgente del programma è giokino.asm ed il file assemblato, pronto per l'esecuzione è giokino.obj.

Per provare il programma, lo si deve caricare in PCMon, assemblare e far funzionare. Può funzionare anche in emulazione


[Home Page dell'ITIS "Fermi"] [Indice Quarta] [Precedente] [Successivo]

© Ing. Stefano Salvi - Released under GPL licence