串口通信中读取COM3、4中的数据(急死!!!)

WilliamY2024 2000-09-06 01:33:00
各位大侠好:
我遇到一个非常棘手的问题。我们的项目中有一部分要求用TC++3.0
编写串口通信,我借用了CSDN上的serial.zip这个例子。但是由于工控机
上有4个串口,我现在无法读取COM3、4上的数据。急死!
我把我修改的下段源程序列出,有人说我是8259寄存器部分写错了,
我恳请高手能帮我指出来到底错在哪里。下面程序试图读取COM3数据,但
不成功:
(对不起,现在我只能给141分了,我真想给高手1000分!)
1 改过的Serial.h
/*---------------------------------------------------------------------*
FILENAME: SERIAL.H

Some definitions used by SERIAL.C

*--------------------------------------------------------------------*/

#define COM1 1
#define COM2 2
#define COM1BASE 0x3F8 /* Base port address for COM1 */
#define COM2BASE 0x2F8 /* Base port address for COM2 */

/*
The 8250 UART has 10 registers accessible through 7 port addresses.
Here are their addresses relative to COM1BASE and COM2BASE. Note
that the baud rate registers, (DLL) and (DLH) are active only when
the Divisor-Latch Access-Bit (DLAB) is on. The (DLAB) is bit 7 of
the (LCR).

o TXR Output data to the serial port.
o RXR Input data from the serial port.
o LCR Initialize the serial port.
o IER Controls interrupt generation.
o IIR Identifies interrupts.
o MCR Send contorl signals to the modem.
o LSR Monitor the status of the serial port.
o MSR Receive status of the modem.
o DLL Low byte of baud rate divisor.
o DHH High byte of baud rate divisor.
*/
#define TXR 0 /* Transmit register (WRITE) */
#define RXR 0 /* Receive register (READ) */
#define IER 1 /* Interrupt Enable */
#define IIR 2 /* Interrupt ID */
#define LCR 3 /* Line control */
#define MCR 4 /* Modem control */
#define LSR 5 /* Line Status */
#define MSR 6 /* Modem Status */
#define DLL 0 /* Divisor Latch Low */
#define DLH 1 /* Divisor latch High */


/*-------------------------------------------------------------------*
Bit values held in the Line Control Register (LCR).
bit meaning
--- -------
0-1 00=5 bits, 01=6 bits, 10=7 bits, 11=8 bits.
2 Stop bits.
3 0=parity off, 1=parity on.
4 0=parity odd, 1=parity even.
5 Sticky parity.
6 Set break.
7 Toggle port addresses.
*-------------------------------------------------------------------*/
#define NO_PARITY 0x00
#define EVEN_PARITY 0x18
#define ODD_PARITY 0x08



/*-------------------------------------------------------------------*
Bit values held in the Line Status Register (LSR).
bit meaning
--- -------
0 Data ready.
1 Overrun error - Data register overwritten.
2 Parity error - bad transmission.
3 Framing error - No stop bit was found.
4 Break detect - End to transmission requested.
5 Transmitter holding register is empty.
6 Transmitter shift register is empty.
7 Time out - off line.
*-------------------------------------------------------------------*/
#define RCVRDY 0x01
#define OVRERR 0x02
#define PRTYERR 0x04
#define FRMERR 0x08
#define BRKERR 0x10
#define XMTRDY 0x20
#define XMTRSR 0x40
#define TIMEOUT 0x80

/*-------------------------------------------------------------------*
Bit values held in the Modem Output Control Register (MCR).
bit meaning
--- -------
0 Data Terminal Ready. Computer ready to go.
1 Request To Send. Computer wants to send data.
2 auxillary output #1.
3 auxillary output #2.(Note: This bit must be
set to allow the communications card to send
interrupts to the system)
4 UART ouput looped back as input.
5-7 not used.
*------------------------------------------------------------------*/
#define DTR 0x01
#define RTS 0x02
#define MC_INT 0x08


/*------------------------------------------------------------------*
Bit values held in the Modem Input Status Register (MSR).
bit meaning
--- -------
0 delta Clear To Send.
1 delta Data Set Ready.
2 delta Ring Indicator.
3 delta Data Carrier Detect.
4 Clear To Send.
5 Data Set Ready.
6 Ring Indicator.
7 Data Carrier Detect.
*------------------------------------------------------------------*/
#define CTS 0x10
#define DSR 0x20


/*------------------------------------------------------------------*
Bit values held in the Interrupt Enable Register (IER).
bit meaning
--- -------
0 Interrupt when data received.
1 Interrupt when transmitter holding reg. empty.
2 Interrupt when data reception error.
3 Interrupt when change in modem status register.
4-7 Not used.
*------------------------------------------------------------------*/
#define RX_INT 0x01


/*------------------------------------------------------------------*
Bit values held in the Interrupt Identification Register (IIR).
bit meaning
--- -------
0 Interrupt pending
1-2 Interrupt ID code
00=Change in modem status register,
01=Transmitter holding register empty,
10=Data received,
11=reception error, or break encountered.
3-7 Not used.
*------------------------------------------------------------------*/
#define RX_ID 0x04
#define RX_MASK 0x07


/*
These are the port addresses of the 8259 Programmable Interrupt
Controller (PIC).
*/
//#define IMR 0x21 /* Interrupt Mask Register port */
//#define ICR 0x20 /* Interrupt Control Port */
//我改的
#define IMR 0xa1 /* Interrupt Mask Register port */
#define ICR 0xa0 /* Interrupt Control Port */



/*
An end of interrupt needs to be sent to the Control Port of
the 8259 when a hardware interrupt ends.
*/
//#define EOI 0x20 /* End Of Interrupt */
//我改的
#define EOI 0xa0 /* End Of Interrupt */

/*
The (IMR) tells the (PIC) to service an interrupt only if it
is not masked (FALSE).
*/
#define IRQ3 0xF7 /* COM2 */
#define IRQ4 0xEF /* COM1 */
//我加的
#define IRQ10 0xFB /* COM3 */
#define IRQ11 0xf7 /* COM4 */

class serial
{
int flag;
int SetSerial();
int SetOthers(int Parity, int Bits, int StopBit);
int SetSpeed(int Speed);
int SetPort(int Port);
void init_serial(void);
void comm_off(void);
public:
serial(int Port, int Speed, int Parity, int Bits, int StopBit);
serial &operator<<( char ch );
serial &operator<<( char *str );
serial &operator>>( char &ch );
~serial();
};


2 serial.cpp


/*------------------------------------------------------------------*
SERIAL.CPP

The following code shows how to take advantage of some of
the Turbo C++ extensions to the C++ language to do asynchronous
communications without having to write supporting assembly-
language routines.

This program bypasses the less-than-adequate PC BIOS
communications routines and installs a serial interrupt
handler. Direct access to PC hardware allows the program to
run at faster baud rates and eliminates the need for
the main program to continuously poll the serial port for
data; thus implementing background communications. Data that
enters the serial port is stored in a circular buffer.

* Compile this program with Test Stack Overflow OFF.

*------------------------------------------------------------------*/

#include <dos.h>
#include <conio.h>
#include <stdio.h>
#include <string.h>
#include "serial.h"

#define VERSION 0x0101

#define FALSE 0
#define TRUE (!FALSE)

#define NOERROR 0 /* No error */
#define BUFOVFL 1 /* Buffer overflowed */

#define ESC 0x1B /* ASCII Escape character */
#define ASCII 0x007F /* Mask ASCII characters */
#define SBUFSIZ 0x4000 /* Serial buffer size */

int SError = NOERROR;
int portbase = 0;
void interrupt(*oldvects[2])(...);

static char ccbuf[SBUFSIZ];
unsigned int startbuf = 0;
unsigned int endbuf = 0;


/* Handle communications interrupts and put them in ccbuf */
void interrupt com_int(...)
{
disable();
if ((inportb(portbase + IIR) & RX_MASK) == RX_ID)
{
if (((endbuf + 1) & SBUFSIZ - 1) == startbuf)
SError = BUFOVFL;

ccbuf[endbuf++] = inportb(portbase + RXR);
endbuf &= SBUFSIZ - 1;
}

/* Signal end of hardware interrupt */
outportb(ICR, EOI);
enable();
}

/* Output a character to the serial port */
serial& serial::operator<<( char x )
{
long int timeout = 0x0000FFFFL;

outportb(portbase + MCR, MC_INT ¦ DTR ¦ RTS);

// Wait for Clear To Send from modem
while ((inportb(portbase + MSR) & CTS) == 0)
if (!(--timeout))
return *this;

timeout = 0x0000FFFFL;

// Wait for transmitter to clear
while ((inportb(portbase + LSR) & XMTRDY) == 0)
if (!(--timeout))
return *this;

disable();
outportb(portbase + TXR, x);
enable();

return *this;
}

/* Output a string to the serial port */
serial& serial::operator<<( char *string )
{
while (*string)
{
(*this) << *string;
string++;
}
return *this;
}

/* This routine returns the current value in the buffer */
serial &serial::operator>>( char &ch )
{
if (endbuf == startbuf)
{
ch = -1;
return *this;
}

ch = ccbuf[startbuf];
startbuf++;
startbuf %= SBUFSIZ;
return *this;
}

/* Install our functions to handle communications */
void setvects(void)
{
oldvects[0] = getvect(0x0B);
oldvects[1] = getvect(0x0C);
setvect(0x0B, com_int);
setvect(0x0C, com_int);
}

/* Uninstall our vectors before exiting the program */
void resvects(void)
{
setvect(0x0B, oldvects[0]);
setvect(0x0C, oldvects[1]);
}

/* Turn on communications interrupts */
void i_enable(int pnum)
{
int c;

disable();
c = inportb(portbase + MCR) ¦ MC_INT;
outportb(portbase + MCR, c);
outportb(portbase + IER, RX_INT);
//c = inportb(IMR) & (pnum == COM1 ? IRQ4 : IRQ3);
c = inportb(IMR) & (IRQ10);
outportb(IMR, c);
enable();
}

/* Turn off communications interrupts */
void i_disable(void)
{
int c;

disable();
//c = inportb(IMR) ¦ ~IRQ3 ¦ ~IRQ4;
c = inportb(IMR) ¦ ~IRQ3 ¦ ~IRQ4 ¦ ~IRQ10;
outportb(IMR, c);
outportb(portbase + IER, 0);
c = inportb(portbase + MCR) & ~MC_INT;
outportb(portbase + MCR, c);
enable();
}

/* Tell modem that we're ready to go */
void comm_on(void)
{
int c, pnum;

pnum = (portbase == COM1BASE ? COM1 : COM2);
i_enable(pnum);
c = inportb(portbase + MCR) ¦ DTR ¦ RTS;
outportb(portbase + MCR, c);
}

/* Go off-line */
void serial::comm_off(void)
{
i_disable();
outportb(portbase + MCR, 0);
}

void serial::init_serial(void)
{
endbuf = startbuf = 0;
setvects();
comm_on();
}

serial::~serial()
{
comm_off();
resvects();
}

/* Set the port number to use */
int serial::SetPort(int Port)
{
int Offset, far *RS232_Addr;

switch (Port)
{ /* Sort out the base address */
case COM1 : portbase = 0x3e8;//0x3f8;
break;
case COM2 : portbase = 0x3e8;//0x2f8;
break;
default : return (-1);
}

return (0);
}

/* This routine sets the speed; will accept funny baud rates. */
/* Setting the speed requires that the DLAB be set on. */
int serial::SetSpeed(int Speed)
{
char c;
int divisor;

if (Speed == 0) /* Avoid divide by zero */
return (-1);
else
divisor = (int) (115200L/Speed);

if (portbase == 0)
return (-1);

disable();
c = inportb(portbase + LCR);
outportb(portbase + LCR, (c ¦ 0x80)); /* Set DLAB */
outportb(portbase + DLL, (divisor & 0x00FF));
outportb(portbase + DLH, ((divisor >> 8) & 0x00FF));
outportb(portbase + LCR, c); /* Reset DLAB */
enable();

return (0);
}

/* Set other communications parameters */
int serial::SetOthers(int Parity, int Bits, int StopBit)
{
int setting;

if (portbase == 0) return (-1);
if (Bits < 5 ¦¦ Bits > 8) return (-1);
if (StopBit != 1 && StopBit != 2) return (-1);
if (Parity != NO_PARITY && Parity != ODD_PARITY && Parity != EVEN_PARITY)
return (-1);

setting = Bits-5;
setting ¦= ((StopBit == 1) ? 0x00 : 0x04);
setting ¦= Parity;

disable();
outportb(portbase + LCR, setting);
enable();

return (0);
}

/* Set up the port */
serial::serial(int Port, int Speed, int Parity, int Bits, int StopBit)
{
flag = 0;
if (SetPort(Port))
flag = -1;
if (SetSpeed(Speed))
flag = -1;
if (SetOthers(Parity, Bits, StopBit))
flag = -1;

if (!flag)
init_serial();
}

/* Control-Break interrupt handler */
int c_break(void)
{
i_disable();
fprintf(stderr, "\nStill online.\n");

return(0);
}

main()
{
/* Communications parameters */
int port = COM1;
int speed = 2400;
int parity = NO_PARITY;
int bits = 8;
int stopbits = 1;

int done = FALSE;
char c;

serial comport(port, speed, parity, bits, stopbits);

ctrlbrk(c_break);

fprintf(stdout, "TURBO C TERMINAL\n"
"...You're now in terminal mode, "
"press [ESC] to quit...\n\n");

/*
The main loop acts as a dumb terminal. We repeatedly
check the keyboard buffer, and communications buffer.
*/
do {
if (kbhit())
{
/* Look for an Escape key */
switch (c=getch())
{
case ESC: done = TRUE; /* Exit program */
break;

/* You may want to handle other keys here... */
}
if (!done)
comport << c;
}
comport >> c;
if (c != -1)
fputc(c & ASCII, stdout);

} while (!done && !SError);

/* Check for errors */
switch (SError)
{
case NOERROR: fprintf(stderr, "\nbye.\n");
return (0);

case BUFOVFL: fprintf(stderr, "\nBuffer Overflow.\n");
return (99);

default: fprintf(stderr, "\nUnknown Error, SError = %d\n",
SError);
return (99);
}
}


...全文
923 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
daoer 2000-09-14
  • 打赏
  • 举报
回复
用dll吧,www.moxa.com.tw里有一个pcommlit,串口就够了
FengSC 2000-09-07
  • 打赏
  • 举报
回复
你的程序可能有以下的问题:
1.你的IRQ10定义是否正确.(你的工控机与PC不一样)。
2.在setvects()函数中你保存的是COM2,COM1的中断向量,中断10,11的向量不是0x0b,0x0c.
因为0x12, 0x13.
WilliamY2024 2000-09-06
  • 打赏
  • 举报
回复
谢谢你!但是这段程序太复杂了。希望有人能对我的程序指点一下。--Shinesoft
Chen_Lin 2000-09-06
  • 打赏
  • 举报
回复
作为参考,可以看看
#define MDMDAT1 0x03F8 /* Address of modem port 1 data */
#define MDMSTS1 0x03FD /* Address of modem port 1 status */
#define MDMCOM1 0x03FB /* Address of modem port 1 command */
#define MDMDAT2 0x02F8 /* Address of modem port 2 data */
#define MDMSTS2 0x02FD /* Address of modem port 2 status */
#define MDMCOM2 0x02FB /* Address of modem port 2 command */
#define MDMDAT3 0x03E8 /* Address of modem port 3 data */
#define MDMSTS3 0x03ED /* Address of modem port 3 status */
#define MDMCOM3 0x03EB /* Address of modem port 3 command */
#define MDMDAT4 0x02E8 /* Address of modem port 4 data */
#define MDMSTS4 0x02ED /* Address of modem port 4 status */
#define MDMCOM4 0x02EB /* Address of modem port 4 command */
#define MDMINTV 0x000C /* Com 1 & 3 interrupt vector */
#define MDINTV2 0x000B /* Com 2 & 4 interrupt vector */
#define MDMINTO 0x0EF /* Mask to enable IRQ3 for port 1 & 3 */
#define MDINTO2 0x0F7 /* Mask to enable IRQ4 for port 2 & 4 */
#define MDMINTC 0x010 /* Mask to Disable IRQ4 for port 1 & 3 */
#define MDINTC2 0x008 /* Mask to Disable IRQ3 for port 2 & 4 */
#define INTCONT 0x0021 /* 8259 interrupt controller ICW2-3 */
#define INTCON1 0x0020 /* Address of 8259 ICW1 */
#define CBS 2048 /* Communications port buffer size */
int comm_open ( int portid, unsigned speed )
{
int be = biosequip ( ); /* to get # installed serial ports */
be <<= 4; /* shift-wrap high bits off */
be >>= 13; /* shift down to low bits */
if ( be >= portid || portid >= 3) {
if ( portid == 1 ) {
dat8250 = MDMDAT1;
stat8250 = MDMSTS1;
com8250 = MDMCOM1;
dis8259 = MDMINTC;
en8259 = MDMINTO;
intv = MDMINTV;
}
else if ( portid == 2 ) {
dat8250 = MDMDAT2;
stat8250 = MDMSTS2;
com8250 = MDMCOM2;
dis8259 = MDINTC2;
en8259 = MDINTO2;
intv = MDINTV2;
}
else if ( portid == 3 ) { /* Ports 3 & 4 cannot be checked */
dat8250 = MDMDAT3; /* with biosquip( ) */
stat8250 = MDMSTS3;
com8250 = MDMCOM3;
dis8259 = MDMINTC;
en8259 = MDMINTO;
intv = MDMINTV;
}
else if ( portid == 4 ) {
dat8250 = MDMDAT4;
stat8250 = MDMSTS4;
com8250 = MDMCOM4;
dis8259 = MDINTC2;
en8259 = MDINTO2;
intv = MDINTV2;
}
else
return ( 0 );

MODEM_STAT = dat8250 + 6; /* Define Modem Status Register */

dobaud ( speed ); /* set baud */
inptr = outptr = buffer; /* set circular buffer values */
c_in_buf = 0;
oldvec = getvect ( intv ); /* Save old int vector */
setvect ( intv, serint ); /* Set up SERINT as com ISR */
outportb ( com8250, 0x3 ); /* 8 bits no parity */
outportb ( com8250 + 1, 0xb ); /* Assert OUT2, RTS, and DTR */
inportb ( dat8250 );
outportb ( dat8250 + 1, 0x1 ); /* Receiver-Data-Ready int */
outportb ( INTCONT, en8259 & inportb ( INTCONT ) );
/* Enable 8259 interrupts */
xoffpt = CBS - 128; /* chars in buff to send XOFF */
xonpt = CBS - xoffpt; /* chars in buff to send XON */
}
else
be = 0;
return ( be );
}

4,354

社区成员

发帖
与我相关
我的任务
社区描述
通信技术相关讨论
社区管理员
  • 网络通信
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧