การ Interface กับ Serial Port (Part VII)
Interrupt Vectors
ก่อนที่จะใช้งาน Interrupt ก็ต้องรู้ว่า communication card ที่ใช้มี address
และ IRQ อย่างไร ย้อนกลับไปดู Table 3. ที่แสดงข้อมูลของ base address และ IRQ
ที่ใช้กันอยู่ โดย IRQ 3 และ 4 ใช้กันเป็นประจำ ส่วน IRQ 5 และ 7 มีใช้ในบางโอกาส
เมื่อรู้ IRQ แล้วต่อไปก็หา interrupt vector หรือ software interrupt ของมัน
ปรกติ processor ในอนุกรมของ 8086 จะมี 256 interrupt vector โดยนับจาก 0 ถึง 255
แต่ละ vector มีขนาด 4 bytes เก็บ address ของ Interrupt Service Routine (ISR)
ไว้ แต่เนื่องจากภาษา C สามารถจัดการกับ address เหล่านี้โดยเพียงแต่รู้ค่า vector
ของมันเท่านั้นดังนั้นจึงใช้เฉพาะ interrupt vector ในการเขียน program ภาษา C
Table 14. แสดง Interrupt Vector ของ Hardware
Table 14. Interrupt Vectors. (Hardware only)
Int. (Hex)
|
IRQ
|
Common uses
|
08
|
0
|
System Timer
|
09
|
1
|
Keyboard
|
0A
|
2
|
Redirected
|
0B
|
3
|
Serial Comms. COM2/COM4
|
0C
|
4
|
Serial Comms. COM1/COM3
|
0D
|
5
|
Reserved/Sound Card
|
0E
|
6
|
Floppy Disk Controller
|
0F
|
7
|
Parallel Comms.
|
70
|
8
|
Real Time Clock
|
71
|
9
|
Reserved
|
72
|
10
|
Reserved
|
73
|
11
|
Reserved
|
74
|
12
|
PS/2 Mouse
|
75
|
13
|
Math Co-Processor
|
76
|
14
|
Hard Disk Drive
|
77
|
15
|
Reserved
|
สมมุติว่าเราใช้ COM 3 ซึ่งมี IRQ อยู่ที่ 0C (Hex) เราก็สามารถ
set ค่า interrupt vector โดยใช้คำสั่งภาษา C ว่า setvec (Ox0C, PORT1INT); โดย
PORT1INT คือ ISR หรือ interrupt handler ที่รองรับ IRQ นี้ แต่ก่อนที่จะทำเช่นนั้นควรเก็บค่าvector
เดิมไว้เพื่อ restore กลับหลังจากที่จบการทำงานของ ISR แล้ว ซึ่งจะใช้คำสั่ง oldport1isr
= getvect (INTVECT); โดย oldport1isr ถูกกำหนดโดยคำสั่ง void interrupt (*oldport1isr)();
นอกจากนั้นยังต้องมีการเก็บค่า status เดิมของ UART และส่งคืนทุกครั้งที่สิ้นสุด
ISR เพื่อให้ program อื่นสามารถใช้ UART ได้
Interrupt Service Routine
PORT1INT ที่ชี้ไปยัง ISR ซึ่งจะทำงานตามที่ได้ออกแบบไว้ ตัวอย่างเช่น
void interrupt PORT1INT()
{
int c;
do { c = inportb(PORT1 + 5);
if (c & 1) {
buffer[bufferin] = inportb(PORT1);
bufferin++;
if (bufferin == 1024) bufferin = 0;
}
} while (c & 1);
outportb(0x20,0x20);
}
ซึ่งจะตรวจว่ามีการรับ character เข้ามาใน UART หรือไม่ ถ้ามีก็จะอ่านไปเก็บไว้ที่
buffer ใน memory ซึ่งจะตรวจต่อเนื่องในกรณีที่ enable ตัว FIFO เพื่อเก็บข้อมูลทั้งหมดเมื่อมี
interrupt เกิดขึ้น
บรรทัดสุดท้าย outportb(0x20,0x20); จะบอกตัว Programmable Interrupt Controller
(PIC) ว่าสิ้นสุดการ interrupt แล้ว routine ข้างบนจะทำงานได้ก็ต่อเมื่อ setup
ตัว register ต่าง ๆ ของ UART และตัว PIC ถูกต้องแล้วเท่านั้น ปรกติ PC จะใช้ PIC
2 ตัวเป็น PIC1 และ PIC2 และมี control word ตามที่แสดงใน Table 15. และ 16. สำหรับรายละเอียดเกี่ยวกับการใช้
Interrupt และตัว PIC ขอให้ดูจากบทความเรื่อง “การใช้ Interrupt”
Table 15. PIC1 Operation Control Word 1 (Address
Ox21)
Bit
|
Disable IRQ
|
Function
|
7
|
IRQ7
|
Parallel Port
|
6
|
IRQ6
|
Floppy Disk Controller
|
5
|
IRQ5
|
Reserved/Sound Card
|
4
|
IRQ4
|
Serial Port
|
3
|
IRQ3
|
Serial Port
|
2
|
IRQ2
|
PIC2
|
1
|
IRQ1
|
Keyboard
|
0
|
IRQ0
|
System Timer
|
Table 16. PIC2 Operation Control Word 1 (Address
OxA1)
Bit
|
Disable IRQ
|
Function
|
7
|
IRQ15
|
Reserved
|
6
|
IRQ14
|
Hard Disk Drive
|
5
|
IRQ13
|
Math Co-Processor
|
4
|
IRQ12
|
PS/2 Mouse
|
3
|
IRQ11
|
Reserved
|
2
|
IRQ10
|
Reserved
|
1
|
IRQ9
|
Redirected IRQ2
|
0
|
IRQ8
|
Real Time Clock
|
UART Configuration
การ config. ตัว UART มีขั้นตอนหลัก ๆ ดังนี้
- Disable การ interrupt ของตัว UART เป็นอันดับแรก เพื่อไม่ให้มี interrupt
จาก UART มารบกวนขณะทำการ config. อยู่
- ทำการ setup ค่า interrupt vector ต่าง ๆ
- กำหนด speed และค่าต่าง ๆ ในการสื่อสารที่ต้องการ โดย set bit 7 ของ LCR ก่อนแล้วค่อยกำหนดค่าอื่น
ๆ
- หลังจากกำหนด speed แล้ว ก็ต้อง reset bit 7 ของ LCR เพื่อจะได้ควบคุม interrupt
enable register และ Tx/Rx buffer ได้และกำหนดค่าต่าง ๆ ที่เกี่ยวกับ FCR และ
MCR
Main Routine (Loop)
ตัวอย่างของ main routine มีดังนี้
do {
if (bufferin != bufferout){
ch = buffer[bufferout];
bufferout++;
if (bufferout == 1024) bufferout = 0;
printf("%c",ch);
}
if (kbhit()){
c = getch();
outportb(PORT1, c);
}
} while (c !=27);
ซึ่งจะ loop จนกว่าค่า c = 27 (คือการกดปุ่ม ESC key) สำหรับ routine นี้ตั้งอยู่บนสมมุติฐานว่า
UART ทำงานเร็วกว่าการพิมพ์ข้อมูลเข้าไป แต่ถ้าใช้ในลักษณะอื่นที่ UART อาจจะทำงานไม่ทัน
ก็ต้องเพิ่มขั้นตอนให้มีการตรวจสอบ bit 5 ของ Line Status Register (LSR) ว่ามีค่าเป็น
“1” ก่อนที่จะส่งข้อมูลใหม่เข้าไปยัง Tx register
Determining the type of UART via Software
การตรวจสอบชนิดของ UART โดยใช้ software มีขั้นตอนดังนี้
Set ให้ bit 0 ของ FCR มีค่าเป็น “1” แล้วอ่านค่าของ bit 6 และ 7 ของ interrupt
identification register (IIR) ถ้า bit ทั้ง 2 มีค่าเป็น “1” แสดงว่า FIFO buffer
ถูก enable หมายความว่า UART เป็นเบอร์ 16550A ถ้า FIFO ถูก enable แต่ใช้ไม่ได้แสดงว่า
UART เป็นเบอร์ 16550 และถ้า FIFO ไม่ได้ถูก enable แสดงว่า UART เป็นเบอร์ 16450
หรือ 8250, 8250A หรือ 8250B ในเครื่อง PC รุ่นเก่า (ส่วนเครื่อง PC/AT จะมี bus
speed ที่สูงขึ้น ซึ่ง UART อนุกรม 8250 ไม่สามารถตอบสนองได้) จากนั้นก็ลองเขียนข้อมูลเข้า
scratch register แล้วอ่านกลับออกมาเทียบกับที่เขียนเข้าไปดูว่าถ้าตรงกันแสดงว่ามี
scratch register อยู่แสดงว่า UART เป็นเบอร์ 16450 หรือ 8250A แต่ถ้าไม่มี scratch
register แสดงว่า UART เป็นเบอร์ 8250 หรือ 8250B สำหรับ UART เบอร์ 16750 จะมี
buffer 64 byte ซึ่งทดสอบโดยการ enable ผ่าน FCR แล้วอ่านค่า status จาก IIR ก็จะรู้ได้
External Hardware – Interfacing Methods
RS-232 Waveforms
การสื่อสารโดย RS-232 เป็นการสื่อสารแบบ asynchronous หมายความว่าสัญญาณ
clock ที่ใช้ควบคุมจังหวะไม่ได้ส่งไปพร้อมกับ Data แต่จะใช้ start bit เป็นตัว
sync.ในแต่ละ word ของการสื่อสารและใช้สัญญาณ clock ภายในของแต่ละด้านเป็นตัวให้จังหวะเอง
Figure 4. TTL/CMOS Serial
Logic Waveform.
Figure 4. แสดงลักษณะของสัญญาณจาก UART เมื่อใช้ format แบบ 8N1
คือ 8 data bits ไม่มี parity bit และมี 1 stop bit ขณะที่ idle จะอยู่ในสถานะ
“Mark” หรือ logic “1” การส่งจะเริ่มจากการส่ง start bit คือ logic “0” และตามด้วย
LSB bit จนหมด data bits และถ้ามี parity bit ก็จะส่งที่จุดนี้แล้วลงท้ายด้วย stop
bit ซึ่งมีค่าเป็น logic “1” ในรูปได้แสดง bit ที่ต่อถัดจาก stop bit ซึงมีค่าเป็น
logic “0” หมายความว่าเป็น start bit ของ การส่ง word ถัดไป แต่ถ้ายังไม่มีการส่ง
word ถัดไป ก็ต้องอยู่ในสถานะของ logic “1” ซึ่งเป็นสถานะของ idle และถ้าสายอยู่ในสถานะของ
logic “0” นานกว่าเวลาของการส่ง 1 full word ระบบจะถือว่าเป็นสัญญาณ “Break” เพื่อหยุดการสื่อสาร
ดังนั้นต้องไม่ลืมที่จะสั่งในสายกลับสู่สถานะ idle เมื่อสิ้นสุดการส่ง
การรับ-ส่งข้อมูลในลักษณะนี้เรียกว่าแบบ frame คือมีกรอบปิดล้อมข้อมูลไว้ด้วย
start bit และ stop bit
RS-232 Level Converters
สัญญาณ RS-232 มีค่าแรงไฟต่างจากที่ใช้ใน UART ดังแสดงใน Figure 5. ดังนั้นจึงต้องมี
converter เพื่อแปลงระดับสัญญาณให้เหมาะสมก่อนที่จะเชื่อมต่อกับ serial port หรือ
RS-232 port ของ computer
Figure 5. RS-232 Logic Waveform.
สำหรับสัญญาณ RS-232 นั้น logic “0” จะมีค่า +3 V ถึง +25 V และ
logic “1” จะมีค่า –3 V ถึง –25 V ส่วนค่าระหว่าง –3 V ถึง +3 V เป็นค่า undefined
ระดับสัญญาณนี้ใช้กับทุกสัญญาณไม่ใช่เฉพาะสัญญาณรับ-ส่งข้อมูลเท่านั้นแต่ยังรวมถึงสัญญาณควบคุมต่าง
ๆ เช่น DTR, RTS, CTS, DCD, DSR เป็นต้น
IC ที่ใช้มักจะเป็นเบอร์ 1488 (RS-232 Driver) และ 1489 (RS-232 Receiver) โดยภายในแต่ละตัวจะประกอบด้วย
inverter 4 ตัวและต้องการไฟเลี้ยง 2 ชุดคือ +7.5 V ถึง +15 V และ –7.5 V ถึง –15
V ซึ่งอาจจะมีปัญหาในเครื่องที่มีไฟเลี้ยง +5 V เพียงชุดเดียว แต่ก็ยังมี IC อีกตัวหนึ่งคือเบอร์
MAX-232 ซึ่งมีวงจร charge pump สามารถสร้างไฟ +10 V และ –10 V จากไฟ +5 V ได้
พร้อมทั้งมี 2 Tx และ 2 Rx อยู่ใน package เดียวกัน และรองรับ baud rate ได้ถึง
120 Kbps จึงสะดวกมากเพราะใช้ IC เพียงตัวเดียว รูปข้างล่างคือ MAX-232

ส่วนการที่เราจะนำข้อมูลมาใช้งานก็ต้องแปลงเป็น parallel ก่อนซึ่งเป็นหน้าที่ของ
UART ซึ่งปัจจุบัน microprocessor และ microcontroller มักจะมี serial communication
interface (SCI) อยู่ในตัว แต่อาจจะมีงานบางอย่างที่ไม่ได้ใช้ microcontroller
และต้องการ process ข้อมูลกับ serial comm. เช่น ต่อ ADC เข้ากับ UART หรือต่อ
LCD display เข้ากับ Serial comm. ก็ต้องใช้ UART ช่วย เช่นเบอร์ 8250 หรือ 16550A
หรือเบอร์อื่น ๆ ที่ได้กล่าวมาแล้ว แต่มี UART อีกพวกหนึ่งที่แยก Tx bus กับ Rx
bus ออกจากกัน ทำให้มีความคล่องตัวมากขึ้น ซึ่งจะกล่าวในหัวข้อต่อไป
CDP6402, AY-5-1015 / D36402R-9 etc UARTS
Table 17. แสดงรายละเอียดหน้าที่ของขาต่าง ๆ ของ UART ในกลุ่ม CDP6402, AY-5-1015
/ D36402R-9 ซึ่งเป็น CMOS สามารถรองรับ baud rate สูงถึง 200 Kbps ที่ 5 V แต่เนื่องจาก
UART เหล่านี้ไม่มี programmable baud rate generator อยู่ใน chip ด้วย จึงต้องใช้วงจรภายนอก
โดยมากจะใช้ IC เบอร์ 74HC4046 ซึ่งเป็น 14 bit binary counter/divider แต่จะมีขา
output เพียงบางส่วนคือ Q4 ถึง Q14 จึงต้องการ clock ที่มีความถี่สูงกว่า max.
baud rate 16 เท่า Table 18. แสดง baud rate ที่เป็นไปได้เมื่อใช้ Crystal ควบคุมความถี่ต่างกัน
Table 17. Pin description for CDP6402, AY-5-1015
/ D36402R-9 and compatible UARTs.
Pin Number
|
Abbr.
|
Full Name
|
Notes
|
1
|
VDD
|
+5 V. Supply Rail.
|
Connected to +5 V Supply.
|
2
|
NC
|
Not Connected.
|
Not Connected.
|
3
|
GND
|
Ground.
|
Ground.
|
4
|
RRD
|
Receiver Register Disable.
|
When driven high, Outputs RBR8:RBR1 are high impedance.
|
5 : 12
|
RBR8 : RBR1
|
Receiver Buffer Register.
|
Receiver’s Data Bus.
|
13
|
PE
|
Parity Error.
|
When high, a parity error has occurred.
|
14
|
FE
|
Framing Error.
|
When high, a framing error has occurred. I.e. The stop bit was not
a logic 1.
|
15
|
OE
|
Overrun Error.
|
When high, data has been received but the nData Received Reset has
not yet been activated.
|
16
|
SFD
|
Status Flag Disable.
|
When high, status flag outputs (PE, FE, OE, DR and TBRE) are high impedance.
|
17
|
RRC
|
Receiver Register Clock.
|
X 16 clock input for the receiver register.
|
18
|
nDRR
|
Data Received Reset.
|
Active low. When low, sets data received outputs low.(i.e. Clears DR)
|
19
|
DR
|
Data Received.
|
When high, data has been received and placed on outputs RBR8:RBR1.
|
20
|
RRI
|
Receiver Register In.
|
RXD-Serial input. Connected to serial port, via RS-232 receiver.
|
21
|
MR
|
Master Reset.
|
UART should be reset after applying power.
|
22
|
TBRE
|
Transmitter Buffer Register Empty.
|
When high, indicates that transmitter buffer register is empty, thus
all bits including stop bit have been sent.
|
23
|
nTBRL
|
Transmitter Buffer Load/Strobe.
|
Active low. When low, data present on TBR8:TBR1 is placed in transmitter
buffer register. A low to high transition on this pin, then sends the
data.
|
24
|
TRE
|
Transmitter Register Empty.
|
When high, transmitter register is empty, thus can accept another byte
of data to be sent.
|
25
|
TRO
|
Transmitter Register Out. (TXD)
|
TXD-Serial output. Connected to serial port, via RS-232 transmitter.
|
26 : 33
|
TBR8 :TBR1
|
Transmitter Buffer Register.
|
Data bus for transmitter. Place data here which you want to send.
|
34
|
CRL
|
Control Register Load
|
When high, control register (PI, SBS, CLS2, CLS1, EPE) is loaded. Can
be tied high, so changes on these pins occur instantaneously.
|
35
|
PI
|
Parity Inhibit.
|
When high, no parity is used for both transmit and receive. When low,
parity is used.
|
36
|
SBS
|
Stop Bit Select..
|
A high select 2 stop bits.(1.5 for 5 character word lengths). A low
select 1 stop bit.
|
37 : 38
|
CLS2 :CLS1
|
Character Length Select.
|
Select word length. 00=5 bits, 01=6 bits, 10=7 bits and 11=8 bits.
|
39
|
EPE
|
Even Parity Enable.
|
When high, even parity is used. When low, odd parity is used.
|
40
|
TRC
|
Transmitter Register Clock.
|
X 16 clock input for the transmitter.
|
Table 18. Possible baud rates using a 74HC4046.
Output
|
1.8432 MHz
|
2.4546 MHz
|
Out2
|
115.2 Kbps
|
153.6 Kbps
|
Q4
|
7200 bps
|
9600 bps
|
Q5
|
3600 bps
|
4800 bps
|
Q6
|
1800 bps
|
2400 bps
|
Q7
|
900 bps
|
1200 bps
|
Q8
|
450 bps
|
600 bps
|
Q9
|
225 bps
|
300 bps
|
การใช้ BIOS Interrupt 14h และ DOS API Interrupt 21h
BIOS Interrupt 14h มี 4 functions ให้ใช้ในการ
program เกี่ยวกับ serial port ดังรายละเอียดต่อไปนี้
Function 00h: Initializes the serial port and sets the speed, data and stop bits and the parity parameters.
Input: AH=00h
DX=Number of serial port (0=first serial port, 1=second serial port)
AL=Configuration parameters
Bits 0-1: Word length
10=7 bits
11=8 bits
Bit 2: Number of stop bits
00=1 stop bit
01=2 stop bits
Bits 3-4: Parity
00=none
01=odd
11=even
Bits 5-7: Baud rate
000=110 baud
001=150 baud
010=300 baud
011=600 baud
100=1200 baud
101=2400 baud
110=4800 baud
111=9600 baud
Output: AH=Serial port status
Bit 0: Data ready
Bit 1: Overrun error
Bit 2: Parity error
Bit 3: Framing error
Bit 4: Break discovered
Bit 5: Transmission hold register empty
Bit 6: Transmission shift register empty
Bit 7: Time out
AL=Modem status
Bit 0: Modem ready to send status change
Bit 1: Modem on status change
Bit 2: Telephone ringing status change
Bit 3: Connection to receiver status change
Bit 4: Modem ready to send
Bit 5: Modem on
Bit 6: Telephone ringing
Bit 7: Connection to receiver modem
หมายเหตุ: ข้อมูลใน BX, CX, DX, SI, DI, BP registers และ segment registers ไม่ได้ถูกกระทบจากการเรียก
ใช้ function นี้ ส่วนข้อมูล ใน registers อื่นอาจมีการเปลี่ยนแปลง
Function 01h: Sends a character to the specified serial port.
Input: AH=01h
DX=Number of serial port (0=first serial port, 1=second serial port)
AL=Character code to be send
Output: AH: Bit 7=0: Character transmitted
Bit 7=1: Error
Bit 0-6: Serial port status
Bit 0: Data ready
Bit 1: Overrun error
Bit 2: Parity error
Bit 3: Framing error
Bit 4: Break discovered
Bit 5: Transmission hold register empty
Bit 6: Transmission shift register empty
หมายเหตุ: ข้อมูลใน BX, CX, DX, SI, DI, BP registers และ segment registers ไม่ได้ถูกกระทบจากการเรียก
ใช้ function นี้ ส่วนข้อมูล ใน registers อื่นอาจมีการเปลี่ยนแปลง
Function 02h: Reads a character from the specified serial port.
Input: AH=02h
DX=Number of serial port (0=first serial port, 1=second serial port)
Output: AH: Bit 7=0: Character received
Bit 7=1: Error
Bit 0-6: Serial port status
Bit 0: Data ready
Bit 1: Overrun error
Bit 2: Parity error
Bit 3: Framing error
Bit 4: Break discovered
Bit 5: Transmission hold register empty
Bit 6: Transmission shift register empty
หมายเหตุ: ควรจะเรียกใช้ function นี้ก็ต่อเมื่อ function 3 พบว่ามี character พร้อมให้รับแล้วเท่านั้น ข้อมูลใน BX,
CX, DX, SI, DI, BP registers และ segment registers ไม่ได้ถูกกระทบจากการเรียกใช้ function นี้ ส่วนข้อมูล ใน
registers อื่นอาจมีการเปลี่ยนแปลง
Function 03h: Returns the state of the specified serial port.
Input: AH=03h
DX=Number of serial port (0=first serial port, 1=second serial port)
Output: AH=Serial port status
Bit 0: Data ready
Bit 1: Overrun error
Bit 2: Parity error
Bit 3: Framing error
Bit 4: Break discovered
Bit 5: Transmission hold register empty
Bit 6: Transmission shift register empty
AL=Modem status
Bit 0: Modem ready to send status change
Bit 1: Modem on status change
Bit 2: Telephone ringing status change
Bit 3: Connection to receiver status change
Bit 4: Modem ready to send
Bit 5: Modem on
Bit 6: Telephone ringing
Bit 7: Connection to receiver modem
หมายเหตุ: function นี้ควรถูกเรียกใช้ก่อนที่จะเรียกใช้ function 2 เสมอ ข้อมูลใน BX, CX, DX, SI, DI, BP
registers และ segment registers ไม่ได้ถูกกระทบจากการเรียกใช้ function นี้ ส่วนข้อมูล ใน registers
อื่นอาจมีการเปลี่ยนแปลง
ส่วน DOS API Interrupt 21h มี 3 functions ที่เกี่ยวข้องกับ serial port ดังรายละเอียดต่อไปนี้
Function 03h: Reads a character from the COM1 serial port, unless a MODE command previously
redirected serial access
Input: AH=03h
Output: AL=Character received
หมายเหตุ: เนื่องจาก serial port ไม่มี buffer อยู่ภายใน ทำให้มันรับ character ได้เร็วกว่าที่จะอ่านได้ หรืออ่าน
ไม่ทันกับการรับเข้ามาและ character ที่อ่านไม่ทันก็จะถูกเลยผ่านไป ซึ่งต้องระวังในจุดนี้ ก่อนที่จะเรียกใช้ function นี้ ต้องใช้
MODE command กำหนด communication parameters ต่าง ๆ เช่น baud rate, จำนวน stop bits และอื่น ๆ ให้เรียบ
ร้อยก่อน มิฉะนั้นก็จะใช้ค่า DOS defaults คือ 2400 baud หนึ่ง stop bit ไม่มี parity และ 8 data bits. และถ้า function
นี้ได้รับค่า <Ctrl><C> (ASCII code 3) จะทำให้ไปเรียกใช้ Interrupt 23h ซึ่งเป็น <Ctrl><C> handler address ได้
การใช้ BIOS functions จาก interrupt 14h จะมีความคล่องตัวและมีประสิทธิภาพกว่า ข้อมูลใน AH, BX, CX, DX, SI, DI,
BP, CS, DS, SS, ES registers และ flag registers ไม่ถูกกระทบจากการเรียกใช้ function นี้.
Function 04h: Writes a character to the COM1 serial port, unless a MODE command previously
redirected serial access.
Input: AH=04h
DL=Character set for output
Output: No output
หมายเหตุ: ทันทีที่ receiving device ส่งสัญญาณไปให้ function เพื่อบอกว่าพร้อมที่จะรับ function ก็จะส่ง
character ให้ แล้วกลับสู่ program ที่จากมา ก่อนที่จะเรียกใช้ function นี้ ต้องใช้ MODE command กำหนด
communication parameters ต่าง ๆ เช่น baud rate, จำนวน stop bits และอื่น ๆ ให้เรียบร้อยก่อน มิฉะนั้นก็จะใช้ค่า DOS
defaults คือ 2400 baud หนึ่ง stop bit ไม่มี parity และมี 8 data bits. และถ้า function นี้ได้รับค่า Ctrl><C>
(ASCII code 3) จะทำให้ไปเรียกใช้ Interrupt 23h ซึ่งเป็น <Ctrl><C> handler address ได้ การใช้ BIOS functions
จาก interrupt 14h จะมีความคล่องตัว และมีประสิทธิภาพกว่า ข้อมูลใน registers ใน processor และ flag registers
ไม่ถูกกระทบจากการเรียกใช้ function นี้
Function 40h: It is a common out function for all files and devices that use a handle access. This
function sends a number of bytes from a buffer to the specified device.
Input: AH=40h
BX=File or device handler
CX=Number of bytes to be read
DS=Buffer segment address
DX=Buffer offset address
Output: Carry flag=0: O.K. (AX=Number of bytes read)
Carry flag=1: Error (AX=Error code)
AX=5: Access denied
AX=6: Illegal handle or file not open
หมายเหตุ: Characters สามารถเขียนไปยัง file หรือ device เช่น screen ซึ่งมีค่า handle=1 เป็นต้น ถ้าหลังจาก
เรียก function นี้แล้ว carry flag ถูก reset แต่ AX register มีค่าเป็น 0 หมายความว่า file pointer ชี้ถึงจุดสิ้นสุด
ของ file ก่อนที่ function จะถูกเรียกใช้ จึงไม่สามารถเขียนเข้าไปใน file ได้ ถ้าหลังจากเรียก function นี้แล้ว carry
flag ถูก reset แต่ ข้อมูลใน AX register มีค่าน้อยกว่าใน CX register (ก่อนที่จะเรียก function) แสดงว่า ไม่สามารถ
เขียนจำนวน bytes ที่ต้องการเข้าไปยัง file ได้ เพราะถึงจุดสิ้นสุดของ file ก่อน ดังนั้นหลังจากเรียก function file
pointer จึงชี้fไปยัง byte ที่ถัดจาก byte สุดท้ายที่เขียนเข้าไปได้ ข้อมูลใน AH, BX, CX, DX, SI, DI, BP, CS, DS,
SS และ ES registers ไม่ถูกกระทบจากการเรียกใช้ function นี้
ตัวอย่างต่อไปนี้เป็น program ภาษา C++ ที่ใช้ serial comm. ติดต่อกันระหว่าง computer
2 เครื่อง
//Program to communicate two PCs via serial port
//00h BIOS function (AL register)
//bits 7, 6, 5 Baud rate (bps.)
// 000 110
// 001 150
// 010 300
// 011 600
// 100 1200
// 101 2400
// 110 4800
// 111 9600
//bits 4, 3 Parity bits
// 00 no parity
// 01 odd parity
// 11 even
//bits 2 stop bits
// 0 1 stop bit
// 1 2 stop bit
//bits 1, 0 Number of bits per data
// 10 7 data bits
// 11 8 data bits
//Register Dx 0->com1, 1->com2, 2->com3, 3->com4
//Configuration: 9600 bps., no parity, 2 stop bits and 8 data bits
//AL register value is 11100111 -> 0xE7
#include <stdio.h>
#include <process.h>
#include <conio.h>
#include <dos.h>
#include <bios.h>
#define TRUE 1
#define PARAM 0xA7
#define COM1 0
#define COM2 1
void init_port(void);
char state_port(void);
void send_byte(unsigned char);
unsigned char read_byte(void);
void keyb(void);
int tecla = 1;
void main ( void )
{
unsigned char read_com;
unsigned char read_kb;
clrscr();
init_port();
while(read_kb != 'c')
{
read_kb=getch();
send_byte(read_kb);
read_com=read_byte();
if(read_com!=0){printf("%c",read_com);}
}
}
void init_port()
{
union REGS regs;
regs.h.ah = 0x00;
regs.x.dx = COM2;
regs.h.al = PARAM;
int86( 0x14, ®s, ®s);
}
//return the state of the port
char state_port()
{
union REGS regs;
regs.h.ah = 0x03;
regs.x.dx = COM2;
int86( 0x14, ®s, ®s);
if(regs.h.ah & 0x80) printf("\t EXCEED TIME\n");
if(regs.h.ah & 0x40) printf("\t TSR EMPTY\n");
if(regs.h.ah & 0x20) printf("\t THR EMPTY\n");
if(regs.h.ah & 0x10) printf("\t INTERRUPTION\n");
if(regs.h.ah & 0x08) printf("\t THREAT ERROR\n");
if(regs.h.ah & 0x04) printf("\t PARITY ERROR\n");
if(regs.h.ah & 0x02) printf("\t OVERLOAD ERROR\n");
return (regs.h.ah);
}
//Keyboard handle
void keyb()
{
union u_type{int a;char b[3];}keystroke;char inkey=0;
if(bioskey(1)==0) return;
keystroke.a=bioskey(0);
inkey=keystroke.b[1];
switch (inkey)
{
case 1: keyb=0;
return; /*ESC*/
default: keyb=15;
return;
}
}
//Send a character to the serial port
void send_byte(unsigned char byte)
{
union REGS regs;
regs.h.ah = 0x01;
regs.x.dx = COM2;
regs.h.al = byte;
int86( 0x14, ®s, ®s);
if( regs.h.ah & 0x80)
{
printf("\t SENDING ERROR ");
exit(1);
}
}
//read a character from serial port
unsigned char read_byte()
{
int x,a;
union REGS regs;
if((estate_port() & 0x01))
{
regs.h.ah = 0x02;
regs.x.dx = COM2;
int86(0x14,®s,®s);
if(regs.h.ah & 0x80)
{
printf("\t RECEIVING ERROR");
exit(1);
}
return(regs.h.al);}
else
{
return(0);
}
}
RS-232, RS-423, RS-422 and RS-485
Table ข้างล่างนี้เป็นการสรุปคุณสมบัติของมาตรฐานต่าง ๆ ที่นิยมใช้กันทั่วไป
Specification
|
RS-232
|
RS-423
|
RS-422
|
RS-485
|
Mode of operation
|
Single-ended
|
Single-ended
|
Differential
|
Differential
|
Total number of drivers and receivers on one line
|
1Tx
1Rx
|
1Tx
10Rx
|
1Tx
10Rx
|
1Tx
32Rx
|
Maximum cable length
|
50Ft
|
4,000Ft
|
4,000Ft
|
4,000Ft
|
Maximum data rate
|
20Kbps
|
100Kbps
|
10Mbps
|
10Mbps
|
Maximum driver output voltage
|
+/-25V
|
+/-6V
|
-0.25V to +6V
|
-7V to +12V
|
Driver output signal level (loaded min.)
|
Loaded
|
+/-5V to +/-15V
|
+/-3.6V
|
+/-2V
|
+/-1.5V
|
Driver output signal level (loaded max.)
|
Unloaded
|
+/-25V
|
+/-6V
|
+/-6V
|
+/-6V
|
Driver load impedance (ohms)
|
3K to 7K
|
>=450
|
100
|
54
|
Max. Driver current in high Z state
|
Power on
|
N/A
|
N/A
|
N/A
|
+/-100uA
|
Max. Driver current in high Z state
|
Power off
|
+/-6mA @ +/-2V
|
+/-100uA
|
+/-100uA
|
+/-100uA
|
Slew rate (max.)
|
30V/uS
|
Adjustable
|
N/A
|
N/A
|
Receiver input voltage range
|
+/-15V
|
+/-12V
|
-10V to +10V
|
-7V to +12V
|
Receiver input sensitivity
|
+/-3V
|
+/-200mV
|
+/-200mV
|
+/-200mV
|
Receiver input resistance (ohms)
|
3K to 7K
|
4K min.
|
4K min.
|
>=12K
|
การสื่อสารระหว่างอุปกรณ์ตั้งแต่ 2 อุปกรณ์ขึ้นไปจะประกอบด้วยตัว Driver หรือตัวส่ง
Receiver หรือตัวรับ และสื่อกลาง หรือ Transmission line (ในกรณีที่เป็นการสื่อสารแบบใช้สาย)
ทาง EIA จึงได้กำหนดมาตรฐานต่าง ๆ ขึ้น ซึ่งมีคุณสมบัติสรุปตามที่แสดงใน Table
ข้างบน โดย RS-232 และ RS-423 เป็นแบบ single-ended ส่วน RS-422 และ RS-485 เป็นแบบ
differential ซึ่งลดปัญหาที่แบบ single-ended ต้องประสบเช่นเรื่อง ground shift,
ground noise เรื่อง induced noise ใน common mode เป็นต้น
วงจรสัญญาณของ RS-232
ระดับสัญญาณของ RS-232
สัญญาณระบบ Balanced Differential Data Transmission
RS-232 มี speed สูงสุดได้ไม่เกิน 20Kbps และไปได้ไกลสุดไม่เกิน 50 ฟุตที่ speed
สูงสุด แต่ถ้าใช้สายพิเศษที่เป็นชนิด low capacitance ก็สามารถไปได้ไกลขึ้น สื่อสารแบบ
full-duplex ได้ สัญญาณ idle เป็น “mark” มีค่าแรงไฟเป็นลบ และสัญญาณ active เป็น
“space” มีค่าแรงไฟเป็นบวก ใช้สัญญาณ handshaking หลายสัญญาณ เหมาะที่จะเชื่อมต่อกับ
modem ดังนั้นถ้าใช้งานด้านอื่นจึงมักประสบปัญหาในการจัดการกับสัญญาณ handshaking
ซึ่งโดยมากมักจะใช้วิธีแก้ที่ software protocol หรือไม่ก็ loopback หรือ pull-up
ด้วย Hardware ส่วน RS-423 เป็นมาตรฐานที่ปรับปรุงให้การทำงานแบบ single-ended
ดีกว่า RS-232 แต่ก็ไม่ค่อยได้รับความนิยมนัก
เปรียบเทียบวงจรระหว่าง RS-422 กับ RS-485
การต่อ Grounding ของ RS-485
RS-422 เป็นแบบ differential สามารถใช้ speed ได้สูงกว่าและไปได้ไกลกว่า RS-232
มาก ดังนั้นถ้าใช้ converter 1 คู่ต่อหัว-ท้าย เพื่อแปลงสัญญาณ RS-232 และ RS-422
จะทำให้สามารถสื่อสารได้ด้วย speed สูงสุดถึง 100Kbps และไปได้ไกลถึง 4,000 ฟุต
และยังสามารถทำงานแบบ multi-drop (party-line) คือ 1 driver ต่อกับ 10 receivers
ในสาย bus เดียวกัน แต่ RS-422 ไม่สามารถทำงานแบบ multi-point network อย่างเต็มรูปแบบได้
ซึ่งประกอบด้วยหลาย driver และหลาย receiver ที่ต่ออยู่บน bus เดียวกัน แต่ก็ได้มีการแก้ไขให้สามารถสื่อสารแบบ
quasi multi-drop โดยใช้สาย 4 wires เพื่อสื่อสารแบบ half-duplex เพื่อหลีกเลี่ยงการชนกันของข้อมูล
(data collision)
RS-485 เป็นการทำงานแบบ multi-point แบบเต็มรูปแบบ โดยใช้สาย 2 wires สามารถต่อกับ
driver และ receiver ได้ถึง 32 ชุดบน bus เดียวกัน และถ้าผนวกกับการใช้ automatic
repeater และ high impedance driver/receiver แล้วจะทำให้สามารถต่อใช้งานได้อีกเป็น
100 เป็น 1,000 nodes บน network เดียวกันได้ และเพิ่มขึดความสามารถในการทนต่อปัญหา
common mode ด้วย tri-state และ power off อีกทั้งทนต่อปัญหาของ data collision
และ bus fault การแก้ปัญหาเรื่อง collision จะใช้การสื่อสารแบบ half-duplex และทางภาคส่งจะเปลี่ยนเป็นภาครับทันทีหลังจากส่งแล้ว
ทำให้สามารถทำงานด้วยความเร็วสูงได้