Esempi di Programmi per 8051/PCMon

- A cura del Prof. Stefano Salvi -


Vengono riportati di seguito alcuni esempi di programmi assembler che mostrano alcune caratteristiche della scheda utilizzata, o dell'emulatore.

test2.asm
Programma che utilizza solamente il processore 8051. Al piedino P1.2 è connesso un diodo LED verde ed un cicalino piezoelettrico. Questo programma produce un suono bitonale intermittente sul cicalino.
ppi.asm
Il resto dell'I/O della scheda avviene attraverso un PPI 8255 mappato in memoria XDATA, agli indirizzi FA00H ... FA03H. Questo esempio programma il PPI, copia i dati letti da una porta sull'altra e, in base ai tasti premuti, suona dei toni.
animals.asm
Quest'ultimo esempio utilizza la serale dell'8051 per comunicare con l'emulatore di terminale contenuto in PCMon. La seriale viene utilizzata in polling, per semplicità e per poter essere utilizzato anche in emulazione. È un esempio di programmazione abbastanza sofisticato, che fà uso di subroutine e strutture dati.

test2.asm

[Scarica il sorgente]
; test2.asm
; Prova di assembler 8051
; usando AS31
;
; La scheda GPC2 con il suo monitor consente di caricare un programma
; dall'indirizzo 8050h.
; Quell'indirizzo viene fatto corrispondere all'inizio della ROM (indirizzo 0), quindi
; dopo quell'indirizzo si trovano i vettori di interruzione.
; Al piedino P1.2 sono connessi un LED ed un cicalino (uscita PWM nella
; documentazione).
;
; Per produrre un suono si utilizza un ciclo di ritardo.
; Ogni istruzione 'djnz ...' impiega 24 cicli. L'oscillatore va a 11,0592 MHz.
; Vengono quindi eseguiti 11.059.200 / 24 =  460.800 loop al secondo.
; Se lasciamo a 0 il registro contatore, l'istruzione DJNZ verra' eseguita 256
; volte, quindi avremo in un secondo 460.800 / 256 = 1800 ripetizioni del loop
; ogni secondo. Dato che un ciclo dell'oinda quadra prodotta dal beeper sara'
; costituito da una parte ad 1 ed una a 0, quindi da due ripetizioni del loop,
; il cicalino oscilera' a 900 Hz. Se invece useremo un conteggio di 128, la 
; frequenza del tono raddoppiera', quindi avremo un tono a 1800 Hz.
;
; Produciamo adesso un suno intermittente: 64 cicli a 900Hz, pari a circa 70 mS,
; seguiti da 128 cicli a 1800 Hz, quindi sempre 70 mS, seguiti da una pausa di 140 mS. 
;
	.org	8050h
;
on:
	mov	r1,128	; Numero di semicicli
lo:	mov	r0,0	; Durata del semiciclo (0 -> 256)
	cpl	p1.2	; commuta l'onda
lo1:	djnz	r0,lo1	; loop di ritardo semiciclo
	djnz	r1,lo	; loop sui semicicli
;
	mov	r1,0	; Numero di semicicli (0 -> 256)
hi:	mov	r0,128	; Durata del semiciclo
	cpl	p1.2	; commuta l'onda
hi1:	djnz	r0,hi1	; loop di ritardo semiciclo
	djnz	r1,hi	; loop sui cicli
;
	mov	r1,0	; Numero di cicli di ritardo (0 -> 256)
off:	mov	r0,0	; Durata del ritardo (0 -> 256)
	setb	p1.2	; Azione nulla (non produce suono)
off1:	djnz	r0,off1	; loop di ritardo
	djnz	r1,off	; loop sui cicli di ritardo
;
	sjmp	on	; loop infinito sul suono
;
	.end

ppi.asm

[Scarica il sorgente]
; ppi.asm
; Uso Porta parallela PPI 8255
;
; L'I/O aggiuntivo di GPC2 e' mappato come segue in memoria XDATA:
;
;	0FA00h .. 0FA3Fh	PPI 8255
;	0FA40h .. 0FA7Fh	TIMER 82C54 (primo)
;	0FA80h .. 0FABFh	TIMET 82C54 (secondo)
;	0FAC0h .. 0FAFFh	RTC 6242b
;
;	0FB00h .. 0FFFFh	BUS esterno (ABACO Bus)
;
; In particolare, per il PPI 8255 avremo:
;	0FA00h	->	PDA = Registro dati del port A
;	0FA01h	->	PDB = Registro dati del port B
;	0FA02h	->	PDC = Registro dati del port C
;	0FA03h	->	CNT = registro di controllo
;
; L'8255 ha tre modi di funzionamento (Mode 0 = Basic Input Output, Mode 1 = Strobed
; Input Output, Mode 3 = Bi-Directional Bus), che possono essere selezionati indipendentemente
; per il gruppo Port B, Port C 0..3 e Port A,Port C 4..7.
; Avendo connesso alla scheda il tastierino (TIO 16), il solo modo che ci interessa e' lo 0,
; nel quale ogni port puo' essere programmato come ingresso o uscita, per  entrambi i gruppi.
; Vediamo ora come programmare il PPI, tramite il port di controllo:
;
; Bit 0 -> Port C 0..3 : 1 = Input, 0 = Output
; Bit 1 -> Port B :      1 = Input, 0 = Output
; Bit 2 -> Modo Port B : 0 = Mode 0, 1 = Mode 1
;
; Bit 3 ->  Port C 4..7 : 1 = Input, 0 = Output
; Bit 4 -> Port A :       1 = Input, 0 = Output
; Bit 5 -+
; Bit 6 -+> Modo port A : 00 -> Mode 0, 01 -> Mode 1, 10-11 Mode 3
;
; Bit 7 -> Programmazione Interrupt : 0 -> Interrupt, 1 -> Modo Polling
;
; Non mi preoccupo della programmazione dll'interrupt, quindi dovremo sempre programmare il
; bit 7 a 1.
;
; Il Port A e' collegato ai piedini 1..8 del connettore CN2 (Tasti rossi)
; Il Port B e' collegato ai DIP Switch
; Il Port C e' collegato ai piedini 9..16 del connettore CN2 (0..3 Tasti gialli, 
;    4..7 Tasti verdi)
;
; Scrivo un programma che:
; - Programmi il Port A in uscita, il Port B in ingresso, i bit 0..3 del Port C in uscita e 
;   i bit 4..7 in ingresso.
; - Copi i bit del Port B (dip switch) sui port A e C (bit 1..3)
; - Emetta un tono alla pressione dei tasti verdi (bit 4..7 di Port C)
;
;
	.org	8050h		; Inizio del programma caricato da Mo52
;
	mov	DPTR,#0FA03h	; Port CNT di PPI
	mov	A,#10001010b	; Mode 0 per A e B, A in out, Chi in in, B in in, Clo in out
	movx	@dptr,a		; Setta il PPI
;
loop:	mov	DPL,#1		; Port B
	movx	a,@DPTR		; Leggo porta B
	mov	DPL,#0		; Port A
	movx	@DPTR,A		; Copio su porta A
	mov	DPL,#2 		; Port C
	movx	@DPTR,A		; Copio su prota C
;
	movx	A,@DPTR		; Leggo i tasti
;
	jb	ACC.4,no4	; Tasto 4 rilasciato?
;	Tasto 4 premuto
;	128 semicicli a 900 Hz
	mov	r1,128		; Numero semicicli
lo:	mov	r0,0		; Durata semiciclo (0 -> 256)
	cpl	p1.2		; inverto l'uscita
lo1:	djnz	r0,lo1		; ritardo semiciclo
	djnz	r1,lo		; loop semicicli
;
no4:	jb	ACC.5,no5	; Tasto 5 Rilasciato?
;	Tasto 5 premuto
;	256 semicicli a 1800 Hz
	mov	r1,0		; Numero semicicli (0 -> 256)
hi:	mov	r0,128		; Durata semiciclo
	cpl	p1.2		; inverto l'uscita
hi1:	djnz	r0,hi1		; ritardo semiciclo
	djnz	r1,hi		; loop semicicli
;
no5:	jb	ACC.6,no6	; Tasto 6 Rilasciato?
;	Tasto 6 premuto
;	Tono basso poi pausa
	mov	r1,128		; Numero semicicli
lob:	mov	r0,0		; Durata semiciclo
	cpl	p1.2		; inverto l'uscita
lob1:	djnz	r0,lob1		; ritardo semiciclo
	djnz	r1,lob		; loop semicicli
;
	mov	r1,0		; Numero ritardi
off:	mov	r0,128		; Durata ritardo
	setb	p1.2		; Azione nulla - non emette suono
off1:	djnz	r0,off1		; ritardo pausa
	djnz	r1,off		; loop pause
;
no6:	jb	ACC.7,no7	; Tasto 7 Rilasciato?
;	Tasto 7 premuto
;	Tono alto poi pausa
	mov	r1,0		; Numero semicicli (0 -> 256)
hib:	mov	r0,128		; Durata semiciclo
	cpl	p1.2		; inverto l'uscita
hib1:	djnz	r0,hib1		; ritardo semiciclo
	djnz	r1,hib		; loop semicicli
;
	mov	r1,0		; Numero pause (0 -> 256)
offb:	mov	r0,128		; Durata pausa
	setb	p1.2		; Azione nulla - non emette suono
offb1:	djnz	r0,offb1	; ritardo pausa
	djnz	r1,offb		; loop pause
;
no7:	sjmp	loop		; Ripete all'infinito

animals.asm

[Scarica il sorgente]
; Animals.asm
;
	.org	8050h		; Punto di caricamento di Mo51
;
        mov     sp,#70h
;
;       Inizializzazione
;
        MOV     IE,#0           ; nessun interrupt
        MOV     SCON,#52H       ;
        MOV     TMOD,#22H       ;
        MOV     TCON,#59H       ;
        MOV     TH1,#0FDH       ; 9600 baud
;
        sjmp     Start   	; Va subito a Start
;
;
.equ	CR, 13
.equ	LF, 10
;
.equ	InLen, 10		; Dimensione buffer di input
;
;	Area Subroutines
;
; -- PutChar
;       Stampa un caratere in ACC
;       Input:
;               ACC = carattere da stampare
;       Output:
;               Nessuno.
;       Modifica
;               Niente.
PutChar:
        jnb     ti,PutChar	; Attende carattere
        mov     sbuf,a		; Mette carattere in ACC
        clr     ti		; Azzera flag carattere ricevuto
        ret
;
; -- PutString
;	Stampa una stringa terminata da 0
;	Input:
;               DPTR = Indirizzo della stringa da stampare
;	Output:
;		Nessuno.
;	Modifica:
;               DPTR,A
;
PutString:
        clr     a		; 'indice' (sommato a DPTR)
        movc    a,@a+dptr	; leggo caratere corrente
	jz	EndPS		; ho leto lo 0 finale: esco
        acall   PutChar		; stampo il carattere (<> 0)
        inc     dptr		; passo al prossimo carattere
        sjmp    PutString	; loop
;
EndPS:	ret

;
; -- GetString
;	Legge una stringa da tatstiera fino a CR. Pone il risultato
;       nella striga puntata da R0 per un massimo indicato in R1
;	Input:
;               R0 = Indirizzo del buffer
;               R1 = Dimensione del buffer
;	Output:
;               R1 = caratteri restanti
;	Modifica:
;               R1,A
;
GetString:
        mov     a,r0
        push    acc     	; per poi
LPGS:   jnb     ri,LPGS		; Attende carattere
        mov     a,sbuf 		; legge il carattere
        clr     ri      	; pulisce il flag
        lcall	PutChar 	; Echo
        cjne    a,#CR,NoCr 	; Controla se CR
        sjmp    EndGs   	; fine ...
NoCr:
        mov     @r0,a   	; mette il carattere nel buffer
        inc     r0		; incrementa puntatore al buffer
        djnz    r1,LPGS 	; continua fino a fine buffer
;
EndGs:
        clr     a
        mov     @r0,a  		; mette il terminatore (0)
        mov     dptr,#CrLf      ; Stringa con CR ed LF
        acall   PutString       ; Stampa CR,LF (echo)
        pop     acc     	; Ripristina R0
        mov     r0,a
	ret
;
;
; -- Question
;	Presenta una domanda, legge la risposta e pone in DPTR
;	il puntatore alla prossima domanda
;	Input:
;               DPTR = puntatore alla domanda
;	Output:
;               DPTR = puntatore prossima domanda (se 0 -> termine)
;	Modifica:
;               DPTR,A,r4,r5,r6,r7
;
Question:
	; R5-R4 -> puntatore a prossima domanda se risposta == 'Si'
        clr     a
        movc    a,@a+dptr  ; parte alta puntatore 'Si'
        mov     r5,a
        inc     dptr
        clr     a
        movc    a,@a+dptr  ; parte bassa puntatore 'Si'
        mov     r4,a
        inc     dptr
	; R7-R6 -> puntatore a prossima domanda se risposta == 'No'
        clr     a
        movc    a,@a+dptr  ; parte alta puntatore 'No'
        mov     r7,a
        inc     dptr
        clr     a
        movc    a,@a+dptr  ; parte bassa puntatore 'No'
        mov     r6,a
        inc     dptr
	; Adesso DPTR punta al testo della domanda
	acall	PutString ; Stampa la domanda
        mov     a,r6
        orl     a,r7    ; r6,r7 = 0? (No) -> nessun'altra domanda (era una risposta)
	jz	No	; copia R6-R7 in DPTR ed esce
;
Ripeti:
;
        mov     dptr,#Quest	; "?\n(Si/No) "
	acall	PutString	; stampa il punto dio domanda dopo la domanda
        mov     r0,#InBuff
        mov     r1,#InLen
	acall	GetString	; Legge la risposta
        mov     a,@r0  		; legge la prima lettera
        cjne    a,#'N',CmpNo	; Risposta <> 'N...' (No)
        sjmp    No		; Risposta 'no'
CmpNo:
        cjne    a,#'n',CmpS	; Risposta <> 'n...' (no)
        sjmp    No		; Risposta 'no'
CmpS:
        cjne    a,#'S',CmpSi	; Risposta <> 'S...' (Si)
        sjmp    Si		; Risposta 'si'
CmpSi:
        cjne    a,#'s',Ripeti	; Risposta <> 's...' -> non valida
;
Si:     mov     dpl,r4		; Copia puntatore R5-R4 (Si) in DPTR (corrente)
        mov     dph,r5
        sjmp    QFine
;
;
No:     mov     dpl,r6		; Copia puntatore R7-R6 (No) in DPTR (corrente)
        mov     dph,r7
QFine:
	ret

;
; Loop principale (main)
;
Start:
        mov     dptr,#benvenuto	; Messaggio di apertura
	acall	PutString
        mov     dptr,#FirstQ	; Puntatore alla radice dell'albero
GameLp:	acall	Question	; Presenta la domanda e legge la risposta
;
        mov     a,dph		; Controlla il dato tornato (DPTR)
        orl     a,dpl
	jnz	GameLp		; Se DPTR <> 0, ho ancora domande, continuo
        sjmp     Start		; altrimenti ritorno all'inizio
;
.equ	InBuff, 8       	; Dopo i registri in ram DATA
;
benvenuto:
        .db      CR,LF,CR,LF,"Programma ANIMALI",CR,LF,CR,LF
        .db      "Programma che indovina l'animale",CR,LF
CrLf:   .db      CR,LF,0
;
; Database domande
;
Quest:  .db      "?",CR,LF,"(Si,No)? ",0
;
FirstQ:	.dw	Uccello,Mammifero
        .db      "L'animale depone le uova",0

Uccello: .dw	Volatile,Terrestre	
        .db      "L'animale vola",0

Volatile: .dw	0,0	; Nessun puntatore -> risposta
        .db      "L'animale e' un'uccello",0

Terrestre: .dw	Struzzo,Pinguino
        .db      "L'animale corre veloce",0

Struzzo: .dw	0,0
        .db      "L'animale e' uno Struzzo",0

Pinguino: .dw	0,0
        .db      "L'animale e' un pinguino",0

Mammifero: .dw	Pipistrello,Mucca
        .db      "L'animale vola",0

Pipistrello: .dw 0,0
        .db      "L'animale e' un pipistrello",0

Mucca:	.dw	0,0
        .db      "L'animale e' una Mucca",0
	.end
;