KT Zár1

2013-01-24

 

Már régóta megvettem egy rotary encoder névre hallgató eszközt. Aki nem ismerné, ez egy olyan tekerőgomb, amit tetszőlegesen tekergethetünk jobbra/balra. Két érintkező van benne, ezek fázisban eltolva kapcsolnak, így megállapítható, hogy balra, vagy jobbra tekertük éppen. Van olyan verziója is, amelyik szerszámgépek tengelyére szerelhető, és precizíós vezérlést tesz lehetővé. Sőt, a régi golyós egerek is ilyen elven működtek. Ezt most kifejezetten gombnak gyártotta az ALPS, és a HQ-Video-nál szereztem be. A két kontaktuson kívül, ebben egy harmadik kapcsoló is van, ezt a gombot megnyomva tudjuk működtetni. Persze sokkal olcsóbb ha veszünk három nyomógombot, és ugyanakkor ennek a cuccnak mégis van több előnye. Pédául, ehhez elegendő egyetlen furat az előlapon. Ez akkor is jó, ha IP-s készüléket kell készítenünk. De az is jó, ha mondjuk egy menüből gyorsan kell választanunk, vagy egy értéket beállítanunk. Mivel most ezt a dugdosós panelt használom, csináltam hozzá egy öcsi panelt. Nem azért van ilyen sok lába mert ennyi kivezetés kellett, hanem hogy stabilabban kapaszkodhasson.

Itt látható az áramkör, amivel az elmúlt napokban küzdöttem.

Ha végig követi az ember a vezetékeket, ez alábbi logikai rajzot kapja :). Jórészt megegyezzik a korábi LCD áramkörökkel. Ki lett egészítve egy SET kapcsolóval, amit valójában egy dugaszolható huzalla valósítottam meg. Továbbá ki lett egészítve az encoder három kontaktusával. Túl mély átgondolás ne keressen a kedves olvasó a lábak kiosztásában, így sikerült.

Korábbi szokásomtól eltérően nem az egész programot, csak az érdekes és újabb kódrészleteket teszem ki ide a web lapra. Az egész program, plusz egy kiegészítő teszt program letölthető egybecsomagolva a lap alján lévő linkről.

Ez az a függvény, ami az encodert kezeli. Egészen addig cirkulálunk egy while ciklusban, amig meg nem tekerjük egy kattanásnyit, vagy meg nem nyomjuk a gombot. A gombnyomás kezelése viszonylag egyszerű, ha az előző periódusban nem volt megnyomva, akkor ez egy új kattintás. A tekerés által létrehozott kombinációkat megjegyzésben a függvény elé tettem. Amikor megváltozik az A-B vezetékek állapota, beléptetem az eg változóba. Ha az eg-ben vagy az egyik, vagy a másik minta van, akkor egy osztasnyit elfordítottuk a gombot. Az első verzióban csak két mintát figyeltem, de az nem volt jó, mert az encodert hajlamosak vagyunk néha kicsit recegtetni, és ezt hibásan tekerésnek jelezte. A függvény három értéket tud visszaadni, a gombnyomást, a tekerés let, és a tekerés felt.


// <- 11 01 00 10 11     vezetekek allapota egy kattanasnyi elfordulas kozben
// -> 11 10 00 01 11

UC jelado( void)                                 // encoder lekerdezese
{
   static UC e= 0;                               // A-B vezetekek elozo allapotai
   static UC eg= 0;                              // nyomogomb elzo allapota
   UC a= 0;                                      // visszaadott kod
   UC i;                                         // A-B vezetek lekerdezesehez
   while( a == 0)
   {
      if( BTC( PINB, 4))                         // gomb le van nyomva?
      {
         if( eg == 0) a= K_GOMB;                 // ha korabban nem volt
         eg= 1;
      }
      else                                       // gomb nincs lenyomva
      {
         eg= 0;
         i= (PIND & 0B00001100) >> 2;            // A-B vezetekek beolvasasa
         if( (e & 0B00000011) != i)              // valtozas?
         {
            e= ( e << 2) | i;                    // valtozas eltarolasa
            if ( e == 0B10000111) a= K_FEL;      // jobbra
            if ( e == 0B01001011) a= K_LE;       // balra
         }
      }
      _delay_us( 500);                           // perges menetesites
   }
   return a;   
}

Ez a rutin egy számjegy beállítását teszi lehetővé. Az x változóban megadjuk, hogy az adott számjegy az LCD második sorában, melyik oszlopban legyen. A számjegynek egy kvázi véletlen kezdőértéket adunk 0..7 tartományban. Ez azért érdekes, mert ha monjuk mindig nulla értékről indulnánk, akár egy sima akusztikus poloskával is meg tudnák hack-kelni a zárunkat. A számjegy 0..9 tartományban állítható, így a hexa kiíró függvénnyel is kiirathatjuk.


UC szamjegy( UC x)                               // egy szamjegy beallitasa
{
   UC n;                                         // szamjegy
   UC k= 0;
   n= rnd & 0B00000111;                          // kvazi veletlen kezdoertek
   while( k != K_GOMB)                           // amig nem nyomjak meg a gombot
   {
      lcd_yx( 1, x);
      lcd_putc_hex( n);
      k= jelado();                               // varakozas beavatkozasra
      if( k == K_FEL) n++;
      if( k == K_LE) n--;
      if( n == 10) n= 0;
      if( n == 255) n= 9;
   }
   return( n);
}

Csináltam egy kis megszakítást, 125 Hz gyakorisággal. 4 MHz- es órajelből ez sikerült :(. Itt van annak a bizonyos kvázi véletlen számnak a képzése. Egy 8 bit-es számláló pörög folyamatosan, aminek az alsó 3 bit-jét használom. A varakozas egy olyan számláló, amibe ha beállítunk egy értéket, másodpercenként 125-tel csökken. Ezt használom hibás kombináció esetén 100 másodperces tiltáshoz, illetve, a nyitáskor csak 4 másodpercre adunk áramot a relének, mert sokat fogyaszt.


ISR( TIMER0_COMPA_vect)                          // 125Hz megszakitas kezelese
{
   if( varakozas) varakozas--;                   // visszaszamlalas
   rnd++;                                        // kvazi veletlen szam leptetese
} 

A WinAVR-ben rendelkezésünkre állnak a belső EEPROM kezelésére függvények, de annyira belezavarodtam, hogy milyen típusú adatot és pointert használjak, hogy inkább aa mikrovezérlő adatlapján lévő C függvényeket tettem bele a programomba, igaz kicsit átalakítottam.


void ee_write( UC cim, UC adat)                  // EEPROM irasa
{
   while( BTS( EECR, EEPE));                     // varakozas mig elozo iras befejezodik
   EEAR= cim;
   EEDR= adat;
   BS( EECR, EEMPE);
   BS( EECR, EEPE);
}
 
UC ee_read( UC cim)                              // EEPROM olvasasa
{
   while( BTS( EECR, EEPE));                     // varakozas mig elozo iras befejezodik
   EEAR= cim;
   BS( EECR, EERE);
   return EEDR;
}

Itt látható a main függvény. Először inicializálásra kerülnek az áramkörök. Megvizsgálja, hogy a SET kapcsoló be van-e kapcsolva? Ha igen akkor bekér 6 számjegyet, és eltárolja. A tárolást megelőzően, tulajdonképpen úgy hagyhatjuk jóvá a beadott kombinációt (N<->I), hogy igen esetén jobbra kell a gombot tekerni. Egyéb esetben a beállítás újra kezdődik. Az új kombináció beállítása után töröljük a TILT flag-e, és szépen végtelen ciklusba kerülünk, vagyis nem csinálunk semmit ki/be kapcsolásig. Azért kellett a TILT flag-et is törölni, mert a programozó az EEPROM tartalmat is feülírja, és nehogy már nekem kelljen minden program letöltés után majdnem 2 percet várnom!

Normálisan a képernyőre ki van írva, hogy Zárva, és az áramkör várja, hogy nyomjuk meg a gombot. Ezt követően betekergethetjük a 6 számjegyet. Jóváhagyás megint jobbra tekeréssel. Ekkor a beállított számjegyeket összehasonlítja a korábban elmentettekkel, ha egyezik, négy másodpercre bekapcsolja a LED-et (erre a vezetékre kell illeszteni a mágnes zárat). Ha nem akkor jön a TILT-ás :). Magukat az ellemeket kívül szokták elhelyezni, lemerülésük ne tegye nyithatatlanná a szekrényt. Viszont, hogy ne lehessen meggyorsítani a TILT-ást, ezért az aljas áramkör felírja az EEPROM-jába, s csak akkor törli, ha letelt a bünti.

Talán a torol() fuggvényről nem beszétem. csupán annyit csinál, hogy törli az LCD második sorát.


int main( void)
{
   UC kod[ 6];
   UC i;
   UC allapot;
   LED_KI;
   TCCR0A= T_CTC;                                // T0 init, 125HZ
   TCCR0B= T_CS256;
   OCR0A= F_CPU/ 256/ F_IT_T0;
   TIMSK= IT_T0CPA_ENABLE;
   IT_ENABLE;
   DDRD= 0B01110000;                             // LCD init
   LCD_PORT_ENABLE;
   lcd_init4();
   lcd_cls();
   lcd_yx( 0, 1);
   lcd_puts( PSTR( "KT_ZAR1 - 2013"));
   if( ZAR_BEALLITAS)                            // uj kod bekeres
   {
      lcd_yx( 1, 3);
      lcd_puts( PSTR( "Beallitas"));
      while( jelado() != K_GOMB);                // varakozas gombnyomasra
      do
      {
         torol();
         kod[ 0]= szamjegy( 1);
         kod[ 1]= szamjegy( 2);
         kod[ 2]= szamjegy( 4);
         kod[ 3]= szamjegy( 5);
         kod[ 4]= szamjegy( 7);
         kod[ 5]= szamjegy( 8);
         lcd_yx( 1, 11);
         lcd_puts( PSTR( "N<->I"));
      } while ( K_FEL != jelado());                 // varakozas FEL tekeresre
      for( i= 0; i < 6; i++) ee_write( i, kod[i]);  // rogzites
      torol();
      lcd_yx( 1, 4);
      lcd_puts( PSTR( "Rogzitve"));
      ee_write( EE_TILT, 0);
      for(;;);
   }
   if( ee_read( EE_TILT))                        // ha ujrainditotta, akkor is ki kell varni a tiltast  
   {
      lcd_yx( 1, 6);
      lcd_puts( PSTR( "Tilt"));
      varakozas= 12500;                          // 100 sec varakozas
      while( varakozas);
      ee_write( EE_TILT, 0);
   }
   for(;;)                                       // kod bekerese
   {
      LED_KI;
      torol();
      lcd_yx( 1, 5);
      lcd_puts( PSTR( "Zarva"));
      while( jelado() != K_GOMB);                // varakozas gombnyomasra
      do
      {
         torol();
         kod[ 0]= szamjegy( 1);
         kod[ 1]= szamjegy( 2);
         kod[ 2]= szamjegy( 4);
         kod[ 3]= szamjegy( 5);
         kod[ 4]= szamjegy( 7);
         kod[ 5]= szamjegy( 8);
         lcd_yx( 1, 11);
         lcd_puts( PSTR( "N<->I"));              // varakozas FEL tekeresre
      } while ( K_FEL != jelado());
      torol();
 
      allapot= 1;                                // kod ellenorzese
      for( i= 0; i < 6; i++)
      {
         if( kod[i] != ee_read( i)) allapot= 0;
      }
      if( allapot) 
      {                                          // jo kod
         LED_BE;
         lcd_yx( 1, 5);
         lcd_puts( PSTR( "Nyitva"));
         varakozas= 600;                         // 4 sec varakozas
         while( varakozas);
      }
      else
      {                                          // rossz kod
         ee_write( EE_TILT, 1);
         lcd_yx( 1, 6);
         lcd_puts( PSTR( "Tilt"));
         varakozas= 12500;                       // 100 sec varakozas
         while( varakozas);
         ee_write( EE_TILT, 0);
      }
   }   
   return 0;
}

Itt a vége, fuss el véle, legytek az én vendégeim, innen letölthetitek a hozzávalókat összecsomagolva.