Behöver nybörjarhjälp att programmera i C

C, C++, Pascal, Assembly, Raspberry, Java, Matlab, Python, BASIC, SQL, PHP, etc.
Användarvisningsbild
Magnus_K
EF Sponsor
Inlägg: 5854
Blev medlem: 4 januari 2010, 17:53:25
Ort: Skogen mellan Uppsala-Gävle

Re: Behöver nybörjarhjälp att programmera i C

Inlägg av Magnus_K »

Hehe, så sant!

Felsöker lite på kommunikationen och tror att felet är att jag inte får till i koden att skicka klocktåg #2 till ADC:n för att begära de sista 8 bitarna.
Kollar jag med skopet så upprepas denna cykel om och om igen vilket jag tycker är en indikation på att "startar om" kommunikationen hela tiden.
Jobbar vidare.
ADC.jpg
Du har inte behörighet att öppna de filer som bifogats till detta inlägg.
Användarvisningsbild
Magnus_K
EF Sponsor
Inlägg: 5854
Blev medlem: 4 januari 2010, 17:53:25
Ort: Skogen mellan Uppsala-Gävle

Re: Behöver nybörjarhjälp att programmera i C

Inlägg av Magnus_K »

Nu är jag nära!
Jag har nog tänkt lite fel med kommunikationen. Varje gång jag får buffer-flaggan och uppfyller någon av de två if-satserna (flag 0 el 1) så körs ju rutinen om.

Testade att baka ihop de två if-satserna, så den kör all kod i ett kör, men med en liten delay i mellan. Då börjar det likna något!
Får upp ett värde på min display som ändrar sig när jag vrider på potten.

Nu blir det nog att scanna nätet på idéer hur man egentligen gör för att få detta riktigt tajt och skottsäkert.
Här är mitt halvhjärtade försök som i alla fall gjorde lite skillnad.

EDIT: Tips mottages tacksamt om hur jag får till en funktion där: Om räknaren är 200 så starta en rutin men istället för delayen nedan så pausar koden tills man får en flagga och sen kör vidare från den punkten. Hur går detta till?
Hmm, är nog livsfarligt att göra så förresten. Vad skulle hända om flaggan inte skulle komma...

Kod: Markera allt

if(Counter >= 200) {                                // När ISR:en scannat 200 ggr så är det dags att
                                                         // hämta nytt ADC-värde
                                                  
              temp_adc_data &= 0x0000;                   // Nolla temp-variablen
              SSP1BUF &= 0x00;                           // Nolla buffern
              LATA.B5 = 0;                               // Chip Select, aktivera ADC:n


                         if(SSP1IF) {                           // Om buffern fyllts på med data så:

                                     temp_adc_data = SSP1BUF;   // Flytta buffern till variablen
                                     temp_adc_data <<= 8;       // Skifta dessa 8 bitar uppåt
                                     SSP1BUF &= 0x00;           // Nolla buffern

                                     Delay_ms(1);
                                     
                                     temp_adc_data |= SSP1BUF;  // OR:a in buffern i lägsta 8 bit
                                     temp_adc_data >>= 1;       // Skifta allt en bit nedåt pga skräp
                                     temp_adc_data &= 0xfff;    // Maska av variablen och nolla översta nibbeln
                                     adc_data &= 0x00;          // Nolla den riktiga variablen
                                     adc_data |= temp_adc_data; // Fyll på med den nya datan
                                     adc_flag = 0;              // Markera att man kan börja om från början
                                     LATA.B5 = 1;               // Inaktivera ADC:n med Chip Select hög
                                     new_value = 1;             // Ge flagga om att vi har ett nytt ADC-värde
                                     Counter = 0;               // Nolla räknaren
                                     PIR1.B3 = 0;               // Nolla buffer-flaggan
                                     }
              }
     }
Användarvisningsbild
Magnus_K
EF Sponsor
Inlägg: 5854
Blev medlem: 4 januari 2010, 17:53:25
Ort: Skogen mellan Uppsala-Gävle

Re: Behöver nybörjarhjälp att programmera i C

Inlägg av Magnus_K »

Nästan där. Displayen visar rätt och uppdaterar när jag vrider potten men det är något skit kvar.
Jag tror fortfarande att jag missar en drös LSB:s då spänningen gör väldigt grova "hopp" när man vrider på potten. Rimligtvis ska jag kunna justera i alla fall 10 mV (om inte 1 mV) men nu hoppar den typ 130 mV i taget.

Så här ser programmet ut nu (plockat bort konfigureringen av µC:n då jag tror det är mindre relevant):

Kod: Markera allt

unsigned int adc_data;
unsigned int temp_adc_data = 0x0000;
unsigned short Counter = 0;
unsigned short new_value = 0;
unsigned short a = 0;
unsigned short b = 0;
unsigned short voltage[4];
unsigned long total_voltage;
int adc_flag = 0;
int i;
int j;


const short DIGIT[4] = {
      0b00000010,
      0b00000100,
      0b00001000,
      0b00010000
};

const short NUMBER[10] = {
      0b11000000,    //0
      0b11111001,    //1
      0b10100100,    //2
      0b10110000,    //3
      0b10011001,    //4
      0b10010010,    //5
      0b10000010,    //6
      0b11111000,    //7
      0b10000000,    //8
      0b10010000     //9
};


void main() {

     init();
     
     while(1) {

              if(new_value){                             // Varje gång ett nytt ADC-värde är satt
                                                         // så ska denna rutin köras
                    total_voltage &= 0x00000000;         // Nolla variablen
                    total_voltage |= adc_data;           // OR:a in ADC-värdet
                    
                    total_voltage *= 12207;              // Omvandla ADC-värdet till spänningsnivå
                    total_voltage /= 10000;              // Skala ner detta så tex 1V blir 1000
                    
                    voltage[3] = total_voltage / 1000;
                    voltage[2] = (total_voltage / 100) % 10;
                    voltage[1] = (total_voltage / 10) % 10;
                    voltage[0] = (total_voltage) % 10;
                    new_value = 0;
                    }

     if(Counter >= 60) {                                // När ISR:en scannat 60 ggr så är det dags att
                                                          // hämta nytt ADC-värde
              if(LATA.B5) {
                    SSP1BUF &= 0x00;                     // Nolla buffern
                    temp_adc_data &= 0x0000;             // Nolla temp-variablen
                    }
              LATA.B5 = 0;                               // Chip Select, aktivera ADC:n


                         if(SSP1IF && (adc_flag == 0)) {        // Om buffern fyllts på med data så:

                                     temp_adc_data = SSP1BUF;   // Flytta buffern till variablen
                                     SSP1BUF &= 0x00;
                                     temp_adc_data <<= 8;       // Skifta dessa 8 bitar uppåt
                                     adc_flag = 1;
                                     }
                         if(SSP1IF && (adc_flag == 1)) {
                                     temp_adc_data |= SSP1BUF;  // OR:a in buffern i lägsta 8 bit
                                     temp_adc_data >>= 1;       // Skifta allt en bit nedåt pga skräp
                                     temp_adc_data &= 0xfff;    // Maska av variablen och nolla översta nibbeln
                                     adc_data &= 0x00;          // Nolla den riktiga variablen
                                     adc_data |= temp_adc_data; // Fyll på med den nya datan
                                     LATA.B5 = 1;               // Inaktivera ADC:n med Chip Select hög
                                     new_value = 1;             // Ge flagga om att vi har ett nytt ADC-värde
                                     Counter = 0;               // Nolla räknaren
                                     adc_flag = 0;
                                     }
              }
     }
}

void interrupt(void) {                            // Denna ISR snurrar med ~500 Hz
                                                  // så varje siffra (4 st) uppdateras
                                                  // med 150 Hz

     if(INTCON.TMR0IF) {                          // När Timer0 överflödar, så:

              LATA &= (PORTA & 0x00);             // Släck anod
              LATD &= (PORTD & 0x00);             // Nolla segmenten
              i++;                                // Räkna upp vilken display som ska laddas nästa gång
              if(i >= 4) {i = 0;}                 // Om >3 så nolla
              j = voltage[i];                     // Ge j värdet som respektive element innehåller
              LATD |= NUMBER[j];                  // Aktivera rätt segment beroende på ovan
              LATA |= DIGIT[i];                   // Tänd ny anod enligt räknaren

              Counter++;                          // Öka räknaren som vid 200 triggar ny ADC-läsning
              INTCON.TMR0IF = 0;                  // Nolla overflow flaggan
              }
}
sodjan
EF Sponsor
Inlägg: 43242
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Behöver nybörjarhjälp att programmera i C

Inlägg av sodjan »

Lägg ut ADC värdet direkt på displerna istället för det omräknade värdet i Volt.
Gärna i HEX så ser man ganska snabbt om det finns bit-fel eller om
några LCB saknas o.s.v.
Användarvisningsbild
Magnus_K
EF Sponsor
Inlägg: 5854
Blev medlem: 4 januari 2010, 17:53:25
Ort: Skogen mellan Uppsala-Gävle

Re: Behöver nybörjarhjälp att programmera i C

Inlägg av Magnus_K »

Bra idé!

Vet inte än hur jag omvandlar binärt tal till hex samt att det tar en del tid att att lägga in A,B,C,D,E och F för visningen.

Kopplade dock om så jag hade samma spänning på Vref som V+ med gemensam 0:a, vilket borde innebära ett visat binärt värde på 4096.
Displayen visade "3968" vilket blir F80 i hex.

Det var nog en riktigt bra idé för det här innebär ju att jag saknar "128" äpplen vilket också innebär första biten i andra byten.
Mycket bra. Nu har jag en bra punkt att felsöka från!

EDIT: Eller kanske snarare, HELA andra byten! Som jag var inne på..
Användarvisningsbild
Jan Almqvist
Inlägg: 1651
Blev medlem: 1 oktober 2013, 20:48:26
Ort: Orust

Re: Behöver nybörjarhjälp att programmera i C

Inlägg av Jan Almqvist »

Jag gissar att felet är att du läser tre gånger istället för två.

Första läsningen är OK.

Vid andra läsningen

(som sker här)

Kod: Markera allt

SSP1BUF &= 0x00;
försvinner nog lågbyten...
Användarvisningsbild
Magnus_K
EF Sponsor
Inlägg: 5854
Blev medlem: 4 januari 2010, 17:53:25
Ort: Skogen mellan Uppsala-Gävle

Re: Behöver nybörjarhjälp att programmera i C

Inlägg av Magnus_K »

Såg precis ditt inlägg Jan Almqvist men måste läsa det och kolla på koden för att förstå vad du menar. Återkommer!

Oavsett så hittade jag en lösning. Kanske något som anses som otroligt farligt att göra i kod och då skulle jag hemskt gärna vilja ha tips på hur man kan ta sig runt det.
Genom att lägga in while-loopar som gör att programmet avstannar till buffern är fylld så fungerar det nu precis som det ska.
Den del som jag mekat med syns nedan och ni ser nog direkt vilka loopar jag pratar om.

Kod: Markera allt

if(Counter >= 60) {                                // När ISR:en scannat 60 ggr så är det dags att
                                                                  // hämta nytt ADC-värde
                                                                      
                          SSP1BUF &= 0x00;                        // Nolla buffern
                          temp_adc_data &= 0x0000;                // Nolla temp-variablen
                          LATA.B5 = 0;                            // Chip Select, aktivera ADC:n


                          while(!SSP1STAT.B0) {}                  // Om buffern är full så:
                          temp_adc_data = SSP1BUF;                // Flytta buffern till variablen
                          SSP1BUF &= 0x00;                        // Nolla bufferm
                          temp_adc_data <<= 8;                    // Skifta dessa 8 bitar uppåt
                          
                          while(!SSP1STAT.B0) {}                  // Om buffern är full igen så:
                          temp_adc_data |= SSP1BUF;               // OR:a in buffern i lägsta 8 bit
                          temp_adc_data >>= 1;                    // Skifta allt en bit nedåt pga skräp
                          temp_adc_data &= 0xfff;                 // Maska av variablen och nolla översta nibbeln
                          adc_data &= 0x00;                       // Nolla den riktiga variablen
                          adc_data |= temp_adc_data;              // Fyll på med den nya datan
                          LATA.B5 = 1;                            // Inaktivera ADC:n med Chip Select hög
                          new_value = 1;                          // Ge flagga om att vi har ett nytt ADC-värde
                          Counter = 0;                            // Nolla räknaren
                                     }
Användarvisningsbild
Magnus_K
EF Sponsor
Inlägg: 5854
Blev medlem: 4 januari 2010, 17:53:25
Ort: Skogen mellan Uppsala-Gävle

Re: Behöver nybörjarhjälp att programmera i C

Inlägg av Magnus_K »

Jan Almqvist skrev:Jag gissar att felet är att du läser tre gånger istället för två.

Första läsningen är OK.

Vid andra läsningen

(som sker här)

Kod: Markera allt

SSP1BUF &= 0x00;
försvinner nog lågbyten...
Hmm, nog jag som inte förstår. Kallas inte det för skrivning, dvs detta -> SSP1BUF &= 0x00 ska då ge klartecken för "klart att sända igen" ?
Eller blir det någon slags läs/skrivning? Det är ju klart, ska man AND:a något så måste det ju läsas först för att veta vad man ska AND:a med.... eller?
Användarvisningsbild
Magnus_K
EF Sponsor
Inlägg: 5854
Blev medlem: 4 januari 2010, 17:53:25
Ort: Skogen mellan Uppsala-Gävle

Re: Behöver nybörjarhjälp att programmera i C

Inlägg av Magnus_K »

Hur gör jag för att tillfälligt ändra ett element i en array?

Problem:

Istället för att ha ytterligare ett element som visar decimaltecknet så tänkte jag prova att tillfälligt modifera den siffra jag ska visa. B7, eller högst biten, i varje element är decimaltecknet. 1 = av, 0 = på.

Jag har denna array deklarerad:

Kod: Markera allt

const short NUMBER[10] = {
      0b11000000,    //0
      0b11111001,    //1
      0b10100100,    //2
      0b10110000,    //3
      0b10011001,    //4
      0b10010010,    //5
      0b10000010,    //6
      0b11111000,    //7
      0b10000000,    //8
      0b10010000     //9
};
Tillfälligt vill jag AND:a en av dessa bytes med 7F (0b01111111).

Har testat att skriva:

Kod: Markera allt

if(i == 3) {NUMBER[j] & 0x7f;}
i == 3 är alltså om scanner ska uppdatera vänstra siffran så gör {}.
Raden ovanför denna if-sats så har också "j" fått ett värde mellan 0 och 9.

"&=" fungerade inte. Kompilatorn klagade på något med "lvalue".
sodjan
EF Sponsor
Inlägg: 43242
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Behöver nybörjarhjälp att programmera i C

Inlägg av sodjan »

> {NUMBER[j] & 0x7f;}

Den AND'ar två värden, men vart ska resultatet ta vägen?
Användarvisningsbild
Magnus_K
EF Sponsor
Inlägg: 5854
Blev medlem: 4 januari 2010, 17:53:25
Ort: Skogen mellan Uppsala-Gävle

Re: Behöver nybörjarhjälp att programmera i C

Inlägg av Magnus_K »

Hmm, misstänkte det...

Hoppas jag svarar på din fråga nu men i nästa rad sker detta:

Kod: Markera allt

LATD |= NUMBER[j];
Alltså det "AND:ande nummerelementet" skrivs till porten.

EDIT: Nej nu förstår jag nog vad du menar. Alltså vart ska det AND:ande värdet ta vägen? Nja, det är lite det som är problemet.
Testat med if(i == 3) {NUMBER[j] = (NUMBER[j] & 0x7f);} men då klagar den på "Assigning to non lvalue" igen.

EDIT2: Hmm, det kompilerar ok när jag använder "&=" och jag får dit lite punkter om jag ändra "const short" till "unsigned short" i deklarationen av arrayen, men å andra sidan börjar alla siffror fladdra och det blir bara skit till slut. Ska fortsätta jobba på det.
Senast redigerad av Magnus_K 15 december 2014, 00:12:58, redigerad totalt 1 gång.
Zeela
Inlägg: 176
Blev medlem: 28 augusti 2008, 11:23:49
Ort: Åtvidaberg
Kontakt:

Re: Behöver nybörjarhjälp att programmera i C

Inlägg av Zeela »

Det är för att du sagt att innehållet i NUMBER ska vara const, alltså inte gå att ändra.
Användarvisningsbild
Magnus_K
EF Sponsor
Inlägg: 5854
Blev medlem: 4 januari 2010, 17:53:25
Ort: Skogen mellan Uppsala-Gävle

Re: Behöver nybörjarhjälp att programmera i C

Inlägg av Magnus_K »

Tack Zeela. Nu när dom är "unsigned" istället så går dom ändra. Dock bläddrar/blinkar hela displayen helt okontrollerat.

Så här ser funktionen ut nu:

Kod: Markera allt

              LATA &= (PORTA & 0x00);             // Släck anod
              LATD &= (PORTD & 0x00);             // Nolla segmenten
              
              if(i == 3) {NUMBER[j] |= 0x80;}     // Om den vänstra LED-displayen uppdaterades senast
                                                  // så OR:a in en 1:a, dvs släck decimaltecknet
                                                  // Detta för att numret ska återställas
              
              i++;                                // Räkna upp vilken display som ska laddas nästa gång
              if(i >= 4) {i = 0;}                 // Om >3 så nolla
              j = voltage[i];                     // Ge j värdet som respektive element innehåller
              
              if(i == 3) {NUMBER[j] &= 0x7f;}     // Om det är vänstra LED-displayen som ska uppdateras
                                                  // så AND:a in en 0:a, dvs tänd decimaltecknet

              LATD |= NUMBER[j];                  // Aktivera rätt segment beroende på ovan
              LATA |= DIGIT[i];                   // Tänd ny anod enligt räknaren
sodjan
EF Sponsor
Inlägg: 43242
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Behöver nybörjarhjälp att programmera i C

Inlägg av sodjan »

Här är det ju absolut enklast med något slags simulator/debugger där du kan
köra en C-rad i taget och kontrollera värden på allt. Då borde det gå ganska
enkelt att se var det inte fungerar så som du tänkte. Fanns det i MikroC?
Användarvisningsbild
Magnus_K
EF Sponsor
Inlägg: 5854
Blev medlem: 4 januari 2010, 17:53:25
Ort: Skogen mellan Uppsala-Gävle

Re: Behöver nybörjarhjälp att programmera i C

Inlägg av Magnus_K »

Mjoo det finns, men att kunna hantera den är en annan femma.
Har kört den några gånger för enkla övningar men jag får den inte att uppdatera variablerna automatiskt, utan jag måste uppdatera själv hela tiden genom att klicka på variablen.

Ska göra ett försök till.
Skriv svar