Sida 1 av 2

atmega16 problem LÖST

Postat: 27 oktober 2008, 19:45:09
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.

Postat: 27 oktober 2008, 20:00:37
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)

Postat: 27 oktober 2008, 22:07:46
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

Postat: 27 oktober 2008, 22:36:06
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.

Postat: 27 oktober 2008, 22:46:44
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?

Postat: 27 oktober 2008, 23:06:11
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...

Postat: 28 oktober 2008, 13:23:34
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
}

Postat: 28 oktober 2008, 14:37:46
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?

Postat: 28 oktober 2008, 17:11:19
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?

Postat: 28 oktober 2008, 19:22:19
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...

Postat: 29 oktober 2008, 09:07:49
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.

Postat: 29 oktober 2008, 12:13:31
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.

Postat: 29 oktober 2008, 12:17:20
av sodjan
Var är koden för ISR(ADC_vect) (se anrhm's inlägg) ??

Postat: 29 oktober 2008, 18:11:49
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.

Postat: 29 oktober 2008, 21:48:38
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.