Operácie

Vstupy a výstupy AVR: Rozdiel medzi revíziami

Zo stránky SensorWiki

Balogh (diskusia | príspevky)
Balogh (diskusia | príspevky)
Riadok 131: Riadok 131:
#define SW1  PB4          // tlacitko
#define SW1  PB4          // tlacitko


enum states { On, Off };
enum states { Off, Down, On, Up };


int main(void)
int main(void)
{
{
   enum states LedState = Off;
   enum states LedState = Off;
   
  enum states Tlacitko = Off;
     
   set_bit(DDRB,LED1);      // set pin LED1 as output
   set_bit(DDRB,LED1);      // set pin LED1 as output
   set_bit(PORTB,SW1);      // pull-up resistor ON
   set_bit(PORTB,SW1);      // pull-up resistor ON
Riadok 142: Riadok 143:
   while(1)
   while(1)
   {
   {
 
if ( (LedState == Off) && bit_is_clear(PINB,SW1) )
  if ( (Tlacitko == Off) && bit_is_clear(PINB,SW1) )
  {  
  {
          LedState = On;
    _delay_ms(10);
          set_bit(PORTB,LED1);   // LED1 = log.1
if ( bit_is_clear(PINB,SW1) )
  }    
Tlacitko = Down;  
else if  ( (LedState == On) && bit_is_clear(PINB,SW1) )
  }
  {  
  else if ( (Tlacitko == Down) &&  bit_is_clear(PINB,SW1)  )
          LedState = Off;
  {
  clear_bit(PORTB,LED1); // LED1 = log.0
  Tlacitko = On;
  }    
  }
   }
  else if  ( (Tlacitko == On) && bit_is_set(PINB,SW1) )  
  {
  Tlacitko = Up;
  }
  else if (  (Tlacitko == Up) &&  bit_is_set(PINB,SW1) )
  {
  Tlacitko = Off;
  }
 
 
  if ( (LedState == Off) && (Tlacitko==Down) )
  { 
set_bit(PORTB,LED1);
LedState = On;        
  }  
  else
  if ( (LedState == On) && (Tlacitko==Down) )
 
clear_bit(PORTB,LED1);
LedState = Off;         
  }  
   
   } /* end of while loop */
   return(0);                // sem nikdy neprideme
   return(0);                // sem nikdy neprideme
}
}
</source></tab></tabs>
</source></tab></tabs>


Riadok 183: Riadok 207:
Jednoduchší a lacnejší spôsob je ošetriť zákmity softvérovo, ale za cenu zdržania programu. Princíp je jednoduchý, ak zistíme, že sa stav tlačítka zmenil, počkáme nejaký čas na ustálenie a potom overíme, či je tento stav stabilný, alebo to bol len náhodný impulz. Realizácia je možná napríklad takto:
Jednoduchší a lacnejší spôsob je ošetriť zákmity softvérovo, ale za cenu zdržania programu. Princíp je jednoduchý, ak zistíme, že sa stav tlačítka zmenil, počkáme nejaký čas na ustálenie a potom overíme, či je tento stav stabilný, alebo to bol len náhodný impulz. Realizácia je možná napríklad takto:


<tabs><tab name="program03-1.c">
<tabs><tab name="program03-3.c">
<source lang="c++">
<source lang="c++">
#include <avr/io.h>
#include <avr/io.h>

Verzia z 18:26, 8. február 2021

Digitálne výstupy (LED)

Teraz už vieme celkom dobre ovládať výstupy, takže by sme mohli skúsiť ten obligátny príkaz na blikanie LED diódou, potrebujeme už len nejaké oneskorenie. Vedeli by sme to robiť pomocou funkcie napísanej v assembleri, ako sme to robili na prvom cvičení. Trocha (ale len trocha) si to zjednodušíme a využijeme už zadefinovanú funkciu _delay_ms()


Využívanie funkcie _delay_ms()

#define F_CPU 16000000UL  // toto je lepsie vlozit do parametrov pre kompilator

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

#define set_bit(ADDRESS,BIT) (ADDRESS |= (1<<BIT))
#define clear_bit(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT))

#define LED1  PB5          // zabudovana dioda 

void delay(int delay)      // vlastna funkcia pre dlhsie casy 
{
  for (int i=1; i<=delay; i++)
  _delay_ms(1);
}	

int main(void)
{
   set_bit(DDRB,LED1);       // set pin LED1 as output
   
   while(1)
   {
	 delay(250);             // 250 ms delay
     set_bit(PORTB,LED1);    // LED1 = log.1
     delay(250);             // 250 ms delay
     clear_bit(PORTB,LED1);  // LED1 = log.0
   }
	
   return(0);                // sem nikdy neprideme
}
void setup() 
{
  pinMode(LED_BUILTIN, OUTPUT);       // initialize digital pin LED_BUILTIN as an output.
}

void loop() 
{
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);                       // wait for a second
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);                       // wait for a second
}

Prečo je tento program napísaný práve takto, s pomocnou funkciou delay a prečo nepoužijeme rovno _delay_ms() sa dočítate v podrobnejšom texte Oneskorenia_s_AVR.

Digitálne vstupy (Tlačidlá)

Chceli by sme ďalej naprogramovať zapínanie a vypínanie jedným tlačítkom. Na predmete Základy počítačov sme tento problém riešili pomocou stavového diagramu.

MIPS_StavovyDiagram01.png
Stavový diagram pre tlačítko.

K nemu zodpovedajúci program môže vyzerať napríklad nasledovne. Na ukladanie aktuálneho stavu {On, Off} sme použili špeciálny datový typ Enumerate, ktorý má práve dve hodnoty. Okrem toho si všimnite, že testujeme, či je vstup v log. 0 (tlačítko spína k zemi).

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

#define set_bit(ADDRESS,BIT) (ADDRESS |= (1<<BIT))
#define clear_bit(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT))

#define LED1  PB5          // zabudovana dioda 
#define SW1   PB4          // tlacitko

enum states { On, Off };

int main(void)
{
   enum states LedState = Off;
     
   set_bit(DDRB,LED1);       // set pin LED1 as output
   set_bit(PORTB,SW1);       // pull-up resistor ON
   
   while(1)
   {
	 
	 if ( (LedState == Off) && bit_is_clear(PINB,SW1) )
	  { 
           LedState = On;
           set_bit(PORTB,LED1);    // LED1 = log.1
	  }	  	  
	 else if  ( (LedState == On) && bit_is_clear(PINB,SW1) )
	  { 
           LedState = Off;
	   clear_bit(PORTB,LED1);  // LED1 = log.0
	  }	  		  	 
   }
	
   return(0);                // sem nikdy neprideme
}

Ak si to skúsite, zistíte, že to ako tak funguje, ale viacmenej len náhodne. Je to spôsobené tým, že mirkopočítač je strašne rýchly, a kým držíme tlačítko stlačené, zmení stav aj niekoľkotisíc krát, takže výsledný stav je potom viacmenej náhodný. Aby to fungovalo správne, musíme rozlišovať až štyri rozličné stavy tlačítka: Vypnuté (Off), Práve stlačené (Down), Zapnuté (On) a Práve pustené (Up).


Stavový diagram tlačítka s rozpoznaním zmeny stavov.

Keď máme nakreslený stavový diagram, ľahko podľa neho preklopíme vyššieuvedený program.


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

#define set_bit(ADDRESS,BIT) (ADDRESS |= (1<<BIT))
#define clear_bit(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT))

#define LED1  PB5          // zabudovana dioda 
#define SW1   PB4          // tlacitko

enum states { Off, Down, On, Up };

int main(void)
{
   enum states LedState = Off;
   enum states Tlacitko = Off;
       
   set_bit(DDRB,LED1);       // set pin LED1 as output
   set_bit(PORTB,SW1);       // pull-up resistor ON
   
   while(1)
   {
	   
	  if ( (Tlacitko == Off) &&  bit_is_clear(PINB,SW1)  )
	  {
	    _delay_ms(10);
		if ( bit_is_clear(PINB,SW1) )	
		 Tlacitko = Down;	  
	  }
	  else if ( (Tlacitko == Down) &&  bit_is_clear(PINB,SW1)  )
	  {
  		 Tlacitko = On;
	  }
	  else if  ( (Tlacitko == On) &&  bit_is_set(PINB,SW1) ) 	  
	  {
		  Tlacitko = Up;
	  }
	  else if (  (Tlacitko == Up) &&  bit_is_set(PINB,SW1) )
	  {
		  Tlacitko = Off;
	  }
	  
	  
	  if ( (LedState == Off) && (Tlacitko==Down) )
	   {  
		 set_bit(PORTB,LED1);
		 LedState = On;          
	   }			  
	  else 
	  if ( (LedState == On) && (Tlacitko==Down) )
	   {  
		 clear_bit(PORTB,LED1);
		 LedState = Off;          
	   }			  
	  
   }  /* end of while loop */
 	
   return(0);                // sem nikdy neprideme
}

Takto by to už malo fungovať, ale napriek tomu môžete občas pozorovať ako keby náhodné prepnutie stavu. Je to spôsobené javom, kedy sa z mechanických príčin nezmení stav na tlačítku okamžite a trvale, ale kontakt niekoľkokrát preskočí, vzniknú tzv. zákmity.


Zákmity zachytené osciloskopom.

Aby nám všetko naozaj správne fungovalo, musíme aj tieto zákmity ošetriť (angl. termín debouncing).

Ošetrenie zákmitov (debouncing)

a) Hardvérové

Jeden spôsob, ako sa vysporiadať so zákmitmi je pridať okolo tlačítka niekoľko ďalších súčiastok, ktoré zákmity eliminujú.


Niekoľko príkladov hardvérového odstránenia zákmitov.

b) Softvérové

Jednoduchší a lacnejší spôsob je ošetriť zákmity softvérovo, ale za cenu zdržania programu. Princíp je jednoduchý, ak zistíme, že sa stav tlačítka zmenil, počkáme nejaký čas na ustálenie a potom overíme, či je tento stav stabilný, alebo to bol len náhodný impulz. Realizácia je možná napríklad takto:

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

#define set_bit(ADDRESS,BIT) (ADDRESS |= (1<<BIT))
#define clear_bit(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT))

#define LED1  PB5          // zabudovana dioda 
#define SW1   PB4          // tlacitko

enum states { On, Off };

int main(void)
{
   enum states LedState = Off;
     
   set_bit(DDRB,LED1);       // set pin LED1 as output
   set_bit(PORTB,SW1);       // pull-up resistor ON
   
   while(1)
   {
	 
	 if ( (LedState == Off) && bit_is_clear(PINB,SW1) )
	  { 
           LedState = On;
           set_bit(PORTB,LED1);    // LED1 = log.1
	  }	  	  
	 else if  ( (LedState == On) && bit_is_clear(PINB,SW1) )
	  { 
           LedState = Off;
	   clear_bit(PORTB,LED1);  // LED1 = log.0
	  }	  		  	 
   }
	
   return(0);                // sem nikdy neprideme
}

Literatúra: