RTS與CTS的含義


====================================我是分割線首先介紹下網上看到的========================================================================================

一、RS232標准中的RTS與CTS

RTS,CTS------請求發送/清除發送,用於半雙工時的收發切換,屬於輔助流控信號。半雙工的意思是說,發的時候不收,收的時候不發。那么怎么區分收發呢?缺省時是DCE向DTE發送數據,當DTE決定向DCE發數據時,先有效RTS,表示DTE希望向DCE發送。一般DCE不能馬上轉換收發狀態,DTE就通過監測CTS是否有效來判斷可否發送,這樣避免了DTE在DCE未准備好時發送所導致的數據丟失。

二、MODEM硬件流控中的RTS與CTS

按照SIMCOM公司的解釋,RTS和CTS是獨立,

1.RTS是模塊的輸入端,用於MCU通知模塊,MCU是否准備好,模塊是否可向MCU發送信息,RTS的有效電平為低。 
2.CTS是模塊的輸出端,用於模塊通知MCU,模塊是否准備好,MCU是否可向模塊發送信息,CTS的有效電平為低 
從文字看,RTS和CTS是獨立的,不存在每次單向數據傳輸的發起者問題。如果主機輸出RTS有效,那么模塊有數據就會發往主機;如果模塊輸出CTS有效,那么主機就可以將數據送達模塊接收。 
三、通信協議中的RTS與CTS

RTS/CTS協議即請求發送/允許發送協議,相當於一種握手協議,主要用來解決"隱藏終端"問題。"隱藏終端"(Hidden Stations)是指,基站A向基站B發送信息,基站C未偵測到A也向B發送,故A和C同時將信號發送至B,引起信號沖突,最終導致發送至B的信號都丟失了。"隱藏終端"多發生在大型單元中(一般在室外環境),這將帶來效率損失,並且需要錯誤恢復機制。當需要傳送大容量文件時,尤其需要杜絕"隱藏終端"現象的發生。IEEE802.11提供了如下解決方案。在參數配置中,若使用RTS/CTS協議,同時設置傳送上限字節數----一旦待傳送的數據大於此上限值時,即啟動RTS/CTS握手協議:首先,A向B發送RTS信號,表明A要向B發送若干數據,B收到RTS后,向所有基站發出CTS信號,表明已准備就緒,A可以發送,其余基站暫時"按兵不動",然后,A向B發送數據,最后,B接收完數據后,即向所有基站廣播ACK確認幀,這樣,所有基站又重新可以平等偵聽、競爭信道了。

附:UART串口歷史

很久很久以前,計算機還沒有出現,那時就已經存在了(計算機)史前的串口設備(電傳打字機,工控測量設備,通信調制解調器),為了連接這些串口,EIA制定了RS232標准,采用DB25接插件,支持同步和異步串口,D型的接口可以有效防止插反。標准化給使用帶來了便利。 
時光荏苒,個人計算機出現了,這些已有的串口設備毫無疑問地成為了最初的外設,自然而然地RS232標准被個人計算機采納。但是設備制造商傾向於體積更小,成本更低的接口,因此,將DB25中未使用的和支持同步模式的引腳去掉,形成DB9。最初的情況相當混亂,因為DB9只定義了信號,卻沒有指定信號和引腳的對應關系,各個制造商只能自行定義。幸運的是,IBM的PC成了工業標准,DB9逐漸統一到IBM的定義上來。 
    DB9只有9根線,遵循RS232標准。定義如下: 
    DTR,DSR------DTE設備准備好/DCE設備准備好。主流控信號。 
RTS,CTS------請求發送/清除發送。用於半雙工時,收發切換。屬於輔助流控信號。半雙工的意思是說,發的時候不收,收的時候不發。那么怎么區分收發呢?缺省時是DCE向DTE發送數據,當DTE決定向DCE發數據時,先有效RTS,表示DTE希望向DCE發送,一般DCE不能馬上轉換收發狀態,DTE就通過監測CTS是否有效來判斷可否發送,這樣避免了DTE在DCE未准備好時發送所導致的數據丟失。全雙工時,這兩個信號一直有效即可。 
隨着計算機的日益普及,很多非RS232的串口也要接入PC機,如果為每一種新出現的串口都增加一個新的I/O口顯然不現實,因為PC后面板位置有限,因此,將RS232串口和非RS232串口都通過RS232口接入是最佳方案。UART的U(通用)指的就是這個意思。早期ROM BIOS和DOS里的通信軟件都是為RS232設計的,在沒有檢測到DCD有效前不會發送數據,因此,就連發送一個字符這樣朴素的應用也要給出DCD、DTR、DSR等控制信號。因此,串口接頭上要將一些控制線短接,或者干脆繞過系統軟件自己寫通信程序。 
到此,UART的涵義就總結為:通用的 異步 (串行) I/O口。 
就在UART冠以通用二字,准備一統江湖的時候,制造商們不滿於它的速度、體積和靈活性(軟件可配置),推出了USB和1394串口。目前,筆記本上的UART串口有被取消的趨勢,因而有網友發出了“沒有串口,吾誰與歸”的慨嘆,古今多少事,都付笑談中,USB取代UART是后話,暫且不表。 
話說自從賀氏(Hayes)公司推出了聰明貓(SmartModem),他們制定的MODEM接口就成了業界標准,自此以后,所有公司制造的兼容貓都符合賀氏標准(連AT指令也兼容)。 
細觀賀氏制定的MODEM串口,與RS232標准大不相同。DTR在整個通信過程中一直保持有效,DSR在MODEM上電后/可以撥號前有效(取決於軟件對DSR的理解),在通信過程的任意時刻,只要DTR/DSR無效,通信過程立即終止。在某種意義上,這也可以算是流控,但肯定不是RS232所指的那種主流控。如果拘泥於RS232,你是不會理解DTR和DSR的用途的。 
賀氏不但改了DTR和DSR,竟然連RTS和CTS的涵義也重新定義了。因此,RTS和CTS已經不具有最開始的意義了。從字面理解RTS和CTS,是用於半雙工通信的,當DTE想從收模式改為發模式時,就有效RTS請求發送,DCE收到RTS請求后不能立即完成轉換,需要一段時間,然后有效CTS通知DTE:DCE已經轉到發模式,DTE可以開始發送了。在全雙工時,RTS和CTS都缺省置為有效即可。然而,在賀氏的MODEM串口定義中,RTS和CTS用於硬件流控,和什么全雙工/半雙工一點關系也沒有。 注意,硬件流控是靠軟件實現的,之所以強調“硬件”二字,僅僅是因為硬件流控提供了用於流量情況指示的硬件連線,並不是說,你只要把線連上,硬件就能自己流控。如果軟件不支持,光連上RTS和CTS是沒有用的。 
RTS和CTS硬件流控的軟件算法如下:(RTS有效表示PC機可以收,CTS有效表示MODEM可以收,這兩個信號互相獨立,分別指示一個方向的流量情況。) 
    PC端處理: 
     發.    當發現(不一定及時發現) CTS (-3v to -15v)無效時,停止發送, 
         當發現(不一定及時發現) CTS (3v to 15v)有效時,恢復發送; 
     收.    當接收buffers中的bytes當接收buffers中的bytes>N 時,給 RTS 無效信號(-3v to -15v); 
    MODEM端處理: 
同上,但RTS與CTS交換。

在RS232中本來CTS 與RTS 有明確的意義,但自從賀氏(HAYES ) 推出了聰明貓(SmartModem)后就有點混淆了。在RS232中RTS 與CTS 是用來半雙工模式下的方向切換;HAYES Modem中的RTS ,CTS 是用來進 行硬件流控的。通常UART的RTC、CTS 的含義指后者,即用來做硬流控的。

硬流控的RTS 、CTS :RTS (Require To Send,發送請求)為輸出信號,用於指示本設備准備好可接收;CTS(Clear To Send,發送清除)為輸入信號,有效時停止發送。假定A、B兩設備通信,A設備的RTS 連接B設備的CTS ;A設備的CTS 連接B設備 的RTS 。 前一路信號控制B設備的發送,后一路信號控制A設備的發送。對B設備的發送(A設備接收)來說,如果A設備接收緩沖快滿的時發出RTS 信號(意思 通知B設備停止發送),B設備通過CTS 檢測到該信號,停止發送一段時間后A設備接收緩沖有了空余,發出RTS 信號,指示B設備開始發送數據。A設備發(B設備接收) 類似。上述功能也能在數據流中插入Xoff(特殊字符)和Xon(另一個特殊字符)信號來實現。A設備一旦接收到B設備發送過來的Xoff,立刻停止發 送;反之,如接收到B設備發送過來的Xon,則恢復發送數據給B設備。同理,B設備也類似,從而實現收發雙方的速度匹配。

半雙工的方向切換:RS232中使用DTR(Date Terminal Ready,數據終端准備)與DSR(Data Set Ready ,數據設備准備好)進行主流控,類似上述的RTS 與CTS 。對半雙工的通信的DTE(Date Terminal Equipment,數據終端設備)與DCE(Data circuit Equipment )來說,默認的方向是DTE接收,DCE發送。如果DTE要發送數據,必須發出RTS 信號,請求發送數據。DCE收到后如果 空閑則發出CTS 回 應RTS 信 號,表示響應請求,這樣通信方向就變為DTE->TCE,同時RTS 與CTS 信號必須一直保持。從這里可以看出,CTS ,TRS雖 然也有點流控的意思(如CTS 沒有發出,DTE也不能發送數據),但主要是用來進行方向切換的。

如果UART只有RX、TX兩個信號,要流控的話只能是軟流控;如果有RX,TX,CTS ,RTS 四個信號,則多半是支持硬流控的UART;如果有 RX,TX,CTS ,RTS ,DTR,DSR 六個信號的話,RS232標准的可能性比較大。

順便提一下:

DCD( Data Carrier Detect, 數據載波檢測):DCE向DTE指示,線路上檢測到載波。

RI(Ring Indicator,振鈴指示):DCE向DTE指示,有呼叫接入。

====================================我是分割線=====================================================================================================

  這兩天基於STM32的串口做了測試。之前一直用的時候根本沒有往串口協議上靠,只是能用起來解決了問題就匆匆完事。直到最近看《深入理解計算機網絡》這本網絡基礎書,里面講232協議以及485協議時,忽然想拿板子測試下。上面提到的CTS/RTS流控方面的應用是我之前使用串口時沒有注意到的。之前在用USART做串口編程時,一般都是設備作為從機來使用,包括一些教程也都是從這樣的應用來講解。大部分的教程都是在將單片機Usart同上位機超級終端之間通過232協議轉換模塊進行通信。最最常見的用法就是使用串口中斷進行流控(當然這種做法是推薦的,因為232的CTS/RTS不是干這個用的,本文只是那上位機的232這么測試一下。。。)

  前幾天看書看到232的時候,我忽然想到是不是可以用RTS/CTS來代替中斷實現上位機的交互。上位機的超級終端或者串口小助手,在接收的數據的時候,可以游刃有余,因為stm32函數庫里面,usart的發送數據是通過串口打印沖定義實現的,將fputs()函數進行了修改,最終使用printf函數進行輸出。這種方法其實是通過函數fputs()本身進行了緩存操作,使得USART_SendData函數能一位位的將數據發出。也就是說,即是不用發送中斷,我們依然能夠井然有序的通過stm32的Usart的TX端口將數據發出。如下代碼是stm32函數庫中串口打印沖定義函數,注意是USART1。

 1 #ifdef __GNUC__
 2 /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
 3      set to 'Yes') calls __io_putchar() */
 4 #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
 5 #else
 6 #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
 7 #endif /* __GNUC__ */
 8 
 9 PUTCHAR_PROTOTYPE
10 {
11     /* Place your implementation of fputc here */
12     /* e.g. write a character to the USART */
13     USART_SendData(USART1,(u8)ch);
14 
15     /* Loop until the end of transmission */
16     while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
17 
18     return ch;
19 }

  但是,如果我們不使用中斷,而從上位機超級終端向stm32發送數據的話,你會發現,單片機只能收到你發的字符串的首個字符。其它的字符全部丟失。這就是沒有做流控的結果。比如下面:

 1 int main(void)
 2 {
 3     u32 i=0xffffff;
 4     SystemInit();
 5     usart_Configuration();    
 6     //NVIC_Configuration();
 7       while(1)
 8     {
 9         printf("Waveshare!\r\n");
10         while(--i);
11         i=0xffffff;
12         printf("%c",USART_ReceiveData(USART1));
}
13 }

  但是如果我們使用中斷,或者是使用RTS/RTS做流控則不會發生這種現象。從機理上講,上面是發生了接收溢出錯誤。串口狀態寄存器的ORE位由於在RENE=1的情況(也就是第一個字符已經被寫滿數據寄存器DR)下接收到了數據,造成了數據溢出,此時SR.ORE位會置1.這點參考硬件手冊,而且讀取DR數據寄存器的話,僅會清除RXNE位,而不會清空數據寄存器DR。所以一直會輸出S。但是如果我們發送再次發送一個字符,比如ASDF。則會發現輸出字符變成了AWaveshare!道理跟之前一樣,因為我們已經通過調用USART_ReceiveData()清空了RXNE,所以第一個字符A還是能讀進去的,只不過當第二字字符S時又發生了前面的事情。所以,在做通信的時候必須做流控。

  使用中斷做流控我們就不說了,很多。這里說一下CTS/RTS。其實這個比中斷簡單,因為中斷我們還得配置,而且中斷可以寫中斷服務函數,所以應用廣。畢竟CTS/RTS其實是用來做流控或者半雙工通信的,具體的含義不一樣,這里只講232的。以RTS為例,其含義如下:

  也就是說,Tx管腳接收到1個字符(默認8bit通信),硬件上RTS會產生一個置位,使得接收數據標志位RXNE=1.所以只要在軟件里我們判斷RXNE的狀態,就可以實現流控。CTS道理一個樣。故而代碼可以如下:

 1 int main(void)
 2 {
 3     SystemInit();
 4 USART_CTRT_Configuartion();
 5     while(NbrOfDataToTransfer--)    
 6       {
 7         USART_SendData(USART1,TxBuffer[TxCounter++]); 
 8         while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); //等待發送結束         
 9       }
10   
11       /*Receive a string (Max RxBufferSize bytes) from the Hyperterminal ended by '\r' (Enter key) */
12     do
13     { 
14         if((USART_GetFlagStatus(USART1, USART_FLAG_RXNE) != RESET)&&(RxCounter < RxBufferSize))    //0xFF:256字符
15         {
16            RxBuffer[RxCounter] = USART_ReceiveData(USART1);
17            USART_SendData(USART1, RxBuffer[RxCounter++]);
18         }   
19         
20     }while((RxBuffer[RxCounter - 1] != '\r')&&(RxCounter != RxBufferSize));
21 
22 //串口配置函數
23 
24 void USART_CTRT_Configuartion(void)
25 {
26     USART_InitTypeDef USART_InitStruct;
27 
28     Rcc_Configuration();
29 
30     USART_InitStruct.USART_BaudRate = 115200;
31     USART_InitStruct.USART_StopBits = USART_StopBits_1;
32     USART_InitStruct.USART_WordLength = USART_WordLength_8b;
33     USART_InitStruct.USART_Parity = USART_Parity_No;
34     USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_RTS_CTS;
35     USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
36     
37     USART_Init(USART1, &USART_InitStruct);
38 
39     USART_Cmd(USART1, ENABLE);
40 
41     UsartGPIO_CTRT_Configuration();
42 }

  完整的代碼可以自己參考庫函數。這里不再貼了。

 

引用參考:http://www.cnblogs.com/sunyubo/archive/2010/04/21/2282176.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM