USART PIC18 XC8

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Lullen
Inlägg: 140
Blev medlem: 16 oktober 2006, 17:37:32

USART PIC18 XC8

Inlägg av Lullen »

Så då var det dags för dagens fråga, hoppas ni orkar med mig :)

Jag har som sagt en PIC18F45K20 och kör med plib och MPLAB X. Den är på 16MHz och klarar 4x PLL med den interna oscillatorn.
Har suttit hela helgen och fram tills igår och försökt fixa lite buggar med min kod som jag gjort och det visade sig vara en hel del så har kopierat delar av koden till ett nytt projekt för att enklare kunna luska fram vad som är problemet. Jag tror att jag har tre lösningar som jag dock inte lyckas implementera.

1. Skicka kommando för att stänga av all output förutom $GPRMC
2. Skicka kommando för att öka baud rate till 115200 (möjliga är:4800,9600,14400,19200,38400,57600,115200)
3. Sätta PICen i 64MHz läge via PLL

Grunden för min USART kod kommer från:
http://singularengineer.com/programming ... 8f-serial/

Det som fungerar är att läsa av en bokstav i taget och sätta på några LEDs när jag får in en hel $GPRMC och om jag får in en $GPGGA sätta på alla LEDs. Jag har en interrupt på RX. Jag försöker skicka kommandot för att endast få $GPRMC men $GPGGA LEDsen fortsätter att blinka, dvs jag får in båda. Fixas med lösning 2.

Det andra problemet är att jag hela tiden vill parsa NMEA stängarna och skapa upp en struct som innehåller longitude, latitude, speed och en timestamp. Jag vet att min design i koden inte är optimal då jag gör allt detta i min interrupt funktion. Men då detta måste ske innan nästa sträng har kommit så ser jag inte att detta egentligen skulle skapa något problem. Problemet är i alla fall att när jag lägger till funktionen så slutar min interrupt att anropas. Vad detta beror på chansar jag mig till att min kod är för långsam och därför blir det något problem (buffer overflow?). Så tanken är att lösa detta genom öka hastigheten på PICen och baud rate för att ha mer tid på mig helt enkelt. Dvs lösning 1-3. Det fungerar om jag sätter en break point innan den långsamma koden ska köras men bara några gånger.

Det tredje problemet har med de två andra att göra och det är att jag inte lyckas skicka mina kommandon. Min första tanke var att sätta upp USART inkl interrupts och sen skicka mina kommandon. Då det inte fungera tänkte jag att det kan ha något att göra med att RX blockerar min TX. Så min lösning var att öppna upp USART och direkt skicka mina kommandon för att sen sätta på interrupts för RX. Det som hände då var att mina interrupts inte anropades och för att lösa det var jag tvungen att stänga USART och öppna upp den igen.

Så varför kan jag inte skicka data när jag kan ta emot den? USART måste vara helt korrekt uppsatt och jag har dubbelcheckat manualen för kommandona och även denna länk visar att det borde fungera (även om han skickar en (int *) till putsUSART() som jag också testat)
http://adafruit.com/forums/viewtopic.php?f=31&p=179239

Varför dör min USART?
Varför fungerar inte min USART när jag sätter PLLEN = 1? Har självklart ökat min baud till 416 när jag sätter på den, har även testat att ha kvar 113. Min baud rate ska vara 9600 från början.


Koden för USART RX interrupt:

Kod: Markera allt

void handleUsartRx(){
    struct Position position = getPosition();
    if(position.fixed != 1){
        PIR1bits.RCIF = 0;
        return;
    }
    PIR1bits.RCIF = 0; // clear rx flag
}
Variabler:

Kod: Markera allt

char rx;
char receivedData[100];
int rxIndex = 0;
int led = 0;
Koden för inläsning av char som skickats från GPSen

Kod: Markera allt

struct Position getPosition(){
    while(BusyUSART());
    struct Position position;
    position.fixed = -1;
    rx = ReadUSART(); //read the byte from rx register

    if(rx == '$'){
        //We got a start char!
        rxIndex = 0;
        for(int i = 0; i < 100; i++){
            receivedData[i] = '\0';
        }
    }
    if(rxIndex < 100){
        receivedData[rxIndex] = rx;
        rxIndex++;
    }else{
        rxIndex = 0;
    }
    if(rx == '\n' && strstr(&receivedData,"$GPRMC")){
        //Should calculate checksum first
        //if(checksumIsOk())
        LATD = led;
        led++;
        if(led == 0xFF){
            led = 0;
        }
        //denna funktion gör att jag inte får interrupts
        //position = createPosition();
    }else if(rx == '\n' && strstr(&receivedData,"$GPGGA")){
        LATD = 0xFF;
    }
    return position;
}
Min main:

Kod: Markera allt

void main(int argc, char** argv) {
    SetupClock();
    
    initPic(); //fungerar som den ska
    initUsart();
    initGps();
    //initTimer();
    
    while(1) //infinite loop
    {
    }
}
Kod för initiering av USART

Kod: Markera allt

void initUsart(){
    TRISCbits.RC6 = 0; //TX pin set as output
    TRISCbits.RC7 = 1; //RX pin set as input

    CloseUSART();
    UART1Config = USART_TX_INT_OFF & USART_RX_INT_OFF & USART_ASYNCH_MODE & USART_EIGHT_BIT & USART_BRGH_HIGH ;
    baud = 103;//51 for 8MHz;
    OpenUSART(UART1Config,baud);

    RCIF = 0; //reset RX pin flag
    RCIP = 1; //High priority
    RCIE = 1; //Enable RX interrupt
    PEIE = 1; //Enable pheripheral interrupt (serial port is a pheripheral)

    ei(); 
}
Kod för initiering av GPS

Kod: Markera allt

void initGps(){

    char strr[] = "$PMTK314,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*29\r\n";
    sendCmd(strr);
}

void sendCmd(char *str){
    while(BusyUSART());
    putsUSART(str);
//    while(BusyUSART());
}
Vart många frågor men hoppas ni orkar läsa igenom allt och kan hjälpa mig att lösa dessa problem!
Användarvisningsbild
Swech
EF Sponsor
Inlägg: 4750
Blev medlem: 6 november 2006, 21:43:35
Ort: Munkedal, Sverige (Sweden)
Kontakt:

Re: USART PIC18 XC8

Inlägg av Swech »

Det är generellt mycket bättre att ha två buffertar som din UART interrupt fyller på

Uarten tar imot ett tecken och lägger i buffer 1.....
detta upprepas tills bufferten är full eller du får \n
Då växlar du buffert för uarten. nästa tecken läggs i buffert 2
Samtidigt talar du om för ditt huvudprogram att nu finns det data i buffert 1 som skall
behandlas.
När buffert 2 är full växlar systemet igen.

På så sätt så får du gott om tid att processa bufferten utan att missa tecken

Swech
Användarvisningsbild
Icecap
Inlägg: 26648
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: USART PIC18 XC8

Inlägg av Icecap »

Swech beskrev ytterst väl hur jag ville råda till att lösa allt.

När man väl har strängarna klara i en buffer är det snabbt att plocka ut den information man vill ha, gör man istället det tecken för tecken ska man göra en massa väntande och sekvensering.
Lullen
Inlägg: 140
Blev medlem: 16 oktober 2006, 17:37:32

Re: USART PIC18 XC8

Inlägg av Lullen »

Swech skrev:Det är generellt mycket bättre att ha två buffertar som din UART interrupt fyller på

Uarten tar imot ett tecken och lägger i buffer 1.....
detta upprepas tills bufferten är full eller du får \n
Då växlar du buffert för uarten. nästa tecken läggs i buffert 2
Samtidigt talar du om för ditt huvudprogram att nu finns det data i buffert 1 som skall
behandlas.
När buffert 2 är full växlar systemet igen.

På så sätt så får du gott om tid att processa bufferten utan att missa tecken

Swech
Jo exakt, jag har tänkt att göra det men tänkte ta det när jag börjar räkna på varvtider och visa det osv och inte när jag bara konverterar positionen till något hanterbart. Om jag i min interrupt inte hinner med att konvertera positionen så kommer buffert2 att hela tiden fyllas på medan buffert1 är okej. Så istället för att jag missar bokstäver vid inläsning från gps så kommer jag missa positioner. Så jag kommer bara flytta problemet egentligen. Sen måste jag kunna skicka kommandon i alla fall för GPSen klarar inte att skicka all data som den gör nu om jag ökar till 10Hz.
Icecap skrev:Swech beskrev ytterst väl hur jag ville råda till att lösa allt.
När man väl har strängarna klara i en buffer är det snabbt att plocka ut den information man vill ha, gör man istället det tecken för tecken ska man göra en massa väntande och sekvensering.
Jag hänger inte riktigt med på detta. När min buffer slutar med '\n' och innehåller "$GPRMC" (kanske bör ändra så att den startar med det för att inte söka igenom hela strängen) så kommer den hantera hela strängen. Innan fyller den bara på.
Eller jag kanske förstår! Om det tar säg 10sek att ta emot strängen på 10 tecken så har jag bara 1sek att ta och parsa hela strängen. Om jag lägger min parsning utanför en interrupt så har jag 10sek minus tiden som interrupten körs på mig att parsa innan nästa gång min buffert fylls på. Med andra ord kanske jag har 6sekunder på mig att parsa allt?
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: USART PIC18 XC8

Inlägg av sodjan »

Ja, det är nog så de menar. Interrupt rutinen (ISR) får fokusera på att
ta emot tecken och fylla på bufferterna. Sedan kör du tolkningen på
en komplett buffert i din main() kod samtidigt som den andra bufferten
fylls via din ISR. När en buffert är full växlar ISR'en buffert och sätter
en flagga som talar om att en viss buffert är klar för bearbetning.

Om du ändå inte hinner med att göra det som behövs, så finns det
helt enkelt inte processor cykler som räcker till och det hela får
designas om. Men det känns som lite osannolikt...
Lullen
Inlägg: 140
Blev medlem: 16 oktober 2006, 17:37:32

Re: USART PIC18 XC8

Inlägg av Lullen »

Okej då är jag med! Får lägga till det när jag kommer hem.
Men min parsning av meningarna är ju disablad pga detta problem så den lösningen kommer bara göra att jag hinner med att parsa. Denna funktion kommer jag försöka slå på när jag väl kan skicka mina kommandon. Lösningen kommer ju inte påverka min sändning då den ändå inte sker i min interrupt rutin. Så det måste vara något annat som är boven...
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: USART PIC18 XC8

Inlägg av sodjan »

Det är lite svårt att ha överblick, just nu
vet jag inte vad "sända" syftar på t.ex.
En annan sak...

Är inte detta:

Kod: Markera allt

void handleUsartRx(){
    struct Position position = getPosition();
    if(position.fixed != 1){
        PIR1bits.RCIF = 0;
        return;
    }
    PIR1bits.RCIF = 0; // clear rx flag
}
samma sak som:

Kod: Markera allt

void handleUsartRx(){
    struct Position position = getPosition();
    PIR1bits.RCIF = 0; // clear rx flag
}
Vad har if'en för funktion?
Sen så ska kanske inte getPosition köras alls från ISR'en, som sagt.
Lullen
Inlägg: 140
Blev medlem: 16 oktober 2006, 17:37:32

Re: USART PIC18 XC8

Inlägg av Lullen »

Jag som försökte göra det så tydligt som möjligt :doh: Men jag försöker igen

Med sända så menar jag att denna funktion ska köras

Kod: Markera allt

void initGps(){

    char strr[] = "$PMTK314,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*29\r\n"; // string att skicka. 
    //Är ett av kommandona som min GPS förstår. Detta kommando kommer göra att min GPS bara skickar ut GPRMC uppdateringar och inte de andra som GPGGA osv
    sendCmd(strr);
}

void sendCmd(char *str){
    while(BusyUSART()); //Vänta tills USART är redo att skicka
    putsUSART(str); //Skicka strängen till GPSen via TX på PIC. Har kopplat den till RX på GPSen
//    while(BusyUSART()); Behövs denna egentligen?
}
Men som du säger så är den koden i dagsläget samma sak. Jag har tagit bort en del kod under ifen. Tanken var att den där skulle kolla om man passerat mållinjen. Nu ska jag ta och flytta den funktionen till main() så det ska ändras till det du skrev.
Användarvisningsbild
Icecap
Inlägg: 26648
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: USART PIC18 XC8

Inlägg av Icecap »

Har du testat om det alls går att sända med UART'en?

När det kör ihop sig är det ganska bra att ta en enda sak i sände och testa funktionen. När den fungerar vet man att inställningarna är rätt för den del och kan ta nästa grej.

Så skriv en mjukvara som ENBART startar upp och initierar UART och andra grejer men inte börjar sända något.

Koppla UART-porten (via en levelconverter) till en COM-port på datorn, kör ett terminalprogram. Programmera in att om du aktiverar en pinne ska strängen sändas en enda gång, alternativt sändas om du skickar ett mellanslag (0x20) på UART Rx.

På detta vis kan du fastställa att kommunikationen in och ut fungerar bra.
Lullen
Inlägg: 140
Blev medlem: 16 oktober 2006, 17:37:32

Re: USART PIC18 XC8

Inlägg av Lullen »

Nej jag har inte testat det då jag inte har några delar för det. Behöver ju en USART till USB konverter också då mina datorer är lite för nya för en sån där COM port :lol: Men skulle jag inte kunna koppla samman RX med TX och kolla vad jag får istället? Känns som en betydligt enklare lösning.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: USART PIC18 XC8

Inlägg av sodjan »

OK... :-)

Frågan är väl hur putsUSART() fungerar. Jag *gissar* att den kommer
att låsa upp processorn/koden under tiden som strängen skickas. Man
måste studera dokumentationen ifall interrupt fungerar parallellt. Om
inte så kan den blockera mottagningen under tiden.

Annars skriver du texten som ska ut till en (annan) buffert och har
en sänd-ISR som sköter om att sända det hela, ett tecken i taget.
Då belastas processorn enbart just när ett nytt tecken skrivs till
USART'en.

BusyUSART() borde inte behövas om man kör putsUSART, den måste
ju i alla fall synkronisera mot USART'en. Om man kör det via en ISR
så synkas det ju med automatik och då behövs inte BusyUSART().
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: USART PIC18 XC8

Inlägg av sodjan »

> Men skulle jag inte kunna koppla samman RX med TX och kolla vad jag får istället?

Jo visst, du ska få samma tecken tillbaka på RX sidan som du skickar på TX sidan...
Användarvisningsbild
Icecap
Inlägg: 26648
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: USART PIC18 XC8

Inlägg av Icecap »

Det kan gå att använda en LED (med strömbegränsermotstånd) för att se om Tx "rör på sig". UART-utgången ska vara '1' vid vila varför man kan koppla LED'n mellan VDD och Tx. Sänder man något ska den blinka till.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: USART PIC18 XC8

Inlägg av sodjan »

I alla fall vid 9600, vid 115200 behövs det nog
en hel del data för att det ska synas... :-)
Användarvisningsbild
Icecap
Inlägg: 26648
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: USART PIC18 XC8

Inlägg av Icecap »

Nja... man ser att det sändas och själv mycket korta blink kan ses. Vi snackar inte morsekod, det är bara blinkande så att man kan se att UART'en vilar kontra sänder.

Med tanke på att TS saknar alla möjligheter för att rent faktisk verifiera funktionerna är det iaf. ett steg på vägen.
Skriv svar