LED a tlačítko on/off

Ahoj, potřebuju udělat jednotlačítkové ovládání s mikrospínačem.
zmáčknu tlačítko a svítí led, zmáčknu podruhé zhasne ale vůbec mi to nejde

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

int main()
{
int i=0;
DDRB=0b11001111;
PORTB=0b00110000;

for(;:wink:
{

  if (bit_is_clear(PINB,5) && i==0)
  {
   i++;
   PORTB=0b01000000;
  
   _delay_ms(100);
  }

  
   else
   {
    PORTB=0b00000000;
    i--;
     _delay_ms(100);
   }
  }
 }

[/code]

a buďte semnou trpěliví, teprve s tím začínám.

cau,asi nejak takle …?, bez osetreni zakmitu

[code]
short flag=0;
int i=0;

while(true)
{
if (tlacitko ==1)
{
if(flag==0)
{
i++;
flag=1;
}
}
else flag=0;

if(test_bit(i,0)) led=ON; //testuje 0 bit v i
else led=OFF;
}[/code]

Pripadne vyskusaj toto:

[code]#define F_CPU 1000000UL
#include <avr/io.h>
#include <avr/interrupt.h>

#define SETBIT(ADDRESS, BIT) ((ADDRESS) |= (1<<(BIT)))
#define CLRBIT(ADDRESS, BIT) ((ADDRESS) &= ~(1<<(BIT)))
#define NEGBIT(ADDRESS, BIT) ((ADDRESS) ^= (1<<(BIT)))
#define TSTBIT(ADDRESS, BIT) ((ADDRESS) & (1<<(BIT)))

volatile unsigned int i=0;

ISR(TIMER0_OVF_vect){  //prerusenie kazdych 2,04mS


if(TSTBIT(PINB,PB5)==0)i++;
	else{ i=0;}

}

int main()
{

DDRB|=0b11001111;
PORTB|=0b00110000;

TIMSK|= (1<<TOIE0);//povolenie prerusenia TIMER0
TCCR0|=(1<<CS00); //prescaler 8 

sei(); //globalne povolenie preruseni

for(;:wink:
{

if(TSTBIT(PINB,PB5)==0 && (i>10))NEGBIT(PORTB,PB7);
					
   
 		}
} [/code]

už jsem to udělal takhle:

[code] if (bit_is_set(PINB,5))
{
if (i==0)
{
PORTB &= ~(1 << PB1); //(T2)
PORTB |= (1 << PB2); //(T3)
PORTB |= (1 << PB7); //logická 1(led)

  i++;
  _delay_ms(5000);
   
 }

 else
 {
  PORTB |=(1 << PB1);   //(T2)
  PORTB &= ~(1 << PB2); //(T3)
  PORTB &= ~(1 << PB7); // logická 0(led)
  
  i=0;
  _delay_ms(5000);
  
 }

}[/code]

Zkoušel jsem to udělat jak mi radil MiloPS3 ale nešlo mi to upravit tak jsem to nějak dal nakonec do kupy sám.
Je to možná trošku krkolomné ale k tomu k čemu to bude to je ideální :wink: ale díky za reakce.

O co když někdo stiskne tlačítko podruhé dříve, než za 5 sekund ?

nevim jestli ti to pomuze ale pomoci jednoho tlacitka se da negovat stav PORTC ^= (1 << 0); // PC0
to posledni cislo je nastaveni PC0 PC1 atd…
funguje to jednoduse po zmacknuti tlacitka se zapne dioda po zmacknuti znovu se vypne.

Případně u některých AVR (např. ATmega169, ATtiny2313) se zápisem “1” na PINx port také překlopí stav výstupního pinu, např.: PINB |= 1 << PB1; . Škoda že to není u více AVR.

To vůbec nevadí, je to právě lepší, protože to slouží k zapínání a vypínání koncového zesilovače :wink:

Tomu se říká z nouze ctnost. Není to v žádném případě příliš čisté řešení, nicméně, pokud funguje, proč ne. Jenom mě udivuje, že na přepínání 1 pinu používáš MCU, když na to stačí například 1 ks IO 7474. To MCU opravdu nedělá nic jiného, než přepíná 1 pin ?. Prodleva 5s, pokud by program dělal i neco jiného, je celkem brutálně dlouhá. A používat MCU na přepínání stavu 1 pinu mi zase přijde jako jít s kanónem na vrabce. Maximálně bych to pochopil jako první test seznamování se s procesorem, ale rozhodně ne jako finální program pro nějaké zařízení (nebo i jen jeho část) …

Pekne by to bolo so 6 pinovym mcu napr. ATTiny4/5/9/10

Balů ale ono to není moc nesmyslné použití a už jsem se s ním vícekrát setkal. Stačí 1 součástka (s vnitřním RC) a obslouží to např. i zákmity tlačítek. V klidovém stavu si může minimalizovat odběr, takže se dobře používá např. ve svítilnách, dají se snadno doplnit další funkce např. aby přidržením přešla na blikání nebo regulace jasu PWM. Jistě je to dobrý začátek na hraní si s MCU a k pozdějšímu rozšíření funkcí.

Na ošetření zákmitů tlačítek a další drobnosti (automatické vypínání při nízkém stavu baterie a jiné přídavné funkce) to beru jako dobré řešení i pro pouhé použití MCU jako vypínače. Toto ale není nic jiného, než začátek hraní si a poznávání MCU. Ale delay_ms nepřepíná mcu do klidového stavu ani nikterak nesnižuje spotřebu MCU. Ten sice “nic nedělá”, ale pořád jede na plný výkon, takže si myslím, že použití delay_ms(5000) sice navenek funguje, ale rozhodně je to maximálně nouzové řešení problému. Zákmity tlačítek a pětisekundová prodleva mezi reakcema na tlačítko se dá vyřešit daleko elegantněji a čistěji a navíc MCU nemusí běžet na 1 MHz, ale bohatě mu postačí kmitočet IntRC 128 kHz i s děličkou klidně až 256.

 _delay_ms(5000); 

za delay dlhší ako pár mikrosekúnd/desiatok mikrosekúnd by už snáď mal byť konečne zavedený nejaký nepodmienečný trest v trestnom sadzobníku za vraždu (procesorového času). :slight_smile:

Ak niekomu “zamrzne” mcu na 5 sekúnd, asi z toho nebude moc nadšený a hlavne nebude vedieť, že čo sa vlastne deje. Mala by tam aspoň niekde blikať LED upokojujúcej farby a svojím pravidelným blikaním tak s periódou jednej sekundy informovať obsluhu, že procesor žije a neutrhol sa napríklad prívod z napájania. To sa bez prerušenia za použitia takýchto zhovadilostí ako je _delay_ms() nedá dosiahnuť. Viem, že sa jedná o prácu začiatočníka a práve preto čím skôr mu to niekto povie, tým preňho lepšie :slight_smile:

To Martin: Líp bych to asi nenapsal …

Ale je to jeho vlastní řešení a účel to splňuje. K eleganci se dopracuje časem.

Mám tam 2x tlačítko se stejným účelem (on/off 1 tlačítkem) a pak tam je ješte u jednoho tlačítka funkce, že při zmačknutí nejdříve připojí trafo od zesilovače a po určitě prodleve zapne funkci MUTE, při vypnutí to same jen naopak, nejdříve vypne MUTE a pak odpojí trafo (je to z toho důvodu, aby se v bednách neprojevovaly pazvuky)

Jako první jsem tam měl MCU DIL8 ale postupně to (jak tu někdo psal) rozšiřuju o další funkce.
Vím že pro vás to vypadá jako naprostá zhovadilost, popravdě mě trošku taky, ale lépe bych to asi nedal do kupy, nedávno jsem teprve blikal LEDkou, takže sem rád že to funguje jak má, rád bych tam přidal funkce jak jste psali, např aby se MCU vypínal a šetřil energii, ale to bych nedokazal, to by jste mi museli dat konkrétní kod, ale to bych se potom nic nenaučil.

Pro tohle uvedené použití se už MCU hodí skvěle.

Nie, samozrejme ze nevypada. Zhovadilost je len to _delay_ms().
No a na to som Ta upozornil, takze vies v ktorom smere sa da vec optimalizovat. :slight_smile:

Dolezite je, ze Ti to funguje k Tvojej spokojnosti. Iba take vysledky prace dokazu cloveka posunut dopredu. Ine nie. Darmo budu efektivne a uhladene napisane. Takze len tak dalej. :slight_smile:

Martine trošku bych Ti oponoval. :slight_smile: V hlavní smyčce, když procesor nemá jinak co dělat (a není důvod k šetření výkonu sleepem) bych dlouhý delay považoval za celkem vyhovující. I když spíš bych viděl rozumnější čas asi tak 1,5 sekundy než 5 sec. V takové jednoduché aplikace bych to takhle také nejspíš řešil. A až se objeví potřeba něčeho dalšího tak to pozměnit. Samozřejmě že v obsluze přerušení by _delay_ms neměl co dělat. … Ta LED “živák” by mohla blikat i takhle, bez přerušení, doplněním zas nějakým _delay_ms(50) s čítačem průchodů do 10. Ale u takové jednoduché aplikace to snad ani není nutné, protože je docela vidět zda funguje nebo ne.

Takhle to dává smysl. Nicméně, doporučil bych Ti vyhodit ten nesmyslný delay 5000 ms a vyřešit to pomocí čítačů s podporou proměnných/příznaků apod. Co se týká úspory energie, tak to má větší smysl především u bateriově napájených zařízení. Pro síťové napájení je úspora tak mizivá, že nemá smysl se s vypínáním MCU nějak příliš zabývat. Ke snižování spotřeby se používají různé režimy SLEEP módů. Jinak SLEEP lze použít i pro případ nějakého časování (i pro těch Tvých 5 sekund). Ne, že bys na 5 sekund uspal MCU, ale použiješ-li časovač, tak si snadno spočítáš, za jak dlouho od něj přijde přerušení. Snadno si spočítáš, kolik přerušení přijde za 5 sekund. V přerušení tedy přičítáš 1 k nějaké proměnné (nebo jednodušeji - na začátku požadovaného cyklu nastavíš nějakou pro a pak jí v přerušení odečítáš až do 0). Po každém přerušení má proměnná jinou hodnotu a přerušení Ti probudí MCU ze SLEEP módu. Ty po probuzení ze SLEEP módu (například každé 2 ms) provedeš, co potřebuješ (například 1x za X1 přerušení = obsluha LCD displeje, 1x za X2 přerušení přečtení AD, 1x za X3 přerušení obsluha toho Tvého tlačítka apod.) a znova MCU uspíš. Tohle používám, když časuju přerušení třeba na refresh 4-místného LED displeje, který se refreshuje na cca 122 Hz => Fmcu IntRC 8 MHz, 8-bitový časovač, prescaler 64, 4 segmentovky => 8000000/256/64=488,28125/4=122,0703125 Hz refresh displeje. Jinými slov, čítač přeteče 488,28125x za sekundu (a provede 256x64 jednocyklových instrukcí = tedy až 16384 instrukcí) => mezi jednotlivýma přerušeníma uběhne 2,048 ms. Hlavní smyčka by byla tedy schopná provést se několiksetkrát. Tudíž provedu hlavní smyčku a procesor opět uspím. Pokud bubu potřebovat interval 5 sek, pak mi stačí nastavit nějakou proměnnou na 5/0,002048=2441 (zaokrouhleno na celá čísla). V přerušení budu proměnnou odečítat a akci provedu až po vynulování proměnné = tedy cca za 5 sekund. Pokud proměnná dosahne požadované hodnoty, tak provedeš, co máš, a proměnnou vynuluješ. Nebo opačně - po vynulování proměnné provedeš, co máš a proměnnou přednastavíš na počet cyklů, po kterých se má akce znova vykonat. Funkce, které je potřeba vykonávat pravidelně (například refresh 7-segmentového LED displeje, refresh 7-segmentového LCD apod.) se dávají právě do přerušení a hlavní program zajišťuje pouze změnu zobrazovyných hodnot. Něco na způsob zápisu do video-RAM a přerušení se stará o přenos dat na segmentovky, zajišťuje blikání LEDkama apod. Například pokud použiješ 7-segmentový LED displej (třeba 3-místný) v multiplexovaném provozu, tak pokud použiješ tu delay 5 sek, pak se stane to, že Ti po obsluze tlačítka na 5 sekund displej zamrzne a bude svítit jenom 1 číslice a pak se teprve znova rozběhne.

Nevím, jestli jsem Ti naznačil jednu z mnoha možností dostatčně srozumitelně. Každopádně zkoušej. Zkušenosti jinak nenasbíráš. Když budeš potřebovat poradit nebo nasměrovat, tak vůbec neboj se zetpat. Já osobně neodpovídám jen na dotazy tipu “mám naprogramovat něco a nevím, jak na to. Napište mi kód.” Tohle nechávám v drtivé většině ležet nebo odpovídám jen tím, že se pokusím naznačit možnost a “snaž se…”. Celý kód píšu pouze tehdy, že vidím snahu, ale nedaří se. Někdy je lepší kousek kódu napsat a když je snaha na druhé straně, pak je velká šance, že si dotyčný kód projde pokusí se z něho poučit.

:arrow_right: administrator: příspěvek byl upraven
Citace byla pozměněna.