hjälp med liten kodbit

Elektronik- och mekanikrelaterad mjukvara/litteratur. (T.ex schema-CAD, simulering, böcker, manualer mm. OS-problem hör inte hit!)
Christian
Inlägg: 86
Blev medlem: 3 november 2003, 22:54:49

hjälp med liten kodbit

Inlägg av Christian »

Hej! Försöker få en 7 segmentsdisplay att räkna uppåt med en AVR när jag trycker på en knapp. Min kod ser ut som följer (skriver i C) :

Kod: Markera allt

#include <avr/io.h>     
#include <util/delay.h>


int main(void)
{
  int temp;
  
  //Display
  DDRD = 0xff;
  unsigned char SEGDISP[16] = {0x50,0xd7,0x4a,0x43,0xc5,0x61,0x60,0xd3,0x40,0xc1,0xc0,0x64,0x78,0x46,0x68,0xe8};
  int digit = 0;

    DDRB = 0x00;

  for ( ; 1==1 ; )
  {
    temp = (PINB & 0x08);
   
    if ( temp == 0 )
    {
		digit++
		PORTD = SEGDISP[digit];
    }
    else
    {
        PORTD = SEGDISP[digit];
    }
  }
  return 1;
}
Med den här koden visar displayen en 0 när jag ansluter till spänningskällan. Inget konstigt här, men när jag sedan trycker på knappen så visar den bara konstiga tecken.

I if-satsen vill jag ju öka variablen digit med 1 varje gång jag trycker på knappen:

Kod: Markera allt

 if ( temp == 0 )
    {
		digit++
		PORTD = SEGDISP[digit];
    }
Det känns som att jag ökar variablen på fel sätt, för om jag i if-satsen istället skriver:

Kod: Markera allt

 if ( temp == 0 )
    {
		PORTD = SEGDISP[digit+1];
    }
 else
    {
        PORTD = SEGDISP[digit];
    }
så skrivs en 1:a ut när jag trycker men en 0:a när jag släpper knappen.

Hoppas jag inte rörde till det för mycket :roll:
Användarvisningsbild
Swech
EF Sponsor
Inlägg: 4750
Blev medlem: 6 november 2006, 21:43:35
Ort: Munkedal, Sverige (Sweden)
Kontakt:

Re: hjälp med liten kodbit

Inlägg av Swech »

Så länge du håller in knappen så räknar väl koden upp med 1.... processorn är
bra mycket snabbare än dig så den visar 1.2.3.4.5.6.7.8.9. osv men för ögat blir det bara knepigt
och ser ut som ett märkligt tecken...

Swech
Användarvisningsbild
callelj
Inlägg: 351
Blev medlem: 9 april 2008, 18:03:25
Ort: Linköping

Re: hjälp med liten kodbit

Inlägg av callelj »

1. Börja med att lägga in en delay på nån millisekund efter knapptrycket.
Det blir massa kontaktstudsar med en knapp, dvs du får flera knapptryck.

1,5. Edit: Glömde att du kanske borde vänta tills knappen släppts också innan
du accepterar ett nytt tryck. Läg en liten loop eller liknande. Annars kommer
bara siffrorna samma som tidigare hända, om än långsammare.

2. Sen borde du ha en koll så du inte ökar "digit" för högt.
Annars kommer du flytta pekaren utanför vektorn och ut i minnesrymden där
du inte har en aning vad som finns.

3. Skriv while(1) istället för en for-sats, det tycker iaf jag är tydligare.

4. "PORTD = SEGDISP[digit++];" Gör att digit ökas med ett efter du har använt den.
"++digit" gör att värdet ökas direkt och används, samma med "digit+1"

SEGDISP var smart, den ska jag köra på nästa gång jag gör en 7-segment.
bos
Inlägg: 2311
Blev medlem: 24 februari 2007, 23:29:15
Kontakt:

Re: hjälp med liten kodbit

Inlägg av bos »

Istället för din for-loop skulle jag gjort såhär:

Kod: Markera allt

PORTD = SEGDISP[0];
while(1) {
  temp = (PINB & 0x08);
   
  if ( !temp ) {
    digit++;
    if (digit > 9) digit = 9;
    PORTD = SEGDISP[digit];
    while(!temp){}
    delay();
  }
}
Med reservation för att jag inte kan AVR, så delay() får du själv implementera. För exemplets skull duger nog det här:

Kod: Markera allt

void delay(void) {
  unsigned int foo = -1;
  while (foo--) {}
}
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: hjälp med liten kodbit

Inlägg av jesse »

while(!temp){}
och hur skulle !temp någonsin kunna ändra värde inuti den här loopen utan att du läser in porten igen?
Annars är tanken rätt - du måste vänta tills knappen släppts upp innan du kollar igen om den trycks ner. skippa variabeln temp helt och hållet och sätt dit (PINB & 0x08) så ska det stämma.

Mot kontaktstuds kan du sätta en 100-330 nF kondensator över kontakten. Om du inte har den så har du just tillverkat en kontaktstudsräknare - om processorn visar 0 först och sedan 7 när dy trycker på knappen en gång så har den studsat 7 gånger!
Senast redigerad av jesse 1 juli 2009, 10:41:10, redigerad totalt 1 gång.
bos
Inlägg: 2311
Blev medlem: 24 februari 2007, 23:29:15
Kontakt:

Re: hjälp med liten kodbit

Inlägg av bos »

Det har du förstås rätt i. Pinnen måste läsas av i loopen.
Christian
Inlägg: 86
Blev medlem: 3 november 2003, 22:54:49

Re: hjälp med liten kodbit

Inlägg av Christian »

Nu har jag uppdaterat min kod så att vektorn ej överskrids. Om jag provar helt utan delay, så visar displayen 0 innan jag trycker på knappen, och ändrar till 9 när jag tryckt. Där gör ju kontaktstudsen sin grej.. Provade att lägga en konding på 100 nF över kontakten men ingen skillnad.
Men var är det jag ska lägga in ett delay i koden? är det direkt efter jag har läst in temp?

Kod: Markera allt

#include <avr/io.h>     
#include <util/delay.h>

int main(void){
DDRD = 0xFF;
unsigned char SEGDISP[16] = {0x50,0xd7,0x4a,0x43,0xc5,0x61,0x60,0xd3,0x40,0xc1,0xc0,0x64,0x78,0x46,0x68,0xe8};  //Vektor för siffror på led-displayen.
DDRB = 0x00;
int temp; //variabel för knapptryck som får värdet 0 om knappen ej är nedtryckt, och 1 om den är nedtryckt.
int digit = 0; // Räknare för displayen.

while(1){
temp = (PINB & 0x08); // Lyssna på knapptryck.
//delay här??
if(!temp){   // Om temp är en 1 / knappen trycks ner.
++digit;   // Öka räknaren med 1.
if (digit > 9){ 
digit = 9;  //Om räknaren överstiger vektorns storlek, så stanna på sista siffran.
}
PORTD = SEGDISP[digit]; //Skriv ut det nya värdet.
}
else{
PORTD = SEGDISP[digit]; //Visa / behåll befintligt värde.
}
}
}
Senast redigerad av Christian 1 augusti 2009, 01:24:01, redigerad totalt 1 gång.
Användarvisningsbild
Swech
EF Sponsor
Inlägg: 4750
Blev medlem: 6 november 2006, 21:43:35
Ort: Munkedal, Sverige (Sweden)
Kontakt:

Re: hjälp med liten kodbit

Inlägg av Swech »

Gör som så att du kommenterar din kod med
beskrivning på vad du förväntar dig att hända.
Så som den är nu så är den svårläst för icke insatta

Av det jag förstår av C så kommer väl din räknare att räkna upp
så fort du trycker på knappen?

Swech
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: hjälp med liten kodbit

Inlägg av jesse »

Nej, du behöver inte lägga in nån delay. Det duger gott med kondensatorn (vanligtvis).

Däremot måste du vänta på att knappen släpps upp innan du börjar om från början. Annars räknar den ju upp tusentals gånger per sekund så länge knappen är nedtryckt.

Det är bra om du använder indentering av koden (hm.. heter det så?) , alltså, flytta texten åt höger en bit för varje ny { och flytta tillbaks lika mycket vid motsvarande } , annars blir det svårt att se vad som är vad bland alla } } }...

Du behöver inte skriva till displayen två gånger inne i IF-satsen - du kan initiera den i början så att den visar "0", sedan räcker det att uppdatera om digit ändras. Alternativt lägga den efter if-satsen och då behöver du inget "else".

I slutet på while- satsen, längst ner i programmet gör du en läsning av knappen igen
det upprepar du tills knappen är uppsläppt igen , dvs...

while (! PINB & 0x08) { }
// antar att det kan se ut nåt i den här stilen i C ???

Då kommer processorn att vänta tills du släppt upp knappen innan den räknar upp nästa gång.


En annan sak, som kanske inte är viktig just nu, men som blir väldigt viktig om du gör större program är att SEGDISP[ ] är en array av konstanter. Men du deklarerar den som vanlig variabel. Det innebär att du lagrar data i ramminnet helt i onödan. Det finns metoder att deklarera konstanter så att data hämtas direkt från flashminnet när de behövs. På så vis sparas både programkod och minnesutrymme.

Även variablerna temp och digit går att effektivisera: De behöver inte vara 32-bitars integer, utan klarar sig med 8 bitar, borde vara "char". Det tjänar du mycket kod (maskinkod alltså, inte C-koden) och tid på.
Christian
Inlägg: 86
Blev medlem: 3 november 2003, 22:54:49

Re: hjälp med liten kodbit

Inlägg av Christian »

Okej men om jag vill slippa kondensatorn och motverka kontaktstuds mjukvarumässigt var lägger jag delay:en då? =)
Är den andra inläsningen korrekt gjord nu i min koden?
Ska tänka på indenteringen nästa gång ;)

Kod: Markera allt

#include <avr/io.h>     
#include <util/delay.h>

int main(void){
DDRD = 0xFF;
unsigned char SEGDISP[16] = {0x50,0xd7,0x4a,0x43,0xc5,0x61,0x60,0xd3,0x40,0xc1,0xc0,0x64,0x78,0x46,0x68,0xe8};  //Vektor för siffror på led-displayen.
DDRB = 0x00;
int temp; //variabel för knapptryck som får värdet 0 om knappen ej är nedtryckt, och 1 om den är nedtryckt.
int digit = 0; // Räknare för displayen.

while(1){
temp = (PINB & 0x08); // Lyssna på knapptryck.
//delay här??
if(!temp){   // Om temp är en 1 / knappen trycks ner.
++digit;   // Öka räknaren med 1.
if (digit > 9){ 
digit = 9;  //Om räknaren överstiger vektorns storlek, så stanna på sista siffran.
}
PORTD = SEGDISP[digit]; //Skriv ut det nya värdet.
}
else{
PORTD = SEGDISP[digit]; //Visa / behåll befintligt värde.
}
while (!temp) { //Vänta tills knappen släppts upp igen
}
}
}
Användarvisningsbild
Icecap
Inlägg: 26636
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: hjälp med liten kodbit

Inlägg av Icecap »

Att lägga in ett delay i en knapptryckningsrutin är nästan alltid onödigt!

Ditt problem är grundläggande att du inte har koll på vad du gör när det finns en knapptryckning. Testa följande:

unsigned char Previous;

Temp = PINB & 0x08; // Reading the key status
if(Temp && !Previous) Digits++;
Previous = Temp;

Då räknas siffran upp en gång för varje knapptryckning. Om den räknar fler steg ska du testa med en kondensator över först innan du gör mer, då vet du om det är programfel eller kontaktstuts.

EDIT: Ha även koll på att denna rutin enbart läser knapporten en enda gången per genomgång, det är viktigt att det är så!
Senast redigerad av Icecap 1 augusti 2009, 08:50:29, redigerad totalt 1 gång.
Användarvisningsbild
Swech
EF Sponsor
Inlägg: 4750
Blev medlem: 6 november 2006, 21:43:35
Ort: Munkedal, Sverige (Sweden)
Kontakt:

Re: hjälp med liten kodbit

Inlägg av Swech »

Jag tror att du rör ihop det hela och tänker att bara för att du
har skrivit

Kod: Markera allt

temp = (PINB & 0x08); // Lyssna på knapptryck.
så uppdateras temp hela tiden...

den här raden kommer ju inte att funka

Kod: Markera allt

while (!temp) { //Vänta tills knappen släppts upp igen
temp är ju samma som tidigare, du läser inte in porten....

Swech
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: hjälp med liten kodbit

Inlägg av jesse »

:doh:

Snart är det väl dags att nån skriver en liten tutorial hur man läser av en knapptryckning med en µC. Verkar som om frågan kommer upp ofta i några olika versioner... börjar bli tröttsamt med samma frågor om och om igen.
Skriv svar