atmega16 problem LÖST

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
jyrgen
Inlägg: 84
Blev medlem: 11 juli 2006, 20:24:54
Ort: Västerås

atmega16 problem LÖST

Inlägg av jyrgen »

Jag har gjort ett litet kretskort till ett projekt med en atmega16, några lysdioder och några knappar på. Jag har även gjort ett testprogram i c så när man håller ner en knapp så lyser en diod. Problemet är när jag nu vill lägga in en while loop som ska göra så att jag kan trycka på en knapp för att tända och sedan låta det vara tänt till en annan knapp blir nertryckt då ska det vara släckt till den andra knappen blir nedtryckt igen. Detta fungerar inte och jag har provat oändligt många sätt att få den att hålla ett värde till knappen blir nedtryckt. Vad kan jag ha gjort för fel, kan det vara hårdvarufel? Jag har skrivit koden som följer:

Kod: Markera allt

while(1)
{
     while(!(PINB & 0x08))
     {
         PORTD = 0b10000111 & PORTD;			//Tänder lysdioden
      }
      while(!(PINB & 0x04))
      {
          PORTD = 0b01111000 | PORTD;			//Släcker lysdioderna
       }
}
Det jag tycker borde hända är att lysdioden blir tänd tills !(PINB & 0x08) ej är uppfyllt. I testprogrammet använder jag !(PINB & 0x08) i en if-sats för att tända dioden när jag håller ner en knapp och det fungerar.
Senast redigerad av jyrgen 8 november 2008, 09:10:37, redigerad totalt 6 gånger.
Användarvisningsbild
vfr
EF Sponsor
Inlägg: 3515
Blev medlem: 31 mars 2005, 17:55:45
Ort: Kungsbacka

Inlägg av vfr »

Använd gärna "CODE"-taggar när du postar kod. Det blir annars nästan helt oläsbart, trots enkelheten i programmet. 8)
thepirateboy
EF Sponsor
Inlägg: 2109
Blev medlem: 27 augusti 2005, 20:57:58
Ort: Borlänge

Inlägg av thepirateboy »

Nu vet vi inte hur du kopplat men det känns som problemet borde kunna lösas med enkel if-else sats.

if(knapp1 nedtryckt)

tänd lysdioder

else if(knapp2 nedtryckt)

släck lysdioder
jyrgen
Inlägg: 84
Blev medlem: 11 juli 2006, 20:24:54
Ort: Västerås

Inlägg av jyrgen »

Sådär ändrat till code taggar. Jo skulle kunna gå med if elseif men är ganksa irriterande att inte kunna göra en vanlig while loop. Får kika på det imorn.
Norpan
Inlägg: 2229
Blev medlem: 12 april 2008, 18:20:27
Ort: Småland

Inlägg av Norpan »

Helt obildad i C, men slutar inte din första while vara så fort du inte uppfyller (PINB & 0x08), eller är det klister på en whilesats?
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Jag har inte funderat så mycket på det, men har *du* funderat
på vad som händer under kontaktstudsarna ? Det är ju inte så
att koden kommer att vandra snyggt från den ena till den andra
while satsen efter hur du trycker, utan kommer att hoppa runt
helt hysteriskt...
jyrgen
Inlägg: 84
Blev medlem: 11 juli 2006, 20:24:54
Ort: Västerås

Inlägg av jyrgen »

Nu har jag felsökt och kommit fram till att jag överst i koden sätter ett register för att använda kontinuerlig AD-omvandling för en avståndssensor. När jag kommenterar bort den raden så fungerar det med while loopar. Koden ser ut som följer och det är raden som är bortkommenterad som är det kritiska(//ADCSRA=0xEE). Jag måste ju uppenbarligen gjort något fel för nog måste det gå att köra kontinuerlig AD-omvandling samtidigt som man vill använda while loopar?

Det som händer när jag kör programmet som fungerar är att jag trycker på en knapp och då släcks dioderna. Trycker jag sedan på den andra knappen så tänds dioderna.
Om jag sedan använder kontinuerlig AD-omvanling så är endast dioderna tända medans jag håller ner en av knapparna, släpper jag den så släcks dioderna. Det är som att programmet skulle startas om hela tiden.

Här kommer koden

Kod: Markera allt

DDRA = 0x00;	//PinA ingång för avläsning av avstångssensorn
DDRB = 0x00;	//PinB ingång
DDRD = 0xFF; 	//PortD utgång		

SREG = 0x80;		//Aktiverar interrupt
//ADCSRA=0xEE;		//Kontinuerlig AD-omvanling
ADMUX =0x20;	        //Läser av AD0
	
PORTD = 0b01111000 | PORTD;			//Släck lysdioderna
	
while(1)
{
while(!(PINB & 0x08))
{
	PORTD = 0b01111000 | PORTD;			//Släcker lysdioderna 
}
while(!(PINB & 0x04))
{
	PORTD = 0b10000111 & PORTD;			//Tänder lysdioderna
}
Användarvisningsbild
anrhm
Inlägg: 371
Blev medlem: 3 november 2005, 15:13:33
Ort: Norrtälje

Inlägg av anrhm »

Det känns som att du i stort sett besvarar din egen fråga.

Du ställer in ADC på att starta en omvandling och generera ett avbrott när den är klar med omvandlingen. Var i koden hanterar du det avbrottet och vad händer om du inte har någon rutin för detta?
jyrgen
Inlägg: 84
Blev medlem: 11 juli 2006, 20:24:54
Ort: Västerås

Inlägg av jyrgen »

Ok, ja det hade jag ju missat att den genererade ett interrupt när den var klar. Hur tar jag hand om ett sådant interrupt?
Användarvisningsbild
anrhm
Inlägg: 371
Blev medlem: 3 november 2005, 15:13:33
Ort: Norrtälje

Inlägg av anrhm »

Kod: Markera allt

#include <avr/interrupt.h>

ISR(ADC_vect)
{
    // user code here
}
Se här: http://www.it.lth.se/digp/Avr-libc-1.4. ... rupts.html

Och tänk på att hålla avbrottshanteraren så kort som möjligt. Du vill inte hänga kvar där allt för länge...
jyrgen
Inlägg: 84
Blev medlem: 11 juli 2006, 20:24:54
Ort: Västerås

Inlägg av jyrgen »

Ok, tackar för det. Om jag nu inte vill använda interrupt borde jag då inte kunna sätta ADCSRA=0xE6 och SREG = 0x00. Får ej detta att fungera utan får samma problem som förut att man måste hålla ner knappen för att lysdioderna ska tändas. Får inte heller interupthanteringen att fungera som den ska tycker jag. Har skrivit så här.

Kod: Markera allt

#include <avr/io.h>
#include <avr/interrupt.h>

ISR(ADC_vect);

int main(void)
{
	DDRA = 0x00;		//PinA ingång för avläsning av avstångssensorn
	DDRB = 0x00;		//PinB ingång
	DDRD = 0xFF; 		//PortD utgång		

	SREG = 0x80;		//Aktiverar interrupt
	ADCSRA=0xEE;		//Kontinuerlig AD-omvanling
	ADMUX =0x20;		//Läser av AD0
	
	PORTD = 0b01111000 | PORTD;	//Släck lysdioderna
        while(1)
        {
               while(!(PINB & 0x08))
               {
                      PORTD = 0b10000111 & PORTD;	//Tänder lysdioden
                }
                while(!(PINB & 0x04))
                {
                     PORTD = 0b01111000 | PORTD;	//Släcker lysdioderna
                }
         }
}

ISR(ADC_vect)
{

}
Borde det nu inte bli likadant som om jag ej använder ad omvandling? Tycker inte det borde märkas eftersom jag inte gör något i interuptfunktionen, men än en gång samma problem som innan.
SvenW
Inlägg: 1156
Blev medlem: 24 april 2007, 16:23:10
Ort: Göteborg

Inlägg av SvenW »

Svårt att gissa exakt vad som är problemet, men här är tre saker att undersöka:

1. Störning på inpinnen.
Lägg på en kondensator nära pinnen.

2. Optimeringsflaggan till kompilatorn.
Variera den. Titta i lst-filen, det är lärorikt.

3. Watchdog-timern.
Prova med #include <avr/wdt.h> och lägg in wdt_reset () i looparna. Även i ISR-rutinen.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Var är koden för ISR(ADC_vect) (se anrhm's inlägg) ??
Användarvisningsbild
cykze
EF Sponsor
Inlägg: 1539
Blev medlem: 8 april 2004, 10:40:28
Ort: Uppsala

Inlägg av cykze »

Lite tips: :)


1. Tilldela inte registrena tal. Använd bitnamnen istället. Det gör det otroligt mycket enklare att tyda koden, både för dig själv och andra.

Ex.
ADCSRA = _BV(ADSC) | _BV(ADEN); (bara ett exempel! Kolla upp bitnamnen i databladet.)
eller
ADCSRA = (1<<ADSC) | (1<<ADEN);

Annars är det omöjligt att avgöra om du sätter rätt bitar, såvida man inte har databladet framför sig.

2. Jag är osäker på att om man kan köra:

Kod: Markera allt

ISR(ADC_vect);

KOD

ISR(ADC_vect)
{
// din kod
}
när det gäller ISR-rutiner. Det vanliga brukar annars vara att man kör:

Kod: Markera allt

ISR(ADC_vect)
{
// din kod
}

KOD
Men det är möjligt att ditt sätt också fungerar.


3. Har du pull-up eller pull-down på ingångarna?


4. PORTD = 0b01111000 | PORTD;
kan skrivas som
PORTD |= 0b01111000;
för att göra det tydligare (när man väl har vant sig vid syntaxen) och minska risken för slarvfel.

För att göra det ännu tydligare:
PORTD &= ~_BV(PD4); // => PD4 = 0
PORTD |= _BV(PD4); // => PD4 = 1


5. För att aktivera/inaktivera interrupts globalt kan du köra sei()/cli(). Då slipper du ändra direkt i SREG.
jyrgen
Inlägg: 84
Blev medlem: 11 juli 2006, 20:24:54
Ort: Västerås

Inlägg av jyrgen »

Efter någon timmes felsökning till har jag inte fått igång det hela. Dock har jag kommit fram till att allt fungerar om jag kopplar ur avståndssensorn. Har jag den i går det inte. Avståndsensorn jag använder är en GP2D12. Har provat med två olika avstådssensorer så den borde inte vara trasig. Har även mätt utspänningen den levererar vilket också ser ut att stämma.


SvenW:
1. Har provar det men bli ingen skillnad.
2. Hur ser jag optimeringsflaggan?
3. Provade watchdog reseten men blev ingen skillnad där heller.

sodjan: Vad menar du för kod, just nu vill jag bara att den ska klara det jag nämnt ovan och där är ju ISR(ADC_vect) med. Jag vill ju inte göra något när det sker ett interrupt.

cykze:
Ypperliga tips det borde jag lära mig och använda.
2 .Provade att lägga interrupfunktionen överts men ingen skillnad.
3. Jag använder poll down.
Skriv svar