Bölüm 9: Aygıt Kontrolü

Mikroişlemciler
IN / OUTYoklamaTrafik ışıklarıINT 15h beklemeStep motorLED ekranTermometreYazıcıRobotTest aygıtı
Sercan KÜLCÜ · Giresun Üniversitesi · Elektrik-Elektronik Mühendisliği

Giriş

Öğrenme Çıktıları

Port tabanlı G/Ç

IN ve OUT komutlarının biçimlerini ve sınırlarını bilmek.

Bit düzeyinde denetim

Bir porttaki her bitin bir lambaya, mıknatısa ya da duruma karşılık geldiğini çözümlemek.

Yoklama (polling)

Aygıtın hazır bitini bekleyen döngüler yazmak.

Zamanlama

INT 15h / AH = 86h ile mikrosaniye cinsinden bekleme süresi hesaplamak.

emu8086 aygıtları

Trafik ışıkları, step motor, LED ekran, termometre, yazıcı, robot ve test aygıtını programlamak.

Gömülü sistem bakışı

Programın ROM'dan RAM'e yüklenip çalıştırılma ilkesini açıklamak.

Giriş

emu8086'ya Bağlı 7 Sanal Aygıt

AygıtPort(lar)YönVeri
Trafik lambaları (traffic lights)4OUTword: 12 lamba biti
Step motor (stepper motor)7OUT / INbit 0–2 mıknatıslar, bit 7 hazır
Robot9, 10, 11OUT / INkomut, veri, durum
Test aygıtı (simple io test)110, 112IN / OUTbyte (110), word (112)
Termometre ve ısıtıcı125, 127IN / OUTsıcaklık, ısıtıcı aç/kapa
Yazıcı (printer)130OUTkarakter (INT 21h/05h ile)
LED ekran (LED display)199OUTword: işaretli sayı

Aygıtlar emu8086'da virtual devices menüsünden açılır; programın başına #start=Traffic_Lights.exe# gibi bir yönerge yazılırsa emülatör aygıtı kendisi başlatır.

G/Ç Temelleri

Aygıt Kontrolü

  • x86 ailesi CPU'lar geniş bir aygıt yelpazesini denetleyebilir. Temel G/Ç port numaraları sistemden sisteme farklılık gösterebilir ve uygun bir donanımla (adres çözücü, “tricky” elektronik devre) değiştirilebilir.
  • Gömülü bir sistemde derlenen .bin dosyası Salt Okunur Bellek (ROM) yongasına yazılır.
  • Sistem açılınca programı ROM'dan okur, RAM'e yükler ve yürütür. Bu ilke birçok modern cihazda (çamaşır makinesi, yazıcı, modem…) kullanılır.
ROMprogram.binRAMçalışan kopyaCPUyürütürG/Ç portları① oku② yükle③ IN / OUT

G/Ç Temelleri

IN ve OUT Komutları

BiçimAnlamıPort aralığı
IN AL, portporttan 1 bayt oku0–255 (sabit)
IN AX, portporttan 1 word oku0–255 (sabit)
IN AL, DX / IN AX, DXport numarası DX'te0–65 535
OUT port, AL / OUT port, AXporta yaz0–255 (sabit)
OUT DX, AL / OUT DX, AXport numarası DX'te0–65 535
Veri yalnızca AL ya da AX üzerinden geçer: OUT 4, BX veya IN CL, 7 geçersizdir.
255'ten büyük port için önce MOV DX, 300 yazılır, sonra OUT DX, AL. Bu derste tüm emu8086 portları 255'in altındadır.

G/Ç Temelleri

Port Eşlemeli ve Bellek Eşlemeli G/Ç

Port eşlemeli (isolated) G/Ç
  • 8086'nın ayrı bir 64 K'lık G/Ç adres uzayı vardır.
  • Erişim yalnızca IN/OUT ile; M/IO̅ pini G/Ç döngüsünü belirtir.
  • Bellek adreslerini tüketmez.
  • Bu bölümdeki tüm aygıtlar böyledir.
Bellek eşlemeli (memory-mapped) G/Ç
  • Aygıt yazmaçları bellek adreslerinde durur.
  • Her MOV/ADD/CMP komutu kullanılabilir.
  • Örnek: PC metin ekranı B800:0000'dan başlar; oraya yazılan bayt ekranda görünür.
Yoklama (polling): CPU aygıtın durum bitini döngü içinde okuyarak “hazır” olmasını bekler. Basittir ama beklerken CPU başka iş yapamaz. Alternatifi aygıtın CPU'ya kesme göndermesidir.

Trafik Işıkları

Trafik Lambaları (Port 4)

  • Kavşakta 4 direk, her direkte 3 lamba: toplam 12 lamba = port 4'e yazılan word'ün bit 0–11'i.
  • Bit = 1 → lamba yanar, 0 → söner. Bit 12–15 kullanılmaz.
  • Her direkte (k = 0…3): bit 3k kırmızı, 3k+1 sarı, 3k+2 yeşil.
  • Örnek: 0000_0011_0000_1100b → bit 2 ve 8 (yeşil), bit 3 ve 9 (kırmızı).
DirekBitler
sağ alt0 1 2
sağ üst3 4 5
sol üst6 7 8
sol alt9 A B
0123456789ABFEDC BA98 7654 32100000 0011 0000 1100

Trafik Işıkları

Durum (Situation) Tablosu

;                 FEDC_BA98_7654_3210
situation     dw  0000_0011_0000_1100b
s1            dw  0000_0110_1001_1010b
s2            dw  0000_1000_0110_0001b
s3            dw  0000_1000_0110_0001b
s4            dw  0000_0100_1101_0011b
sit_end = $
all_red       equ 0000_0010_0100_1001b
AdHexLambalar
situation030Chsağ alt: yeşil; sağ üst: kırmızı; sol üst: yeşil; sol alt: kırmızı
s1069Ahsağ alt: sarı; sağ üst: kırmızı + sarı; sol üst: sarı; sol alt: kırmızı + sarı
s20861hsağ alt: kırmızı; sağ üst: yeşil; sol üst: kırmızı; sol alt: yeşil
s30861hsağ alt: kırmızı; sağ üst: yeşil; sol üst: kırmızı; sol alt: yeşil
s404D3hsağ alt: kırmızı + sarı; sağ üst: sarı; sol üst: kırmızı + sarı; sol alt: sarı
all_red0249hsağ alt: kırmızı; sağ üst: kırmızı; sol üst: kırmızı; sol alt: kırmızı

s2 ve s3 aynıdır: yan yol yeşili iki aralık (10 s) sürer. s1 ve s4 sarı geçişleridir (kırmızı + sarı = “hazırlan”).

Trafik Işıkları

Durumlar Adım Adım

0123456789ABFEDC BA98 7654 32100000 0010 0100 1001

all_red = 0249h → sağ alt: kırmızı; sağ üst: kırmızı; sol üst: kırmızı; sol alt: kırmızı

0123456789ABFEDC BA98 7654 32100000 0011 0000 1100

situation = 030Ch → sağ alt: yeşil; sağ üst: kırmızı; sol üst: yeşil; sol alt: kırmızı

0123456789ABFEDC BA98 7654 32100000 0110 1001 1010

s1 = 069Ah → sağ alt: sarı; sağ üst: kırmızı + sarı; sol üst: sarı; sol alt: kırmızı + sarı

0123456789ABFEDC BA98 7654 32100000 1000 0110 0001

s2 = 0861h → sağ alt: kırmızı; sağ üst: yeşil; sol üst: kırmızı; sol alt: yeşil

0123456789ABFEDC BA98 7654 32100000 1000 0110 0001

s3 = 0861h → sağ alt: kırmızı; sağ üst: yeşil; sol üst: kırmızı; sol alt: yeşil

0123456789ABFEDC BA98 7654 32100000 0100 1101 0011

s4 = 04D3h → sağ alt: kırmızı + sarı; sağ üst: sarı; sol üst: kırmızı + sarı; sol alt: sarı

Program önce tüm yönleri kırmızı yapar, sonra situation → s1 → s2 → s3 → s4 → situation… diye 5 saniyelik aralıklarla döner.

Trafik Işıkları

INT 15h / AH = 86h ile Bekleme

; 5 saniye bekle (5 milyon µs)
mov cx, 4Ch    ; 004C4B40h = 5 000 000
mov dx, 4B40h
mov ah, 86h
int 15h
  • BIOS işlevi INT 15h, AH = 86h: CX:DX mikrosaniye bekler.
  • CX yüksek word, DX düşük word: 32 bitlik bekleme süresi.

5 s = 5 × 1 000 000 = 5 000 000 µs

Süre mikrosaniyeye çevrilir.

5 000 000 ÷ 16 = 312 500 kalan 0
312 500 ÷ 16 = 19 531 kalan 4
19 531 ÷ 16 = 1 220 kalan 11 (B)
1 220 ÷ 16 = 76 kalan 4
76 ÷ 16 = 4 kalan 12 (C)
4 ÷ 16 = 0 kalan 4

Ardışık 16'ya bölme: kalanlar sondan başa okunur → 4C4B40h.

0 0 4 C | 4 B 4 0
CX = 004Ch · DX = 4B40h

32 bitlik değer 0000 0000 0100 1100 0100 1011 0100 0000b ikiye bölünür.

1 s → 1 000 000 = 000F4240h → CX = 000Fh, DX = 4240h

Başka bir örnek: 1 saniyelik bekleme.

Trafik Işıkları · Kodu adım adım çalıştır

Trafik Işıkları Programı

0123456789ABFEDC BA98 7654 32100000 0000 0000 0000

Tablo 0124h'de varsayıldı (ORG 100h; adres derleyiciye göre değişebilir). sit_end = 012Eh.

0123456789ABFEDC BA98 7654 32100000 0000 0000 0000

AX = all_red = 0249h (sabit, EQU).

0123456789ABFEDC BA98 7654 32100000 0010 0100 1001

Port 4'e yaz: tüm yönler kırmızı.

0123456789ABFEDC BA98 7654 32100000 0010 0100 1001

SI = 0124h: tablonun başı (situation).

0123456789ABFEDC BA98 7654 32100000 0010 0100 1001

AX ← [SI] = 030Ch.

0123456789ABFEDC BA98 7654 32100000 0011 0000 1100

OUT 4, AX: lambalar yeni duruma geçer (SI = 0124h).

0123456789ABFEDC BA98 7654 32100000 0011 0000 1100

CX = 004Ch (bekleme süresinin yüksek word'ü).

0123456789ABFEDC BA98 7654 32100000 0011 0000 1100

DX = 4B40h (düşük word).

0123456789ABFEDC BA98 7654 32100000 0011 0000 1100

AH = 86h: BIOS bekleme işlevi.

0123456789ABFEDC BA98 7654 32100000 0011 0000 1100

INT 15h: 5 saniye bekle.

0123456789ABFEDC BA98 7654 32100000 0011 0000 1100

SI = 0126h: sonraki word.

0123456789ABFEDC BA98 7654 32100000 0011 0000 1100

CMP SI, sit_end (012Eh): SI < sit_end → CF = 1.

0123456789ABFEDC BA98 7654 32100000 0011 0000 1100

JB: CF = 1, next'e dön.

0123456789ABFEDC BA98 7654 32100000 0110 1001 1010

… bekleme ve SI artırma … OUT 4, AX: SI = 0126h → port 4 = 069Ah.

0123456789ABFEDC BA98 7654 32100000 1000 0110 0001

… bekleme ve SI artırma … OUT 4, AX: SI = 0128h → port 4 = 0861h.

0123456789ABFEDC BA98 7654 32100000 1000 0110 0001

… bekleme ve SI artırma … OUT 4, AX: SI = 012Ah → port 4 = 0861h.

0123456789ABFEDC BA98 7654 32100000 0100 1101 0011

… bekleme ve SI artırma … OUT 4, AX: SI = 012Ch → port 4 = 04D3h.

0123456789ABFEDC BA98 7654 32100000 0100 1101 0011

CMP SI, sit_end (012Eh): SI = sit_end → CF = 0.

0123456789ABFEDC BA98 7654 32100000 0100 1101 0011

JB: CF = 0, atlama yok: tablo bitti.

0123456789ABFEDC BA98 7654 32100000 0100 1101 0011

SI = 0124h: tabloya baştan başla.

0123456789ABFEDC BA98 7654 32100000 0100 1101 0011

JMP next: sonsuz döngü.

0123456789ABFEDC BA98 7654 32100000 0011 0000 1100

… bekleme ve SI artırma … OUT 4, AX: SI = 0124h → port 4 = 030Ch.

#start=Traffic_Lights.exe#
mov ax, all_red
out 4, ax
mov si, offset situation
next:
mov ax, [si]
out 4, ax
mov cx, 4Ch      ; 5 s bekle
mov dx, 4B40h
mov ah, 86h
int 15h
add si, 2        ; sonraki durum
cmp si, sit_end
jb  next
mov si, offset situation
jmp next

Döngü hiç bitmez: gömülü sistemlerde ana program genellikle sonsuz bir döngüdür.

Trafik Işıkları

Etkileşimli Trafik Bit Düzenleyici

Bitlere tıklayın (F…0). Bit 12–15 kullanılmaz.

Step Motor

Step Motor (Port 7)

  • Motor hem saat yönünde (CW) hem de tersine (CCW) döndürülebilir.
  • Port 7'ye yazılan baytın bit 0, 1, 2'si üç elektromıknatısı açar/kapatır.
  • Yarı adım 11,25°, tam adım 22,5°'dir.
  • Yarı adım: çift mıknatıs, ardından tek mıknatıs açılarak döndürülür.
  • Tam adım: çift mıknatıs, çift mıknatıs, tek mıknatıs şeklinde devam eder.
  • Motor yeni komut almaya hazır olduğunda porttan okunan baytın bit 7'sini 1 yapar.
2107654321000000110port 7 = 00000110b

Step Motor

Step Motor Veri Tabloları

TabloAnlam1234
datcwCW yarı adım110100011010
datccwCCW yarı adım011001110010
datcw_fsCW tam adım001011110000
datccw_fsCCW tam adım100110011000
  • Tablolar bellekte arka arkaya durur: her biri 4 bayt. Bu yüzden add bx, 4 bir sonraki tabloya geçirir.
  • Program 32 (20h) tur sonra tabloyu değiştirir: CW yarı → CCW yarı → CW tam → CCW tam → başa.
  • Bayt değerindeki bitler mıknatısları gösterir: 110b = mıknatıs 2 ve 1 açık; 000b = hepsi kapalı.
  • Kaynak koddaki biçim: datcw db 0000_0110b ve alt satırlarda db 0000_0100b… (alt çizgi yalnızca okunabilirlik içindir).

Step Motor

Mıknatıs Dizileri Adım Adım

  • Yarı adım dizisi (datcw): çift → tek → çift → tek mıknatıs.
  • Tam adım dizisi (datcw_fs): tek, çift, çift ve “hepsi kapalı” bayt.
  • Her OUT komutundan sonra motor yeni konumuna gidene kadar meşguldur; bu yüzden program her bayttan önce bit 7'yi yoklar.
2107654321000000110datcw[0] = 110b

CW yarı adım, 1. bayt: açık mıknatıslar → 2, 1

2107654321000000100datcw[1] = 100b

CW yarı adım, 2. bayt: açık mıknatıslar → 2

2107654321000000011datcw[2] = 011b

CW yarı adım, 3. bayt: açık mıknatıslar → 1, 0

2107654321000000010datcw[3] = 010b

CW yarı adım, 4. bayt: açık mıknatıslar → 1

2107654321000000001datcw_fs[0] = 001b

CW tam adım, 1. bayt: açık mıknatıslar → 0

2107654321000000011datcw_fs[1] = 011b

CW tam adım, 2. bayt: açık mıknatıslar → 1, 0

2107654321000000110datcw_fs[2] = 110b

CW tam adım, 3. bayt: açık mıknatıslar → 2, 1

2107654321000000000datcw_fs[3] = 000b

CW tam adım, 4. bayt: açık mıknatıslar → hiçbiri

Step Motor

Step Motor Kontrol Programı

ORG 100h
steps_before_direction_change = 20h
jmp start
datcw     db 110b,100b,011b,010b
datccw    db 011b,001b,110b,010b
datcw_fs  db 001b,011b,110b,000b
datccw_fs db 100b,110b,011b,000b
start:
mov bx, offset datcw
mov si, 0
mov cx, 0   ; tur sayacı
  • Yoklama (wait): bit 7 = 0 ise motor meşgul, tekrar oku.
  • [bx][si] = [BX + SI]: BX tablonun başı, SI sıra (0–3).
  • 4 bayt gönderilince SI = 0, CX +1; CX = 20h olunca BX 4 artar, son tablodan sonra başa döner.
  • steps_before_direction_change = 20h bir sabittir (EQU gibi), bellekte yer kaplamaz.
next_step:
wait: in al, 7
test al, 10000000b
jz wait
mov al, [bx][si]
out 7, al
inc si
cmp si, 4
jb next_step
mov si, 0
inc cx
cmp cx, steps_before_direction_change
jb  next_step
mov cx, 0
add bx, 4   ; sonraki tablo
cmp bx, offset datccw_fs
jbe next_step
mov bx, offset datcw
jmp next_step

Step Motor · Kodu adım adım çalıştır

Step Motor: İlk Tur

2107654321000000000

ORG 100h, steps_before_direction_change = 20h. Port 7 önce 00h (meşgul), sonra 80h (hazır) döndürecek.

2107654321000000000

Veri tablolarının üzerinden atla.

2107654321000000000

BX = 0102h: datcw tablosu (CW yarı adım).

2107654321000000000

SI = 0: tablonun ilk baytı.

2107654321000000000

CX = 0: tur sayacı.

2107654321000000000

IN AL, 7 → AL = 00h (bit 7 = 0, motor meşgul).

2107654321000000000

TEST AL, 80h → ZF = 1.

2107654321000000000

JZ: ZF = 1 → tekrar bekle.

2107654321000000000

IN AL, 7 → AL = 80h (bit 7 = 1, hazır).

2107654321000000000

TEST AL, 80h → ZF = 0.

2107654321000000000

JZ: ZF = 0 → devam.

2107654321000000000

AL ← [BX+SI] = [0102h] = 110b.

2107654321000000110

OUT 7, AL: mıknatıslar 110b → motor yarım adım (11,25°) döner.

2107654321000000110

SI = 1.

2107654321000000110

CMP SI, 4 → CF = 1.

2107654321000000110

JB: SI < 4 → next_step.

2107654321000000110

IN AL, 7 → AL = 80h (bit 7 = 1, hazır).

2107654321000000110

TEST AL, 80h → ZF = 0.

2107654321000000110

JZ: ZF = 0 → devam.

2107654321000000110

AL ← [BX+SI] = [0103h] = 100b.

2107654321000000100

OUT 7, AL: mıknatıslar 100b → motor yarım adım (11,25°) döner.

2107654321000000100

SI = 2.

2107654321000000100

CMP SI, 4 → CF = 1.

2107654321000000100

JB: SI < 4 → next_step.

2107654321000000100

IN AL, 7 → AL = 80h (bit 7 = 1, hazır).

2107654321000000100

TEST AL, 80h → ZF = 0.

2107654321000000100

JZ: ZF = 0 → devam.

2107654321000000100

AL ← [BX+SI] = [0104h] = 011b.

2107654321000000011

OUT 7, AL: mıknatıslar 011b → motor yarım adım (11,25°) döner.

2107654321000000011

SI = 3.

2107654321000000011

CMP SI, 4 → CF = 1.

2107654321000000011

JB: SI < 4 → next_step.

2107654321000000011

IN AL, 7 → AL = 80h (bit 7 = 1, hazır).

2107654321000000011

TEST AL, 80h → ZF = 0.

2107654321000000011

JZ: ZF = 0 → devam.

2107654321000000011

AL ← [BX+SI] = [0105h] = 010b.

2107654321000000010

OUT 7, AL: mıknatıslar 010b → motor yarım adım (11,25°) döner.

2107654321000000010

SI = 4.

2107654321000000010

CMP SI, 4 → CF = 0.

2107654321000000010

JB: SI = 4: tablo bitti.

2107654321000000010

SI = 0: tabloyu baştan oku.

2107654321000000010

CX = 1: bir tur (4 adım) tamamlandı.

2107654321000000010

CMP CX, 20h → CF = 1 (henüz 32 tur olmadı).

2107654321000000010

JB next_step: aynı tabloyla devam. 32 turdan sonra add bx, 4 sonraki tabloya geçer.

jmp start   ; tablolar 0102h-0111h
start:
mov bx, offset datcw
mov si, 0
mov cx, 0   ; tur sayacı
next_step:
wait: in al, 7
test al, 10000000b
jz wait
mov al, [bx][si]
out 7, al
inc si
cmp si, 4
jb next_step
mov si, 0
inc cx
cmp cx, steps_before_direction_change
jb  next_step

LED Ekran

LED Ekran (Port 199)

  • Port 199'a yazılan word 5 haneli onluk sayı olarak gösterilir.
  • Değer işaretli (ikiye tümleyen) yorumlanır: −32 768 … 32 767.
  • −5678 = 10000h − 162Eh = E9D2h; ekranda -5678 görünür.
  • Yalnızca OUT 199, AX kullanılır (199 ≤ 255 olduğundan sabit port yeterli).
00355port 199 (2 bayt) · AX = 0163h

LED Ekran · Kodu adım adım çalıştır

LED Ekran Kontrolü

00000port 199 (2 bayt) · AX = 0000h

Ekran başlangıçta 00000 gösterir.

00000port 199 (2 bayt) · AX = 0000h

AX = 1234 (onluk) = 04D2h.

01234port 199 (2 bayt) · AX = 04D2h

OUT 199, AX: ekranda 1234.

01234port 199 (2 bayt) · AX = 04D2h

AX = −5678 = E9D2h (ikiye tümleyen).

-5678port 199 (2 bayt) · AX = E9D2h

OUT 199, AX: ekranda -5678.

-5678port 199 (2 bayt) · AX = E9D2h

AX = 0: sayaç.

00000port 199 (2 bayt) · AX = 0000h

OUT 199, AX: ekranda 0.

00000port 199 (2 bayt) · AX = 0000h

AX = 1.

00000port 199 (2 bayt) · AX = 0000h

JMP x1: sonsuz döngü (alttaki HLT'ye hiç ulaşılmaz).

00001port 199 (2 bayt) · AX = 0001h

OUT 199, AX: ekranda 1.

00001port 199 (2 bayt) · AX = 0001h

AX = 2.

00001port 199 (2 bayt) · AX = 0001h

JMP x1: sonsuz döngü (alttaki HLT'ye hiç ulaşılmaz).

00002port 199 (2 bayt) · AX = 0002h

OUT 199, AX: ekranda 2.

00002port 199 (2 bayt) · AX = 0002h

AX = 3.

00002port 199 (2 bayt) · AX = 0002h

JMP x1: sonsuz döngü (alttaki HLT'ye hiç ulaşılmaz).

#start=led_display.exe#
mov ax, 1234
out 199, ax
mov ax, -5678
out 199, ax
; port'a sonsuz döngüde yaz:
mov ax, 0
x1:
out 199, ax
inc ax
jmp x1
hlt              ; hiç çalışmaz

emu8086'da adım gecikmesi (step delay) 0 iken sayılar çok hızlı akar; döngüye INT 15h/86h ile bekleme eklenebilir.

Termometre

Termometre ve Isıtıcı (Port 125, 127)

  • IN AL, 125: anlık hava sıcaklığını (°C, işaretli bayt) okur.
  • OUT 127, AL: AL = 1 ısıtıcıyı açar, AL = 0 kapatır.
  • Isıtıcı açıkken sıcaklık yavaşça artar, kapalıyken düşer.
  • Amaç: sıcaklığı 60–80 °C arasında tutan bir termostat.
  • Sıcaklık eksi olabileceği için karşılaştırmalar işaretli atlamalarla (JL, JLE, JG) yapılır.
-4004080120port 125: 70 °Cısıtıcı KAPALIport 127 = 0hedef aralık: 60–80 °C

Termometre · Kodu adım adım çalıştır

Termostat Programı

-4004080120port 125: 50 °Cısıtıcı KAPALIport 127 = 0hedef aralık: 60–80 °C

Port 125 sırayla 55, 70 ve 85 °C döndürecek. Isıtıcı başlangıçta kapalı.

-4004080120port 125: 50 °Cısıtıcı KAPALIport 127 = 0hedef aralık: 60–80 °C

AX = CS = 0700h.

-4004080120port 125: 50 °Cısıtıcı KAPALIport 127 = 0hedef aralık: 60–80 °C

DS = 0700h (kesim yazmacına sabit doğrudan yazılamaz).

-4004080120port 125: 55 °Cısıtıcı KAPALIport 127 = 0hedef aralık: 60–80 °C

IN AL, 125 → sıcaklık 55 °C.

-4004080120port 125: 55 °Cısıtıcı KAPALIport 127 = 0hedef aralık: 60–80 °C

CMP AL, 60: 55 − 60 → SF = 1, OF = 0.

-4004080120port 125: 55 °Cısıtıcı KAPALIport 127 = 0hedef aralık: 60–80 °C

JL (SF ≠ OF): 55 < 60 → low.

-4004080120port 125: 55 °Cısıtıcı KAPALIport 127 = 0hedef aralık: 60–80 °C

AL = 1.

-4004080120port 125: 55 °Cısıtıcı AÇIKport 127 = 1hedef aralık: 60–80 °C

OUT 127, AL: ısıtıcı açıldı.

-4004080120port 125: 55 °Cısıtıcı AÇIKport 127 = 1hedef aralık: 60–80 °C

JMP ok.

-4004080120port 125: 55 °Cısıtıcı AÇIKport 127 = 1hedef aralık: 60–80 °C

JMP start: yeni ölçüm.

-4004080120port 125: 70 °Cısıtıcı AÇIKport 127 = 1hedef aralık: 60–80 °C

IN AL, 125 → sıcaklık 70 °C.

-4004080120port 125: 70 °Cısıtıcı AÇIKport 127 = 1hedef aralık: 60–80 °C

CMP AL, 60: 70 − 60 → SF = 0, OF = 0.

-4004080120port 125: 70 °Cısıtıcı AÇIKport 127 = 1hedef aralık: 60–80 °C

JL (SF ≠ OF): atlama yok.

-4004080120port 125: 70 °Cısıtıcı AÇIKport 127 = 1hedef aralık: 60–80 °C

CMP AL, 80 → ZF = 0, SF = 1.

-4004080120port 125: 70 °Cısıtıcı AÇIKport 127 = 1hedef aralık: 60–80 °C

JLE: 60 ≤ 70 ≤ 80 → ok (ısıtıcıya dokunma).

-4004080120port 125: 70 °Cısıtıcı AÇIKport 127 = 1hedef aralık: 60–80 °C

JMP start: yeni ölçüm.

-4004080120port 125: 85 °Cısıtıcı AÇIKport 127 = 1hedef aralık: 60–80 °C

IN AL, 125 → sıcaklık 85 °C.

-4004080120port 125: 85 °Cısıtıcı AÇIKport 127 = 1hedef aralık: 60–80 °C

CMP AL, 60: 85 − 60 → SF = 0, OF = 0.

-4004080120port 125: 85 °Cısıtıcı AÇIKport 127 = 1hedef aralık: 60–80 °C

JL (SF ≠ OF): atlama yok.

-4004080120port 125: 85 °Cısıtıcı AÇIKport 127 = 1hedef aralık: 60–80 °C

CMP AL, 80 → ZF = 0, SF = 0.

-4004080120port 125: 85 °Cısıtıcı AÇIKport 127 = 1hedef aralık: 60–80 °C

JLE: atlama yok.

-4004080120port 125: 85 °Cısıtıcı AÇIKport 127 = 1hedef aralık: 60–80 °C

JG: 85 > 80 → high.

-4004080120port 125: 85 °Cısıtıcı AÇIKport 127 = 1hedef aralık: 60–80 °C

AL = 0.

-4004080120port 125: 85 °Cısıtıcı KAPALIport 127 = 0hedef aralık: 60–80 °C

OUT 127, AL: ısıtıcı kapatıldı.

-4004080120port 125: 85 °Cısıtıcı KAPALIport 127 = 0hedef aralık: 60–80 °C

JMP start: yeni ölçüm.

; DS'yi CS'ye eşitle:
mov ax, cs
mov ds, ax
start:
in  al, 125
cmp al, 60
jl  low
cmp al, 80
jle ok
jg  high
low:
mov al, 1
out 127, al   ; ısıtıcı açık
jmp ok
high:
mov al, 0
out 127, al   ; ısıtıcı kapalı
ok:
jmp start     ; sonsuz döngü

jg high yerine jmp high da yazılabilirdi: JLE atlamadıysa sıcaklık zaten 80'den büyüktür.

Termometre

Etkileşimli Termostat

Yazıcı

Yazıcı (Printer, Port 130)

  • emu8086 yazıcısı port 130'a bağlıdır; ama program porta doğrudan yazmak yerine DOS işlevini kullanır:
  • INT 21h, AH = 05h: DL'deki karakteri yazıcıya (PRN) gönderir.
  • Denetim karakterleri yazıcıyı yönetir:
KodAdEtki
0Ah (10)LFbir satır aşağı
0Dh (13)CRsatır başına dön
09h (9)HTyatay sekme (tab)
0Ch (12)FFyeni sayfa (form feed)
Düzeltme: kaynak kodda db 13, 9 için “carriage return and vertical tab” yazıyordu. 9 yatay sekmedir (HT); dikey sekme (VT) 11 = 0Bh'dir.

Ayrıca 0Ah, 0Dh sırası LF + CR'dir; alışılmış sıra CR + LF'tir, ama ikisi birlikte aynı sonucu verir.

Yazıcı

Yazıcı Programı: Veri

org 100h
jmp start
msg db "Hello, Printer!", 0Ah, 0Dh
    db "***************"
    db 13, 9    ; CR ve yatay sekme (HT)
    db "Have a nice printing day!"
msg_end db 0
msg2 db "press any key to eject the page.$"
Uzunlukoffset msg_end - offset msg derleme zamanında hesaplanır: 15 + 2 + 15 + 2 + 25 = 59 = 3Bh bayt.
msg_endSon karakterden hemen sonraki adres; değeri (0) yazdırılmaz, yalnızca bir işarettir.
msg2'$' ile biter: INT 21h / AH = 09h ekrana yazdırırken $'a kadar gider.

Yazıcı · Kodu adım adım çalıştır

Yazıcı Programı: Yazdırma Döngüsü

Çıktı paneli yazıcı kâğıdını gösterir: LF satır atlar, CR satır başına döner, TAB 8 sütunluk sekmeye gider.

DL = 12 (0Ch): form feed.

AH = 05h: DOS yazıcı çıkışı.

INT 21h: yazıcı yeni sayfaya geçer.

SI = 0102h: msg'nin adresi.

CX = 59 (003Bh): karakter sayısı.

DL ← [SI] = 'H'.

AH = 05h: DOS yazıcı çıkışı.

INT 21h: 'H' yazıcıya gider.

SI = 0103h.

LOOP: CX = 58 → devam.

DL ← [SI] = 'e'.

AH = 05h: DOS yazıcı çıkışı.

INT 21h: 'e' yazıcıya gider.

SI = 0104h.

LOOP: CX = 57 → devam.

DL ← [SI] = 'l'.

AH = 05h: DOS yazıcı çıkışı.

INT 21h: 'l' yazıcıya gider.

SI = 0105h.

LOOP: CX = 56 → devam.

… INT 21h: 'l' yazıldı (CX = 56).

… INT 21h: 't' yazıldı (CX = 48).

… INT 21h: '*' yazıldı (CX = 40).

… INT 21h: '*' yazıldı (CX = 32).

… INT 21h: 'a' yazıldı (CX = 24).

… INT 21h: 'c' yazıldı (CX = 16).

… INT 21h: 'i' yazıldı (CX = 8).

DL ← [SI] = '!'.

AH = 05h: DOS yazıcı çıkışı.

… INT 21h: '!' yazıldı (CX = 1).

SI = 013Dh.

LOOP: CX = 0 → 59 karakter bitti.

start:
mov dl, 12      ; form feed: yeni sayfa
mov ah, 5
int 21h
mov si, offset msg
mov cx, offset msg_end - offset msg
print:
mov dl, [si]
mov ah, 5       ; DOS yazıcı işlevi
int 21h
inc si          ; sonraki karakter
loop print

CR (13) LF olmadan gelince üçüncü metin yıldızların üzerine basılır (panelde üzerine yazma olarak gösterildi). Döngüden sonra: mov dx, offset msg2 / mov ah, 9 / int 21h ekrana mesaj yazar; int 16h (AH = 0) bir tuş bekler; son form feed sayfayı yazıcıdan çıkarır.

Robot

Robot (Port 9, 10, 11)

command (9): 00000001data (10): 00000000status (11): 00000000yanan lambasönük lambaduvar
  • Robot bir ızgara dünyasında hareket eder; duvarları ve lambaları algılayabilir, lambaları yakıp söndürebilir.
  • Port 9 komut (OUT), port 10 veri (IN), port 11 durum (IN). Dünya, aygıt penceresindeki araç kutusuyla düzenlenir.

Robot

Robot Komutları ve Durum Bitleri

Komut (port 9)Etki
0hiçbir şey yapma
1ileri git
2sola dön
3sağa dön
4önündekini incele (examine)
5lambayı yak
6lambayı söndür
Veri (port 10)Önündeki
255 (FFh)duvar
0boş
7yanan lamba
8sönük lamba
Durum (port 11)1 ise
bit 0veri yazmacında yeni veri var
bit 1robot meşgul (komut sürüyor)
bit 2son komutta hata

Robot

Robot Programı: Lambayı Bul ve Yak

#start=robot.exe#
dongu: CALL hazir_bekle
       MOV  AL, 4       ; incele
       OUT  9, AL
       CALL veri_bekle
       IN   AL, 10
       CMP  AL, 0FFh    ; duvar?
       JE   don
       CMP  AL, 8       ; sönük lamba?
       JNE  ilerle
       CALL hazir_bekle
       MOV  AL, 5       ; yak
       OUT  9, AL
       JMP  dongu
don:   MOV  AL, 3       ; sağa dön
       JMP  gonder
ilerle: MOV AL, 1       ; ileri
gonder: PUSH AX         ; komutu koru
       CALL hazir_bekle
       POP  AX
       OUT  9, AL
       JMP  dongu
  • Her komuttan önce meşgul biti (bit 1) sıfır olana kadar beklenir.
  • İncele (4) komutundan sonra veri hazır biti (bit 0) beklenir, sonra port 10 okunur.
  • Duvarsa sağa dön, sönük lambaysa yak, yoksa ilerle.
  • Bekleme yordamları CALL ile çağrılır: dönüş adresi yığında (Bölüm 8).

Robot

Robot: Bekleme Yordamları ve Dikkat Edilecekler

hazir_bekle PROC
b1:    IN   AL, 11
       TEST AL, 010b    ; meşgul?
       JNZ  b1
       RET
hazir_bekle ENDP

veri_bekle PROC
v1:    IN   AL, 11
       TEST AL, 001b    ; yeni veri?
       JZ   v1
       RET
veri_bekle ENDP
AL'yi koruyunhazir_bekle AL'yi IN ile ezer. gonder yolunda AL komut değerini taşıdığı için yordamdan önce PUSH AX, sonra POP AX yapılır; aksi hâlde porta durum baytı gönderilirdi.
Hata bitiDuvara doğru “ileri” komutu hata (bit 2) üretir; durum okunup kontrol edilmelidir.
Yoklama maliyetiCPU bekleme döngüsünde tamamen meşguldür; gerçek sistemlerde kesmeler tercih edilir.

Robot

Basit G/Ç Test Aygıtı (Port 110, 112)

  • Port 110: bir bayt; port 112: bir word.
  • Pencereye yazılan değerler programa giriş olur (hex için h soneki), programın yazdıkları pencerede görünür.
  • Giriş portları her 100 ms'de güncellenir.
  • IN/OUT'u denemek ve hata ayıklamak için idealdir.
IN   AL, 110    ; ör. A7h okunur
INC  AL
OUT  110, AL    ; A8h yazılır
IN   AX, 112    ; ör. 1234h
ADD  AX, 1
OUT  112, AX    ; 1235h
simple io testwrite byte to port 110:write word to port 112:read byte from port 110:A8hread word from port 112:1235h

Özet

Özet

AygıtPortAnahtar fikir
Trafik lambaları4Her bit bir lamba; durum tablosu + INT 15h/86h bekleme.
Step motor7Bit 0–2 mıknatıs, bit 7 hazır; yarı adım 11,25°, tam adım 22,5°.
LED ekran199Word, işaretli onluk gösterim.
Termometre125, 127Okuma + işaretli karşılaştırma + ısıtıcı aç/kapa.
Yazıcı130INT 21h/05h; denetim karakterleri LF, CR, HT, FF.
Robot9, 10, 11Komut, veri, durum; meşgul/veri bitlerini yokla.
Test aygıtı110, 112Bayt ve word G/Ç denemesi.

Ortak desen: durum oku → bit test et → hazırsa veri yaz/oku → döngü. IN/OUT yalnızca AL/AX ile, port > 255 ise DX ile.

Özet

Alıştırmalar

  1. Tüm yönlerde yalnızca sarı lambaları yakan port 4 değeri nedir?
  2. 2,5 saniyelik bekleme için CX ve DX ne olmalıdır?
  3. LED ekranda −1 göstermek için AX'e hangi hex değer yazılır?
  4. Termostatı 20–25 °C aralığına göre değiştirin; sıcaklık −10 °C iken JB kullanılsaydı ne olurdu?
  5. Step motor programında motoru yalnızca saat yönünde, tam adımla döndürmek için hangi satırlar değişmeli?
  6. Yazıcıya “Merhaba” yazıp sayfayı çıkaran en kısa programı yazın.
Cevaplar
  1. Bit 1, 4, 7, 10 → 0000_0100_1001_0010b = 0492h.
  2. 2 500 000 = 002625A0h → CX = 0026h, DX = 25A0h.
  3. FFFFh.
  4. cmp al, 20 / jl low / cmp al, 25 / jle ok / .... −10 = F6h; işaretsiz JB için 246 > 20 olur ve ısıtıcı açılmazdı.
  5. mov bx, offset datcw_fs ve tablo değiştiren kısım (inc cx … jmp next_step) kaldırılıp jmp next_step yazılır.
  6. Her karakter için MOV DL, 'M' / MOV AH, 5 / INT 21h (veya döngü), sonunda DL = 12 ile form feed.

Özet

Kaynaklar

  • emu8086 yardım belgeleri: I/O ports and hardware interrupts, Virtual devices ve örnek programlar (traffic_lights.asm, stepper_motor.asm, led_display_test.asm, thermometer.asm, printer.asm, robot.asm).
  • Intel, The 8086 Family User's Manual, 1979 — IN/OUT komutları ve G/Ç adres uzayı.
  • R. Brown, Ralf Brown's Interrupt List — INT 15h/86h, INT 21h/05h, INT 16h/00h.
  • B. B. Brey, The Intel Microprocessors, 8. baskı, Pearson, 2009 — Bölüm 11 (Temel G/Ç arabirimi).

Son

Bölüm 9: Aygıt Kontrolü
Sonraki bölüm: Bölüm 10: Komut Kümesi
1 / 1 Sercan KÜLCÜ, Tüm hakları saklıdır.