[c]Zonder printf geen goede output

Pagina: 1
Acties:

  • I-King
  • Registratie: Maart 2003
  • Laatst online: 23:56
Beste Tweakers,

Ik ben voor een project op de faculteit Industrial Design in Eindhoven bezig met het uitlezen van een GPS apparaat. Het apparaat stuurt via mini usb seriële data naar mijn micro controller (pic: 18f4550).

Het probleem is nu als volgt. Ik kan de gegevens perfect uitlezen op de computer via Hyperterminal/Realterm. Ik gebruik dit dan ook om uit te lezen waar het een en ander goed of fout gaat. Nu gaat het uitlezen van deze data goed, als ik een printf() gebruik om een bufferoutput te genereren. (regel 114) Laat ik deze printf() functie weg, dan bereken ik corrupte gegevens bij de coordinaten.(Output regel 118)

Ik hoop dat jullie mij kunnen helpen. Ik weet dat de code niet 100% efficiënt zal zijn, maar als jullie mij kunnen wijzen in de richting waar de fout kan zitten ben ik al heel erg geholpen. Het probleem is namelijk dat het met printf() wel werkt, maar op andere stappen fout gaat. Ik vermoed dan ook dat ergens intern iets fout gaat. Ik ben geen programmeur, ik heb redelijk oppervlakkige kennis, dus ik hoop dat jullie daar rekening mee kunnen houden. Het commentaar heb ik er nu snel bijgezet, kan zijn dat het niet overal duidelijk is.

De output van de GPS ontvanger:
code:
1
2
3
$GPGGA,081254.000,5126.9197,N,00529.1739,E,1,03,11.0,14.5,M,47.3,M,,0000*51
$GPRMC,081254.000,A,5126.9197,N,00529.1739,E,0.00,68.76,260508,,,A*56
$GPVTG,68.76,T,,M,0.00,N,0.0,K,N*3D


Mijn main.c:
C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#include <p18f4550.h>   // library definitions for PIC 18f4550
#include <stdio.h>
#include "serial.h"     // Serial communication
#include "stdlib.h"

// Code required for bootloader
// and serial interrupt handling

void Timer1Interrupt(void);         //Interrupt service routine prototype

extern void _startup (void);
#pragma code _RESET_INTERRUPT_VECTOR = 0x000800
void _reset (void)
{
    _asm goto _startup _endasm
}
#pragma code

#pragma code _HIGH_INTERRUPT_VECTOR = 0x000808
void _high_ISR (void)
{
#ifdef _SERIAL_RX_ON_INTERRUPT
    _asm 
        goto SerialReceiveInterrupt 
    _endasm
#else
    ;
#endif      
}
#pragma code

#pragma code _LOW_INTERRUPT_VECTOR = 0x000818
void _low_ISR (void)
{
;
}
#pragma code

#pragma interruptlow Timer1Interrupt    //High priority interrupt service routine
void Timer1Interrupt(void)
{
;
}

// initialisation GPS
void readLine(void);
int readCoordinates(void);
char ReceiveBuffer[50];
unsigned long coorN[3]; //latitude received by GPS receiver
unsigned long coorE[3]; //longtitude received by GPS receiver

// Initialise hardware
//
void init(void)
{
    // Switch off interrupts
    INTCONbits.GIE = 0;
    TRISA = 0b11111111;
    TRISB = 0b00000000;
    TRISD = 0b00000000;
    PORTA = 0b00000000;
    PORTD = 0b00000000;
    ADCON1 = 0b00001111;
}

void readLine(void)
{
    char c = 0;
    int index = 0;

    ReceiveBuffer[0] = '\0';
    do
    {
        if (SerialDataAvailable())
        {
            c = SerialReceive();

            if (c >= ' ' && c <= '~'){ //alleen leesbare karakters inlezen.

                if (index == 0 && c !='$') //alleen de else uitvoeren als er een dollarteken ontvangen wordt / er al tekens ontvangen zijn dus index != 0
                {
                }
                else 
                {
                    if(index < 49){ //voorkomt bufferoverflow
                        ReceiveBuffer[index++] = c; 
                    }
                    else{
                        break;
                    }
                    if (c == ',' && ReceiveBuffer[3] != 'R') //Check bij de eerste komma of de juiste regel ontvangen wordt.
                    {
                        ReceiveBuffer[0] = '\0';
                        break;
                    }
                }
            }
        }
    }
    while (c != 'E' ); //doorgaan met ontvangen tot de E ontvangen wordt. Als dat het geval is, is de regel voldoende afgemaakt.
    ReceiveBuffer[index] = '\0';
}

int readCoordinates(void)
{
    int i;
    unsigned long atoltest;

    coorN[0] = 0;
    coorE[0] = 0;
    
    if (ReceiveBuffer[0] == '$' && ReceiveBuffer[1] == 'G' && ReceiveBuffer[2] == 'P' && ReceiveBuffer[3] == 'R' && ReceiveBuffer[4] == 'M' && ReceiveBuffer[5] == 'C' && ReceiveBuffer[6] ==',') //check of de juiste regel is ontvangen.
    {
//      printf("line read: %s\r\n", ReceiveBuffer); //indien deze printf functie uitstaat, krijg ik bij de volgende corrupte code
        coorN[0] = 10000*atol(&ReceiveBuffer[20]) + atol(&ReceiveBuffer[25]); //leest de eerste 4 cijfers in tot aan de punt en 4 cijfers erna. Maakt er 8cijferige unsigned long van.
        coorE[0] = 10000*atol(&ReceiveBuffer[34]) + atol(&ReceiveBuffer[38]); // idem als boven, alleen dan de oost coordinaat
            
//      printf("north equals %lu and east equals %lu\n\r", coorN[0], coorE[0]);
        return 1;
    }
    else 
    {   
        return 0; 
    }
}
// voids program

// Main program
//
void main(void)
{
    unsigned char c;
    
    // Initialise microcontroller ports
    init();

    SerialOpenConnection(baud_38400);
    while(1) {
        do
        {
            readLine();
        }
        while (!readCoordinates()); // loop readLine until a good line is received
    }
}


Mijn serial.c en serial.h is aangeleverd door de faculteit, ik denk dan ook niet dat ik dit in eerste instantie op het forum mag zetten. In principe is het gewoon vreemd dat als ik die eerste printf() functie aanzet (regel 114) dat ik dan corrupte output krijg bij regel 118. Ik kom er zelf totaal niet meer uit waar ik de fout moet zoeken.

Ter illustratie, ik krijg de bovenste 4 regels binnen als ik de printf functies beide aanzet. De onderste 4 regels krijg ik binnen als ik de bovenste printf() functie uitzet. Ik ben het spoor bijster, ik hoop dat iemand me kan helpen!

Afbeeldingslocatie: http://www.driekes.nl/files/uploads/realterm.jpg

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Ik vind je code een beetje rommelig, maar ik zie zo snel niet een echte fout. Bij dit soort problemen denk ik altijd meteen aan buffer over-runs, maar dat lijkt niet het geval te zijn. De tweede veelvoorkomende fout is dan het linken aan verschillende CRT-libraries, bijvoorbeeld een single-threaded release voor je applicatie, en een multi-threaded debug voor een statische library.

  • I-King
  • Registratie: Maart 2003
  • Laatst online: 23:56
Zoijar schreef op maandag 26 mei 2008 @ 12:40:
Ik vind je code een beetje rommelig, maar ik zie zo snel niet een echte fout. Bij dit soort problemen denk ik altijd meteen aan buffer over-runs, maar dat lijkt niet het geval te zijn. De tweede veelvoorkomende fout is dan het linken aan verschillende CRT-libraries, bijvoorbeeld een single-threaded release voor je applicatie, en een multi-threaded debug voor een statische library.
Naja zoals ik al zei, ben geen ICT'er van beroep of programmeur. Bij onze opleiding krijgen we er alleen mee te maken om prototypes uit te werken. Zodoende kom ik dus op dit probleem uit. Ik ga eens uitzoeken wat je met de 2e mogelijkheid precies bedoelt :)

Maar het vreemde is dat de printf() functie normaliter toch 0 invloed moet hebben op het programma? Wat kan er mogelijk anders lopen als ik een printf() functie uitzet?

  • pkuppens
  • Registratie: Juni 2007
  • Laatst online: 17-11 23:50
I-King schreef op maandag 26 mei 2008 @ 13:18:
[...]

Naja zoals ik al zei, ben geen ICT'er van beroep of programmeur. Bij onze opleiding krijgen we er alleen mee te maken om prototypes uit te werken. Zodoende kom ik dus op dit probleem uit. Ik ga eens uitzoeken wat je met de 2e mogelijkheid precies bedoelt :)

Maar het vreemde is dat de printf() functie normaliter toch 0 invloed moet hebben op het programma? Wat kan er mogelijk anders lopen als ik een printf() functie uitzet?
Waar C nogal een handje van heeft is dat als je op plek 1 over de grenzen van een array heen schrijft, je het probleem pas tegenkomt op een andere plek, bv. als er weer eens een nieuwe functie aangeroepen wordt, de functie pointer wordt dan op een corrupte stack gezet.

Kanshebbers/huiswerk.

1. ReceiveBuffer ophogen tot 1024 of iets dat ruim voldoende is.
(Functie call stack verplaatst dan naar een gebied dat door je data misschien niet geraakt wordt).

2. doe eens een prinft("tekst zonder mogelijk corrupte parameters\r\n");
(Dan weet je of het aan het uitvoeren van een functie call ligt, of aan parameters die corrupt zijn)

En anders later meer....

PS. if (strncmp(ReceiveBuffer, "$GPRMC,", 7) == 0) doet een string compare op de eerste 7 karakters, met 0 als er 0 verschil is dus ze gelijk zijn.

[ Voor 5% gewijzigd door pkuppens op 26-05-2008 14:42 ]


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 16-11 18:33
Ik heb sterk het vermoeden dat je ergens over je buffergrenzen gaat, een bug die met een call naar printf in de callstack niet zichtbaar is.

Verder zou ik je willen aanraden om het onlezen van de GPS string in een aantal stappen te doen ( controleren op een 'E' is bollox als je in het 'W' halfrond zit :P ), die GPS string heeft nl een aantal kenmerken:

- begint met '$'
- na de start delimiter volgen 5 characters die het sentence type aangeven
- eindigt met '*'
- na de eind delimiter volgt een checksum die een XOR is van alle tekens tussen begin en eindteken, hexadecimale notatie.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • I-King
  • Registratie: Maart 2003
  • Laatst online: 23:56
pkuppens schreef op maandag 26 mei 2008 @ 14:31:
[...]


Waar C nogal een handje van heeft is dat als je op plek 1 over de grenzen van een array heen schrijft, je het probleem pas tegenkomt op een andere plek, bv. als er weer eens een nieuwe functie aangeroepen wordt, de functie pointer wordt dan op een corrupte stack gezet.

Kanshebbers/huiswerk.

1. ReceiveBuffer ophogen tot 1024 of iets dat ruim voldoende is.
(Functie call stack verplaatst dan naar een gebied dat door je data misschien niet geraakt wordt).

2. doe eens een prinft("tekst zonder mogelijk corrupte parameters\r\n");
(Dan weet je of het aan het uitvoeren van een functie call ligt, of aan parameters die corrupt zijn)

En anders later meer....

PS. if (strncmp(ReceiveBuffer, "$GPRMC,", 7) == 0) doet een string compare op de eerste 7 karakters, met 0 als er 0 verschil is dus ze gelijk zijn.
1. Ik heb ReceiveBuffer verhoogd naar 150 dat zou in principe meer dan voldoende moeten zijn. Hoger gaat hij niet, dan zit denk ik het geheugen van de chip vol. Bji het compileren geeft hij dan een error.

2. Ik heb een aantal 'kale' printf() geprobeerd zoals ook onderstaand te zien is. Het ligt nogal aan de lengte van de printf voordat ik goede waardes uitkrijg. Zoals je ziet moeten dit minimaal 22 karakters zijn.
Afbeeldingslocatie: http://www.driekes.nl/files/uploads/printfstringlengte.jpg

Als ik de printf op de eerste positie uitzet (regel 114) en gewoon een string print zonder parameters op regel 118 dan krijg ik ook perfecte output.

Ik ben verder echter een aardige onbekende in de precieze details van programmeren. Bij mijn opleiding wordt een prototype als ondersteuning verwacht. Tot bepaalde mate mag dit gefaked worden, maar aangezien ik er zo dichtbij zit, wil ik dit graag volledig werkend krijgen. Ik heb geprobeerd met de code verder te werken inclusief printf, maar dit leidt verderop in de code tot problemen.

Ik ben dus niet helemaal thuis in alle termen. Zoals ik het nu begrijp worden alle parameters en functies etc op een bepaalde geheugenlocatie opgeslagen. Bij een overschrijding van de buffer kan dat leiden tot corrupte code in andere functies. Ik begrijp alleen niet helemaal wat de invloed van een printf functie is (met een output die groot genoeg is).
farlane schreef op maandag 26 mei 2008 @ 19:53:
Ik heb sterk het vermoeden dat je ergens over je buffergrenzen gaat, een bug die met een call naar printf in de callstack niet zichtbaar is.

Verder zou ik je willen aanraden om het onlezen van de GPS string in een aantal stappen te doen ( controleren op een 'E' is bollox als je in het 'W' halfrond zit :P ), die GPS string heeft nl een aantal kenmerken:

- begint met '$'
- na de start delimiter volgen 5 characters die het sentence type aangeven
- eindigt met '*'
- na de eind delimiter volgt een checksum die een XOR is van alle tekens tussen begin en eindteken, hexadecimale notatie.
Ja dat weet ik, maar de oost/west notatie bevat altijd een E zoals ook in mijn eerste post te zien is. Hier controleerde ik gewoon op omdat ik dan kan stoppen met het inlezen van de regel omdat ik dan alle informatie heb die ik nodig heb. Ik had inderdaad ook opgezocht wat alles betekent in de GPS output.

  • The End
  • Registratie: Maart 2000
  • Laatst online: 21:56

The End

!Beginning

Ligt het nou aan mij of is dit een aangepaste versie van printf die ook de CR en LF tekens laat zien of doet je console dat?

In de eerste regel doe je trouwens CRLF (\r\n) en in de andere LFCR (\n\r).

het lijkt erop dat die 'corrupte' tekens gegenereerd worden door die printf (of door de console) ze zien er namelijk hetzelfde uit als die CRLF tekens.

[ Voor 27% gewijzigd door The End op 27-05-2008 14:28 ]


  • Jewest
  • Registratie: Juni 2007
  • Laatst online: 13-11 14:43
simpele vraag, de serial send is blocking?
of wordt de data is een buffer array gestopt?

Flickr
Canon 7D + Glas + Licht
Komt het rot over dan bedoel ik het anders en taalfouten zijn inbegrepen.


  • I-King
  • Registratie: Maart 2003
  • Laatst online: 23:56
The End schreef op dinsdag 27 mei 2008 @ 14:27:
Ligt het nou aan mij of is dit een aangepaste versie van printf die ook de CR en LF tekens laat zien of doet je console dat?

In de eerste regel doe je trouwens CRLF (\r\n) en in de andere LFCR (\n\r).

het lijkt erop dat die 'corrupte' tekens gegenereerd worden door die printf (of door de console) ze zien er namelijk hetzelfde uit als die CRLF tekens.
Ik gebruik realterm om de output van de microcontroller uit te lezen. Deze is ingesteld op ASCII, hij laat dus alles precies zien wat hij binnenkrijgt, dus ook \r\n. De 'corrupte' tekens zijn dus ook waardes die je bijvoorbeeld niet ziet als je ANSI weergave instelt.
Jewest schreef op dinsdag 27 mei 2008 @ 14:34:
simpele vraag, de serial send is blocking?
of wordt de data is een buffer array gestopt?
Doel je hier op de printf funcie? Of het verzenden van de GPS ontvanger?

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 16-11 18:33
I-King schreef op dinsdag 27 mei 2008 @ 14:17:
Ja dat weet ik, maar de oost/west notatie bevat altijd een E zoals ook in mijn eerste post te zien is.
Als je programma alleen op het oostelijk halfrond hoeft te functioneren wel ja
Hier controleerde ik gewoon op omdat ik dan kan stoppen met het inlezen van de regel omdat ik dan alle informatie heb die ik nodig heb.
De checksum staat helemaal achteraan in de sentence.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.

Pagina: 1