Räknare går bara till 20

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
Kalf
Inlägg: 249
Blev medlem: 5 november 2005, 09:59:45

Räknare går bara till 20

Inlägg av Kalf »

Hej. Jag håller på och labba lite med en PIC16F628A och en 4*7segments display. Men jag har lite problem med koden. Tanken med koden är att räkna upp en siffra per ca 0.5s. Detta fungerar bra upp till när displayen visar 0020 då visas det i ca 0.5s för att sedan nollställas till 0000.

Här är koden, visningen fungerar bra, så det är troligtvis fel någonstans i sista delen.

Kod: Markera allt

unsigned short shifter, digit, portd_index;
unsigned int   number;
unsigned short portd_array[4];
unsigned short digit1 = 0;
unsigned short digit2 = 0;
unsigned short digit3 = 0;
unsigned short digit4 = 0;

unsigned short mask(unsigned short num) {
  switch (num) {
    case 0 : return 0x3F;
    case 1 : return 0x06;
    case 2 : return 0x5B;
    case 3 : return 0x4F;
    case 4 : return 0x66;
    case 5 : return 0x6D;
    case 6 : return 0x7D;
    case 7 : return 0x07;
    case 8 : return 0x7F;
    case 9 : return 0x6F;
  } //case end
}//~

void interrupt() {
  PORTA = 0;                             // Turn off all 7seg displays
  PORTB = portd_array[portd_index];      // bring appropriate value to PORTB
  PORTA = shifter;                       // turn on appropriate 7seg. display

  // move shifter to next digit
  shifter <<= 1;
  if (shifter > 8u)
    shifter = 1;

  // increment portd_index
  portd_index++ ;
  if (portd_index > 3u)
    portd_index = 0;                     // turn on 1st, turn off 2nd 7seg.

  TMR0   =   0;                          // reset TIMER0 value
  INTCON = 0x20;                         // Clear TMR0IF
}


void main() {

  while(1)
    {
    OPTION_REG     = 0x80;         // Timer0 settings
    portd_index    = 0;
    shifter        = 1;
    TMR0           = 0;
    INTCON         = 0xA0;         // Enable GIE, TMR0IE
    PORTA          = 0;            // make sure that all segments are off
    TRISA          = 0;            // designate porta pins as output
    PORTB          = 0;            // make sure that nothing is displayed
    TRISB          = 0;            // designate portd pins as output
    portd_array[0] = mask(digit1);
    portd_array[1] = mask(digit2);
    portd_array[2] = mask(digit3);
    portd_array[3] = mask(digit4);


    digit1++;
    delay_ms(500);
    if (digit1 > 9)
       {
       digit1 = 0;
       digit2++;
       if (digit2 > 9)
           {
           digit2 = 0;
           digit3++;
           if (digit3 > 9)
               {
               digit3 = 0;
               digit4++;
               if (digit4 > 9)
                   {
                   digit4 = 0;
                   }
               }
           }
       }
    }
}
//Kalf
bearing
Inlägg: 11676
Blev medlem: 2 mars 2006, 01:01:45
Ort: Ängelholm

Re: Räknare går bara till 20

Inlägg av bearing »

Jag kan inte se något fel i koden som skulle kunna göra att den nollställs efter 0020. Förmodligen betyder det att processorn startas om efter 20.

Tycker att du borde ta bort initeringen ur while-loopen i main. Initieringen borde bara behöva göras en gång, i början av main, innan loopen.

För att se om processorn startas om skulle du kunna göra så att initieringen sätter siffror 9999 på displayen, eller liknande.
Användarvisningsbild
Micke_s
EF Sponsor
Inlägg: 6741
Blev medlem: 15 december 2005, 21:31:34
Ort: Malmö

Re: Räknare går bara till 20

Inlägg av Micke_s »

Har du kollat vakthunden (WDT)?
Användarvisningsbild
Swech
EF Sponsor
Inlägg: 4750
Blev medlem: 6 november 2006, 21:43:35
Ort: Munkedal, Sverige (Sweden)
Kontakt:

Re: Räknare går bara till 20

Inlägg av Swech »

Rent allmänt om kodningen eftersom jag är kass på C.
Vad returnerar din CASE om siffran inte är inom 0-9 ?

Varje IF utför ju två saker , öka siffra och kontrollera om den är inom 0-9
Kontrollen 0-9 bör man köra på alla siffror kontinuerligt oavsett om man fått föregående siffra att slå runt.
Får du av någon anledning in något annat än 0-9 i de högre så tar det lång tid innan programmet rättar till det.

Swech
Användarvisningsbild
Micke_s
EF Sponsor
Inlägg: 6741
Blev medlem: 15 december 2005, 21:31:34
Ort: Malmö

Re: Räknare går bara till 20

Inlägg av Micke_s »

flytta ut

Kod: Markera allt

    OPTION_REG     = 0x80;         // Timer0 settings
    portd_index    = 0;
    shifter        = 1;
    TMR0           = 0;
    INTCON         = 0xA0;         // Enable GIE, TMR0IE
    PORTA          = 0;            // make sure that all segments are off
    TRISA          = 0;            // designate porta pins as output
    PORTB          = 0;            // make sure that nothing is displayed
    TRISB          = 0;            // designate portd pins as output
utanför while också...

Sedan hade jag flyttat ut digit++ osv till en egen funktion istället.
bearing
Inlägg: 11676
Blev medlem: 2 mars 2006, 01:01:45
Ort: Ängelholm

Re: Räknare går bara till 20

Inlägg av bearing »

Det var alltså ovanstående kod jag kallade "initieringen".
Användarvisningsbild
Kalf
Inlägg: 249
Blev medlem: 5 november 2005, 09:59:45

Re: Räknare går bara till 20

Inlägg av Kalf »

Hej.
Jag flyttade ut initieringen från while loopen. dessutom la jag till att lysa upp hela displayen i en sekund efter initieringen för att lokalisera problemet. Det som händer nu är att 1: displayen lyser med alla 4*8segment (7+en prick) 2. den räknar upp från 0000 till 0020 som innan. 3. hela displayen lyser upp igen. 4. den räknar om från 0000.

Detta betyder altså att efter 20 så nollställs variablerna och den börjar om från början i main. Den faller altså ur while loopen.

Micke_s: WDT är avstängd.
Swech: Jag fixade så CASE retunerar ett värde även om det ligger utanför 0-9

//Kalf

Kod: Markera allt

unsigned short shifter, digit, portd_index;
unsigned int   number;
unsigned short portd_array[4];
unsigned short digit1 = 0;
unsigned short digit2 = 0;
unsigned short digit3 = 0;
unsigned short digit4 = 0;


unsigned short mask(unsigned short num) {
  switch (num) {
    case 0 : return 0x3F;
    case 1 : return 0x06;
    case 2 : return 0x5B;
    case 3 : return 0x4F;
    case 4 : return 0x66;
    case 5 : return 0x6D;
    case 6 : return 0x7D;
    case 7 : return 0x07;
    case 8 : return 0x7F;
    case 9 : return 0x6F;
    default: return 0xFF;
  } //case end
}//~

void interrupt() {
  PORTA = 0;                             // Turn off all 7seg displays
  PORTB = portd_array[portd_index];      // bring appropriate value to PORTB
  PORTA = shifter;                       // turn on appropriate 7seg. display

  // move shifter to next digit
  shifter <<= 1;
  if (shifter > 8u)
    shifter = 1;

  // increment portd_index
  portd_index++ ;
  if (portd_index > 3u)
    portd_index = 0;                     // turn on 1st, turn off 2nd 7seg.

  TMR0   =   0;                          // reset TIMER0 value
  INTCON = 0x20;                         // Clear TMR0IF
}


void main() {

  OPTION_REG     = 0x80;         // Timer0 settings
  portd_index    = 0;
  shifter        = 1;
  TMR0           = 0;
  INTCON         = 0xA0;         // Enable GIE, TMR0IE
  PORTA          = 0;            // make sure that all segments are off
  TRISA          = 0;            // designate porta pins as output
  PORTB          = 0;            // make sure that nothing is displayed
  TRISB          = 0;            // designate portd pins as output
  portd_array[0] = 0xFF;
  portd_array[1] = 0xFF;
  portd_array[2] = 0xFF;
  portd_array[3] = 0xFF;
  delay_ms(1000);
  while(1)
    {
    portd_array[0] = mask(digit1);
    portd_array[1] = mask(digit2);
    portd_array[2] = mask(digit3);
    portd_array[3] = mask(digit4);


    digit1++;
    delay_ms(500);
    if (digit1 > 9)
       {
       digit1 = 0;
       digit2++;
       if (digit2 > 9)
           {
           digit2 = 0;
           digit3++;
           if (digit3 > 9)
               {
               digit3 = 0;
               digit4++;
               if (digit4 > 9)
                   {
                   digit4 = 0;
                   }
               }
           }
       }
    }
}
bearing
Inlägg: 11676
Blev medlem: 2 mars 2006, 01:01:45
Ort: Ängelholm

Re: Räknare går bara till 20

Inlägg av bearing »

Är 20 tänt hela sin halvsekund, eller dör den snabbt efter att 20 visas?
Det skulle kunna bero på en "kortslutning" med av kombinationen PORTA=2 och PORTD=mask(2)

Jag tror det är dags för dig att visa oss hur allt är kopplat.
Användarvisningsbild
Glenn
Inlägg: 36772
Blev medlem: 24 februari 2006, 12:01:56
Ort: Norr om Sthlm
Kontakt:

Re: Räknare går bara till 20

Inlägg av Glenn »

BOR då ? nu minns jag inte om just den picen har BOR iofs, men jag har för mej det.

Har du picen ordentligt avkopplad ? gärna med en mindre (typ 100nF) och en större (1uF ?) konding ?
Användarvisningsbild
Kalf
Inlägg: 249
Blev medlem: 5 november 2005, 09:59:45

Re: Räknare går bara till 20

Inlägg av Kalf »

Så, tack för hjälpen. Det var BOR som var problemet. Jag stängde det och det fungerar felfritt nu.

//Kalf
Användarvisningsbild
Glenn
Inlägg: 36772
Blev medlem: 24 februari 2006, 12:01:56
Ort: Norr om Sthlm
Kontakt:

Re: Räknare går bara till 20

Inlägg av Glenn »

Whee :)
sneaky
Inlägg: 1621
Blev medlem: 22 juni 2009, 18:38:42

Re: Räknare går bara till 20

Inlägg av sneaky »

Även om det nu fungerar med BOR avstängt så kanske det kan vara en idé att kika på varför den löste ut? Bara en tanke.
Användarvisningsbild
Glenn
Inlägg: 36772
Blev medlem: 24 februari 2006, 12:01:56
Ort: Norr om Sthlm
Kontakt:

Re: Räknare går bara till 20

Inlägg av Glenn »

Ja, därav min frågha ang avkoppling, har man bara en mindre konding (eller ingen alls) kan det ju bli just sådär..
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Räknare går bara till 20

Inlägg av sodjan »

> Så, tack för hjälpen. Det var BOR som var problemet.

*NEJ*, det var det inte !

Problemet var det som fick BOR att "trigga". Om du inte
hittar det så har du fortfarande problemet kvar. Ditt val...
Användarvisningsbild
Kalf
Inlägg: 249
Blev medlem: 5 november 2005, 09:59:45

Re: Räknare går bara till 20

Inlägg av Kalf »

Sodjan: Det har du helt rätt i, nu när jag tänker efter. Det måste vara något i min koppling då?

saxat från databladet:
...If VDD falls below VBOR for longer than TBOR, the
brown-out situation will reset the chip....
Betyder det att uC'n tappar spänning då eller?

Sedan har det dykt upp ett till problem. Det kan kanske ha med samma sak och göra? Men Jag har kopplat in en tryckknapp som jag hade tänkt att styra uppräkningen med. Men när jag trycker på knappen fortsätter den räkna upp ca 100 gånger. (detta tar betydligt längre tid än vad jag håller knappen intryckt.)

Min misstanke var att det har något med min interrupt och göra. att den får interrupt precis i samband med digit1++; och när den då åter går så kör den samma sak igen så får den interuppt osv.....

Här är iaf koden:

Kod: Markera allt

void display(void);
void button_check(void);

unsigned short shifter, digit, portd_index;
unsigned int   number;
unsigned short portd_array[4];
unsigned short digit1 = 0;
unsigned short digit2 = 0;
unsigned short digit3 = 0;
unsigned short digit4 = 0;


unsigned short mask(unsigned short num) {
  switch (num) {
    case 0 : return 0x3F;
    case 1 : return 0x06;
    case 2 : return 0x5B;
    case 3 : return 0x4F;
    case 4 : return 0x66;
    case 5 : return 0x6D;
    case 6 : return 0x7D;
    case 7 : return 0x07;
    case 8 : return 0x7F;
    case 9 : return 0x6F;
    default: return 0xFF;
  } //case end
}//~

void display(void) {
while(1)
    {
    portd_array[0] = mask(digit1);
    portd_array[1] = mask(digit2);
    portd_array[2] = mask(digit3);
    portd_array[3] = mask(digit4);

    if (button(&PORTA, 7, 100, 1)) digit1++;

    if (digit1 > 9)
       {
       digit1 = 0;
       digit2++;
       if (digit2 > 9)
           {
           digit2 = 0;
           digit3++;
           if (digit3 > 9)
               {
               digit3 = 0;
               digit4++;
               if (digit4 > 9)
                   {
                   digit4 = 0;
                   }
               }
           }
       }
    }
}

void interrupt() {
  PORTA = 0;                             // Turn off all 7seg displays
  PORTB = portd_array[portd_index];      // bring appropriate value to PORTB
  PORTA = shifter;                       // turn on appropriate 7seg. display

  // move shifter to next digit
  shifter <<= 1;
  if (shifter > 8u)
    shifter = 1;

  // increment portd_index
  portd_index++ ;
  if (portd_index > 3u)
    portd_index = 0;                     // turn on 1st, turn off 2nd 7seg.

  TMR0   =   0;                          // reset TIMER0 value
  INTCON = 0x20;                         // Clear TMR0IF
}


void main() {

  OPTION_REG     = 0x80;         // Timer0 settings
  portd_index    = 0;
  shifter        = 1;
  TMR0           = 0;
  INTCON         = 0xA0;         // Enable GIE, TMR0IE
  PORTA          = 0;            // make sure that all segments are off
  TRISA          = 0b10000000;            // designate porta pins as output
  PORTB          = 0;            // make sure that nothing is displayed
  TRISB          = 0;            // designate portd pins as output
  portd_array[0] = 0xFF;
  portd_array[1] = 0xFF;
  portd_array[2] = 0xFF;
  portd_array[3] = 0xFF;
  delay_ms(1000);

  display();
}
//Kalf
Skriv svar