?? com.c
字號:
/****************************************************************
程序(函數(shù))名稱:ser977
功能描述: BBPC系列串口,除了可以調(diào)用
bios進(jìn)行通訊外,為了使用更高的串口通訊速率可以直接對串
口硬件直接操作,例子用后一種方式編程,并使用中斷方式接收,
接收到的數(shù)據(jù)緩存在環(huán)行隊(duì)列中。程序把串口波特率固定為115200,
串口號用命令行參數(shù)傳入,如:com 1為用1號串口,該例子
能通用于1~6號串口.用中斷方式編寫串口程序時(shí),在中斷服務(wù)程
序中沒有特殊要求不需要用disable()、enable()關(guān)閉、打開中
斷。運(yùn)行中程序會把鍵盤輸入字符發(fā)送到相應(yīng)的串口。按“ESC”
鍵退出,該程序在bc45的large模式下測試通過。
參數(shù): 串口號,1~6
作者: 周巍
****************************************************************/
#include <dos.h>
#include <conio.h>
#include <stdio.h>
#include <string.h>
#include "COM.h"
#include <stdlib.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 */
unsigned int COMMC;
unsigned char TXR,RXR,IER,IIR,LCR,MCR,LSR,MSR,DLL,DLH;
unsigned int IMR;
unsigned char FLAG;
unsigned char INTVECT;
int SError = NOERROR;
int portbase = COM1BASE;
void interrupt(*old_handler)();
static char ccbuf[SBUFSIZ]; /*接受緩存,改變SBUFSIZ來改變大小*/
unsigned int startbuf = 0;
unsigned int endbuf = 0;
unsigned char LastStatus = 0;
unsigned char OldStatus = 0;
/*****************************************************************************************
未用fifo的中斷服務(wù)程序例子,例子用中斷接收數(shù)據(jù)并放入緩存中。發(fā)送沒有用中斷實(shí)現(xiàn)。用戶如需要
用中斷發(fā)送字符,需要一個(gè)發(fā)送緩存,并把串口的發(fā)送中斷打開。發(fā)送緩存的定義請參考接收緩存的定義。
在中斷處理例程里面需要增加發(fā)送中斷處理。在用發(fā)送中斷時(shí)主程序除了需要發(fā)送的數(shù)據(jù)放入發(fā)送緩存中,
還需要判斷緩存是否為空或滿。當(dāng)為空時(shí)必須重新啟動(dòng)發(fā)送否則不會產(chǎn)生發(fā)送中斷。如緩存滿時(shí)可以丟棄
或等待。
******************************************************************************************/
void far interrupt com_int(void)
{
unsigned char Status = 0;
char Loop = 0;
unsigned int reg_serv;
reg_serv = inport(REG_SVER);
if(FLAG)
{
if(((reg_serv&0x0400)!= 0) && (portbase == 0xff80))
goto HARDINT;
if(((reg_serv&0x0200)!= 0) && (portbase == 0xff10))
goto HARDINT;
ENTRY_SOFT_INT(old_handler)
}
HARDINT:
while(Loop == 0)
{
Status = inportb(portbase + IIR) & RX_MASK;
switch(Status)
{
case NO_INT:
LastStatus = 1;
break;
case URS_ID:
inportb(portbase + LSR); //撤銷中斷
LastStatus = 2;
break;
case RX_ID: //未用fifo時(shí)處理例子
if (((endbuf + 1) &(SBUFSIZ - 1)) == startbuf)
SError = BUFOVFL;
ccbuf[endbuf++] = inportb(portbase + RXR);//如果使用fifo必須讀至激活狀態(tài)
endbuf &= SBUFSIZ - 1;
LastStatus = 3;
break;
case FDT_ID:
inportb(portbase + RXR); //撤銷中斷
LastStatus = 4;
break;
case TBRE_ID:
LastStatus = 5;
break;
case HSR_ID:
inportb(portbase + MSR); //撤銷中斷
LastStatus = 6;
break;
default:
LastStatus = 7;
break;
}
if((LastStatus == 1) || (LastStatus == 7)) break;
}
if(!FLAG)
outportb(ICR977, EOI977); /*中斷應(yīng)答*/
else
outport(ICRCPU, EOICPU);
}
/************************************************************************
不用中斷發(fā)送時(shí)的發(fā)送函數(shù),該函數(shù)每次發(fā)送一個(gè)字節(jié)。
*************************************************************************/
int SerSend(char x )
{
long int timeout;
outportb(portbase + MCR, MC_INT | DTR | RTS);
/* 硬件握手,如果用三線制時(shí),需要把串口接成硬件握手自環(huán)方式或者把下面三句注釋掉。*/
if(!FLAG)
{
timeout = 0x0000FFFFL;
while ((inportb(portbase + MSR) & CTS) == 0)
if (!(--timeout))
return -1;
}
timeout = 0x0000FFFFL;
/* Wait for transmitter to clear */
while ((inportb(portbase + LSR) & XMTRDY) == 0)
if (!(--timeout))
return -1;
disable();
outportb(portbase + TXR, x);
enable();
return 0;
}
/* Output a string to the serial port */
SerSendStr( char *string )
{
while (*string)
{
SerSend(*string);
string++;
}
return 0;
}
/**********************************************************************
從緩存中取出一個(gè)字符,并修改指針,當(dāng)緩存為空時(shí)返回-1。
***********************************************************************/
int SerRev(char *ch)
{
if (endbuf == startbuf)
{
*ch = -1;
return -1;
}
*ch = ccbuf[startbuf];
startbuf++;
startbuf %= SBUFSIZ;
return 0;
}
/********************************************************************************
設(shè)置中斷向量函數(shù),com1用中斷4向量號為0xc,com2用中斷3向量號為0xb,該中斷號是固定的
用戶不可以修改。
*********************************************************************************/
void setvects(void)
{
old_handler = getvect(INTVECT); /*保存中斷向量,以便在退出時(shí)恢復(fù)*/
setvect(INTVECT, com_int); /*把中斷向量改為com_int*/
}
/**************************************************************************************
恢復(fù)原來的中斷向量。在編寫中斷程序時(shí),需要在程序結(jié)束時(shí)恢復(fù)原來的中斷向量,原來的向量一般
指向系統(tǒng)默認(rèn)中斷處理程序。以避免該硬件產(chǎn)生中斷時(shí)跑飛,造成死機(jī)。
***************************************************************************************/
void resvects(void)
{
setvect(INTVECT, old_handler);
}
/*******************************************************************
打開中斷函數(shù)i_enable,功能是打開串口中斷和系統(tǒng)中斷。
********************************************************************/
void i_enable(void)
{
int c;
disable();
c = inportb(portbase + MCR) | MC_INT;
outportb(portbase + MCR, c);
outportb(portbase + IER, RX_INT);
c = inportb(IMR) & COMMC;
outportb(IMR, c);
enable();
}
/*******************************************************************
關(guān)閉中斷函數(shù)i_disable,功能是關(guān)閉串口中斷和系統(tǒng)中斷。
********************************************************************/
void i_disable(void)
{
int c;
disable();
c = inportb(IMR)| ~COMMC;
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;
if(!FLAG)
i_enable();
c = inportb(portbase + MCR) | DTR | RTS;
outportb(portbase + MCR, c);
}
/* Go off-line */
void comm_off(void)
{
if(!FLAG)
{
i_disable();
outportb(portbase + MCR, 0);
resvects();
}
else
{
resvects();
if(VID && portbase==0xff10)
{
comm_on();
i_enable();
}
}
}
void OpenSer(void)
{
endbuf = startbuf = 0;
setvects();
comm_on();
}
/*******************************************************************
設(shè)置通訊波濤率參數(shù)子函數(shù)SetSpeed,由SerInit調(diào)用。
設(shè)置波濤率時(shí)需要保證DLAB=1
********************************************************************/
int SetSpeed(unsigned long int Speed)
{
char c;
unsigned int divisor;
if (Speed == 0) /* Avoid divide by zero */
return (-1);
else
if(!FLAG)
divisor = (int) (115200L/Speed);
else
divisor = (unsigned int)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);
}
/*******************************************************************
設(shè)置通訊參數(shù)子函數(shù)SetOthers,由SerInit調(diào)用。
********************************************************************/
int 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;
if(StopBit == 1)
Setting |= 0x00;
else
Setting |= 0x04;
Setting |= Parity;
disable();
outportb(portbase + LCR, Setting);
enable();
return (0);
}
/***************************************************************************
串口初始化函數(shù)SerInit
入口參數(shù): Port 串口地址如0x3f8;Speed 速率 如115200
Parity 奇偶效驗(yàn)NO_PARITY無,EVEN_PARITY偶效驗(yàn),ODD_PARITY奇效驗(yàn)
Bits 數(shù)據(jù)位數(shù)如8,StopBit 停止位如1。
****************************************************************************/
SerInit(int Port, unsigned long int Speed, int Parity, int Bits, int StopBit)
{
int flag = 0;
portbase = Port;
if (SetSpeed(Speed))
flag = -1;
if (SetOthers(Parity, Bits, StopBit))
flag = -1;
/***************************************************
用戶如需要打開FIFO請?jiān)谶@加入設(shè)置代碼。
****************************************************/
if (!flag)
OpenSer();
return flag;
}
int main(argc,argv)
int argc;
char *argv[];
{
/* Communications parameters */
unsigned long int speed = 115200L; /*波特率參數(shù)*/
int parity = NO_PARITY; /*奇偶效驗(yàn)*/
int bits = 8; /*數(shù)據(jù)位數(shù)*/
int stopbits = 1; /*停止位數(shù)*/
int done = FALSE;
char c;
if(argc != 2)
{
printf("com COM_NUMBER\nCOM_NUMBER must be 1~5.\n");
return 0; /*命令行參數(shù)*/
}
switch(atoi(argv[1]))
{
case 1:
portbase = COM1BASE;
COMMC=COM1MC;
INTVECT=0xc;
FLAG=0;
break;
case 2:
portbase = COM2BASE;
COMMC=COM2MC;
INTVECT=0xb;
FLAG=0;
break;
case 3:
portbase = COM3BASE;
COMMC=COM3MC;
INTVECT=0xe;
FLAG=0;
break;
case 4:
portbase = COM4BASE;
COMMC=COM4MC;
INTVECT=0xd;
FLAG=0;
break;
case 5:
portbase = COM5BASE;
COMMC=COM5MC;
INTVECT=0x14;
FLAG=1;
break;
case 6:
portbase = COM6BASE;
COMMC=COM6MC;
INTVECT=0x11;
FLAG=1;
break;
default:
printf("com COM_NUMBER\nCOM_NUMBER must be 1~5.\n");
return 0;
}
if(!FLAG)
{
TXR=TXR977; /* Transmit register (WRITE) */
RXR=RXR977; /* Receive register (READ) */
IER=IER977; /* Interrupt Enable */
IIR=IIR977; /* Interrupt ID */
LCR=LCR977; /* Line control */
MCR=MCR977; /* Modem control */
LSR=LSR977; /* Line Status */
MSR=MSR977; /* Modem Status */
DLL=DLL977; /* Divisor Latch Low */
DLH=DLH977;
IMR=IMR977;
speed = 115200L;
}
else
{
TXR=TXRCPU; /* Transmit register (WRITE) */
RXR=RXRCPU; /* Receive register (READ) */
IER=IERCPU; /* Interrupt Enable */
IIR=IIRCPU; /* Interrupt ID */
LCR=LCRCPU; /* Line control */
MCR=MCRCPU; /* Modem control */
LSR=LSRCPU; /* Line Status */
MSR=MSRCPU; /* Modem Status */
DLL=DLLCPU; /* Divisor Latch Low */
DLH=DLHCPU;
IMR=IMRCPU;
speed = F115200;
}
if(FLAG)
i_enable();
SerInit(portbase, speed, parity, bits, stopbits);
/*
The main loop acts as a dumb terminal. We repeatedly
check the keyboard buffer, and communications buffer.
*/
do {
if (kbhit()) //按鍵發(fā)送字符或退出
{
/* 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)
SerSend(c);
}
if(SerRev(&c)!= -1) //接收字符并顯示
{
//if (c != -1);
//fputc(c & ASCII, stdout);
printf("%c",c);
}
/*打印接收狀態(tài)*/
if((LastStatus != OldStatus) && (LastStatus != 0))
{
switch(LastStatus)
{
case 1:
printf("NO_INT\n");
break;
case 2:
printf("URS_ID\n");
break;
case 3:
printf("RX_ID\n");
break;
case 4:
printf("FDT_ID\n");
break;
case 5:
printf("TBRE_ID\n");
break;
case 6:
printf("HSR_ID\n");
break;
case 7:
printf("defaut\n");
break;
default:
printf("no int\n");
break;
}
OldStatus = LastStatus;
LastStatus = 0;
}
} while (!done && !SError);
comm_off();
/* Check for errors */
switch (SError)
{
case NOERROR: printf("\nbye.\n");
return (0);
case BUFOVFL: printf("\nBuffer Overflow.\n");
return (99);
default: printf("\nUnknown Error, SError = %d\n");
return (99);
}
}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -