vic asked in 電腦與網際網路程式設計 · 1 decade ago

關於gps資料抓取問題(使用C++ Builder 6開發)

先付上程式碼

rs232跟結構都寫好了,這是判斷的程式碼部分

while (hPort != INVALID_HANDLE_VALUE)

{

WaitCommEvent (hPort, &dwCommModemStatus, 0);

if (dwCommModemStatus & EV_RXCHAR)

{

if ((dwBytesTransferred == 1)&(Byte == '$'))

{char info [ ] = {'\0'};

int i, j;

for (i = 1; i <= 5; i++)

{ ReadFile (hPort, &Byte, 1, &dwBytesTransferred, 0);

strcat(info, &Byte); }

char GPS_info[ ]={'\0'};

j = 0;

do

{ReadFile (hPort, &Byte, 1, &dwBytesTransferred, 0);

if (Byte != ',')

{strcat(GPS_info, &Byte);}

else

{j = j +1;

if ((info[1]== 'G')&(info[2]=='P')&(info[3]=='G')&(info[4]=='G')&(info[5]== 'A'))

{ if (j == 1) GGA_info.strUttcTime = GPS_info;

if (j == 2) GGA_info.varLatitude = GPS_info;

if (j == 3) GGA_info.strNSIndicator = GPS_info;

if (j == 4) GGA_info.varlongitude = GPS_info;

if (j == 5) GGA_info.strEWIndicator = GPS_info;

if (j == 6) GGA_info.strPositionFix = GPS_info;

if (j == 7) GGA_info.strSatsUsed = GPS_info;

if (j == 8) GGA_info.strIIDOP = GPS_info;

if (j == 9) GGA_info.strAltitude = GPS_info;

if (j == 10) GGA_info.strAltUnits = GPS_info;

if (j == 11) GGA_info.strGeoid = GPS_info;

if (j == 12) GGA_info.strSepUnits = GPS_info;

if (j == 13) GGA_info.strDgpsAge = GPS_info;

if (j == 14) GGA_info.strDgpsid = GPS_info;}

GPS_info = '\0';

}

}

while (dwBytesTransferred == 1);

}

}

}

這台gps資料進來後會是像以下這樣

$GPGGA,48428.54,......(以下略)

他們之間是用","做分閣,所以有寫道判斷","的部分

而希望步驟為這樣

資料進來>判斷點把資料分開>判斷開頭的字元>找到對應結構並放入資料

>放完後清空GPS_info>等待下一個資料

而現組譯後,會有錯誤

錯誤都是

if (j == 數值) 結構定義子.結構內成員 = GPS_info;

例如:(if (j == 1) GGA_info.strUttcTime = GPS_info;)

這一系列的產生的

而錯誤全為

[C++ Error] gps1.cpp: E2277 Lvalue required

而且

GPS_info = '\0';

清空已定義的GPS_info這一段組譯也是不通過,錯誤依然為

[C++ Error] gps1.cpp: E2277 Lvalue required

請問是否那邊有錯誤呢?

又如何更正呢?

以及

strcat用法

若我這樣設定

strcat(A,B)這樣會把A跟B給結合對吧?

例如A="G" B="P"

strcat(A,B)候

會變成A="GP"

這是我的想法,但是那A為什麼卻還是被認定成字元呢?

因為有高手能幫我解答

以上感激

Update:

先付上我結構程式碼

struct GGA

{

char strUttcTime [20];

char varLatitude [20];

.

.

}GGA_info;

(因為字數關係省略)

Update 2:

先感謝shlinho的回答

但我在書上看到的結構用法

都是說

struct A

{

int a;

int b;

}A_info;

A_info.a=5;

這樣的話a就會被放入5

還是說因為是字串的關係所以要使用

strcpy呢?

以上期待指教

Update 3:

再次感謝shlinho的解答

"你的 info 與 GPS_Info 操作有誤"這點

若我改成這樣

char info [6];(這邊資料只有6英數子)

char GPS_info[100];(這邊可能很多)

是否正確呢?

還有關於

A_info.a=5;

shlinho大,你的意思是說,這種寫法,並不支援字串的傳輸

所以要用strcpy?是這樣意思嘛?

Update 4:

還有有人說

strcat(info, &Byte);

是有問題的,但我在組議上是可以通過的

可否也請shlinho幫忙看看呢?

最後還有一個

GPS_info跟info,都要在清空後使用

如何清空已經定義過的字串呢?

以上感謝回覆,也希望能繼續賜教

PS.若覺得這樣回覆過於麻煩,可以利用小弟及時通

good3125@yahoo.com.tw跟小弟聯絡

Update 5:

感謝阿福大的回答

strcat方面的問題,我已經了解了

程式也改寫過了

照shlinho大的方式,可以讓結構過關

也可以讓組譯,但產生出的來執行檔,還是會有問題

問題也如shlinho大所說,會有Access Violation

的錯誤..

但小弟也已經給了, info 與 GPS_Info 足夠的空間了

Update 6:

製於shlinho大,所提供的原始碼

想在這裡請教一下

因為小弟的程式,實際上除了GGA系列

還有GSA、GLL的其他的系列

若要把其他系列也寫進去,請問該寫在哪邊呢?

小弟真的只是C新手..

以上感謝回覆,也希望繼續賜教

Update 7:

shlinho大,你所提供的程式碼

我已經改好,而且可以使用,也能組議通過

但是還是有些錯誤,我試圖

把linebuf給顯現出來,但是沒想到顯現出來的不如我預期

GGA應該會有14個資料

但是linebuf顯現出來,只有兩個

$GPGGA,48480.185(緯度)

後面的都沒有被讀到....

Update 8:

小弟猜想

是不是

q++;

pField = q + 1;

這段的問題呢?

而我也在這裡加上j++變成

q++;

pField = q + 1;

j++;

因為看shlinho大的程式,似乎沒有處理到j...

以上感謝回覆,也希望賜教

(總覺得指給20點好像太少了...)

Update 9:

也很好奇shlinho大,你q == 0xD || *q == 0xA

這段的意思,若可以煩請說一下

2 Answers

Rating
  • 生鏽
    Lv 5
    1 decade ago
    Favorite Answer

    你的 GGA_info 的結構定義不允許你作這種指派工作。假如 strUttcTime 的宣告是 char [14],要指派其內容,就應該使用 strcpy(GGA_info.strUttcTime, GPS_info);

    另外有關 strcat,它的運作只適用於 null terminated string。A 與 B 都是 null terninated string 時,strcat(A, B) 應該會成功的如你所預料的結果。建議用 debug watch 來看一下 A 與 B 的內容是否如你的預期。

    2008-02-18 10:16:26 補充:

    int 型別的長度 (在該執行平台上) 是固定的,所以你直接指派內容時,編譯器可以知道如何將數值資料放進那個變數裡。但是對其他型別來講,例如 char [20],它被 allocate 的大小是 20 bytes,但是你可以塞進去 3 個 bytes 的資料,也可以塞進 18 bytes,多出來的記憶體沒用到也沒關係。所以程式必須明確的指定要處理記憶體的方式。上面的回答利用 strcpy 來複製字串到目標變數 allocate 的記憶體,直到碰到 null char 為止。

    2008-02-18 10:22:57 補充:

    另外你的 info 與 GPS_Info 操作有誤,程式執行時應該會有 Access Violation 的錯誤。你應該 allocate 足夠的記憶體空間給他們使用。

    2008-02-18 16:39:18 補充:

    我按照 NMEA 的規格改寫了程式 (但是沒有 debug,就留給你了)

    char linebuf[1024], *p, *q, *pField;

    p = linebuf;

    while (hPort != INVALID_HANDLE_VALUE)

    {

    WaitCommEvent (hPort, &dwCommModemStatus, 0);

    if (dwCommModemStatus & EV_RXCHAR == EV_RXCHAR)

    {

    if( ReadFile (hPort, p, 1, &dwBytesTransferred, 0) == 0)

    break;

    2008-02-18 16:39:27 補充:

    if( *p == 0xA )

    {

    // one line is received

    // does the line start with "$GPGGA"?

    if(strncmp(linebuf, "$GPGGA,", 7) == 0)

    {

    // this is the line that we want!

    // parse the line

    memset(&GGA_info, 0, sizeof(GGA_info));

    int j = 1;

    pField = linebuf + 7;

    2008-02-18 16:39:57 補充:

    for(q = pField, *q != 0; q++)

    {

    if(*q == ',' || *q == 0xD || *q == 0xA)

    {

    *q = 0;

    if (j == 1) GGA_info.strUttcTime = pField;

    if (j == 2) GGA_info.varLatitude = pField;

    if (j == 3) GGA_info.strNSIndicator = pField;

    if (j == 4) GGA_info.varlongitude = pField;

    if (j == 5) GGA_info.strEWIndicator = pField;

    2008-02-18 16:40:16 補充:

    if (j == 6) GGA_info.strPositionFix = pField;

    if (j == 7) GGA_info.strSatsUsed = pField;

    if (j == 8) GGA_info.strIIDOP = pField;

    if (j == 9) GGA_info.strAltitude = pField;

    if (j == 10) GGA_info.strAltUnits = pField;

    if (j == 11) GGA_info.strGeoid = pField;

    if (j == 12) GGA_info.strSepUnits = pField;

    2008-02-18 16:40:27 補充:

    if (j == 13) GGA_info.strDgpsAge = pField;

    if (j == 14) GGA_info.strDgpsid = pField;

    q++;

    pField = q + 1;

    }

    }

    // Do something about the GGA_info here

    ...

    }

    // reset the pointer

    p = linebuf;

    }

    2008-02-18 16:40:37 補充:

    else

    {

    // advance pointer to the next position

    p++;

    // TODO: ensure the pointer not exceeding the linebuf size

    }

    }

    }

    2008-02-18 16:44:28 補充:

    所有的程式語言都有 programming reference,例如 strcat,你可以去查相關的文件,會比較清楚。(提示: strcat 與許多 string function 一樣都只適用於 null termicated string)

    2008-02-18 16:50:58 補充:

    直接 copy 你的程式,忘記改掉 XD

    if (j == 1) GGA_info.strUttcTime = pField;

    請改為

    f (j == 1) strcpy(GGA_info.strUttcTime, pField);

    其他各行也依此修改。

    2008-02-18 16:51:26 補充:

    上面的程式主要是一開始就有一個足夠大的 buffer (char[1024]) 用來接收資料,當碰到 new line character,就表示已經接收到一行資料,可以開始分析這一行的語法。否則將 pointer 往前移到下一個位置繼續接收資料。同樣的 pointer 操作方法也使用在分析該行內容上,我把每一個逗點或是行尾換為 null terminated char,就可以交給 strcpy 處理。

    2008-02-24 01:02:15 補充:

    為了容易撰寫程式,你可以把每一種不同紀錄的內容放在不同的 function 裡面,然後檢查收到的每一行資料的開頭 (同樣用 strncmp 來判斷),來決定到底要呼叫哪個 function,例如:

    if(strncmp(linebuf, "$GPGGA,", 7) == 0)

    process_GGA(linebuf);

    else if(strncmp(linebuf, "$GPGSA,", 7) == 0)

    process_GSA(linebuf);

    ...

    2008-02-25 00:27:59 補充:

    沒錯,我忘了 j++

    XD

    2008-02-25 00:30:55 補充:

    有關 0xD, 0xA:每筆 NMEA 的紀錄都是以換行符號為結束,所以程式一直等碰到 0xA 才算結束一行,我手邊的 GPS 紀錄,一行的結束其實是 0xD (ASCII CR) 與 0xA (ASCII NEW LINE)。

    所以在每一個欄位的結束可能是逗點或換行符號。

  • 1 decade ago

    我覺得有兩個問題您必須先釐清:

    第一個

    strcat定義是這樣的:

    char * strcat ( char * destination, const char * source );

    strcat()不會自行配置空間

    所以destination必須要有足夠的空間給source才不會發生錯誤

    第二個

    陣列宣告時,必須告知陣列大小,若沒有陣列大小的宣告,

    也得給予初始值。

    int abc[10] = {0};

    double xy[10] = {0.0};

    char sttring[10] = {'\0'};

    請先釐清這兩個問題,再來解決程式裡有爭議的語法。

    如有任何疑問,請到巨匠電腦各分校詢問C或C++課程

    或教授C或C++課程老師,我相信老師會盡力協助您,

    謝謝!

    Source(s): 巨匠電腦C與C++課程教材
Still have questions? Get your answers by asking now.