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 »

Nu ska vi vara lugna och fina. Mycket nära en lösning tror jag! Så här gjorde jag nu:

Ändrade voltage[3] till voltage[4]. (Har även testat detta tidigare utan framgång men nu bortser vi från det)
Resultat: 4 st väldigt stabila nollor. Inget fladder som det var innan.

Sedan gav jag fasta elementvärden enligt vad du skrev.
Resultat: Displayen började fladdra okontrollerat.

Sist provade jag att ha kvar fasta "voltage"-värde och ändrade tillbaka till voltage[3].
Resultat: Displayen visar stabilt "2234".

För mig helt oförklarligt men kanske säger er något?

EDIT: Har bekräftat att första siffran följer med vad man skriver ut på andra siffran..
Användarvisningsbild
adent
Inlägg: 4245
Blev medlem: 27 november 2008, 22:56:23
Ort: Utanför Jönköping
Kontakt:

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

Inlägg av adent »

unsigned short voltage[3]; <- 3:an ska vara 4 om du accessar [0], [1], [2] och [3]. (fyra stycken!).

I övrigt vette tusan just nu :) Jag är inte så bra på Pic även om det inte borde spela någon roll i det här fallet.

MVH: Mikael
Användarvisningsbild
adent
Inlägg: 4245
Blev medlem: 27 november 2008, 22:56:23
Ort: Utanför Jönköping
Kontakt:

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

Inlägg av adent »

hmmm, är ditt interrupt ett riktigt interrupt? Ser ut som en vanlig funktion där du kollar interruptflaggan? Men det kan vara jag som inte begriper
mig på just den c-kompilatorn för Pic :)

Klistra in hela koden, så kanske det blir lättare. Skulle kunna vara nått med avsaknad volatile kanske... (Brukar jag förslå, men det brukar i regel inte vara det :) )

MVH: Mikael
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ä nu blir det läggdags.
Provade att ändra den arrayen från en short till en int samt från 3 till 4. Ingen framgång så jag ändrade tillbaka till en short men behöll 4. Vad tror du hände? Displayen visar "1234", precis som den ska.

Nä, det är nog för sent nu. Lite synd bara att man inte förstår vad som var fel...

Också fundersam kring det du precis skrev. Fick lära mig i en annan tråd att om man har en array, tex test[10], så består denna av 11 element då man börjar räkna från 0.
Lärde mig detta då jag skulle ha 100 element och skulle då skriva [99]. Det ä därför jag är lite envis med att skriva 3 nu då jag har 4 element.

EDIT: Såg din post nu. Får man säga pass? :wink: Trodde interrupt vad just en rutin som körs när en flagga/overflow händer. Har nog förstått fel.
Volatile vet jag inte vad det är men ska läsa lite! Tack för hjälpen adent!
Användarvisningsbild
adent
Inlägg: 4245
Blev medlem: 27 november 2008, 22:56:23
Ort: Utanför Jönköping
Kontakt:

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

Inlägg av adent »

Kom ihåg att det är kompilatorspecifikt (och kanske processorspecifikt) hur du talar om för kompilatorn vad som är interrupt (det är inte riktigt en del av C så att säga) och jag kan inte din kompilator. Det var därför jag var nyfiken på att se allt, då kanske jag fattat eller kunnat säga bu eller bä eller va? :)

Det du lärt dig är fel. skriver du: unsigned char buffer[4]; så får du en 4 tecken stor array. första tecknet nås via buffer[0], andra via buffer[1], tredje via buffer[2] och fjärde och sista via buffer[3].

Om du deklarerar: unsigned char buffer[3]; och skriver till buffer[3] så kommer du med all sannolikhet att skriva över en annan variabel som kompilatorn valt att lägga efter din 3 bytes stora array. Det kan skapa väldigt mystiska fel... :) Kanske är det detta som spökar någonannanstans i din kod?

MVH: Mikael
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 »

Jag får nog ta och läsa igenom både detta och den andra tråden igen med friska ögon. Smått förvirrad just nu :humm:
Du har säkert helt rätt i att det kan vara detta som spökar. Det kanske blev någon skillnad på detta när jag temporärt ändrade från short till int och tillbaka, dvs ändrade storlek på variabeln.

Ska posta hela koden imorrn när jag fått städa den lite.
Användarvisningsbild
Icecap
Inlägg: 26647
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

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

Inlägg av Icecap »

Varför använder du short som sifferminne? Behöver du verkligen 16 bit till ett 7-segment display?

Vad med att använda 4 st unsigned char?

För att säkerställa hur den specifika kompiler använder vissa variabler har jag testat att skriva ut deras storlekar:
printf("Byte: %u\r\n", sizeof(char));
printf("int: %\r\nu", sizeof(int));
printf("Short: %\r\nu", sizeof(short));
printf("Long: %u\r\n", sizeof(long));
Då vet jag exakt hur kompilern uppfattar de olika variablers storlek och kan anpassa programmet.

Men för att göra det enkelt för dig: du behöver 4 st bytes (unsigned char) som scannerminne.
Senast redigerad av Icecap 13 december 2014, 13:10:12, redigerad totalt 1 gång.
sodjan
EF Sponsor
Inlägg: 43251
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 »

> För att säkerställa hur den specifika kompiler använder vissa variabler har jag testat att skriva ut deras storlekar:

Jag har inte sett en C-kompilator som inte har det tydligt angivet i dokumentationen.

> Trodde interrupt vad just en rutin som körs när en flagga/overflow händer.

Interrupt är ett avbrott som sker i hårdvaran. Varje C-kompilator har sitt
sätt att ange vilken C-funktion som ska kopplas till detta avbrott.

Från XC8 (Microchips egen kompilator. tc_int() är alltså ISR'en.

Kod: Markera allt

void interrupt tc_int(void)
{
  if (TMR0IE && TMR0IF) {
    TMR0IF=0;
    ++tick_count;
    return;
  }
  // process other interrupt sources here, if required
}
Motsvararde i MikroC. Själva ISR'en är hårt namnsatt till "interrupt()" i MikroC.:

Kod: Markera allt

void interrupt()
{
  if (TMR0IE && TMR0IF) {
    TMR0IF=0;
    ++tick_count;
    return;
  }
  // process other interrupt sources here, if required
}
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 »

Då tror jag nog att jag gjort rätt ändå va?
Jag valde variabeltyp utifrån denna lista i manualen:
Screenshot.JPG
Som jag tolkar detta så är det lämpligast om jag använder unsigned short eller char. Sen kan man också använda "bit" och "sbit" men dom är för små.

ISR:en blev nog rätt för att jag kollat hur andra har gjort. Vet inte anledningen till när man skriver "void" eller lämnar tomt mellan () men det kan jag nog läsa mig till.
Hade inte en aning om att sättet att skriva interrupten var styrt av kompilatorn men nu vet jag det!
Du har inte behörighet att öppna de filer som bifogats till detta inlägg.
Användarvisningsbild
Icecap
Inlägg: 26647
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

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

Inlägg av Icecap »

OK, jag är van vid att short är 16 bit men är det 8 är det helt fint.

Det som skiljer med interrupt kontra icke-interrupt rutiner är vilka instruktioner som de börjar och slutar med.

En interruptrutin avslutas med "return from interrupt" medan en icke-interrupt avslutas med "return."
Om det behövs kommer interrupt-rutiner att inledas med att spara undan viktiga register, t.ex. statusregister och det/de återställs såklart innan avslut.

Detta betyder att man måste berätta för kompilern måste veta att "detta är en interrupt-rutin" så att inledningen och avslutet kan vara korrekt.

Annars är det ingen skillnad.
hummel
Inlägg: 2543
Blev medlem: 28 november 2009, 10:40:52
Ort: Stockholm

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

Inlägg av hummel »

Om du lägger upp hela projektet här ska jag ta en titt på problemet.
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å här ser denna del av projektet ut. Detta kompilerar ok. Har lagt till en miljard kommentarer bara för att du tydligt ska få se hur jag tänker. Blir det rörigt så kan jag radera alla kommentarer och posta igen.
Det som fungerar kanon nu är interruptscannern (längst ner).

Jag misstänker det är tok i både "new_value"-rutinen och "counter"-rutinen.
Det gick bra att ge de olika voltage[]-elementen fasta värden och detta visade på de 4 LED:arna men mitt lilla hittepå som ska splitta tex "1234" till "1", "2", "3" och "4" fungerar inte. Jobbar på detta just nu.

Sist men inte minst så måste jag få ordning på kommunikationen mellan PIC:en och ADC:n. Jag har kollat med skopet och jag får data tillbaka från ADC:n men jag tror jag inte lyckas med att ta hand om MSBs+LSBs utan jag får hela tiden MSBs+MSBs+MSBs osv.

Kommer sitta med detta ikväll så hittar jag själv vad som är tok så säger jag till.
Tack för hjälpen!

Kod: Markera allt

void init() {
     OSCCON = 0b11111000;        //x4 PLL and 32MHz
     //OSCCON = 0b01011000;      // 1 MHz
     
     OPTION_REG = 0b00000101;    //1:64 prescaler

     ANSELA = 0;
     ANSELB = 0;
     ANSELD = 0;
     ANSELE = 0;

     CM1CON0 = 0;
     CM2CON0 = 0;
     CM3CON0 = 0;
     CM4CON0 = 0;
     
     OPA1CON = 0;
     OPA2CON = 0;
     OPA3CON = 0;
     
     PSMC1CON.B7 = 0;
     PSMC2CON.B7 = 0;
     PSMC3CON.B7 = 0;
     PSMC4CON.B7 = 0;
     
     INTCON.GIE = 1;
     INTCON.PEIE = 1;
     INTCON.TMR0IE = 1;

     SSP1CON = 0b00111010;        //Clock idle low, start SPI-module and use ADD-reg to calculate clock
     SSP1ADD = 0b00000100;        //Slow SPI-clock to 1,6MHz

     TRISD = 0;
     LATD = 0;
     TRISA = 0;
     LATA = 0;
     TRISE = 0;
     LATE = 0;

     TRISC.B3 = 0;
     TRISC.B4 = 1;
     TRISC.B5 = 0;
     
     LATA.B5 = 1;                // Hold ADC SS high for stby-mode
     LATE.B0 = 0;                // Debug LED, start black
     LATE.B1 = 0;                // Debug LED, start black
     

}

#define SEGMENTPORT PORTD
#define DIGITPORT PORTA

unsigned int adc_data;
unsigned int temp_adc_data = 0x0000;
unsigned int 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 *= 48823;              // Omvandla ADC-värdet till spänningsnivå
                    total_voltage /= 10000;              // Skala ner detta så tex 1V blir 1000

                    voltage[3] = total_voltage % 1000;   // I resterande kod så skalas spänningsnivån
                    total_voltage /= 10;                 // ner i dekader och placerade i respektive
                    voltage[2] = total_voltage % 100;    // element. Avslutas med att sätta rutinen i
                    total_voltage /= 10;                 // väntestadie med att nolla new_value.
                    voltage[1] = total_voltage % 10;
                    total_voltage /= 10;
                    voltage[0] = total_voltage % 1;
                    new_value = 0;
                    }

     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 && (adc_flag == 0)) {            // Om buffern fyllts på med data och
                                                                    // ingen tidigare data behandlats så:

                                     temp_adc_data = SSP1BUF;   // Flytta buffern till variablen
                                     temp_adc_data <<= 8;       // Skifta dessa 8 bitar uppåt
                                     adc_flag = 1;              // Sätt "data behandlad"-variablen
                                     SSP1BUF &= 0x00;           // Nolla buffern
                                     PIR1.B3 = 0;               // Nolla buffer-flaggan
                                     }
                                     
                         if(SSP1IF && (adc_flag == 1)) {            // Om buffern fyllts på med data och
                                                                    // ingen tidigare data behandlats 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
                                     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
                                     }
              }
     }
}

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
              }
}
Användarvisningsbild
Icecap
Inlägg: 26647
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

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

Inlägg av Icecap »

voltage[3] = total_voltage % 1000; ger värdet mellan 0 och 999.

Testa:
voltage[3] = total_voltage / 1000;
voltage[2] = (total_voltage / 100) % 10;
voltage[1] = (total_voltage / 10) % 10;
voltage[0] = (total_voltage) % 10;
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 »

Vad ska man säga Icecap? Klockrent säger jag! :tumupp:

Gjorde din ändring och gav sedan total_voltage ett fast värde men struntade i biten att konvertera till "spänningsnivå".
Funktionen presenterade värdet så fint på displayen.

Nästa steg så gav jag total_voltage ett fast "ADC-värde" med spänningskonvertering och visningen fungerade exemplariskt!

Kanon. Tack!

Testade slutligen att köra skarpt men då blir det bara nollor. Med andra ord är kommunikationen med ADC:n inte bra.
Ska jobba vidare med detta nu samt försöka förstå lite närmre vad din ändring verkligen gjorde jämfört med min.
Användarvisningsbild
Icecap
Inlägg: 26647
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

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

Inlägg av Icecap »

Jag tycker att du sköter det bra. Det kanske är en brant inlärningskurva men du tar en sak i sände och får den att fungera - och det är så jag gör också. Om det sedan är "rätt" vete gudarna ;-)

Det fungerar för mig - så något bra är det ju i det.
Skriv svar