none
rs232通訊 RRS feed

  • 問題

  • 大大您們好,想請問一下,我在測試rs232通訊部份,可是我發現,我單只用一個程式做rs232傳和接收用,去工作管理員發現cpu佔了大概30%左右,這是因為c#關係,還是我本身程式設計不良的因素,而我rs232就是write和read,麻請大大幫忙,謝謝
    2010年4月9日 上午 07:47

解答

  • 最近剛好處理公司交換機的Log接收處理,也是透過RS 232.

    你應該要透過DataReceived Event來被動式的等待RS 232有資料時自動接收,而非是用輪詢機制,程式設計架構中除非真的不得已否則不應該採用輪詢機制,輪詢機制是造成效能瓶頸的主因,且輪詢機制必須架構在輪詢間隔中一定能接收完資料的前提.但這點通常很難預測.

    採用DataReceived Event後也會有個問題點,如果你的程式來不及處理而導致資料吞吐量瞬間資料會超出你RS232的Buffer,這時候DataReceived Event中應該採用獨立的Worker Thread來處理資料讓DataReceived Event隨時都會保持可接收RS232的資料狀態下.如同撰寫Server/Client應用程式中的Server端Listing動作.

     

     

    • 已標示為解答 冰糖旋風 2010年4月12日 上午 04:57
    2010年4月9日 上午 08:58
  • 你的寫法本來就很奇怪, 你可以用一次Tick就做完, 為什麼要第一次Tick先送, 第二次Tick再收,

    你可以先把Interval設大一些, 然後在一次Tick做完, Tick中的程序會變成  送-->Sleep(30)--->收, 這樣不就好了 ?

    不過說實話, 這種程式應該用backgroundworker or thread 之類的去做會更好.

     


    MSDN 文件庫很重要
    回應幫助你的人是一種禮貌, 良好的禮貌有助於激發大家對你問題回應的熱情
    進步的人會找尋自己程式中的缺點,半桶水則把自己程式的錯誤推到不相干事物的身上
    • 已標示為解答 冰糖旋風 2010年4月12日 上午 04:56
    2010年4月12日 上午 04:17
    版主

所有回覆

  • 你的 read 部分  是 用  LOOP 回圈  一直讀 嗎
    Cmf.Net (C) 2010
    2010年4月9日 上午 07:56
  • 大大您好,我是利用timer送和收,間隔30ms,謝謝
    2010年4月9日 上午 08:06
  • 你在 timer 中所建立的送及收都是用「同一個物件」嗎?
    還是 timer 觸發一次就建立一次?


    逐步學習,逐夢踏實;腳步要踩穩,這樣下一步才不會跌倒。 http://www.dotblogs.com.tw/nobel12
    2010年4月9日 上午 08:18
  • 大大您好,我只有再form_load()裡載入我的物件,接下來都是用同一個物件去做傳送接收動作,是不是覺得不會有這種情況發生,謝謝

    2010年4月9日 上午 08:32
  • Hi!

    您提到是使用 timer,是否考慮接收使用 SerialPort.DataReceived 事件 : 該方法將會處理 SerialPort 物件的資料接收事件


    歡迎參觀我的Blog.NET菜鳥自救會
    2010年4月9日 上午 08:47
    版主
  •  

    不知道這是不是因在建置時做的測試會有如此的影響

    你是用 Debug 建置模式直接測試  還是建置成 Release 版再執行程式測試的呢?

     


    逐步學習,逐夢踏實;腳步要踩穩,這樣下一步才不會跌倒。 http://www.dotblogs.com.tw/nobel12
    2010年4月9日 上午 08:52
  • 最近剛好處理公司交換機的Log接收處理,也是透過RS 232.

    你應該要透過DataReceived Event來被動式的等待RS 232有資料時自動接收,而非是用輪詢機制,程式設計架構中除非真的不得已否則不應該採用輪詢機制,輪詢機制是造成效能瓶頸的主因,且輪詢機制必須架構在輪詢間隔中一定能接收完資料的前提.但這點通常很難預測.

    採用DataReceived Event後也會有個問題點,如果你的程式來不及處理而導致資料吞吐量瞬間資料會超出你RS232的Buffer,這時候DataReceived Event中應該採用獨立的Worker Thread來處理資料讓DataReceived Event隨時都會保持可接收RS232的資料狀態下.如同撰寫Server/Client應用程式中的Server端Listing動作.

     

     

    • 已標示為解答 冰糖旋風 2010年4月12日 上午 04:57
    2010年4月9日 上午 08:58
  • 大大您好,DataReceived 不是本來就他會再產生一個執行緒去做監聽的動作嗎,另外在請教一下大大,您所謂的輪詢動作,那像如果我使用一個timer先畫圖後顯示資料在儲存資料,這樣算是輪詢動作嗎,還是您所謂的輪詢是對某些對外通訊而言,謝謝

    2010年4月9日 上午 09:09
  • 大大您們好,想請問一下,我在測試rs232通訊部份,可是我發現,我單只用一個程式做rs232傳和接收用,去工作管理員發現cpu佔了大概30%左右,這是因為c#關係,還是我本身程式設計不良的因素,而我rs232就是write和read,麻請大大幫忙,謝謝

    這有很多種寫法, 你沒有貼碼上來, 要怎麼找出問題 ?
    MSDN 文件庫很重要
    回應幫助你的人是一種禮貌, 良好的禮貌有助於激發大家對你問題回應的熱情
    進步的人會找尋自己程式中的缺點,半桶水則把自己程式的錯誤推到不相干事物的身上
    2010年4月9日 上午 09:50
    版主
  •      大大您好,我先說我原本寫法,如下,至於另一類別,我怕程式碼太複雜,所以利用寫在後面方式告知呼叫此方法的意思,謝謝   

          int Step = 0;

          private RS232Class RS232 = new RS232Class();       

          private void Form1_Load(object sender, EventArgs e)
            {
               設定RS232 此類別的包率和comport

            }

            private void timer1_Tick(object sender, EventArgs e)
            {           

                switch (Step)
                {
                    case 0:
                        SendByte = new byte[] { 1, 0x03, 0x80, 0x00, 0, 0x06 };
                        RS232 .SetCommand(SendByte1);             //利用Port.Write();
                        break;
                    case 1:

                        byte[] RecByte = RS232 .GetReceive();      //Port.Read();

                        if (RecByte != null && RecByte.Length != 0)
                        {
                            label2.Text = RecByte[0].ToString();
                        }
                        break;
                }

              Step++;
                if (Step > 1)
                    Step = 0;

           }

    2010年4月9日 上午 10:06
  • 突然想起一件事, 你的RS232的設備有辦法在 30ms的時間中傳回資料嗎 ?

    MSDN 文件庫很重要
    回應幫助你的人是一種禮貌, 良好的禮貌有助於激發大家對你問題回應的熱情
    進步的人會找尋自己程式中的缺點,半桶水則把自己程式的錯誤推到不相干事物的身上
    2010年4月9日 下午 02:14
    版主
  • 這 RS232 是啥鬼東西?

    我直接用 SerialPort 對 3 個 rs485 設備發收命令,每 500 ms 內完成收發一次,CPU 使用率低於 10% 。

    你自己直接用 .Net 內建的 SerialPort 寫吧,找個不知道誰寫的 rs232 類別,說不定問題就在這個物件內。

    另外掛個 COM 的擷取器,比如說 AccessPort ,監控收發狀態,如果你收資料時,Byte 是一個個收,不是一次收,這就會是你 CPU 負載很高的原因之一。


    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    提問時,錯誤情境描述與錯誤訊息很重要,情境描述包含你做了什麼,預期的結果與實際發生的結果。一個最爛的問法範例:「我的電腦電腦怎麼不能開機?」誰知道你家是不是沒電還是你根本找不到電源鈕。
    2010年4月9日 下午 03:52
  • 大大您好,我是利用包率去算收回的秒數,所以我是將它設為合理範圍內,謝謝
    2010年4月12日 上午 12:43
  • 大大您好,抱歉我程式貼的不是很清楚,我的rs232類別,其實是用c#他的serial port,只是我將他寫道別的類別罷了,至於我在後面所註明的Port.Write();其實就是serialport port=new serialport();,造成您的困惱我很抱歉,謝謝
    2010年4月12日 上午 12:45
  • 大大您好,我是利用包率去算收回的秒數,所以我是將它設為合理範圍內,謝謝

    你認為這是合理的 ? 你有將設備回應時間算進來嗎 ? 當一個設備收到由通訊端傳來的資料時, 它必須做一些運算與控制的動作, 尤其當設備是8051等單晶片系統時, 它需要一點時間才能運算完畢回復資料.

    MSDN 文件庫很重要
    回應幫助你的人是一種禮貌, 良好的禮貌有助於激發大家對你問題回應的熱情
    進步的人會找尋自己程式中的缺點,半桶水則把自己程式的錯誤推到不相干事物的身上
    2010年4月12日 上午 02:55
    版主
  • 大大您好,我是詢問過設備他們需要傳回的時間,再做的(因為資料很短,所以時間我設比較短),我是可以收的到值,所以時間上是可以的,另一方面,時間上我若調至500 ms 內完成收發一次,是可以降低沒錯,但是時間我不想設那麼長,謝謝
    2010年4月12日 上午 03:34
  • 你的寫法本來就很奇怪, 你可以用一次Tick就做完, 為什麼要第一次Tick先送, 第二次Tick再收,

    你可以先把Interval設大一些, 然後在一次Tick做完, Tick中的程序會變成  送-->Sleep(30)--->收, 這樣不就好了 ?

    不過說實話, 這種程式應該用backgroundworker or thread 之類的去做會更好.

     


    MSDN 文件庫很重要
    回應幫助你的人是一種禮貌, 良好的禮貌有助於激發大家對你問題回應的熱情
    進步的人會找尋自己程式中的缺點,半桶水則把自己程式的錯誤推到不相干事物的身上
    • 已標示為解答 冰糖旋風 2010年4月12日 上午 04:56
    2010年4月12日 上午 04:17
    版主
  • 大大謝謝,我會試試
    2010年4月12日 上午 04:56
  • 大大您好,我是建置下作測試的,且若再debug下作測試,仍一樣結果,謝謝

    2010年4月12日 上午 09:35
  • 用 Thread 收,如果沒控制好,一樣會造成 CPU Loading 很重,在這個 Thread 上。

    叫你掛 AccessPort 這類軟體的目的就可以看清楚你自己程式是怎樣收資料,此外,計算資料預期長度,直接檢查資料傳回的數量是否符合指定的 bytes 數,計算合理等待時間,如果不耐久候,(反應時間 + 接收目標時間)/2+10ms 來做分段接收是我慣用的方式。


    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    提問時,錯誤情境描述與錯誤訊息很重要,情境描述包含你做了什麼,預期的結果與實際發生的結果。一個最爛的問法範例:「我的電腦電腦怎麼不能開機?」誰知道你家是不是沒電還是你根本找不到電源鈕。
    2010年4月12日 下午 02:01
  • 大大您好,我有利用類似Bus Hound看過,應該跟您說的性質差不多吧,謝謝

    2010年4月13日 上午 06:40
  • 那麼你收資料的情形到底是怎樣?你這邊不說清楚怎樣判斷是不是這邊造成 CPU Loading 飆高?
    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    提問時,錯誤情境描述與錯誤訊息很重要,情境描述包含你做了什麼,預期的結果與實際發生的結果。一個最爛的問法範例:「我的電腦電腦怎麼不能開機?」誰知道你家是不是沒電還是你根本找不到電源鈕。
    2010年4月13日 下午 04:52
  • 大大您好,我請問一下c#會有限制設計出的程式最大可以消耗系統多少的cpu嗎,謝謝

    2010年4月16日 上午 04:18
  • 大大您好,我就是利用while()迴圈,再搭配c#的port.Read()和write還有接收事件,就送-->判斷-->收,一直不斷循環,謝謝
    2010年4月16日 上午 07:16
  • 大大您好,我就是利用while()迴圈,再搭配c#的port.Read()和write還有接收事件,就送-->判斷-->收,一直不斷循環,謝謝

    這是在回答哪一段 ? 你給的Code完全沒見到While, 可以請你發文時描述清楚一些嗎 ? 不然我們越看越糊塗.

    MSDN 文件庫很重要
    回應幫助你的人是一種禮貌, 良好的禮貌有助於激發大家對你問題回應的熱情
    進步的人會找尋自己程式中的缺點,半桶水則把自己程式的錯誤推到不相干事物的身上
    2010年4月16日 上午 07:21
    版主
  • 抱歉,那是我一直不斷改之前大大說的方法,試試看的,因為我想要將表單程式和通訊寫分開,所以我另開一個執行緒,即用while達到此程式不會關閉的結果,並在rs2323接收上利用事件觸發,流程大概是如下,至於()裡註明的都是我另外寫的class但仍是c#內建的涵式庫

     while (true)
                {
                   是否連線(沒連線-->連線測試,反之不跑此判斷式)                                                 
                   連線成功-->傳送(c#的port.Write())

                                    等待傳送的資料長度已經正確或超過可允許的時間(再利用一個while()等待)

                                    接收(c#的port.Read())

                                     判斷資料是否正確

                  }

    謝謝

    2010年4月16日 上午 07:45
  • 等待傳送的資料長度已經正確或超過可允許的時間(再利用一個while()等待) <--這邊不要用While, 用 Thread.Sleep()會好一點

    MSDN 文件庫很重要
    回應幫助你的人是一種禮貌, 良好的禮貌有助於激發大家對你問題回應的熱情
    進步的人會找尋自己程式中的缺點,半桶水則把自己程式的錯誤推到不相干事物的身上
    2010年4月16日 上午 07:57
    版主
  • 大大您好,我改成

    whle(timeout)

    {

        thread.sleep(1);
    }

    但效果仍一樣,我只睡一毫秒,是因為若在此我判斷到,以接收到資料,我就繼續執行,但結果仍一樣沒改善,我發現,若我再最外圍的while()裡最後面加入thread.sleep(1000);則效能有效減少20~30%左右,可若是這樣,我的接收傳送,時間上就又會花費較多,大大可否再請您幫幫我,謝謝

    2010年4月19日 上午 12:46
  • 還是強烈建議你不要使用輪巡方式來處理這種問題,因為如同你上面來來往往的討論,都是在處理一件事情-"多久時間間隔來接收處理資料",而因為你的資料並不是一種很固定式週期性的傳遞,故使用輪巡很容易造成不可預期的情況,就算找出方式解決目前的問題,但未來不可預期的錯誤是可預見的.

    使用DataReceived事件處理這類需求比較合適,程式碼如下

    ...
    _rs232.DataReceived += new SerialDataReceivedEventHandler(rs232_DataReceived);
    ...

            void rs232_DataReceived(object sender, SerialDataReceivedEventArgs e)
            {
                const int eof = 0; //每筆資料的結束判斷

                byte[] data = new byte[1024];
                byte b;
                int count = 0;
                do
                {
                    b = (byte)_rs232.ReadByte();
                    data[count] = b;
                    count++;
                }while(b != eof);
                
                ParserData(data); //處理資料
             }

    eof變數代表你的每筆資料結束位元的判斷值,通常大多數RS232都使用0作為判斷.當然這要看你的裝置如何定義,如果你的資料是ASCII字串還可以將這段程式直接使用_rs232.ReadLine();取代.

    上面的程式要注意一點ParserData(data);這段程式如果需要長時間來處理,而RS232接收的裝置本身buffer無法緩衝如此長的時間,這時候要考量將ParserData使用獨立的Thread來處理資料,讓rs232_DataReceived可以處理一直可運作狀態下來避免資料遺失的問題.
    如果你不清楚會不會有此種情況,建議一開始設計就採用Thread來處理.

    2010年4月19日 上午 02:30
  • 大大您好,我是有改成事件觸發的方式(如上面我回答Bill Chung),也就是在下面粗體部分,程式碼我將他寫再另一個類別,也如同您使用的方式,只是我又用一while()等待,是因為我要計算他可允許延遲時間(當然從接收資料開始,我也會計算目前等的timer時間),亦指若超過這時間我仍沒接收到(資料長度),我就判斷斷線了,而我是要不斷做傳、接收動作,並不是使用者要求才做的,謝謝

    while (true)
                {
                   是否連線(沒連線-->連線測試,反之不跑此判斷式)                                                 
                   連線成功-->傳送(c#的port.Write())

                                    等待傳送的資料長度已經正確或超過可允許的時間(再利用一個while()等待)

                                    接收(c#的port.Read())

                                     判斷資料是否正確

                  }

    2010年4月19日 上午 02:56