ATTINY 2313-běžící LED světlo, změna směru stiskem tlačítka

Zdravim, podle tohoto zadání se snazim napsat program v C: Napište program pro běžící světlo. Svítít bude vždy 1 LED 300ms. Po spuštění programu světlo poběží vpravo. Po každém stisku tlačítka (PD2) s směr změní v opačný. Časový interval realizujte smyčkou.

Program ale nefunguje spravne… po spusteni sviti vsechny diody…

PROGRAM :

r-scape.over.cz/img/HOTOVO.txt

:arrow_right: administrator: přejmenováno z “ATTINY 2313 - LED”

:arrow_right: administrator: přiloženy externí soubory
HOTOVO.txt (1.6 KB)

Zdar.

Takže začnu tím jednodužším.

DDR=0xFF; PORT = 0xFF;

Sice funguje, jak má, ale pro lepší přehlednost použij DDRB a PORTB.

if((PIND & 0x03) == 0)

Sice něco testuje, ale tlačítko PD2 to zcela určitě není.
To by bylo asi takhle: if(PIND & (1<<PD2))
Navíc ti je tato smyčka zcela k ničemu, protože přerušení má vždycky přednost.
Takže se vlastně žádné zpoždění nekoná.
Ve výsledku to vypadá zhruba tak, že je ISR(INT0_vect) voláno stále dokola, velmi ryvhle se přepínají LEDky a ty ti neustále svítí.

Být tebou tak zapomenu na nějaké přerušení a udělám to pořádně v mainu klasickým testováním vstupů.

Aha, muzes mi dat aspon priklad toho testovani v vstupu v mainu ? Diky

:arrow_right: administrator: příspěvek byl upraven
Odkaz byl vyjmut z code.

První věc je zapojení, není jasné jestli tlačítko spíná na L nebo na H.
Další věc je, že jsi uplně mimo zadání. Dioda se má posouvat ve smyčce, takže ten posun zřejmně nesmíš mít v přerušení


while(1)
{

	if(smer == 0xFF)
	{
		//beh hada vlevo
		PORT = ~ posledni_bit;								//PORTB = 01111111 sviti prvni dioda vlevo
		if(posledni_bit == 0x80)posledni_bit = 0x01;		//10000000 -->00000001 jestli bude dioda posledni tak zase zpet na 1.
		else posledni_bit <<= 1;							//jinak posunuj doleva	
	}
	//smer vpravo
	if(smer == 0x00)
	{
		//beh hada vpravo
		PORT = ~ posledni_bit;								//PORTB = 01111111 sviti prvni dioda vlevo
		if(posledni_bit == 0x01)posledni_bit = 0x80;		//00000001 -->10000000 jestli bude dioda posledni tak zase zpet na 1.
		else posledni_bit >>= 1;							//jinak posunuj doprava

    }

_delay_ms(300);

}

a do preruseni pak das zmenu smeru

ISR(INT0_vect)												//preruseni od INT0 na Portu D 
{
smer = ~smer;
}

a dalsi vec, preruseni INT0 rising edge je

GIMSK=0x40;
MCUCR=0x03;
EIFR=0x40;



Zaldo: iv tom přerušení to má ve smyčce :smiley:

[code]
#define F_CPU 20000000UL // 20 MHz
#include <avr/io.h>
#include <util/delay.h>

#define LEDkrok 500 // 500ms krokování ledek

char smer = 0x00;
char posledni_bit = 0x80;

int main(void)
{
unsigned char LAST_D, INC_D=0;
unsigned int odp_led=0;

DDRB=0xFF; PORTB = 0xFF;
LAST_D = PIND & _BV(PD2);

while(1)
{
_delay_ms( 1 ) ;
// Detekce tlačítka s ochranou proti zákmitům
if (LAST_D == (PIND & _BV(PD2)))
{
INC_D = 0;
}
else if (++INC_D > 10)
{
INC_D = 0;
LAST_D = PIND & _BV(PD2);
if (LAST_D & _BV(PD2)) smer = ~smer;
}
//krokování ledek
if (++odp_led >= LEDkrok)
{
odp_led = 0;
if(smer == 0xFF)
{
PORTB=~posledni_bit;
if(posledni_bit == 0x80) posledni_bit = 0x01;
else posledni_bit <<=1;
}
if(smer == 0x00)
{
PORTB=~posledni_bit;
if(posledni_bit == 0x01) posledni_bit = 0x80;
else posledni_bit >>= 1;
}
}
}
}[/code]

njn, ted jsem si vsiml, že časový intervel má být realizován smyčkou. Ono jak to tady čtu tyto domaci ukoly tak v tech zadani je vcelku zmatek.
Ono je otazka, jestli vubec muzou pouzit funkci delay a jestli to zpozdeni nemaji udelat treba funci for(;;:wink:

Díky za vysvetleni a za program, jen moc nechapu tendle zapis :
LAST_D = PIND & _BV(PD2);

a při simulaci na portu B se diody nepohybuji ani na jednu stranu a kdyz sem nastavil na portu D PD2 na 1 tak taky nic vzdy to skonci u tohodle :

if (++odp_led >= LEDkrok)
program2.txt (971 Bytes)

Při ručním krokování v simulatoru AVR Studio 5 jsem zadnou chybu nenasel.

if (++odp_led >= LEDkrok) to je moc fajne ani by ma nenapadlo nieco take napisať…

Ja to zkousel v AtmelStudiu 6

Jen nechápu tendle zápis PIND & _BV(PD2); je to neco jako
PIND & <<(PD2); ? bitovy posun vlevo o hodnotu PD2 na PIND ?

_BV je makro (bit value):

#define _BV(bit) (1 << (bit))

Ok, uz vim ze je to makro, mohl bys mi jeste podrobneji vysvetlit funkci? tak jak sem to ja rozepsal trosku vis nevim jak tomu mam porozumnet. Diky :smiley:

Nasel by se tu nekdo kdo by mi vysvetlil co PRESNE dela todle :
PIND & _BV(PD2); ? DIKY

Uz sem na to mozna prisel :smiley: napsal sem si to takhle if(PIND & (1<<PD2))
takze testuje jestli na pinu D je PD2 = 1 ? nic jinyho me uz nenapada :smiley:

:arrow_right: administrator: příspěvek byl upraven
Předchozí příspěvky se necitují.

Ano.
PIND & _BV(PD2);
(PIND & (1<<PD2))

je v podstatě jedna a tá samá podmínka.

A pokud ještě stále dumáš nad "if (++odp_led >= LEDkrok) ",
tak tato podmínka tě pustí dál až celý cyklus while(1) proběhne 500x.

**Atlan: **Teď nevím… to myslíš pochvalně nebo sarkasticky?

Jestli je potřeba ještě podrobnější vysvětlení:

PD2 je číslo pinu 2 portu D, což je číslo 2. Makro _BV(PD2) vytvoří číslo (1 << 2), což znamená jednička posunutá o 2 bity doleva. Výsledkem je číslo 4, tedy binárně číslo 00000100b. Operace PIND & 00000100b maskuje hodnotu portu D tímto číslem, to znamená že v závislosti na stavu bitu 2 portu D bude výsledek 00000100b nebo 00000000b (všechny ostatní bity se vynulují). Použije-li se výsledek v podmínce, je podmínka splněna pro nenulová čísla, tedy je-li bit 2 portu D nastavený.

Ok, uz to chapu DIKY vsem