培訓信息
贊助商
PC機與單片機的通訊
PC機與單片機的通訊
作者:佚名 來源:不詳 錄入:Admin 更新時間:2008-7-26 19:54:20 點擊數(shù):3
【字體:
】
大多數(shù)的電腦設備都具有RS-232C接口,盡管它的性能指標并非很好。在廣泛的市場支持下依然常勝不衰。就使用而言,RS-232也確實有其優(yōu)勢:僅需3根線便可在兩個數(shù)字設備之間全雙工的傳送數(shù)據(jù)。不過,RS-232C的控制要比使用并行通訊的打印機接口更難于控制。RS-232C使用了遠較并行口更多的寄存器。這些寄存器用來實現(xiàn)串行數(shù)據(jù)的傳送及RS-232C設備之間的握手與流量控制。本文將分別描述PC機及單片機MCS-51的串行通訊的原理及具體的軟件設計。 (1)RS-232C介紹與PC硬件: RS-232C使用-3到-25V表示數(shù)字“1”,使用3V到25V表示數(shù)字“0”,RS-232C在空閑時處于邏輯“1”狀態(tài),在開始傳送時,首先產(chǎn)生一起始位,起始位為一個寬度的邏輯“0”,緊隨其后為所要傳送的數(shù)據(jù),所要傳送的數(shù)據(jù)有最低位開始依此送出,并以一個結(jié)束位標志該字節(jié)傳送結(jié)束,結(jié)束位為一個寬度的邏輯“1”狀態(tài)。 PC機一般使用8250或16550作為串行通訊的控制器,使用9針或25針的接插件將串行口的信號送出。該插座的信號定義如下: DB-25 DB-9 信號名稱 方向 含 義 2 3 TXD 輸出 數(shù)據(jù)發(fā)送端 3 2 RXD 輸入 數(shù)據(jù)接收端 4 7 RTS 輸出 請求發(fā)送(計算機要求發(fā)送數(shù)據(jù)) 5 8 CTS 輸入 清除發(fā)送(MODEM準備接收數(shù)據(jù)) 6 6 DSR 輸入 數(shù)據(jù)設備準備就緒 7 5 SG - 信號地 8 1 DCD 輸入 數(shù)據(jù)載波檢測 20 4 DTR 輸出 數(shù)據(jù)終端準備就緒(計算機) 22 9 RI 輸入 響鈴指示 以上信號在通訊過程之中可能會被全部或部分使用,最簡單的通訊僅需TXD及RXD及SG即可完成,其他的握手信號可以做適當處理或直接懸空,至于是否可以懸空這視乎你的通訊軟件。比如說,如果使用DOS所提供的BIOS通訊驅(qū)動程序,那么,這些握手信號則需要做如下處理,因為BIOS的通訊驅(qū)動使用了這些信號。如果使用自己編寫的串行驅(qū)動程序則可以完全不使用這些握手信號(詳見下面有關(guān)章節(jié))。 PC機一般使用8250或16550的作為串行通訊控制器,8250及16550的管腳排列如下: 8250(16550)的寄存器如下表所示: 基地址 讀/寫 寄存器縮寫 注 釋 0 Write - 發(fā)送保持寄存器(DLAB=0) 0 Read - 接收數(shù)據(jù)寄存器(DLAB=0) 0 Read/Write - 波特率低八位(DLAB=1) 1 Read/Write IER 中斷允許寄存器 1 Read/Write - 波特率高八位(DLAB=1) 2 Read IIR 中斷標識寄存器 2 Write FCR FIFO控制寄存器 3 Read/Write LCR 線路控制寄存器 4 Read/Write MCR MODEM控制寄存器 5 Read LSR 線路狀態(tài)寄存器 6 Read MSR MODEM狀態(tài)寄存器 7 Read/Write - Scratch Register PC機支持1-4個串行口,即COM1-COM4,其基地址在BIOS數(shù)據(jù)區(qū)0000:0400-0000:0406中描述,對應地址分別為3F8/2F8/3E8/2E8,COM1及COM3使用PC機中斷4,COM2及COM4使用中斷3。 在上表中,8250共有12個寄存器,使用了8個地址,其中部分寄存器共用一個地址,由DLAB=0/1來區(qū)分,在DLAB=1用于設定通訊所需的波特率。常用的波特率參數(shù)見下表: 速率(BPS) 波特率高八位 波特率低八位 50 09h 00h 300 01h 80h 600 00h C0h 2400 00h 30h 4800 00h 18h 9600 00h 0Ch 19200 00h 06h 38400 00h 03h 57600 00h 02h 115200 00h 01h 以下幾個表格為8250的寄存器的功能描述: 中斷允許寄存器(IER): 位 注 釋 7 未使用 6 未使用 5 進入低功耗模式(16750) 4 進入睡眠模式(16750) 3 允許MODEM狀態(tài)中斷 2 允許接收線路狀態(tài)中斷 1 允許發(fā)送保持器空中斷 0 允許接收數(shù)據(jù)就緒中斷 Bit0置1將允許接收到數(shù)據(jù)時產(chǎn)生中斷,Bit1置1時允許發(fā)送保持寄存器空時產(chǎn)生中斷,Bit2置1將在LSR變化時產(chǎn)生中斷,相應的Bit3置位將在MSR變化時產(chǎn)生中斷。 中斷識別寄存器(IIR): 位 注 釋 Bit6:7=00 無FIFO Bit6:7=01 允許FIFO,但不可用 Bit6:7=11 允許FIFO Bit5 允許64字節(jié)FIFO(16750) Bit4 未使用 Bit3 16550超時中斷 Bit2:1=00 MODEM狀態(tài)中斷(CTS/RI/DTR/DCD) Bit2:1=01 發(fā)送保持寄存器空中斷 Bit2:1=10 接收數(shù)據(jù)就緒中斷 Bit2:1=11 接收線路狀態(tài)中斷 Bit0=0 有中斷產(chǎn)生 Bit0=1 無中斷產(chǎn)生 IIR為只讀寄存器,Bit6:7用來指示FIFO的狀態(tài),均為0時則無FIFO,此時為8250或16450芯片,為01時有FIFO但不可以使用,為11時FIFO有效并可以正常工作。Bit3用來指示超時中斷(16550/16750)。 Bit0用來指示是否有中斷發(fā)生,Bit1:2標識具體的中斷類型,這些中斷具有不同的優(yōu)先級別,其中LSR中斷級別最高,其次是數(shù)據(jù)就緒中斷,然后是發(fā)送寄存器空中斷,而MSR中斷級別最低。 FIFO控制寄存器(FCR): 位 注 釋 Bit7:6=00 1Byte產(chǎn)生中斷 Bit7:6=01 4Byte產(chǎn)生中斷 Bit7:6=10 8Byte產(chǎn)生中斷 Bit7:6=11 14Byte產(chǎn)生中斷 Bit5 允許64字節(jié)FIFO Bit4 未使用 Bit3 DMA模式選擇 Bit2 清除發(fā)送FIFO Bit1 清除接收FIFO Bit0 允許FIFO FCR可寫但不可以讀,該寄存器用來控制16550或16750的FIFO寄存器。Bit0置1將允許發(fā)送/接收的FIFO工作,Bit1和Bit2置1分別用來清除接收及發(fā)送FIFO。清除接收及發(fā)送FIFO并不影響移位寄存器。Bit1:2可自行復位,因此無需使用軟件對其清零。Bit6:7用來設定產(chǎn)生中斷的級別,發(fā)送/接收中斷將在發(fā)送/接收到對應字節(jié)數(shù)時產(chǎn)生。 線路控制寄存器(LCR): 位 注 釋 Bit7=1 允許訪問波特率因子寄存器 Bit7=0 允許訪問接收/發(fā)送及中斷允許寄存器 Bit6 設置間斷,0-禁止,1-設置 Bit5:3=XX0 無校驗 Bit5:3=001 奇校驗 Bit5:3=011 偶校驗 Bit5:3=101 奇偶保持為1 Bit5:3=111 奇偶保持為0 Bit2=0 1位停止位 Bit2=1 2位停止位(數(shù)據(jù)位6-8位),1.5位停止位(5位數(shù)據(jù)位) Bit1:0=00 5位數(shù)據(jù)位 Bit1:0=01 6位數(shù)據(jù)位 Bit1:0=10 7位數(shù)據(jù)位 Bit1:0=11 8位數(shù)據(jù)位 LCR用來設定通訊所需的一些基本參數(shù)。Bit7為1指定波特率因子寄存器有效,為0則指定發(fā)送/接收及IER有效。Bit6置1會將發(fā)送端置為0,這將會使接收端產(chǎn)生一個“間斷”。Bit3-5用來設定是否使用奇偶校驗以及奇偶校驗的類型,Bit3=1時使用校驗,Bit4為0則為奇校驗,1為偶校驗,而Bit5則強制校驗為1或0,并由Bit4決定具體為0或1。Bit2用來設定停止位的長度,0表示1位停止位,為1則根據(jù)數(shù)據(jù)長度的不同使用1.5-2位停止位。Bit0:1用來設定數(shù)據(jù)長度。 MODEM控制寄存器(MCR): 位 注 釋 Bit7 未使用 Bit6 未使用 Bit5 自動流量控制(僅16750) Bit4 環(huán)路測試 Bit3 輔助輸出2 Bit2 輔助輸出1 Bit1 設置RTS Bit0 設置DSR MCR寄存器可讀可寫,Bit4=1進入環(huán)路測試模式。Bit3-0用來控制對應的管腳。 線路狀態(tài)寄存器(LSR): 位 注 釋 Bit7 FIFO中接收數(shù)據(jù)錯誤 Bit6 發(fā)送移位寄存器空 Bit5 發(fā)送保持寄存器空 Bit4 間斷 Bit3 幀格式錯 Bit2 奇偶錯 Bit1 超越錯 Bit0 接收數(shù)據(jù)就緒 LSR為只讀寄存器,當發(fā)生錯誤時Bit7為1,Bit6為1時標示發(fā)送保持及發(fā)送移位寄存器均空,Bit5為1時標示僅發(fā)送保持寄存器空,此時,可以由軟件發(fā)送下一數(shù)據(jù)。當線路狀態(tài)為0時Bit4置位為1,幀格式錯時Bit3置位為1,奇偶錯和超越錯分別將Bit2及Bit1置位為1。Bit0置位為1表示接收數(shù)據(jù)就緒。 MODEM狀態(tài)寄存器(MSR): 位 注 釋 Bit7 載波檢測 Bit6 響鈴指示 Bit5 DSR準備就緒 Bit4 CTS有效 Bit3 DCD已改變 Bit2 RI已改變 Bit1 DSR已改變 Bit0 CTS已改變 MSR寄存器的高4位分別對應MODEM的狀態(tài)線,低4位表示MODEM的狀態(tài)線是否發(fā)生了變化。 以上我們詳細介紹了PC機的串行通訊硬件環(huán)境,以下將分別給出使用查詢及中斷驅(qū)動的方法編寫的串行口驅(qū)動程序。這些程序僅使用RXD/TXD,無需硬件握手信號。 (2)使用查詢方法的串行通訊程序設計: polling.c 下載polling.c #include <dos.h> #include <stdio.h> #include <conio.h> #define PortBase 0x2F8 void com_putch(unsigned char); int com_chkch(void); main() { int c; unsigned char ch; outportb(PortBase +1,0);/*Turn off interrupts -Port1*/ /*Set COM1:9600,8,N,1*/ outportb(PortBase +3,0x80); outportb(PortBase +0,0x0C); outportb(PortBase +1,0x00); outportb(PortBase +3,0x03); clrscr(); while(1){ c =com_chkch(); if(c!=-1){ c &=0xff;putch(c); if(c==’\n’)putch(’\r’); } if(kbhit()){ ch =getch();com_putch(ch); } } } void com_putch(unsigned char ch){ unsigned char status; while(1){ status =inportb(PortBase+5); if(status&0x01)inportb(PortBase+0);else break; } outportb(PortBase,ch); } int com_chkch(void){ unsigned char status; status =inportb(PortBase+5); status &=0x01; if(status)return((int)inportb(PortBase+0));else return(-1); } 使用查詢方式的通訊程序適合9600bps以下的應用。 (3)使用中斷的串行通訊程序設計: 該程序由兩部分組成,serial.c及sercom.c,sercom.c為通訊的底層驅(qū)動,使用中斷的串行通訊程序可以工作到115.2Kbps. serial.c 下載serial.c #include <dos.h> #include <stdio.h> #include <conio.h> #include <string.h> #include <bios.h> #include "sercom.c" COM*c; main() { unsigned char ch; c =ser_init(PORT_B,BAUD_9600,_COM_CHR8,_COM_NOPARITY,4096,4096); while(1){ if(serhit(c)){ ch =getser(c); putchar(ch); } if(kbhit()){ ch =getch(); putser(ch,c); } } } llio.c 下載llio.c #include <stdio.h> #include <dos.h> #include <bios.h> #include <malloc.h> #define CR0x0d #define TRUE0xff #define FALSE0 #define PORT_A 0/*COM1*/ #define PORT_B 1/*COM2*/ #define BAUD_9600 _COM_9600 #define BAUD_4800 _COM_4800 #define BAUD_2400 _COM_2400 #define BAUD_1200 _COM_1200 #define BAUD_600 _COM_600 #define BAUD_300 _COM_300 #define BAUD_110 _COM_110 typedef struct { char ready; /*TRUEwhen ready */ unsigned com_base; /*8250Base Address */ char irq_mask; /*IRQ Enable Mask */ char irq_eoi; /*EOIreply for this port */ char int_number; /*Interrupt #used */ void (_interrupt _far *old)(void ); /*Old Interrupt */ /*Buffers for I/O*/ char *in_buf; /*Input buffer */ int in_tail; /*Input buffer TAILptr */ int in_head; /*Input buffer HEADptr */ int in_size; /*Input buffer size */ int in_crcnt; /*Input <CR>count */ char in_mt; /*Input buffer FLAG*/ char *out_buf; /*Output buffer */ int out_tail; /*Output buffer TAILptr */ int out_head; /*Output buffer HEADptr */ int out_size; /*Output buffer size */ char out_full; /*Output buffer FLAG*/ char out_mt; /*Output buffer MT*/ }COM; COM *ser_init(int port,int baud,int bit,int parity,int isize,int osize ); void ser_close(COM*c ); int getsers(COM*c,int len,char *str ); int putsers(char *str,COM*c ); char serline(COM*c ); int getser(COM*c ); char serhit(COM*c); char putser(char outch,COM*c); void cntl_rts(int flag,COM*c); void cntl_dtr(int flag,COM*c); void clean_ser(COM*c ); #define COM1_BASE 0x03F8 #define COM1_IRQ_MASK 0xEF /*11101111BIRQ4For COM1*/ #define COM1_IRQ_EOI 0x64 /*IRQ4Spec EOI*/ #define COM1_INT_NUM 0x0C /*Int #for IRQ4*/ #define COM2_BASE 0x02F8 #define COM2_IRQ_MASK 0xF7 /*11110111BIRQ3For COM2*/ #define COM2_IRQ_EOI 0x63 /*IRQ3Spec EOI*/ #define COM2_INT_NUM 0x0B /*Int #for IRQ3*/ /*8250ACEregister defs */ #define THR 0 /*Offset to Xmit hld reg (write)*/ #define RBR 0 /*Receiver holding buffer (read)*/ #define IER 1 /*Interrupt enable register */ #define IIR 2 /*Interrupt identification reg */ #define LCR 3 /*Line control register */ #define MCR 4 /*Modem control register */ #define LSR 5 /*Line status register */ #define MSR 6 /*Modem status register */ #define SREG(x) ((unsigned)((unsigned)x +c->com_base)) /*8259Int controller registers */ #define INTC_MASK 0x21 /*Interrupt controller MASKreg */ #define INTC_EOI 0x20 /*Interrupt controller EOIreg */ #define MAX_PORTS 2 /*#I/Oports (DOSlimit)*/ static int count =0; static COM com_list[MAX_PORTS]; /*I/Odata structure */ static COM *com1; /*Pointers for interrupt actions */ static COM *com2; static COM *com_xfer; /*Transfer interrupt data structure */ COM *ser_init0(int port,char *ibuf,int isize,char *obuf,int osize); void ser_close0(COM*c ); void (_interrupt _far int_ser1)(void ); /*Int rtn for serial I/O COM1*/ void (_interrupt _far int_ser2)(void ); /*Int rtn for serial I/O COM2*/ void (_interrupt _far int_ser_sup)(void );/*Support int actions */ COM *ser_init(int port,int baud,int bit,int parity,int isize,int osize ) { unsigned status; char ch; COM*c; char *in_buf,*out_buf; status =_bios_serialcom(_COM_INIT,port,(bit |parity |_COM_STOP2|baud )); in_buf =malloc(isize ); if(in_buf ==NULL)return(NULL); out_buf =malloc(osize ); if(out_buf ==NULL)return(NULL); c =ser_init0(port,in_buf,isize,out_buf,osize ); clean_ser(c); return(c ); } void ser_close(COM*c) { int i; if(!c->ready )return; ser_close0(c); free(c->in_buf ); free(c->out_buf ); } char serline(COM*c ) { if(!c->ready )return(FALSE); if(c->in_crcnt >0)return(TRUE); else return(FALSE); } int getsers(COM*c,int len,char *str ) { char ch; int i; i =0; while(i<len ){ while(!serhit(c)){ if(kbhit())return(-1); } ch =0x7f &getser(c); switch(ch ){ case 0x0d:str[i++]=’\0’; return(i ); case 0x00: case 0x0a:break; default:str[i++]=ch; break; } } str[i]=’\0’; return(len ); } int putsers(char *str,COM*c ) { int n,i,j; n =strlen(str ); for(i=0;i<n;i++){ while(!putser(str[i],c )); } return(n ); } char putser(char outch,COM*c ) { char val; if(!c->ready )return(FALSE); while(!c->out_mt &&(c->out_head ==c->out_tail)); if(!c->out_full ){ c->out_buf[c->out_head++]=outch; if(c->out_head ==c->out_size ) c->out_head =0; /*Reset buffer circularly */ } if(c->out_head ==c->out_tail ){ c->out_full =TRUE; return(FALSE); }else c->out_full =FALSE; val =inp(SREG(LCR)); /*Reset DLABfor IERaccess */ val &=0x7F; /*Clear IERaccess bit */ outp(SREG(LCR),val); val =inp(SREG(IER)); if(!(val &0x02)) /*Interrupt ON?*/ { c->out_mt =FALSE; /*Not MTnow */ _disable(); /*Interrupts OFF NOW*/ outp(SREG(IER),0x03); /*RX&TXinterrupts ON*/ _enable(); /*Interrupts ONagain */ } return(TRUE); } char serhit(COM*c ) { if(!c->ready )return(FALSE); if(!c->in_mt )return(TRUE); else return(FALSE); } int getser(COM*c ) { int ch; if(!c->ready )return(FALSE); if(!serhit(c))return(0); _disable(); ch =0xff &c->in_buf[c->in_tail++]; if(c->in_tail ==c->in_size )c->in_tail =0; if(c->in_tail ==c->in_head )c->in_mt =TRUE; if(ch ==CR) /*Keep track of CR’s */ c->in_crcnt--; _enable(); return(ch ); } void clean_ser(COM*c ) { _disable(); c->in_head =0; c->in_tail =0; c->in_mt =TRUE; c->in_crcnt =0; _enable(); } void cntl_dtr(int flag,COM*c ) { char val; if(!c->ready )return; val =inp(SREG(MCR)); if(flag )val |=1; else val &=~1; outp(SREG(MCR),val); } void cntl_rts(int flag,COM*c ) { char val; if(!c->ready )return; val =inp(SREG(MCR)); if(flag )val |=2; else val &=~2; outp(SREG(MCR),val); } COM *ser_init0(int port,char *ibuf,int isize,char *obuf,int osize) { int i; char val; COM*c; while(port >=MAX_PORTS) /*Get port #in range */ port--; for(i=0;i<MAX_PORTS;i++)/*Select data structure */ { if(!com_list[i].ready ){ c =&(com_list[i]); break; } } if(i ==MAX_PORTS)/*Not found */ return(NULL); c->in_buf =ibuf; c->in_size =isize; c->in_mt =TRUE; c->in_head =0; c->in_tail =0; c->in_crcnt =0; c->out_buf =obuf; c->out_size =osize; c->out_full =FALSE; c->out_mt =TRUE; c->out_head =0; c->out_tail =0; switch(port ){ case 0: /*Here set up for COM1*/ c->ready =TRUE; c->com_base =COM1_BASE; c->irq_mask =COM1_IRQ_MASK; c->irq_eoi =COM1_IRQ_EOI; c->int_number =COM1_INT_NUM; _disable(); com1=c; c->old =_dos_getvect(c->int_number ); _dos_setvect(c->int_number,int_ser1); break; case 1: /*Here set up for COM1*/ c->ready =TRUE; c->com_base =COM2_BASE; c->irq_mask =COM2_IRQ_MASK; c->irq_eoi =COM2_IRQ_EOI; c->int_number =COM2_INT_NUM; _disable(); com2=c; c->old =_dos_getvect(c->int_number ); _dos_setvect(c->int_number,int_ser2); break; default:return(NULL); /*Bad port SKIP*/ } val =inp(INTC_MASK); val &=c->irq_mask; outp(INTC_MASK,val ); val =inp(SREG(LSR)); /*Read and discard STATUS*/ val =inp(SREG(RBR)); /*Read and discard DATA*/ val =inp(SREG(LCR)); /*Rst DLABfor IERaccess */ val &=0x7F; /*01111111B*/ outp(SREG(LCR),val ); outp(SREG(IER),1); /*Enable Data READY INT*/ outp(SREG(MCR),0xB); /*Enable OUT2,RTS&DTR*/ _enable(); return(c ); } void ser_close0(COM*c ) { char val; if(!c->ready )return; _disable(); val =inp(INTC_MASK); val |=~c->irq_mask; outp(INTC_MASK,val); val =inp(SREG(LCR)); /*Reset DLABfor IERaccess */ val &=0x7F; /*Clear IERaccess bit */ outp(SREG(LCR),val); val =inp(SREG(RBR)); val =inp(SREG(LSR)); val =inp(SREG(IIR)); val =inp(SREG(IER)); outp(SREG(IER),0); /*Disable 8250Interrupts */ outp(SREG(MCR),0); /*Disable RTS,DTRand OUT2*/ outp(SREG(MCR),0); /*Disable OUT2*/ _dos_setvect(c->int_number,c->old ); _enable(); c->ready =FALSE; } void _interrupt _far int_ser1(void ) { com_xfer =com1; _chain_intr(int_ser_sup ); } void _interrupt _far int_ser2(void ) { com_xfer =com2; _chain_intr(int_ser_sup ); } void _interrupt _far int_ser_sup(void ) { char val; char ch; int ptr; COM*c; c =com_xfer; while(TRUE){ val =inp(SREG(LSR));/*Read and discard STATUS*/ val =inp(SREG(IIR));/*Get interrupt status register */ if(val &0x04)/*Receive Interrupt */ { ptr =c->in_head; ch =inp(SREG(RBR)); if(c->in_mt ||ptr !=c->in_tail ){ c->in_buf[ptr++]=ch; if(ptr ==c->in_size )ptr =0; c->in_head =ptr; c->in_mt =FALSE; if(ch ==CR) /*Count lines */ c->in_crcnt++; } }else { if(val &0x02)/*Transmit Interrupt */ { if((!c->out_full)&&(c->out_head ==c->out_tail)){ c->out_mt =TRUE; val =inp(SREG(LCR)); val &=0x7F; outp(SREG(LCR),val); outp(SREG(IER),0x01); /*RXinterrupts ON*/ }else { outp(SREG(THR), c->out_buf[c->out_tail++]); if(c->out_tail ==c->out_size )c->out_tail =0; } }else return; /*No Interrupt */ } outp(INTC_EOI,c->irq_eoi); } } (4)MCS-51串行通訊: MCS-51的串行口使用起來非常簡單,因為MCS-51單片機的串行口沒有與MODEM控制相關(guān)的信號。這使得51的通訊口非常易于使用。使用查詢方式時,僅需初始化有關(guān)的寄存器即可。演示程序如下: #include <stdio.h> #include <reg51.h> void putch(unsigned char); unsigned char getch(void); main() { unsigned char ch; SCON=0x50; TMOD|=0x20; TH1=0xfd; TL1=0xfd; TR1=1; TI=1; RI=0; while(1){ ch =getch();putch(ch); } } void putch(unsigned char ch){ SBUF=ch; TI=0; while(!TI); } unsigned char getch(void){ while(!RI); RI=0; return(SBUF); } 使用中斷驅(qū)動的程序比較復雜,下面為完整的MCS-51串行通訊底層驅(qū)動程序,由頭文件serint.hJ及serint.c組成! serint.h unsigned char RR_iHead; /*receiver head index */ unsigned char RR_iTail; /*receiver tail index */ unsigned char RR_cLev; /*receiver buffer count */ unsigned char RR_cMax; /*receiver buffer count */ unsigned char TR_iHead; /*transmitter head index */ unsigned char TR_iTail; /*transmitter tail index */ unsigned char TR_cLev; /*transmitter buffer count */ unsigned char TR_cMax; /*transmitter buffer count */ unsigned char UnGotCh; /*saved char for ungetch()*/ unsigned char SerFlags; /*serial flag */ , bit FlagTransIdle; /*set when transmitter is finished */ bit FlagStripOutLF; /*don’t send linefeeds */ bit FlagCvtInCR; /*convert incoming CRto LF*/ unsigned char TestBits; #define INRINGSIZE128 /*must be <=254to avoid wraps */ #define OUTRINGSIZE250 /*ditto */ #define T1RELOAD253 #define CR13 #define LF10 #define ESC27 #define EOF-1 unsigned char xdata RRing[INRINGSIZE]; /*receiver ring buffer */ unsigned char xdata TRing[OUTRINGSIZE]; /*receiver ring buffer */ int putstr (const char *); int putch(int); int chkch(); int getch(); void SerWaitOutDone(); int SerFlushIn(); int putc(int TransChar); serint.c 下載seint.c /*CONSOLE.C--serial I/Ocode */ /*---------------------------------------------------------------------------*/ /*Initialize serial port hardware and variables */ #include <reg51.h> #include "serint.h" void SerInitialize(){ SerFlags =0; FlagTransIdle =1; FlagCvtInCR=1; /*want to turn CRs into LFs */ RR_iHead =RR_iTail =RR_cLev =RR_cMax =0; TR_iHead =TR_iTail =TR_cLev =TR_cMax =0; UnGotCh =-1; /*---set up Timer 1to produce serial rate */ TCON&=0x3F; /*clear run &interrupt flags */ TMOD&=0x0F; /*flush existing Timer 1setup */ TMOD|=0x20; /*flush existing Timer 1setup */ SCON=0x50; /*flush existing Timer 1setup */ PCON|=0x00; TH1=TL1=T1RELOAD&0x00FF; /*flush existing Timer 1setup */ TR1=1; /*start the timer */ ES=1; /*enable serial interrupts */ } /*---------------------------------------------------------------------------*/ /*Serial console interrupt handler */ /*If transmitter output is disabled,we fake trans interrupts until empty */ void SerInt()interrupt 4 { if(RI){ /*receiver interrupt active?*/ if(RR_cLev<INRINGSIZE){/*room for newest char?*/ RRing[RR_iHead]=SBUF;/*pick up the character and stick in ring */ RR_iHead++; /*tick the index */ RR_cLev++; /*tick size counter */ if(RR_iHead==INRINGSIZE)RR_iHead =0; /*hit end of array yet?*/ } RI=0; /*indicate we have it */ } if(TI){ /*transmitter interrupt active?*/ if(TR_cLev){ /*anything to send?*/ SBUF=TRing[TR_iTail];/*fetch next char and send it */ TR_cLev--; /*tick size counter */ TR_iTail++; /*tick the index */ if(TR_iTail==OUTRINGSIZE)TR_iTail =0; /*hit end of array yet?*/ }else FlagTransIdle =1;/*no,flag inactive */ TI=0; /*indicate done with it */ } } /*---------------------------------------------------------------------------*/ /*Send character to console */ /*Can strip LFs,in which case you get CRinstead of LF/CR*/ int putch(int TransChar) { putc(TransChar); /*if not LF,handle normally */ if(TransChar==’\n’)putc(’\r’); /*if LF,send a CR*/ } int putc(int TransChar) { while(TR_cLev>=OUTRINGSIZE); /*wait for space in ring */ ES=0; TRing[TR_iHead]=TransChar; /*point to char slot */ TR_iHead++; /*tick counter &index */ TR_cLev++; if(TR_iHead==OUTRINGSIZE)TR_iHead =0; if(FlagTransIdle){ FlagTransIdle =0; /*kickstart transmitter if idle */ TI=1; } ES=1; return(TransChar); } /*---------------------------------------------------------------------------*/ /*Decide if there are any pending chars */ /*Returns nonzero if there’s a char */ int chkch(){ return(RR_cLev); /*tack on current level */ } /*---------------------------------------------------------------------------*/ /*Wait for the serial transmitter to go idle */ /*If the transmitter is disabled,that’s considered to be the same thing */ void SerWaitOutDone(){ while (TR_cLev); /*wait for ring empty */ while(!FlagTransIdle); /*wait for last char */ } /*---------------------------------------------------------------------------*/ /*Flush the input buffer */ /*Returns number of chars flushed */ int SerFlushIn(){ ES=0; /*turn off serial interrupts */ RR_iTail =0; /*reset ring variables */ RR_iHead =0; RR_cLev =0; ES=1; /*turn on serial interrupts */ } /*---------------------------------------------------------------------------*/ /*Get character from console */ /*CRs turn into LFs unless we’re not doing that...*/ int getch(){ int RetVal; ES=0; /*avoid interruptions */ if(RR_cLev){ /*anything pending?*/ RetVal =RRing[RR_iTail]; if(RetVal==’\r’)RetVal =’\n’; /*use LFinstead of CR*/ RR_iTail++; /*tick size index &counter */ RR_cLev--; if(RR_iTail==INRINGSIZE)RR_iTail =0;/*hit end of array yet?*/ }else RetVal =-1; ES=1; return(RetVal); } /*---------------------------------------------------------------------------*/ /*Send string to console */ /*putstr(char *pString);*/ /*The ?putstr entry point has *pString in DPTR*/ int putstr (char *pstring) { while(*pstring){ /*fetch character if zero done */ putch(*pstring); pstring++; /*continue...*/ } } 使用查詢的程序可以做到多高的波特率取決于主程序的工作量,使用中斷方式的通訊驅(qū)動程序在使用11.0592MHz晶振時可以達到57.6Kbps的速率。 (5)關(guān)于RS485 以上幾個方面詳細介紹了PC及MCS-51的RS-232C的串行通訊程序的設計方法,RS-485與RS-232C相類似,其區(qū)別在于使用雙端平衡驅(qū)動及半雙工模式,這些措施使RS-485傳輸距離更遠,同時,RS-485還可以組網(wǎng)。在同一個RS-485網(wǎng)絡中,可以多達32個模塊,某些器件可以多達256個甚至更多。相應的,RS-485具有接收/發(fā)送控制端,RS-485的接收控制端可以在需要接收的時候打開或者一直打開以便無條件的接收線路上的數(shù)據(jù)。RS-485的發(fā)送控制端僅在需要發(fā)送時打開,平時應關(guān)端發(fā)送器,因為在同一RS-485網(wǎng)絡中在同一時刻僅允許一個發(fā)送器工作。在數(shù)據(jù)發(fā)送完成后關(guān)閉發(fā)送器。這可以通過以下兩種方法實現(xiàn)。 一、在數(shù)據(jù)完全移出后,對于PC機為發(fā)送移位寄存器空,對于MCS-51為TI置位。這些調(diào)件既可使用查詢的方法得到,也可以在中斷程序中實現(xiàn)。 二、將RS-485的接收器始終打開,這樣一來,所有在RS-485上的數(shù)據(jù)均被接收回來,包括自己發(fā)送出去的數(shù)據(jù)。因此,當自己發(fā)送的數(shù)據(jù)完全被自己接收回來時即可關(guān)閉發(fā)送器。原則上說,這一方法無論是查詢或中斷方式都適用,但實際上,由于RS-485的數(shù)據(jù)通常打包后發(fā)送,因此,使用查詢的方法并不理想。這一方法非常適合中斷方式,尤其是以數(shù)據(jù)包傳送的RS-485通訊。
發(fā)表評論 告訴好友 打印此文 收藏此頁 關(guān)閉窗口 返回頂部
網(wǎng)友評論:(只顯示最新5條。)