การ Interface กับ Serial Port (Part VI)


Modem Control Register (MCR)

Table 11. แสดงรายละเอียดของ Modem Control Register.

Table 11. Modem Control Register.

Bit

Notes

7

Reserved

6

Reserved

5

Autoflow Control Enabled (16750 only)

4

Loopback Mode

3

Aux. Output 2

2

Aux. Output 1

1

Force Request To Send

0

Force Data Terminal Ready

 

MCR เป็น register ชนิด read/write สำหรับ bit 5, 6 และ 7 ถูก reserve ไว้


Line Status Register (LSR)

Table 12. แสดงรายละเอียดของ Line Status Register

Table 12. Line Status Register.

Bit

Notes

7

Error in Received FIFO

6

Empty Data Holding Registers

5

Empty Transmitter Holding Register

4

Break Interrupt

3

Framing Error

2

Parity Error

1

Overrun Error

0

Data Ready

 

Line Status Register เป็น register ชนิด read only

Bit 7 จะบ่งบอกถึงความผิดปรกติของสิ่งที่รับเข้ามาใน FIFO เช่น มี bit ที่เสียหายหรือ parity ไม่ถูกต้องหรือ frame ของข้อมูลไม่ถูกต้องเป็นต้น

Bit 6 ถ้ามีค่าเป็น “1” จะแสดงว่าทั้งใน Tx holding register และ shift register ว่าง ซึ่ง Tx holding register จะเป็นตัวเก็บข้อมูลที่จะส่งในรูปแบบ parallel ส่วน shift register จะทำหน้าที่แปลงข้อมูลจาก parallel ให้เป็น serial ส่งออกไป

Bit 5 บ่งบอกว่าเฉพาะ Tx holding register ที่ว่างลง แต่ยังมีข้อมูลใน shift register อยู่ ความแตกต่างระหว่าง bit5 และ bit 6 คือ bit 5 บอกว่าสามารถส่งข้อมูลเข้าไปยัง Tx holding register และ Tx ก็ยังส่งข้อมูลอีก 1 byte ที่ค้างอยู่ใน shift register อยู่ ส่วน bit 6 บอกว่าไม่มีข้อมูลเหลือค้างในระบบการส่งแล้ว

Bit 4 เป็นตัวบอกว่าทางด้าน Rx อยู่ในสถานะ “space” หรือ “0” นานกว่าระยะเวลาของ 1 full word แล้ว ซึ่งระยะเวลาของ 1 full word หมายถึงเวลาของ (data bits)+(parity bit)+(start bit)+(stop bits)

Bit 3 จะเกิดขึ้นเมื่อปรากฏว่า bit สุดท้ายไม่ใช่ stop bit ซึ่งอาจจะเกิดจาก timing error เช่นการปรับ speed ของตัวรับกับตัวส่งไม่เท่ากัน

Bit 2 เป็นตัวบอกว่ามี parity error เกิดขึ้น แสดงว่าข้อมูลที่รับได้มี error หรือไม่ก็ตั้งเงื่อนไขของ parity ระหว่างตัวรับกับตัวส่งไม่ตรงกัน

Bit 1 บอกว่าเกิด overrun ขึ้น แสดงว่า software อ่านข้อมูลไม่ทัน ทำให้ข้อมูลที่รับเข้ามาใหม่ไปทับซ้อนแทนที่ข้อมูลเก่าที่ยังไม่ได้รับการ อ่านจาก software

Bit 0 บอกว่าข้อมูลรับเข้ามารออยู่ใน Rx buffer แล้ว พร้อมรอให้อ่านอยู่

Modem Status Register (MSR)

Table 13. แสดงรายละเอียดของ Modem Status Register

Table 13. Modem Status Register.

Bit

Notes

7

Carrier Detect

6

Ring Indicator

5

Data Set Ready

4

Clear To Send

3

Delta Data Carrier Detect

2

Trailing Edge Ring Indicator

1

Delta Data Set Ready

0

Delta Clear To Send

 

Modem Status Register เป็น register ชนิด read only

Bit 0 บอกว่า delta clear to send คำว่า delta หมายถึงมีการเปลี่ยนแปลงเกิดขึ้น เช่นในกรณีนี้แสดงว่ามีการเปลี่ยนแปลงของสัญญาณ clear to send เกิดขึ้นเมื่อเทียบกับการอ่าน register นี้ในครั้งที่แล้ว bit 1 และ 3 ก็ทำหน้าที่ในทำนองเดียวกัน

Bit 2 บอกว่ามีการเปลี่ยนสถานะจาก “low เป็น “high” ที่สัญญาณ ring indicator เกิดขึ้น

Bit 4 ถึง 7 บอกถึงสถานะของสัญญาณนั้น ๆ

Scratch Register

Scratch register ไม่ได้นำมาใช้ในการสื่อสารของ PC โดยตรง แต่ใช้เป็นที่พักข้อมูลในการอื่น ซึ่งประโยชน์ที่พอจะพบใน PC/AT คือใช้ตรวจว่า UART เป็นเบอร์ 8250/8250B ซึ่งไม่ได้ออกแบบมาให้ใช้กับ PC/AT หรือเบอร์ 8250A/16450

Programming

Polling or Interrupt Driven?

การเขียน Program ทางสื่อสารจะมี 2 วิธีหลัก ๆ คือ

    1. Polling คือไปคอยอ่าน UART ว่ามีข้อมูลมาหรือไม่เป็นระยะ ๆ ซึ่งเป็นวิธีที่ต้องใช้เวลาของ CPU อย่างมาก และทำให้สื่อสารด้วย speed ที่ไม่สูงเพราะจะทำให้ poll ไม่ทันเช่นอาจจะใช้ได้เพียง สิบ ๆ Kbps ขึ้นอยู่กับความเร็วของ CPU
    2. สร้าง Interrupt handler เพื่ออ่านข้อมูลจาก UART เมื่อมี interrupt เกิดขึ้น วิธีนี้จะสามารถสื่อสารได้เร็วขึ้นมากเช่น 115.2 Kbps หรือมากกว่านี้ขึ้นอยู่กับความเร็วของ UART และ CPU ที่ใช้
Termpoll.c - A Simple Comms Program using Polling
/* Name : Sample Comm's Program - Polled Version - termpoll.c */
/* Written By : Craig Peacock (cpeacock@senet.com.au) */
/* Date : Saturday 22nd February 1997 */
/* Copyright 1997 CRAIG PEACOCK (cpeacock@senet.com.au)*/
/* See http://www.senet.com.au/~cpeacock/serial.htm */
/* For More Information */
#include 
#include 
#include 
#define PORT1 0x3F8
/* Defines Serial Ports Base Address */
/* COM1 0x3F8 */
/* COM2 0x2F8 */
/* COM3 0x3E8 */
/* COM4 0x2E8 */
void main(void)
{
int c;
int ch;
outportb(PORT1 + 1 , 0); 			/* Turn off interrupts - Port1 */
/* PORT 1 - Communication Settings */
outportb(PORT1 + 3 , 0x80); 			/* SET DLAB ON */
outportb(PORT1 + 0 , 0x03); 			/* Set Baud rate - Divisor Latch Low Byte */
/* Default 0x03 = 38,400 BPS */
/* 0x01 = 115,200 BPS */
/* 0x02 = 56,700 BPS */
/* 0x06 = 19,200 BPS */
/* 0x0C = 9,600 BPS */
/* 0x18 = 4,800 BPS */
/* 0x30 = 2,400 BPS */
outportb(PORT1 + 1 , 0x00); 			/* Set Baud rate - Divisor Latch High Byte */
outportb(PORT1 + 3 , 0x03); 			/* 8 Bits, No Parity, 1 Stop Bit */
outportb(PORT1 + 2 , 0xC7); 			/* FIFO Control Register */
outportb(PORT1 + 4 , 0x0B); 			/* Turn on DTR, RTS, and OUT2 */
printf("\nSample Comm's Program. Press ESC to quit \n");
do { c = inportb(PORT1 + 5); 			/* Check to see if char has been */
					/* received. */
if (c & 1) {ch = inportb(PORT1); 			/* If so, then get Char */
printf("%c",ch);} 				/* Print Char to Screen */
if (kbhit()){ch = getch(); 			/* If key pressed, get Char */
outportb(PORT1, ch);} 			/* Send Char to Serial Port */
} while (ch !=27); 				/* Quit when ESC (ASC 27) is pressed */
}

การ polling ไม่ใช่ว่าจะไม่ควรใช้เสียทีเดียว มันยังมีประโยชน์อยู่เช่น ใช้ตรวจสอบว่า UART อยู่ที่ address ไหนและใช้ IRQ ใดโดยการ enable ทีละ IRQ ผ่าน PIC ซึ่งสามารถใช้ตรวจหาอุปกรณ์อื่น ๆ ด้วยเช่น Modem เป็นต้น

Buff1024.c - An Interrupt Driven Comms Program

/* Name : Sample Comm's Program - 1024 Byte Buffer - buff1024.c */
/* Written By : Craig Peacock (cpeacock@senet.com.au) */
/* Copyright 1997 CRAIG PEACOCK (cpeacock@senet.com.au) */
/* See http://www.senet.com.au/~cpeacock/serial.htm */
/* For More Information */
#include 
#include 
#include 
#define PORT1 0x2E8 			/* Port Address Goes Here */
/* Defines Serial Ports Base Address */
/* COM1 0x3F8 */
/* COM2 0x2F8 */
/* COM3 0x3E8 */
/* COM4 0x2E8 */
#define INTVECT 0x0B 			/* Com Port's IRQ here */
					/* (Must also change PIC setting) */
int bufferin = 0;
int bufferout = 0;
char ch;
char buffer[1025];
void interrupt (*oldport1isr)();
void interrupt PORT1INT() 			/* Interrupt Service Routine (ISR) for PORT1 */
{
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);
}
void main(void)
{
int c;
outportb(PORT1 + 1 , 0); 			/* Turn off interrupts - Port1 */
oldport1isr = getvect(INTVECT); 		/* Save old Interrupt Vector for */
/* later recovery */
setvect(INTVECT, PORT1INT); 			/* Set Interrupt Vector Entry */
/* COM1 - 0x0C */
/* COM2 - 0x0B */
/* COM3 - 0x0C */
/* COM4 - 0x0B */
/* PORT 1 - Communication Settings */
outportb(PORT1 + 3 , 0x80); 			/* SET DLAB ON */
outportb(PORT1 + 0 , 0x03); 			/* Set Baud rate - Divisor Latch Low Byte */
					/* Default 0x03 = 38,400 BPS */
/* 0x01 = 115,200 BPS */
/* 0x02 = 56,700 BPS */
/* 0x06 = 19,200 BPS */
/* 0x0C = 9,600 BPS */
/* 0x18 = 4,800 BPS */
/* 0x30 = 2,400 BPS */
outportb(PORT1 + 1 , 0x00); 			/* Set Baud rate - Divisor Latch High Byte */
outportb(PORT1 + 3 , 0x03); 			/* 8 Bits, No Parity, 1 Stop Bit */
outportb(PORT1 + 2 , 0xC7); 			/* FIFO Control Register */
outportb(PORT1 + 4 , 0x0B); 			/* Turn on DTR, RTS, and OUT2 */
outportb(0x21,(inportb(0x21) & 0xF7)); 		/* Set Programmable Interrupt */
					/* Controller */
/* COM1 (IRQ4) - 0xEF */
/* COM2 (IRQ3) - 0xF7 */
/* COM3 (IRQ4) - 0xEF */
/* COM4 (IRQ3) - 0xF7 */
outportb(PORT1 + 1 , 0x01); 			/* Interrupt when data received */
printf("\nSample Comm's Program. Press ESC to quit \n");
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);
outportb(PORT1 + 1 , 0); 			/* Turn off interrupts - Port1 */
outportb(0x21,(inportb(0x21) | 0x08));		/* MASK IRQ using PIC */
/* COM1 (IRQ4) - 0x10 */
/* COM2 (IRQ3) - 0x08 */
/* COM3 (IRQ4) - 0x10 */
/* COM4 (IRQ3) - 0x08 */
setvect(INTVECT, oldport1isr); 			/* Restore old interrupt vector */
}

หมายเหตุ Source code ข้างบนนี้เป็นการย่นย่อเพื่อให้ง่ายต่อการเข้าใจ ในทางปฏิบัติจริง เมื่อเข้าสู่ communication program ควรมีการเก็บค่า status ของ registers ต่าง ๆ ใน UART ไว้ และก่อนที่จะออกจาก communication program ก็ต้องทำการ restore มันกลับสภาพเดิม เพื่อ program อื่นจะได้ใช้ต่อไป

รายการหน้าเว็บย่อย

Comments