AVR - RC lámpa - Távírányitású jelzőlámpa modell

2016-04-12

 

Eredeti ötletem az volt, hogy az előző jelzőlámpa programot kicsit továbbfejlesztve bemutatom, mennyivel egyszerűbb C++-ban programozni. Azután egy csomót lamentáltam, például, hogy lehetne belőle csinálni terepasztalhoz modell jelzőlámpát (mondom ezt úgy, hogy hallottam van a terepasztalokhoz elterjedt vezérlési szabvány, de azt nem ismerem, szóval, ha ez stimmelne hozzá, az csak a véletlen). Az ATtiny13a olcsó, 40mA-t tud lábanként, vagyis képes LED-eket direktben hajtani. Egyszerűen lehet távirányítani, egyik lábán figyeli a bejövő LOW aktív (alapban a vezeték 1-ben van, az impulzus időtartámára 0-ba kerül lehúzásra) vezérlő impulzusokat. A jelzőlámpa bekapcsolás után tilost jelez. Két impulzus ismer, a rövidebb léptetőt, és a hosszabb alapba/tilosra állítót. A rém egyszerű dolog végül 3 ATtiny13a téglásításához (megdögléséhez) vezetett. Azután gondolom sokan halottátok a legendát, hogy az Angol Nemzeti Bankban egyszer találtak 2-3 penny eltérést. Jó alaposan kivizsgálták, mire vége lett az ügynek, több millió fontsterlinges elszámolásokra derült fény. De menjünk sorjában.

Életkép az asztalomról. A teszt panelemet kiegészítettem a "multiprocessoros rendszernek" megfelelően egy újabb programozó csatival, így egyszerűbb volt hol az egyik, hol a másik prociba letölteni a progit. Az ATiny13a-k halálozásának az volt az oka, hogy programozó fejnek beterheltek az IC lábain lógó LED-ek (in circuit). Az az érdekes, hogy néha letöltődött a program, néha meg kukázni kellett utána a procit. Nem annyira szembeötlő, de elővettem a mühely rovatban ismertetett proc kártyámat, arra került egy ATtiny13a, és hol az áramkörbe dugtam, hol meg előrébb, a programozó fej vezetékeire.

Ez az a nagyon egyszerű progi, amivel egy ATmega8-ból impulzus generátort csináltam. Két gombbal vezérelhető, az egyikre 5 msec, a másikra 10 msec L aktív impuzust ad ki. A fotón látható egy LED is a kimenten. Munka közben jó ha látjuk, hogy működik az impulzus generátorunk.


/*******************************************************************************
*   Author       -  Kiraly Tibor
*                   www.tkiraaly.hu
*   Date         -  2016.04.11.
*   Chip         -  ATmega8
*
*   Tavvezerlo RC lamapahoz
*   
*   Egy-egy nyomogombbal a földre van kötve az ATmega8 PD4 és PD6 laba.
*   A PD4 (STEP) lenyomasara 5 msec, a PD6 (RESTART) lenymasara 10 msec hosszu
*   L impulzust ad ki az IC a PB2 (CONTROL) labon. 
*
*                              +---------+
*               NRESET - PC6  ++ 1    28 |  PC5 - ADC5 - SCL
*                  RXD - PD0  |  2    27 |  PC4 - ADC4 - SDA
*                  TXD - PD1  |  3    26 |  PC3 - ADC3
*                 INT0 - PD2  |  4    25 |  PC2 - ADC2
*                 INT1 - PD3  |  5    24 |  PC1 - ADC1
*             XCK - T0 - PD4  |  6    23 |  PC0 - ADC0
*                        VCC  |  7    22 |  GND
*                        GND  |  8    21 |  AREF
*         XTAL1 - OSC1 - PB6  |  9    20 |  AVCC
*         XTAL2 - OSC2 - PB7  | 10    19 |  PB5 - SCK
*                   T1 - PD5  | 11    18 |  PB4 - MISO
*                 AIN0 - PD6  | 12    17 |  PB3 - MOSI - OC2
*                 AIN1 - PD7  | 13    16 |  PB2 - NSS - OC1B
*                 ICP1 - PB0  | 14    15 |  PB1 - OC1A
*                             +----------+
*
*******************************************************************************/
#define F_CPU                4 MHZ


#include "tkiraaly_atmega8.h"
#include "tkiraaly_kbutton.cpp"
#include "tkiraaly_kled.cpp"
#include <util/delay.h>


int main( void)
{
   kbutton step( D_PORT_4);
   kbutton restart( D_PORT_6);       
   kled control( B_PORT_2);
   for(;;)
   {
      if( step.check())                // leptetes, 5 msec hosszu L impulzus
      {
         control.on();
         _delay_ms( 5);
         control.off();
      }
      if( restart.check())            // alapba allitas, 10 msec hosszu L impulzus
      {
         control.on();
         _delay_ms( 10);
         control.off();
      }
   }
}

Így néz ki alaphelyzetben 3 LED vezérlése.

Ha valaki panellal dolgozik, mindent abból akar megcsinálni. Egy volt gépész kollégám, mesélte, hogy a barátaival fiatal korukban magnó mechanikát csináltak NYÁK-ból. Az volt az elképzelésem, hogy a lámpa testét egy panel csíkból tervezem meg. Ezért az áramkört úgy módosítottam, hogy a szárban csak 3 vezeték fusson. A LED-eket az IC kimenetei közé kötöttem. Ha az ember nagyon akarja, 3 vezetéken keresztül akár 6 LED-et is vezérelhetne. Nekem most elég volt 3 is.

Így néznek ki a panelek. Csináltam egy egy vasúti átjáróhoz való, meg piros-sárga-zöld jelző lámpát is. Pontosabban csak megterveztem, remélem nincs bennük hiba. Sorozatgyártáshoz oda kellett volna figyelni, hogy a LED-ek katódja egy irányba nézzen a panelen, meg a vezérlő kártyán is lehetnének rendezettebbek az alkatrészek :(. Így viszont szebb a vezetékzés, és egy oldalas panel is elég volt. A lámpa panelja a LED-ek beforrasztását követően festhető. A LED-ek tetejét és a panel alját, ahol majd forrasztjuk, valamilyen kupakkal/ragasztó szalaggal takarjuk ki festéskor. Mielőtt a részletekbe mennénk, az a terv, hogy a vezérlő panelt bevágva a lámpa paneljét a résbe toljuk, a keresztező vezetékeket összeforrasztjuk. A két panelt valamilyen ragasztóval (mondjuk meleg pisztoly) megerősítjük. Egyszerűbb esetben a vezérlő panelt az asztalra csavarozzuk. Bonyolultab esetben a terepasztalt átfúrjuk, a lámpát keresztül dugjuk a furaton, a vezérlő panelt az asztal alá csavarozzuk, és ott forrasztjuk, ragasztjuk. Ezt azért tehetjük meg, mert csak három vezetékünk van, szinte szimmetrikus a lámpafejünk. Az áramkörbe épített jumper-rel (átkötés) a vezérlés tükörben megfordítható a beépítéstől függően. A vezérlő panel vezetékeket is összeköthető a lámpa panellel. A többi csatlakozó vezetéket a vezérlő panelbe forrasztott csavaros sorkapocs fogadja.

Íme az áramkör. Jobb szélén van a két lámpa rajza. Alul látható, hogy került a panelra egy tápegség is. Lehet, hogy egy terepasztalon körbe lehet vinni az 5V-t, az is lehet, hogy jobb egy lokális táp. Egy dióda biztosítja, hogy ne tudjuk fordított polaritással tönketenni az áramkörünket, de azért figyeljünk a bekötésére. A J2 jumper vezérli a tükrözést. Van egy tüskesor a programozófejhez. Programot csak akkor töltsük a vezérlőbe, amikor a lámpa panel nincs csatlakoztatva! A bemenet azért lett így kialakítva, mert jártam én egszer az Andrássy út elején a Miniversum-ban. (Hatalmas terepasztal, terepasztal rendszer.) Az ember tesztelés közbe összeköti a két IC-t egy darab dróttal. Ha néhány méterre vannak egymástól, akkor már illik egy kis R-C szűrést alkalmazni a bemeneten. Tehát egy othoni 2-3 m-es terepasztalnál úgy gondolom ez elegendő az RC bemenetet használni, az optós rész el is hagyható. De egy nagy rendszer, az több tápról jár, feszülség különbségek vannak az áramkörök között, nagyobb zavart szednek össze a vezetékek, szóval betettem egy optót. Nem bonyolítottam el a kezelését, mert itt csak igen kis frekit kell átvinnie (kisebb mint 1kHz). Az optós vezérlés használatakor a J1 jumper-rel az IC bementét fel kell húzni tápra. A optó bemenetén az ellennállás úgy lett méretezve, hogy 12V-os feszültségre olyan 10mA áram follyon a bemneti LED-en keresztül.

Az alábbi program vezérli a piros-sárga-zöld jelzőlámpát (jelzolampa_psz.c). Itt kanyarodjunk vissza a bankos story-ra. A két IC esetében nem akartak összejönni az impulzus hosszak. Írtam egy-egy kis 1Hz-es LED villogtató teszt programot, mire kiderült, hogy az ATtiny13a teljesen rossz értéken fut. Rögtön a program elején látható, hogy kénytelen voltam visszatérni, az F_CPU értékének teljes kiírásához, ami tök olvashatatlan, de egyenlőre nem találtam jobb megoldást. A MHZ makróm nem működik tört számokkal, pontosabban a makro előfeldolgozó értetlenkedik, tehát nem írhattam azt, hogy 1.2 MHZ.

Úgy gondolom a definíciós rész érthető. Még az sem komplikált, hogy a main() elején konfigurálom a lábakat. A fő hurok (for()) már érdekesebb. A ciklus végén van egy 1 msec késleltetés, ami jelenlegi feledatnak megfelelő pontosággal meghatározza egy ciklus futási idejét. A program a cikus elején a J2 (MIRROR) állásától és a lámpa állapotától függően beállítja a LED-eket meghajtó L1-L2-L3 vonalakat. Ezután következik az impulzus hossz mérése, és kiértékelése. Amíg a bemenet 0-ban van, addig ciklusonkén számolja a hosszát (+1ms). Ha 1-ben van, megnézi az impulus hosszat. Ha 0, akkor nem volt impulzus, csak várakozás. Ha az értéke nagyobb mint 0, akkor volt impulzus. Ha ez 7 ciklusnál( ~7ms) nagyobb, akkor a vezérlő alpba áll, ha kisebb, akkor a lámpa állapotát lépteti. A 0 állapot a piros, az 1 a piros+sárga, a 2 a zöld, a 3 a sárga. Ezen felül van a villogó sárga, amikor lépeget 4 és 5 között. A ciklus utolsó része felelős ezért.


/*******************************************************************************
*   Author       -  Kiraly Tibor
*                   www.tkiraaly.hu
*   Date         -  2016.04.11.
*   Chip         -  ATtiny13A
*
*   Tavvezerelt jelzolampa modell - piros/sarga/zold
*
*                   +---------+
*                  ++ 1    8  |  +VCC
*   CONTROL - PB3  |  2    7  |  PB2 - L1
*   MIRROR  - PB4  |  3    6  |  PB1 - L2 (kozos, common)
*             GND  |  4    5  |  PB0 - L3
*                  +----------+
*
*   LED-ek vezerlese:  -  tukrozve:
*   piros: L1-1, L2-0  -  L3-1, L2-0
*   sarga: L3-1, L2-0  -  L1-1, L2-0
*   zold:  L1-0, L2-1  -  L3-0, L2-1
*
*******************************************************************************/

//                        000...000
#define F_CPU               1200000                   // 1,2 Mhz


#include "tkiraaly_attiny13a.h"
#include <util/delay.h>


// L1
#define L1_OUTPUT           PB2_OUTPUT
#define L1_0                PB2_0
#define L1_1                PB2_1

// L2
#define L2_OUTPUT           PB1_OUTPUT
#define L2_0                PB1_0
#define L2_1                PB1_1

// L3
#define L3_OUTPUT           PB0_OUTPUT
#define L3_0                PB0_0
#define L3_1                PB0_1

// CONTROL
#define CONTROL_PULLUP      PB3_PULLUP
#define CONTROL_R           PB3_R

// MIRROR
#define MIRROR_PULLUP       PB4_PULLUP
#define MIRROR_R            PB4_R

// State:
#define RED                 L1_1; L2_0; L3_0
#define RED_YELLOW          L1_1; L2_0; L3_1
#define GREEN               L1_0; L2_1; L3_1
#define YELLOW              L1_0; L2_0; L3_1
#define BLANK               L1_0; L2_0; L3_0

#define MIRRORED_RED        L3_1; L2_0; L1_0
#define MIRRORED_RED_YELLOW L3_1; L2_0; L1_1
#define MIRRORED_GREEN      L3_0; L2_1; L1_1
#define MIRRORED_YELLOW     L3_0; L2_0; L1_1


int main( void)
{
   U8 lamp_state= 0;                                  // lampa allapot szamlalo
   U8 pulse_lenght= 0;                                // impulzus hossz szamolasa
   U16 blink_counter= 0;                              // sarga villogas idozites szamlalo
   CONTROL_PULLUP;                                    // vezerles bemenete
   MIRROR_PULLUP;                                     // tukrozes jumper
   L1_OUTPUT;                                         // kimenetek
   L2_OUTPUT;
   L3_OUTPUT;
   for(;;)
   {
      if( MIRROR_R)                                   // lampa beallitasa MIRROR jumper szerint
      {
         switch( lamp_state )
         {

            case 0: RED; break;                       // piros - alap
            case 1: RED_YELLOW; break;                // piros + sarga
            case 2: GREEN; break;                     // zold
            case 3: YELLOW; break;                    // sarga
            case 4: YELLOW; break;                    // villogas sarga
            case 5: BLANK;                            // villogas fekete
         }
      }
      else
      {
         switch( lamp_state )
         {
            case 0: MIRRORED_RED; break;
            case 1: MIRRORED_RED_YELLOW; break;
            case 2: MIRRORED_GREEN; break;
            case 3: MIRRORED_YELLOW; break;
            case 4: MIRRORED_YELLOW; break;
            case 5: BLANK;
         }
      }     
      if( CONTROL_R == 0)                             // L - impulzus hossz szamolasa
      { 
         if( pulse_lenght < 9) pulse_lenght++;        // szamlalo ne fordulhasson korbe igen hosszu impulzus eseten
      }        
      else                                            // H - nincs impulzus
      {
         if( pulse_lenght)                            // volt impulzus, feldolgozas
         {
            if( pulse_lenght > 7)                     // 7 msec-nel hosszabb - alapba allitas
            {                      
               lamp_state= 0;
               blink_counter= 0;
            }
            else                                      // 7 msec-nel rovidebb - leptetes
            {
               if ( lamp_state < 4) lamp_state++;     // ne foroghasson korbe
            }
            pulse_lenght= 0;                          // kovetkezo impulzushoz
         }
      }        
      if( lamp_state > 3)                             // villogo sarga 
      {
         if( blink_counter == 300) lamp_state= 5;     // 300 msec-nel sotet
         if( blink_counter == 600)                    // 600 msec-nel sarga, szamlalo ujrainditas
         {
            lamp_state= 4;
            blink_counter= 0; 
         }
         blink_counter++;
      }
      _delay_ms( 1);
   }
}

Ez itt a vasúti átjárókhoz való piros-piros-fehér jelzőlámpa (jelzolampa_ppf.c) programja. Lényegesen egyszerűbb mint az előző. Itt csak két állapot van, igaz mind a kettő villogó. Hosszú impulzusra piros váltakozó villogóra, rövidre villogó fehérr vált.


/*******************************************************************************
*   Author       -  Kiraly Tibor
*                   www.tkiraaly.hu
*   Date         -  2016.04.11.
*   Chip         -  ATtiny13A
*
*   Tavvezerelt jelzolampa modell - piros/piros/feher
*
*                   +---------+
*                  ++ 1    8  |  +VCC
*   CONTROL - PB3  |  2    7  |  PB2 - L1
*   MIRROR  - PB4  |  3    6  |  PB1 - L2 (kozos, common)
*             GND  |  4    5  |  PB0 - L3
*                  +----------+
*
*   LED-ek vezerlese:  -  tukrozve:
*   piros1: L1-1, L2-0  -  L3-1, L2-0
*   piros2: L1-0, L2-1  -  L3-0, L2-1
*   feher:  L3-1, L2-0  -  L1-1, L2-0
*
*******************************************************************************/

//                        000...000
#define F_CPU               1200000                   // 1,2 Mhz


#include "tkiraaly_attiny13a.h"
#include <util/delay.h>


// L1
#define L1_OUTPUT           PB2_OUTPUT
#define L1_0                PB2_0
#define L1_1                PB2_1

// L2
#define L2_OUTPUT           PB1_OUTPUT
#define L2_0                PB1_0
#define L2_1                PB1_1

// L3
#define L3_OUTPUT           PB0_OUTPUT
#define L3_0                PB0_0
#define L3_1                PB0_1

// CONTROL
#define CONTROL_PULLUP      PB3_PULLUP
#define CONTROL_R           PB3_R

// MIRROR
#define MIRROR_PULLUP       PB4_PULLUP
#define MIRROR_R            PB4_R

// State:
#define RED1                L1_1; L2_0; L3_0
#define RED2                L1_0; L2_1; L3_1
#define WHITE               L1_0; L2_0; L3_1
#define BLANK               L1_0; L2_0; L3_0

#define MIRRORED_RED1       L3_1; L2_0; L1_0
#define MIRRORED_RED2       L3_0; L2_1; L1_1
#define MIRRORED_WHITE      L3_0; L2_0; L1_1




int main( void)
{
   U8 lamp_state= 0;                                  // lampa allapot szamlalo
   U8 pulse_lenght= 0;                                // impulzus hossz szamolasa
   U16 blink_counter= 0;                              // sarga villogas idozites szamlalo

   CONTROL_PULLUP;                                    // vezerles bemenete
   MIRROR_PULLUP;                                     // tukrozes jumper

   L1_OUTPUT;                                         // kimenetek
   L2_OUTPUT;
   L3_OUTPUT;

   for(;;)
   {
      if( MIRROR_R)                                   // lampa beallitasa MIRROR jumper szerint
      {
         switch( lamp_state )
         {

            case 0: RED1; break;                      // piros1
            case 1: RED2; break;                      // piros2
            case 3: WHITE; break;                     // feher
            case 4: BLANK;                            // sotet
         }
      }
      else
      {
         switch( lamp_state )
         {
            case 0: MIRRORED_RED1; break;             // piros1
            case 1: MIRRORED_RED2; break;             // piros2
            case 3: MIRRORED_WHITE; break;            // feher
            case 4: BLANK;                            // sotet
         }
      }     
      if( CONTROL_R == 0)                             // L - impulzus hossz szamolasa
      { 
         if( pulse_lenght < 9) pulse_lenght++;        // szamlalo ne fordulhasson korbe igen hosszu impulzus eseten
      }        
      else                                            // H - nincs impulzus
      {
         if( pulse_lenght)                            // volt impulzus, feldolgozas
         {
            if( pulse_lenght > 7) lamp_state= 0;      // 7 msec-nel hosszabb - piros
            else lamp_state= 3;                       // 7 msec-nel rovidebb - feher
            blink_counter= 0;
            pulse_lenght= 0;                          // kovetkezo impulzushoz
         }
      }        
      if( blink_counter == 400) lamp_state++;         // x msec-nel sotet/piros2
      if( blink_counter >= 800)                       // 2x msec-nel feher/piros1, szamlalo ujrainditas
      {
         lamp_state--;
         blink_counter= 0; 
      }
      _delay_ms( 1);
      blink_counter++;
   }
}

Itt a vége, fuss el véle, legytek az én vendégeim, innen letölthetitek a programokat, miegymást összecsomagolva.