0

如何更改通过端口的字节传输?

  • 是:打断。
  • 需要:根据民意调查。                                        

插件-> http://pastie.org/3994352

客户:

#include <stdio.h>
#include <conio.h>
#include <dos.h>
#include "comm.h"  // Connect module

void main(void)
{
   char cmd[128];

   /* Set the COM port */
   printf("Adjustable com-port ...\n");
   OpenSerial(COM_1, SER_BAUD_9600, SER_STOP_2 | SER_BITS_8 | SER_PARITY_EVEN);

   printf("Submitting a request for a connection ...\n");
   WriteSer(0xFF);

   while (1)
   {
      if (kbhit())
      {
         int c = getche();
         if (c == 13) putch(10);
         WriteSer(c);
      }

      if (DataReadyCount())
      {
         int c = ReadQueue();
         if (c == 0xFF) break;

         putch(c);
      }
   }

   printf("Ending a connection ...\n");
   CloseSerial();
}
4

1 回答 1

0

我在网上找到了一个可能有价值的示例,至少在展示轮询与中断驱动方法方面。请注意,中断方法需要调用setvect, outportb,保存旧中断并恢复它等。

接下来不要问 TSR。:)

// http://ragestorm.net
// serial communications example
// interrupt driven/polled method
#include <dos.h>
#include <conio.h>
#include <stdio.h>

// serial port base addresses:
#define COM1 (0x3f8)
#define COM2 (0x2f8)

// stack size for interrupt
#define STACK_SIZE 1024

// serial ports registers:

// receive buffer
#define RBR (0x0)
// transmitter hold
#define THR (0x0)
// interrupt enable
#define IER (0x1)
// interrupt identification
#define IIR (0x2)
// fifo control
#define FCR (0x2)
// line control
#define LCR (0x3)
// modem control
#define MCR (0x4)
// line status
#define LSR (0x5)
// modem status
#define MSR (0x6)
// scratch-pad
#define SPR (0x7)

// divisor lsb byte
#define DIVLSB (0x0)
// divisor msb byte
#define DIVMSB (0x1)

// possible irqs for com ports
int com_irqs[4] = {4, 3, 4, 3};

// the com port addr being used
int used_com_addr = 0;

// the irq being used if interrupt driven
int used_com_irq = 0;

// interrupt driven or polling method?
int intr_used = 0;

// built in stack for interrupt usage
unsigned char recv_stack[STACK_SIZE];
unsigned char* next_char = recv_stack;

// old handler address
void interrupt (*old_handler)(...) = NULL;
void interrupt new_handler(...);

// get com address from bios
unsigned short get_com_addr(int com_no)
{
 if ((com_no <= 0) || (com_no >= 5)) return -1;

 // bios seg addr
 unsigned char* biosaddr = (unsigned char *)0x400;

 // set irq according to com number
 used_com_irq = com_irqs[com_no - 1];

 // retreive addresses bios
 return *(unsigned short*)&biosaddr[(com_no -  1) << 1];
}


// detect the uart type of the used com prot addr
// this is mainly to know if fifo is available.
// 0: no uart found, 1: 8250, 2: 16450 or 8250(with spr), 3: 16550, 4: 16550A
int detect_uart_type()
{
 char old_data = 0;

 // check UART presentation by checking loopback mode
 old_data = inportb(used_com_addr + MCR);
 outportb(used_com_addr + MCR, 0x10);
 if ((inportb(used_com_addr + MSR) & 0xf0)) return 0;
 outportb(used_com_addr + MCR, 0x1f);
 if ((inportb(used_com_addr + MSR) & 0xf0) != 0xf0) return 0;
 outportb(used_com_addr + MCR, old_data);

 // write values to scratch pad and readback
 old_data = inportb(used_com_addr + SPR);
 outportb(used_com_addr + SPR, 0x55);
 if (inportb(used_com_addr + SPR) != 0x55) return 1;
 outportb(used_com_addr + SPR, 0xAA);
 if (inportb(used_com_addr + SPR) != 0xAA) return 1;
 outportb(used_com_addr + SPR, old_data);

 // enable fifo and determine version by part identification
 outportb(used_com_addr + FCR, 1);
 old_data = inportb(used_com_addr + FCR);
 outportb(used_com_addr + FCR, 0);

 if ((~old_data & 0x80)) return 2; // 16450
 if ((~old_data & 0x40)) return 3; // 16550
 return 4; // 16550a +
}

// inits the serial com port with a specific baud rate,
// using interrupt or polling method.
void init_com_port(int com_no, long baudrate, int intr = 0)
{
 // calculate divisor relative to the baudrate
 short divisor = (long)115200 / baudrate;

 used_com_addr = get_com_addr(com_no);

 if (used_com_addr == 0) {

    printf("no valid com port!\n");
    return ;
 }
 printf("serial com port addr 0x%x", used_com_addr);
 if (intr)
    printf(" [irq %d, ", used_com_irq);
 else printf("[");

 int uart_type = detect_uart_type();
 switch(uart_type) {
    //case 0: break; // port must be found already by bios.
    case 1: printf("8250"); break;
    case 2: printf("16450"); break;
    case 3: printf("16550"); break;
    case 4: printf("16550a"); break;
 }

 printf("] is initialized!\n");

 intr_used = intr;

 disable();

 // turn off interrupts
 outportb(used_com_addr + 1, 0);

 // set dlab bit, so we can update the divisor
 outportb(used_com_addr + LCR, 0x80);

 // set divisor lsb
 outportb(used_com_addr + DIVLSB, divisor & 0xff);
 // set msb
 outportb(used_com_addr + DIVMSB, (divisor >> 8) & 0xff);

 // frame: 8 data bits, no parity and 1 stop bit
 outportb(used_com_addr + LCR, 0x3);

 // set RTS | DTR | OUT2(if intr) to inform remote system that we are ready
 outportb(used_com_addr + MCR, 0x3 | ((intr == 1) << 3));

 // support interrupt?
 if (intr) {

    // save old serial port interrupt handler address
    old_handler = getvect(8 + used_com_irq);
    setvect(8 + used_com_irq, new_handler);

    // enable serial port irq at pic
    outportb(0x21, inportb(0x21) & ~(1 << used_com_irq));

    // let the interrupt be triggered upon data arrival
    outportb(used_com_addr + IER, 1);

 } else {
    // no interrupt should be triggered
    outportb(used_com_addr + IER, 0);
 }

 // does the uart support fifo?
 if (uart_type == 4) {
    // set fifo buffer of 14 bytes, clear receive and transmit fifo's
    outportb(used_com_addr + FCR, 0xc7);
 }

 // clear delta bits
 inportb(used_com_addr + LSR);

 // clear incoming byte
 inportb(used_com_addr + RBR);

 enable();
}

// the serial port interrupt handler
// called upon received data only
// saves data in a stack
void interrupt new_handler(...)
{
 unsigned char status = 0;
 disable();

 // read iir and msr to acknowledge the uart
 inportb(used_com_addr + IIR);
 inportb(used_com_addr + MSR);

 // as long as data is arriving, put it in the stack
 do {
    // read status register
    status = inportb(used_com_addr + LSR) & 0x1;

    if (status & 1) {
     // read data from com port to the stack
     *next_char++ = inportb(used_com_addr + RBR);
     // overlap offset in case the stack is full
     next_char = ((next_char - recv_stack) % STACK_SIZE) + recv_stack;
    }
 }while (status & 1);

 enable();
 // let the pic know we are done
 outportb(0xa0, 0x20);
 outportb(0x20, 0x20);
}

// send a byte to the initialized com port
void send_byte(unsigned char ch)
{
 // make sure the connection is alive
 if (inportb(used_com_addr + MSR) & 0x80 == 0) return;

 // make sure the transmit hold register is empty
 while (inportb(used_com_addr + LSR) & 0x20 == 0) ;

 // send the character
 outportb(used_com_addr + THR, ch);
}

// receive a byte from the initialized com port
unsigned char recv_byte(int* is_read)
{
 int i;

 *is_read = 0;
 if (intr_used)
    if (next_char > recv_stack)
    {
     *is_read = 1;
     return *--next_char;
    } else return 0;

 // is data set ready high?
 for (i = 5; i > 0; i--)
    if (inportb(used_com_addr + MSR) & 0x20) break;
 if (!i) return -1;

 // is there anything to read?
 for (i = 5; i > 0; i--)
    if (inportb(used_com_addr + LSR) & 0x1) break;
 if (!i) return -2;

 *is_read = 1;
 return inportb(used_com_addr + RBR);
}

// enter loop-mode for debugging and testing.
void enter_loop_mode()
{
 outportb(used_com_addr + MCR, inportb(used_com_addr + MCR) | 0x10);
}

// exit a loop mode, change to transimtter/receiver mode
void exit_loop_mode()
{
 outportb(used_com_addr + MCR, inportb(used_com_addr + MCR) & ~0x10);
}

// shut down serial port connection
void shutdown_com_port()
{
 disable();

 if (intr_used) {

    // set the old handler
    setvect(8 + used_com_irq, old_handler);

    // disable used serial port interrupt at pic
    outportb(0x21, inportb(0x21) | (1 << used_com_irq));
 }

 // disable serial port interrupt
 outportb(used_com_addr + IER, 0);

 // disable interrupt, RTS and DTR
 outportb(used_com_addr + MCR, 0);

 outportb(used_com_addr + FCR, 0);

 enable();
}

int main()
{
 clrscr();
 init_com_port(1, 9600, 1);

 for(;;) {
    if (kbhit()) {
     int c = getch();
     if (c == 27) break;
     printf("%c", c);
     send_byte(c);
    }
    int b = 0;
    unsigned char c = recv_byte(&b);
    if (b) printf("%c", c);
 }

 shutdown_com_port();
 return 1;
}
于 2012-05-30T10:42:18.243 回答