討論區快速選單
知識庫快速選單
討論區最近新進100則主題 政府補助!學嵌入式+物聯網 軟體開發過程中有哪些資安漏洞?
[ 回上頁 ] [ 討論區發言規則 ]
請問RS232傳送資料問題
更改我的閱讀文章字型大小
作者 : jack0128(bm)
[ 貼文 6 | 人氣 2695 | 評價 0 | 評價/貼文 0 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2006/6/16 上午 09:46:50
各位大大:
     我用VC++寫一個RS232傳送接收資料的程式,我有開一個thread去專門做讀取資料的動作,是用
ReadFile()來讀取,在寫入方面,則是單純使用WriteFile()這個function,目前讀取資料都沒問題,可是
在寫入資料上卻有問題,並不是無法寫入資料,而是有時寫入次數多一點程式就會當掉,而且並沒有秀出
任何錯誤訊息,程式就這樣當掉了,連在debug模式用單步執行也會掛,不知道問題出在哪,盼各位大大能給小弟指點指點,感激不盡!!
作者 : theboy(小猴子) VC++優秀好手貼文超過200則
[ 貼文 350 | 人氣 8375 | 評價 960 | 評價/貼文 2.74 | 送出評價 17 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2006/6/16 上午 10:19:00

>各位大大:
> 我用VC++寫一個RS232傳送接收資料的程式,我有開一個thread去專門做讀取資料的動作,是用
>ReadFile()來讀取,在寫入方面,則是單純使用WriteFile()這個function,目前讀取資料都沒問題,可是
>在寫入資料上卻有問題,並不是無法寫入資料,而是有時寫入次數多一點程式就會當掉,而且並沒有秀出
>任何錯誤訊息,程式就這樣當掉了,連在debug模式用單步執行也會掛,不知道問題出在哪,盼各位大大能給小弟指點指點,感激不盡!!
>
你把程式碼PO上來....
大家討論看看....
純粹這樣描述...比較難發覺問題的所在..
作者 : johnpage(阿璋) 貼文超過500則
[ 貼文 519 | 人氣 4090 | 評價 1130 | 評價/貼文 2.18 | 送出評價 0 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2006/6/16 上午 10:23:05
高速傳輸時
要外加資料流控制
應該只有接RX TX對不對
作者 : jack0128(bm)
[ 貼文 6 | 人氣 2695 | 評價 0 | 評價/貼文 0 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2006/6/21 下午 05:25:43
>你把程式碼PO上來....
>大家討論看看....
>純粹這樣描述...比較難發覺問題的所在..

我把程式碼PO上來:

開啟com port部分:
void RS232::COMPORT_OPEN(HWND hWnd) //open comport

{
    DCB dcb={0};

    COMMTIMEOUTS TimeOut;
    TimeOut.ReadIntervalTimeout = 0;
    TimeOut.ReadTotalTimeoutMultiplier= 0;
    TimeOut.ReadTotalTimeoutConstant= 500;
    TimeOut.WriteTotalTimeoutMultiplier = 0;
    TimeOut.WriteTotalTimeoutConstant = 500;

    BuildCommDCB("38400,n,8,1",&dcb))

    comhandle=CreateFile(COM2,
     GENERIC_READ|GENERIC_WRITE,
     0,
     0,
     OPEN_EXISTING,
     FILE_ATTRIBUTE_NORMAL,
     0);

if(comhandle==INVALID_HANDLE_VALUE)
Add2List (hWnd,"COM PORT 開啟失敗");


SetCommState(comhandle,&dcb);

SetupComm(comhandle,2048,1024);

SetCommTimeouts(comhandle,&TimeOut);

Thread_rs232.hWnd=hWnd;
Thread_rs232.handle=comhandle;
AfxBeginThread(DownloadThread_RS232, (LPvoid)&Thread_rs232);
}

Read thread部分:

struct THREAD_RS232
{

     HANDLE handle;
     HWND hWnd;

} Thread_rs232;

void RS232_Read(HANDLE handle,HWND hWnd)// read RS232 data
{
int i=0;
CString str1="0";
DWORD dwNoByte;
char RxdBuffer;
while(1)
{
ReadFile(handle,&RxdBuffer,1,&dwNoByte,NULL);
{
str1+=RxdBuffer;
}
if(RxdBuffer==ASCII_CR)
{

ListBox->AddString(str1); //list讀到的訊息 str1="\0";
i=0;
}
i++;
}
}

Write data部分:

bool RS232::comwrite(char* TXD)// TXD為寫入的資料
{
DWORD dwWritten;
    
int i,n;
char XD=ASCII_CR;
n=strlen(TXD);
for(i=0;i<n;i++)
{
WriteFile(comhandle,(TXD+i),1,&dwWritten,0);
}

WriteFile(comhandle,&XD,1,&dwWritten,0);

return true;
}

read部分是沒問題,不過write部分卻有問題,目前是可以寫入資料,寫入的時間有時粉快
快的時候1秒,但有時卻很慢,最長還有等到快一分鐘才寫入成功,幾乎以為是當掉了,目前
不知道問題出在哪,所以把程式po上來,希望各位高手可幫忙解答,是不是還要加一些東西或是程式上有錯誤的,還請各位幫忙指教,感激不盡!!^^


作者 : quickwolf(疾風之狼) 貼文超過200則
[ 貼文 258 | 人氣 1837 | 評價 1420 | 評價/貼文 5.5 | 送出評價 11 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
主題發起人jack0128註記此篇回應為很有道理 2006/6/22 上午 09:18:39
原以為多半是因為Hardware Handshaking(RTS/CTS/DTR/DSR)所致
但 BuildCommDCB() 造出來的DCB預設是將所有flow control都disable的,
因此推測與flow rate control無關..

由程式寫法來推斷.. 理論上每傳送1byte最快須耗時(1+8+1)/38400約26ms
由於是逐字傳送,OS對Thread進行優先權排程可能造成實際傳送時間間隔達到
數10ms..(隨機) 因此當傳送資料較大時可能時快時慢..

建議
for(i=0;i<n;i++)
{
WriteFile(comhandle,(TXD+i),1,&dwWritten,0);
}

BOOL bRet=WriteFile(comhandle,TXD,n,&dwWritten,0);
不要分多次寫入,並檢查回傳值若有錯用GetLastError()取Error Code回來分析原因..



作者 : quickwolf(疾風之狼) 貼文超過200則
[ 貼文 258 | 人氣 1837 | 評價 1420 | 評價/貼文 5.5 | 送出評價 11 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2006/6/22 上午 09:24:26
另外也有可能跟Read thread寫法有關
或許因為Read thread佔用了大部分CPU資源
造成WriteFile分不到執行時間,當然執行起來就不順暢了..

這部分還要看程式碼才能確定.. 純屬推測
作者 : sunrise_wx(sunrise)
[ 貼文 3 | 人氣 0 | 評價 20 | 評價/貼文 6.67 | 送出評價 0 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2006/6/22 上午 09:26:23
看了你的代码了。你在写入RS232的时候,采用了一次写入一个byte的方法有问题。必须采用一次写入整个字符串的方法。

DWORD CPSerialPort::WritePort(char *data,int length)
{
if(m_hComm==INVALID_HANDLE_VALUE)
{
return 0;
}

BOOL fWriteState;
DWORD dwBytesWritten=0;

fWriteState=WriteFile(m_hComm,data,length*sizeof(char),&dwBytesWritten,NULL);

return dwBytesWritten;
}
作者 : sunrise_wx(sunrise)
[ 貼文 3 | 人氣 0 | 評價 20 | 評價/貼文 6.67 | 送出評價 0 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
主題發起人jack0128註記此篇回應為很有道理 2006/6/22 上午 09:26:37
看了你的代码了。你在写入RS232的时候,采用了一次写入一个byte的方法有问题。必须采用一次写入整个字符串的方法。

DWORD CPSerialPort::WritePort(char *data,int length)
{
if(m_hComm==INVALID_HANDLE_VALUE)
{
return 0;
}

BOOL fWriteState;
DWORD dwBytesWritten=0;

fWriteState=WriteFile(m_hComm,data,length*sizeof(char),&dwBytesWritten,NULL);

return dwBytesWritten;
}
作者 : theboy(小猴子) VC++優秀好手貼文超過200則
[ 貼文 350 | 人氣 8375 | 評價 960 | 評價/貼文 2.74 | 送出評價 17 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
主題發起人jack0128註記此篇回應為很有道理 2006/6/22 上午 09:56:04
依小弟實做過的RS-232的經驗...
RS-232本身都有一個緩衝區....
可以存放你Write進去的DATA以及從RS-232另一端傳回來的DATA
所以當你送出COMMAND之後....在進行READ的動作即可...
不需要特地為接收訊號來READ....
每次在WRITE以及READ之前....
可以先將緩衝區清空...PurgeComm(...)
在進行WRITE以及READ的動作...


>看了你的代码了。你在写入RS232的时候,采用了一次写入一个byte的方法有问题。必须采用一次写入整个字符串的方法。
>
>DWORD CPSerialPort::WritePort(char *data,int length)
>{
> if(m_hComm==INVALID_HANDLE_VALUE)
> {
> return 0;
> }
>
> BOOL fWriteState;
> DWORD dwBytesWritten=0;
>
> fWriteState=WriteFile(m_hComm,data,length*sizeof(char),&dwBytesWritten,NULL);
>
> return dwBytesWritten;
>}

ㄏㄏㄏ....小弟在修改一點..
DWORD CPSerialPort::WritePort( char *data,
     int length,
     DWORD* pdwWritten,
     DWORD dwTimeout )
{
    BOOL bWrite;
    DWORD dwWritten;
    DWORD dwRemain = length;
    DWORD dwTick = ::GetTickCount();

    if ( m_hComm==INVALID_HANDLE_VALUE ) {
     return ERROR_INVALID_HANDLE;
    }

    *pdwWritten = 0;

    do
    {
     bWrite = ::WriteFile( m_hComm,
     data,
     // 每次以 dwRemain 為長度來寫入資料
     dwRemain * sizeof( char ),
     &dwWritten,
     NULL );
     if ( bWrite == true )
     { // dwRemain:剩餘未寫完的資料數
     dwRemain -= dwWritten;
     *pdwWritten += dwWritten;
     }
     if ( GetTickCount() - dwTick > dwTimtout ) {
     // 代表Timeout...在時間內並未寫完全部的資料
     return 0xffffffff;
     }
    } while( bWrite == true && dwRemain != 0 );
 
    return ERROR_SUCCESS;
}

以上的Function供你參考...
大概的構想是這樣...
Read也可以如法泡製....
WRITE以及READ時...若是不能完整讀回指定的長度...
那就繼續讀取/寫入...直到全部讀取/寫入完成
或者是Timeout發生....

作者 : jack0128(bm)
[ 貼文 6 | 人氣 2695 | 評價 0 | 評價/貼文 0 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2006/6/22 下午 02:05:36
>BOOL bRet=WriteFile(comhandle,TXD,n,&dwWritten,0);
>不要分多次寫入,並檢查回傳值若有錯用GetLastError()取Error Code回來分析原因..

小弟依各位大大的方法,也就是一次寫入字串的方式,沒有分多次寫入,狀況有改善一點點,不過有時還是會卡住,就是會停粉久,狀況時好時壞,不知道為什麼

     n=strlen(TXD);
BOOL bRet=WriteFile(comhandle,TXD,n,&dwNoByte,0);
是不是還有方法可以改善呢?
用DEBUG模式單步執行時,有時就會卡在WriteFile()的FUNCTION就過不去了,連WriteFile的回傳值都無法得知,所以也不知道是否有沒有寫入,希望各位大大能夠幫忙看一下,感激不盡!!





作者 : jack0128(bm)
[ 貼文 6 | 人氣 2695 | 評價 0 | 評價/貼文 0 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2006/6/22 下午 02:48:58
另外我寫入資料是以手動輸入的方式,在測試時有時候寫入動作太快好像也會卡住
,在WRITE和READ之前我都有先做PurgeComm()清除緩衝區的動作,可是還是會卡住
請問是否有方法可以克服這個問題呢?

我看微軟的msdn文件有提到OVERLAPPE I/O與nonoverlapped I/O的作法
請問是不是用OVERLAPPE I/O的方法是不是就比較不會發生這樣的問題呢?
作者 : quickwolf(疾風之狼) 貼文超過200則
[ 貼文 258 | 人氣 1837 | 評價 1420 | 評價/貼文 5.5 | 送出評價 11 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
主題發起人jack0128註記此篇回應為很有道理 2006/6/22 下午 05:08:29
看起來 WriteFile() 跟 RaedFile() 像是在同一台PC上分兩個Thread執行??
且用的是同一個RS232 port將RX,TX互接 (亦即ReadFile跟WriteFile用的為同一個handle)??

兩個Thread 共用同一裝置應該必須有一機制來避免數個Thread同時去存取..
這邊的碼似乎沒有處理這部分..
這個建議先將ReadFile註解掉看WriteFile是否變順暢即可確認
還有
SetCommState(comhandle,&dcb);
SetupComm(comhandle,2048,1024);
SetCommTimeouts(comhandle,&TimeOut);
這些API建議應該monitor其回傳值以確保執行無誤..

以nonoverlapped I/O的方式來設計,主要是用timeout來控制,防止程式長時間被咬住
若採用overlapped I/O則是利用kernel object及API來處理同步..
但還是必須注意上述問題..
作者 : jack0128(bm)
[ 貼文 6 | 人氣 2695 | 評價 0 | 評價/貼文 0 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2006/6/22 下午 05:33:31
>看起來 WriteFile() 跟 RaedFile() 像是在同一台PC上分兩個Thread執行??
>且用的是同一個RS232 port將RX,TX互接 (亦即ReadFile跟WriteFile用的為同一個handle)??
>
>兩個Thread 共用同一裝置應該必須有一機制來避免數個Thread同時去存取..
>這邊的碼似乎沒有處理這部分..
>這個建議先將ReadFile註解掉看WriteFile是否變順暢即可確認
>還有
>SetCommState(comhandle,&dcb);
>SetupComm(comhandle,2048,1024);
>SetCommTimeouts(comhandle,&TimeOut);
>這些API建議應該monitor其回傳值以確保執行無誤..
>
>以nonoverlapped I/O的方式來設計,主要是用timeout來控制,防止程式長時間被咬住
>若採用overlapped I/O則是利用kernel object及API來處理同步..
>但還是必須注意上述問題..
>

這位大大您好,謝謝您這麼熱心的回答我的問題,的確如你所說,把ReadFile拿掉後,WriteFile變得很順暢,不過我writefile並沒有特別開一個thread去執行,而是以手動的方式
去執行,也就是我開一個EditBox和一個button去填入和傳送要寫入的資料,還有你所說的
SetCommState(),SetupComm(),SetCommTimeouts()我在程式都有加判斷式看是否
執行有誤,不過於由篇幅有限,無法全部po上來,這些狀態都一一確認過了是ok的,
而且如你所說ReadFile()和WriteFile()是用同一個handle,請問有沒有比較好的方法來避免READ和WRITE同時存取呢?
作者 : quickwolf(疾風之狼) 貼文超過200則
[ 貼文 258 | 人氣 1837 | 評價 1420 | 評價/貼文 5.5 | 送出評價 11 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
主題發起人jack0128註記此篇回應為很有道理 2006/6/22 下午 06:43:00
處理UI的部分算是主執行緒,另外開一個Thread (工作執行緒)
所以你的程式(process)裡至少有2個Thread同時在執行..

若是不使用overlapped I/O的話,目前有想到2種方法來寫:
法一:
     利用Critical Section之類的同步物件將WriteFile,ReadFile包住
     例:
     while(1)
     {
     EnterCriticalSection(&csFileSync);
     ReadFile(handle,&RxdBuffer,1,&dwNoByte,NULL);
     LeaveSection(&csFileSync);
     ...

     EnterCriticalSection(&csFileSync);
     WriteFile(...)
     LeaveSection(&csFileSync);
     但此種方法若設定read timeout的話會嚴重影響效能,建議將read timeout
     設0,每次buffer中若無資料則立即返回,否則會卡到WriteFile()

法二:
     Read thread用呼叫 MsgWaitForMultipleObjects() 等待事件觸發
     待接收到主執行緒送出觸發事件後才去讀取資料..
     等待時還必須處理Windows Message否則會卡住(因為Read thread 有使用MFC物件: ListBox)
    
     主執行緒在成功寫出資料後才去送觸發事件,而且開始寫資料前必須確認ReadFile()
     已完成(這邊簡單的方法就是用CriticalSection(法一),或一樣去等待Read Thread的觸發)
     這樣就可避免兩個執行緒搶用同一個裝置
    
方法二須要了解較多MultiThread的內容,寫起來複雜的多,但效率較佳
這是之前相關的討論,希望會有幫助:
http://www.programmer-club.com/pc2020v5/forum/showsametitle.asp?board_pc2020=vc&id=25625&szKeyword=Wait&selectmethod=subject
作者 : jack0128(bm)
[ 貼文 6 | 人氣 2695 | 評價 0 | 評價/貼文 0 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2006/6/23 上午 01:35:58
謝謝疾風之狼所提出的方法,我會努力試看看的,由於我剛跨入這個領域,所以有很多地方都不太懂,謝謝您好心的回答!!感恩感恩!!^^

 板主 : 青衫 , Raymond
 > Visual C++ - 討論區
 - 最近熱門問答精華集
 - 全部歷史問答精華集
 - Visual C++ - 知識庫
  ■ 全站最新Post列表
  ■ 我的文章收藏
  ■ 我最愛的作者
  ■ 全站文章收藏排行榜
  ■ 全站最愛作者排行榜
  ■  月熱門主題
  ■  季熱門主題
  ■  熱門主題Top 20
  ■  本區Post排行榜
  ■  本區評價排行榜
  ■  全站專家名人榜
  ■  全站Post排行榜
  ■  全站評價排行榜
  ■  全站人氣排行榜
 請輸入關鍵字 
  開始搜尋
 
Top 10
評價排行
Visual C++
1 青衫 11070 
2 Raymond 10090 
3 Clier 7630 
4 小約翰 2500 
5 Cog 2030 
6 coco 1870 
7 aming 1410 
8 牧童哥 1400 
9 r2109 1380 
10 Akira 1350 
Visual C++
  專家等級 評價  
  一代宗師 10000  
  曠世奇才 5000  
  頂尖高手 3000  
  卓越專家 1500  
  優秀好手 750  
Microsoft Internet Explorer 6.0. Screen 1024x768 pixel. High Color (16 bit).
2000-2019 程式設計俱樂部 http://www.programmer-club.com.tw/
0.203125