Sida 1 av 1
hjälp med liten kodbit
Postat: 30 juni 2009, 22:14:09
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

Re: hjälp med liten kodbit
Postat: 30 juni 2009, 22:33:30
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
Re: hjälp med liten kodbit
Postat: 30 juni 2009, 22:55:30
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.
Re: hjälp med liten kodbit
Postat: 1 juli 2009, 09:15:18
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--) {}
}
Re: hjälp med liten kodbit
Postat: 1 juli 2009, 10:36:56
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!
Re: hjälp med liten kodbit
Postat: 1 juli 2009, 10:40:48
av bos
Det har du förstås rätt i. Pinnen måste läsas av i loopen.
Re: hjälp med liten kodbit
Postat: 1 augusti 2009, 00:10:14
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.
}
}
}
Re: hjälp med liten kodbit
Postat: 1 augusti 2009, 01:03:36
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
Re: hjälp med liten kodbit
Postat: 1 augusti 2009, 01:22:07
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å.
Re: hjälp med liten kodbit
Postat: 1 augusti 2009, 01:34:40
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
}
}
}
Re: hjälp med liten kodbit
Postat: 1 augusti 2009, 08:41:02
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å!
Re: hjälp med liten kodbit
Postat: 1 augusti 2009, 08:45:26
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
Re: hjälp med liten kodbit
Postat: 2 augusti 2009, 00:16:04
av jesse
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.