Operácie

Blik!

Z SensorWiki

Programovateľný astabilný multivibrátor


Typický elektronický obvod, ktorý si postaví každý začiatočník je nejaké jednoduché blikátko, obvykle s dvoma tranzistormi, alebo s populárnym časovačom NE555. V roku 2023 však máme predsa len viac možností. Jednou z nich je namiesto obvodu 555 použiť rovnako veľký mikroprocesor ATtiny45, ktorý však môže okrem samotného blikania realizovať aj náročnejšie funkcie. Keďže procesor má možnosť budiť viac ako jednu jedinú LED diódu, využili sme to a v zapojení je použitá trojfarebná RGB dióda OSTAMA51A5A. Pripojená je na tie tri vývody mikroprocesora, ktoré majú okrem bežného digitálneho výstupu aj alternatívnu funkciu s výstupom PWM signálu. Týmto spôsobom môžeme ovládať všetky tri farby spojito (nielen zapni/vypni, ale aj rôzne stupne intenzity a dosiahnuť tak mnoho farebných kombinácií.

Obvody zrealizované študentmi na predmete DTV v roku 2023.


Opis a schéma zapojenia

Srdcom celého zariadenia je 8-bitový mikroprocesor ATtiny45V v DIL-8 puzdre. Okrem dvoch napájacích vývodov máme k dispozícii celkom 6 vstupov/výstupov ak použijeme menej presný interný oscilátor. Pre naše účely je celkom dostačujúci. Napájanie je zabezpečené lítiovou batériou Bt1 typu CR2032 s priemerom 20 mm a kapacitou 220mAh. Na plošný spoj umiestnime vhodný držiak, ktorý je umiestnený zo spodnej časti. Vypínač sme do zapojenia nezaradili zámerne, jednak aby sme znížili náklady, ale aj preto, lebo batéria sa dá jednoducho vybrať, alebo aspoň odizolovať malým kúskom plastu priamo v držiaku.

Jediným vstupom je tlačidlo SW1, ktoré spína vstup voči zemi. Aby zapojenie správne fungovalo, musí mať príslušný vstup PB3 mikroprocesora zapnutý interný pull-up rezistor, inak zapojenie nebude fungovať.

Na výstupoch PB0, 1 a 4 sú zapojené tri LED diódy (resp. jedna RGB dióda v ktorej sú všetky tri integrované). Všetky tri diódy majú zapojený aj predradný rezistor R1-3, ktorý obmedzuje maximálny prúd cez diódu. Pri oživovaní sa ukázalo, že intenzita jednotlivých farebných zložiek je ľudským okom vnímaná rozlične, preto sú odpory R1 a R3 menšie (680R) ako R1 (1k) - je to preto, aby subjektívne vnímaná intenzita bola vyrovnaná u všetkých troch diód. Keďže použitá RGB dióda má spoločnú anódu, programátor ju musí ovládať s inverznou logikou, teda zápis log. 0 na výstup LED diódu rozsvieti a log. 1 ju zhasne.


Schéma zapojenia.

Plošný spoj

Blik01.jpg

Plošný spoj je obojstranný, rozmerov AxB mm navrhnutý v programe KiCAD7. Na obrázku je rozmiestnenie súčiastok a obrazec plošného spoja, ktorý bol napokon vyrobený vo firme JLC PCB (China). Pri návrhu sme zohľadnili najmä to, že výrobok je určený pre začiatočníkov a tak sú všetky súčiastky v prevedení s vývodmi, namiesto miniatúrnych SMD prvkov. Okrem jednoduchšieho spájkovania sa tak zjednoduší aj prípadné meranie alebo výmena prvkov. Snažili sme sa dosiahnuť čo najmenšie rozmery plošného spoja, aby cena ostala primeraná. Plošný spoj je pripravený aj na osadenie alternatívnych prevedení, ktoré sú opísané nižšie.


Plošný spoj - strana súčiastok, strana spojov a osadzovací plán.

Osadzovanie súčiastkami začneme päticou na procesor DIL8, ktorá je najnižšia. Dáme pritom pozor na orientáciu výrezom nahor. Potom osadíme tlačidlo a rezistory R1-R3, tu na orientácii súčiastok nezáleží. Napokon osadíme trojfarebnú LED diódu D1 (najkratší vývod 1 je na plošnom spoji označený štvorčekom) a pozície D2, D3 ostanú prázdne. Ako posledný spájkujeme z opačnej strany držiak na gombíkovú batériu. Ak by sme ho osadili skôr, nedostali by sme sa k vývodom ostatných súčiastok. Osadený plošný spoj je na obrázku X.


Zoznam súčiastok

Amount Product / Datasheet Reference Value Názov Footprint
1 GOLD-8P Conn1 DIL8 Pätica na integrovaný obvod DIL8 nie je
1 1-1825910-0 SW1 Mikrospinac TACT Mikrospínač do plošného spoja Button_Switch_THT:SW_PUSH_6mm_H4.3mm
1 CF1/4W-180R R1 180R Rezistor 1/8W Resistor_THT:R_Axial_DIN0309_L9.0mm_D3.2mm_P12.70mm_Horizontal
1 CF1/4W-180R R2 180R Rezistor 1/8W Resistor_THT:R_Axial_DIN0309_L9.0mm_D3.2mm_P12.70mm_Horizontal
1 CF1/4W-180R R3 180R Rezistor 1/8W Resistor_THT:R_Axial_DIN0309_L9.0mm_D3.2mm_P12.70mm_Horizontal
1 OSTAMA51A5A D1 OSTAMA51A5A LED 5mm trojfarebná, RGB LED_THT:LED_D5.0mm-4_RGB_Staggered_Pins
1 L-7113F3BT D2 L-7113F3BT LED 5mm infračervená LED_THT:LED_D5.0mm
1 L-53LID D3 L53-LID LED 5mm červená, nízkopríkonová LED_THT:LED_D5.0mm
1 ATTINY45-20PU IC1 ATtiny45-20P Mikroprocesor Attiny45 DIL8 Package_DIP:DIP-8_W7.62mm
1 KEYS1066 BT1 [Keystone1016] Držiak gombíkovej batérie Battery:BatteryHolder_Keystone_103_1x20mm
1 BAT-CR2032/A Batt1 CR2023 Gombíková batéria 3V typ CR2032 nie je
1 GOLD-8P Conn1 DIL8 Pätica na integrovaný obvod DIL8 nie je


Pri osádzaní vám môže pomôcť tento interaktívny diagram, v ktorom sa okrem ľahkej orientácie na doske môžete aj začiarkovať, ktoré súčiastky už máte pripravené a ktoré sú už aj osadené.

Software

Pre programátora je potrebné vedieť, kam je ktorý komponent pripojený, pozri nasledujúcu tabuľku.

Component Pin Arduino
Red 5 PB0
Green 6 PB1
-- 7 PB2
SW1 2 PB3
Blue 3 PB4
-- 1 PB5

Program 1: blikanie LED

Najjednoduchší program je naozaj obyčajné blikanie jednou z trojice LED diód. Ak chceme využiť niektorú inú, stačí zmeniť číslo podľa tabuľky vyššie.

Blik Program01.png
Program v grafickom jazyku Blockly (TinkerCAD).

/*  pin0 - Red LED / 1 - Green / 4 - Blue   */

void setup()
{
  pinMode(0, OUTPUT);
}

void loop()
{
  digitalWrite(0, LOW);  // LED On (common Anode)
  delay(200);            // Wait for 200 ms
  digitalWrite(0, HIGH); // LED Off 
  delay(200);            // Wait for 200 ms
}
##define F_CPU 8000000UL  // toto je lepsie vlozit do parametrov pre kompilator

#include <avr/io.h>
#include <util/delay.h>

#define LED1  PB0  // pripojena dioda 

int main(void)
{
    DDRB |= (1 << LED1);  // set pin as OUTPUT	
	
    while(1)
    {
         PORTB |=  (1<<LED1);       // zhasni LED, t.j. clear PB0 na log. 0
	 _delay_ms(200);
         PORTB &= ~(1<<LED1);       // ... tak rozsviet LED, t.j. set PB0 na log. 1 
	 _delay_ms(2000);
    }
}
/*
 *  LED Blink s periodou 100:1000 ms 
 *  delay vygenerovane tu http://darcy.rsgc.on.ca/ACES/TEI4M/AVRdelay.html
 *  pre frekvenciu 8 MHz (ATtiny45, internal osc.)
 * 
 *  LED je pripojena na pin5 (PORTB.0)
 */ 

START:	        SBI DDRB,0       ; DDRB.0 = 1 (t.j. Output)
LOOP:
		CBI PORTB,0      ; PORTB.0 = 0 (t.j. Low, rozsviet LED so spol. Anodou)

;		CALL DELAY      ; UNSUPPORTED INSTRUCTION ON ATtiny!!!! - treba nahradit RCALL + RET
	    
		ldi  r18, 5     ; 100ms SVIETI
		ldi  r19, 15
		ldi  r20, 242
L1:		dec  r20
		brne L1
		dec  r19
		brne L1
		dec  r18
		brne L1
		nop

		SBI PORTB,0     ; PORTB.0 = 1 (t.j. High, zhasni LED v obratenej logike)

		ldi  r18, 41    ; jedna seunda nesvieti (vypocet pre 8MHz!!!)
		ldi  r19, 150
		ldi  r20, 128
L2:		dec  r20
		brne L2
		dec  r19
		brne L2
		dec  r18
		brne L2
		nop

		RJMP LOOP		; Skok na zaciatok (JMP nepodporovane)


Program 2: LED a tlačítko

Asi druhý najjednoduchší program je ovládanie LED diódy tlačítkom. Podľa toho, ktorú si vyberieme, zmeníme číslo výstupu podľa tabuľky vyššie.

ATtinyProgram02blockly.png
Program v grafickom jazyku Blockly (TinkerCAD).

#define SW1  1
#define LED1 2

void setup()
{
  pinMode(SW1,INPUT_PULLUP);
  pinMode(LED1,OUTPUT);
}

void loop()
{
  if (digitalRead(SW1) == 0) 
      digitalWrite(LED1, HIGH);
  else 
      digitalWrite(LED1, LOW);
  
}
#define F_CPU 8000000UL  // toto je lepsie vlozit do parametrov pre kompilator
#define set_bit(ADDRESS,BIT) (ADDRESS |= (1<<BIT))
#define clear_bit(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT))


#include <avr/io.h>
#include <util/delay.h>

#define LED1  PB2  // pripojena dioda 
#define SW1   PB1  // pripojene tlacitko

int main(void)
{
    DDRB |= (1 << LED1);  // set LED1 pin as OUTPUT	
	DDRB &= ~(1<<SW1);    // set SW1 pin as INPUT (not necessary, default)
	PORTB |= (1<<SW1);    // SW1 pull-up ON
	
    while(1)
    {
      if ( bit_is_clear(PINB, SW1) )   // ak je stlacene tlacitko SW1
 	    set_bit(PORTB,LED1);           // LED1 = log.1
      else                             // inak
	    clear_bit(PORTB,LED1);         // LED1 = log.0
    }
	
	return 0;
}
/*
 *	Program01.asm
 *  
 *  Ovladanie LED diody tlacitkom
 *  Created: 16. 2. 2023 18:18:35
 */ 

START:	SBI DDRB,2       ; DDRB.2 = 1 (t.j. Output) - LED
		CBI DDRB,1       ; DDRB.1 = 0 (t.j. Input) - SW1
		SBI PORTB,1      ; PORTB.1 = 1 set SW1 Pull Up ON

LOOP:   SBI PORTB,2      ; PORTB.2 = 1 (t.j. High, rozsviet LED)
ON:     SBIS PINB,1      ; IF input on pin = 1 (button NOT pressed), skip next instruction
		RJMP ON          ; otherwise just loop here

	    CBI PORTB,2      ; PORTB.2 = 0 (t.j. Low, zhasni LED)
OFF:    SBIC PINB,1      ; if input on pin = 0 (button IS pressed),  skip next instruction
		RJMP OFF         ; otherwise just loop here

		RJMP LOOP		 ; Skok na LED On

Program 3: Stavový automat ovládaný tlačidlom

V tomto programe budeme prepínať tlačidlom jednotlivé stavy, v ktorých bude vždy svietiť jedna farba. Jednoducho sa dá program rozšíriť o viac stavov a teda aj viac farieb. V programe kladieme dôraz na správne a jednoznačné vyhodnotenie stavu tlačidla, takže prechody nastávajú naozaj až pri stlačení a pri podržaní program nepokračuje dalej.


FSManimation.gif
Stavový diagram so 4 stavmi medzi ktorými prechádzame po stlačení tlačidla.

#define   RedLED 0
#define GreenLED 1
#define  BlueLED 4
#define     SW1  3

#define LED_OFF HIGH   // common Anode mode
#define LED_ON LOW

int StateCounter = 0;
int    lastState = 0;
int  buttonState = 0;

void setup()
{
  pinMode(RedLED, OUTPUT);
  pinMode(GreenLED, OUTPUT);
  pinMode(BlueLED, OUTPUT);
  pinMode(SW1, INPUT_PULLUP);  // pozn.: Tento riadok TinkerCAD nevie
}

void loop()
{
  buttonState = digitalRead(SW1);  // nacitame stav tlacitka

  // ak sme stlacili tlacitko a je to zmena oproti minulemu
  if ( ( buttonState == 0)  && ( buttonState != lastState) ) 
  {
    StateCounter += 1;          // presun sa do nasledujuceho stavu
  
    if (StateCounter >= 4) 
    {
      StateCounter = 0;         // a po poslednom zacni od znova
    }
  }
  
  switch (StateCounter)
  {
   case 1:                       // Red LED On
          digitalWrite(RedLED, LED_ON);
          digitalWrite(GreenLED, LED_OFF);
          digitalWrite(BlueLED, LED_OFF);
          break; 
   case 2:                      // Green LED On
          digitalWrite(GreenLED, LED_ON);
          digitalWrite(RedLED, LED_OFF);
          digitalWrite(BlueLED, LED_OFF);
          break;
  case 3:                        // Blue LED On
          digitalWrite(BlueLED, LED_ON);
          digitalWrite(RedLED, LED_OFF);
          digitalWrite(GreenLED, LED_OFF);
          break;
  default:                       // vsetky LED zhasnute
          digitalWrite(RedLED, LED_OFF);
          digitalWrite(GreenLED, LED_OFF);
          digitalWrite(BlueLED, LED_OFF);
  }

  
  delay(50);                // Wait for 50 millisecond(s)
  lastState = buttonState;  // a zapamataj si predosly stav tlacitka

}


Program 4: stmievanie LED

Doteraz sme LED diódy ovládali iba dvojstavovo - zapni alebo vypni, kedy dióda buď ostala vypnutá, alebo svietila max. jasom. Príkaz analogWrite nám však umožní nastaviť na výstupe jednu z 255 úrovní od 0 po maximum. Potom môžeme v jednoduchej slučke postupne jas zvyšovať alebo znižovať. Nezabudnite, že diódu máme zapojenú s obrátenou logikou, takže max. hodnota 255 znamená vypnutú LED a hodnota 0 naopak maximálny svit.


Blik Program04.png
Program v grafickom jazyku Blockly (TinkerCAD).

// pin0 - Red LED / 1 - Green / 4 - Blue
  #define LEDpin 0

int i = 0;

void setup()
{
     pinMode(LEDpin, OUTPUT);
}

void loop()
{
  for (i = 255; i >= 0; i--)   // zvysujeme jas
  {
    analogWrite(LEDpin, i);
    delay(10);                 // Wait  10 ms
  }
  for (i = 0; i <= 255; i++)   // znizujeme jas
  {
    analogWrite(LEDpin, i);
    delay(10);                 // Wait 10 ms
  }
}

Ak sa vám bude zdať nárast a pokles jasu nerovnomerný, máte pravdu. Je to preto, lebo ľudské oko nemá rovnakú citlivosť na rovnomernú zmenu jasu. Ak to chcete napraviť, môžete použiť komplikovanejší program, napríklad podľa návodu Róberta Ulbrichta na Arduino Slovakia.


Program 5: RGB demo

Teraz už vieme spraviť program, ktorý predvedie všetky možné farby na RGB dióde. Tento demo program si môžete aj priamo stiahnuť ako .hex súbor.

Prechod medzi všetkými farbami rozhodne nie je jednoduchý, pohybujeme sa totiž v 3-rozmernom farebnom priestore. Na to aby sme vyskúšali naozaj všetky farby sa nám RGB priestor celkom nehodí a ako vhodnejší sa ukazuje priestor HSV, kde stačí meniť jeden parameter, Hue určujúci farebnosť. Nie je to síce celkom dokonalé, ale lepšie ako trojitý vnorený cyklus. Podrobnejší opis tohto problému nájdete napr. v tomto článku.

Konverzné rutiny napísal Karsten Schmidt. Vypočítané hodnoty RGB sa potom posielajú na výstup invertované (teda 255-hodnota), pretože naše LED diódy sú v zapojení so spoločnou anódou a teda 0 je plný svit, zatiaľ čo 1 je zhasnutá dióda.

/* 
 *  tento program vychadza z HSV2RGB odtialto: 
 *  https://gist.github.com/postspectacular/2a4a8db092011c6743a7
 *
*/
  
const int RED_PIN = 0;
const int GREEN_PIN  = 1;
const int BLUE_PIN  = 4;
const int DELAY_MS = 20; // delay in ms between changing colors

float col[3];
float hue = 0.0;

void setup() 
{
  // Set the RGB pins to output
  pinMode(RED_PIN, OUTPUT);
  pinMode(GREEN_PIN, OUTPUT);
  pinMode(BLUE_PIN, OUTPUT);
}


void loop() {
  setColor(hsv2rgb(hue, 1.0, 1.0, col));
  delay(DELAY_MS);
  hue += 0.01;
  if (hue >= 1.0) hue = 0.0;
}


void setColor(float *rgb) {
  analogWrite(RED_PIN, (int)((1.0 - rgb[0]) * 255));
  analogWrite(GREEN_PIN, (int)((1.0 - rgb[1]) * 255));
  analogWrite(BLUE_PIN, (int)((1.0 - rgb[2]) * 255));  
}



// HSV->RGB conversion based on GLSL version
// expects hsv channels defined in 0.0 .. 1.0 interval
float fract(float x) { return x - int(x); }

float mix(float a, float b, float t) { return a + (b - a) * t; }

float step(float e, float x) { return x < e ? 0.0 : 1.0; }

float* hsv2rgb(float h, float s, float b, float* rgb) {
  rgb[0] = b * mix(1.0, constrain(abs(fract(h + 1.0) * 6.0 - 3.0) - 1.0, 0.0, 1.0), s);
  rgb[1] = b * mix(1.0, constrain(abs(fract(h + 0.6666666) * 6.0 - 3.0) - 1.0, 0.0, 1.0), s);
  rgb[2] = b * mix(1.0, constrain(abs(fract(h + 0.3333333) * 6.0 - 3.0) - 1.0, 0.0, 1.0), s);
  return rgb;
}

Programovanie

Najjednoduchšie si programy vyskúšate v prostredí TinkerCAD

Ak ste navrhli program v simulátore prostredia TinkerCAD, musíte vygenerovať C-kód a ten v prostredí Arduino IDE skompilovať (preložiť) do strojového kódu, ktorý je uložený v tzv. formáte IntelHEX (.hex).

Prenos z TinkerCADu si ušetríte, ak budete písať program priamo v jazyku C s Arduino nadstavbou v Arduino IDE. Aj tam treba zdrojový kód preložiť do IntelHEX formátu.

Okrem toho môžete program napísať v prostredí AVR Studio / AtmelStudio v jazyku C a skompilovať prekladačom avr-gcc, alebo ho napísať priamo v assembleri tohoto procesora.

Napokon potrebujeme preložený .hex súbor nahrať do pamäte mikroprocesora. To sa dá spraviť buď profesionálnym programátorom (napr. Elnec BeeProg2), alebo použijeme ako programátor dosku Arduino so špeciálnym softvérom.

Na otestovanie môžeme použiť už preložený súbor demo.hex


Postup

  1. Zoberieme bežné Arduino UNO alebo Nano a pod. V programe Arduino otvoríme File -> Examples -> ArduinoISP -> ArduinoISP a nahráme tento program do mikroprocesora Arduino UNO. Tým sme ho zmenili na programátor.
    ArduinoISPprogrammer02.png
  2. K takto vytvorenému programátoru pripojíme procesor ATtiny45, ktorý chceme naprogramovať (pozri obr. nižšie)
    ArduinoISPprogrammer.png
  3. Ak sme tak už neurobili predtým, doinštalujeme knižnicu a podporu pre procesory radu ATtiny. V menu potom vyberieme typ procesora ATtiny45 bez bootloadera.

ArduinoISPprogrammer03.png
  1. Napíšeme (alebo prenesieme z TinkerCADu) program pre Blik!
  2. Bežným spôsobom ho skompilujeme a naprogramujeme

ArduinoISPprogrammer05.png
  1. Naprogramovaný procesor vyberieme z programátora a vložíme do doštičky Blik!
  2. Ak chceme program zmeniť za iný, pokračujeme bodom 4.

Varianty

Semafor

Blik02.jpg


Namiesto trojfarebnej RGB diódy osadíme tri samostatné diódy - červenú, žltú a zelenú. Dostaneme tak jednoduchý semafor.

Program uvedený nižšie postupne prechádza všetkými stavmi semafora dookola. Časovanie je nastavené na pevno a tlačítko v tomto prípade nemá žiadnu funkciu, mohlo by slúžiť ako vypínač prepínajúci procesor do sleep modu.

Úpravou programu podľa vzoru uvedeného pri stavovom automate (Program 3) dostaneme semafor, ktorý zmení stav vždy po stlačení tlačidla.

Program 6: Semafor

Program
Blik Program06.png
void setup()
{
  pinMode(0, OUTPUT);
  pinMode(1, OUTPUT);
  pinMode(4, OUTPUT);
}

void loop()
{
  // Červená
  digitalWrite(0, LOW);
  digitalWrite(1, HIGH);
  digitalWrite(4, HIGH);
  delay(4000); // Wait for 4000 millisecond(s)

  // Červená+Žltá
  digitalWrite(0, LOW);
  digitalWrite(1, HIGH);
  digitalWrite(4, LOW);
  delay(1000); // Wait for 1000 millisecond(s)

  // Zelená
  digitalWrite(0, HIGH);
  digitalWrite(1, LOW);
  digitalWrite(4, HIGH);
  delay(4000); // Wait for 4000 millisecond(s)

  // Žltá
  digitalWrite(0, HIGH);
  digitalWrite(1, HIGH);
  digitalWrite(4, LOW);
  delay(1000); // Wait for 1000 millisecond(s)

}

Infračervený ovládač

Blik03.jpg


Namiesto trojfarebnej RGB diódy osadíme infračervenú diódu (napr. Vihay TSAL6100) a po stlačení tlačidla odvysielame nejaký špeciálny kód, napr. na vypnutie zariadenia. Získame tak jednoduchý diaľkový ovládač. Aby sme vedeli skontrolovať funkciu zariadenia, pridáme na dosku aj jednu bežnú červenú LED diódu na pozíciu D2. Aby ovládač fungoval spoľahlivo aj na väčšiu vzdialenosť, zameníme rezistor R3 za iný s menšou hodnotou, napr. 27 až 47 Ohm. Pozor však, hoci IR LED zvládne často až prúd 100mA, procesor vie dať na výstup max. 20mA.


Tu sme program zatiaľ nerozchodili, ale v princípe máme dve možnosti, pričom obe spomínajú možnosť inverznej funkcie aj pre indikačnú aj pre vysielaciu LED diodu.






Všetky tri varianty osadenia plošného spoja.

Podklady

Ak by si zariadenie chcel niekto postaviť, na GitHube sú k dispozícii všetky zdrojáky pre KiCAD ako aj vygenerované Gerber súbory.


Pomôcka pre programátora - označenie vývodov a ich funkcie.