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 ;