Vengono riportati di seguito alcuni esempi di programmi assembler che mostrano alcune caratteristiche della scheda utilizzata, o dell'emulatore.
; 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 ; 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
;
.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
;