Operácie

Meranie dĺžky impulzu 2: Rozdiel medzi revíziami

Z SensorWiki

Riadok 1: Riadok 1:
'''''Toto je staršia verzia, ktorú sme mali na cvičeniach kedysi dávno.'''''
 
  
 +
V tomto návode vytvoríme program na meranie krok za krokom.
  
  
=== Literatúra ===
+
Najprv si vytvorte nový projekt, ktorý bude pozostávať z nasledovných súborov.
 +
 
 +
<tabs>
 +
<tab name="main.c"><source lang="c++" style="background: LightYellow;">
 +
 
 +
#include <stdio.h>
 +
#include <avr/io.h>
 +
#include <avr/interrupt.h>
 +
#include <util/delay.h>
 +
 
 +
#include "hardware.h"
 +
#include "uart.h"
 +
 
 +
FILE uart_stream = FDEV_SETUP_STREAM(uart_putc, uart_getc, _FDEV_SETUP_RW);
 +
 
 +
 
 +
int main(void)
 +
 +
  hw_init();              // tu je skryte nastavenie vystupu D13 (PD5) na nejaku frekvenciu a plnenie
 +
 
 +
  uart_init(57600);      // konfiguracia seriovej linky na rychlost 57600 Bd
 +
 
 +
  stdout = stdin = &uart_stream;
 +
 
 +
  printf("Ready to start...\n\n"); 
 +
 +
    /*
 +
    * v nekonecnej slucke budeme do terminalu vypisovat
 +
    * hodnotu na vstupe PB0 (na doske oznaceny ako D8)
 +
    * vypis bude 10x za sekundu (preto 100ms)
 +
    */
 +
 
 +
  while(1) 
 +
    {
 +
    unsigned char inputValue =0;
 +
 +
    if bit_is_set(PINB,PB0)
 +
      inputValue = 1;
 +
    else
 +
      inputValue = 0;
 +
 +
    printf("Input D8: %u\r",inputValue);
 +
    _delay_ms(100);
 +
 
 +
    }
 +
 
 +
return(0);
 +
}
 +
 
 +
</source></tab>
 +
<tab name="hardware.h"><source lang="c++" style="background: LightYellow;">
 +
 
 +
#include <stdio.h>
 +
#include <avr/io.h>
 +
#include <avr/interrupt.h>
 +
 
 +
#define LED1  PB5          // Arduino D13 - zabudovana dioda
 +
#define RCinput PB3        // Arduino D8
 +
 
 +
#define set_bit(ADDRESS,BIT) (ADDRESS |= (1<<BIT))
 +
#define clear_bit(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT))
 +
#define toggle_bit(ADDRESS,BIT) (ADDRESS ^= (1<<BIT))
 +
 
 +
void hw_init(void);
 +
void timer0_init(void);
 +
 
 +
 
 +
 
 +
</source></tab>
 +
 
 +
<tab name="hardware.c"><source lang="c++" style="background: LightYellow;">
 +
 
 +
#include <stdio.h>
 +
#include <avr/io.h>
 +
#include <avr/interrupt.h>
 +
 
 +
#define LED1  PB5            // Arduino D13 - zabudovana dioda
 +
#define inputPulse PB0        // Arduino D8
 +
 
 +
#define set_bit(ADDRESS,BIT) (ADDRESS |= (1<<BIT))
 +
#define clear_bit(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT))
 +
#define toggle_bit(ADDRESS,BIT) (ADDRESS ^= (1<<BIT))
 +
 
 +
unsigned volatile static int timer0ext = 0;
 +
 
 +
 
 +
ISR (TIMER0_OVF_vect)   
 +
 +
  timer0ext++;       // pomocne pocitadlo
 +
 
 +
  if (timer0ext>20)
 +
      set_bit(PORTB,LED1);
 +
 +
  if (timer0ext>64)  // po 61 preruseniach zmeni stav
 +
    {
 +
  timer0ext = 0;
 +
      clear_bit(PORTB,LED1); //predtym len toggle a zmenilo to 50:50
 +
  }
 +
}
 +
 
 +
void timer0_init(void)  /* CTC match mode */
 +
{
 +
    /* Timer 0 Normal mode with clock = I/O clock / 1024 */   
 +
TCCR0A = 0x00;                // Mode 0: normal
 +
TCCR0B = (1<<CS02)|(1<<CS00);  // Clock :1024 
 +
TCNT0 = 0x00;                // 8-bit Counter reset
 +
TIFR0 = (1 << TOV0);          // Clear interrupt flag
 +
TIMSK0 = (1 << TOIE0);        // Enable Overflow Interrupt
 +
  sei();   // Enable interrupts
 +
 +
}
 +
 
 +
void hw_init(void)
 +
{
 +
  cli();                    // zakaz vsetky prerusenia
 +
 
 +
  set_bit(DDRB,LED1);        // set pin LED1 as output
 +
  clear_bit(DDRB,inputPulse);    // set RC input as input
 +
  timer0_init();
 +
}
 +
 
 +
</source></tab>
 +
 
 +
<tab name="uart.h"><source lang="c++" style="background: LightYellow;">
 +
 
 +
/* použite vlastný z predošlého cvičenia */
 +
 
 +
</source></tab>
 +
<tab name="uart.c"><source lang="c++" style="background: LightYellow;">
 +
 
 +
/* použite vlastný z predošlého cvičenia */
 +
 
 +
</source></tab>
 +
 
 +
 
 +
</tabs>
 +
 
  
* [http://www.atmel.com/dyn/resources/prod_documents/doc2505.pdf AVR130: Setup and Use the AVR® Timers.]  Aplication Note, Atmel Corporation 2002.<BR> + [http://www.atmel.com/dyn/resources/prod_documents/AVR130.zip software download]
+
Tento program preložte, nahrajte do procesora a pripojte sa cez sériový terminál. LED dióda na doske by mala začať blikať
* [http://www.atmel.com/dyn/resources/prod_documents/doc8014.pdf AVR135: Using Timer Capture to Measure PWM Duty Cycle.] Aplication Note, Atmel Corporation 2005.<BR> + [http://www.atmel.com/dyn/resources/prod_documents/AVR135.zip software download]
+
cca 1x za sekundu a vo výpise by ste mali vidieť, že na vstupe je stále log. 0.  
  
 +
Chceme najskôr zmerať, s akou frekvenciou sa mení výstup s LED diódou (teda PB5, na doske D13). Na to použijeme to najpresnejšie počítadlo,
 +
ktoré na procesore máme k dispozícii, t.j. 16-bitové počítadlo T1. Necháme ho len samovoľne počítať s nejakou frekvenciou a vždy, keď príde
 +
nábežná hrana, odchytíme aktuálny stav počítadla TCNT1 do záchytného (capture) registra ICR1 (Input Capture Register). Toto odchytenie by sme
 +
síce mohli spraviť aj softvérovo, teda kontrolovať stav na vstupe PB5 a pri zmene sa pozrieť do TCNT1 a odpamätať si aktuálny stav. Ale to je
 +
nepohodlné a nepresné, preto na to využijeme možnosť spraviť to automaticky - počítadlo T1 to umožňuje spraviť signálom na vstupe PB0. Preto musíte
 +
prepojiť káblikom výstup D13 (PB5) so vstupom D8 (PB0).
  
 +
V demonštračnom programe by ste už mali vidieť meniaci sa stav na vstupe.
  
'''Príklad ([[Médiá:avrdemo7.hex|avrdemo7.hex]])'''
+
Ready to measure...
 +
 +
Input D8: 0
 +
Input D8: 0
 +
Input D8: 1
 +
Input D8: 1
  
Na vstupe ICP1 (na doske Acrob D8, na čipe ATmega328P je to PB0, pin 14) máme pripojený [[555|zdroj externého kmitočtu]] cca 1Hz:
+
 +
Ďalším krokom bude nakonfigurovanie počítadla T1 tak, aby jednak samostatne počítalo od 0 po 65 535 a zároveň aby sa aktuálny stav počítadla
 +
odchytil do registra ICR1. Pri konfigurácii sa dá vybrať, či sa odchytávanie uskutoční pri nábežnej, alebo dobežnej hrane.
  
[[Obrázok:Oscillogram7.png|center]]
+
Zvolíme spúšťanie ICR nábežnou hranou, počítadlo bude počítať s frekvenciou 16 MHz:1024 (prescaler 1024), a do výpisu si pridáme aj stavy
 +
všetkých zúčastnených registrov
  
Nastavené máme spúšťanie ICR dobežnou hranou, počítadlo počíta 16 MHz:1024, vypisujeme  niekoľkokrát za sekundu stavy všetkých registrov
 
 
<source linenumbers lang="c">
 
<source linenumbers lang="c">
 
Input D8 = 1  TCNT1 =  353  ICR =    0  
 
Input D8 = 1  TCNT1 =  353  ICR =    0  
Riadok 134: Riadok 284:
 
</source>
 
</source>
  
 +
 +
=== Literatúra ===
 +
 +
* [http://www.atmel.com/dyn/resources/prod_documents/doc2505.pdf AVR130: Setup and Use the AVR® Timers.]  Aplication Note, Atmel Corporation 2002.<BR> + [http://www.atmel.com/dyn/resources/prod_documents/AVR130.zip software download]
 +
* [http://www.atmel.com/dyn/resources/prod_documents/doc8014.pdf AVR135: Using Timer Capture to Measure PWM Duty Cycle.] Aplication Note, Atmel Corporation 2005.<BR> + [http://www.atmel.com/dyn/resources/prod_documents/AVR135.zip software download]
  
  
 
[[Category:AVR]][[Category:MMP]][[Category:DVPS]]
 
[[Category:AVR]][[Category:MMP]][[Category:DVPS]]

Verzia zo dňa a času 06:29, 17. máj 2021

V tomto návode vytvoríme program na meranie krok za krokom.


Najprv si vytvorte nový projekt, ktorý bude pozostávať z nasledovných súborov.

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

#include "hardware.h"
#include "uart.h"

FILE uart_stream = FDEV_SETUP_STREAM(uart_putc, uart_getc, _FDEV_SETUP_RW);


int main(void)
{   
   hw_init();              // tu je skryte nastavenie vystupu D13 (PD5) na nejaku frekvenciu a plnenie
   
   uart_init(57600);       // konfiguracia seriovej linky na rychlost 57600 Bd

   stdout = stdin = &uart_stream;
   
   printf("Ready to start...\n\n");   
 
    /* 
     * v nekonecnej slucke budeme do terminalu vypisovat
     * hodnotu na vstupe PB0 (na doske oznaceny ako D8)
     * vypis bude 10x za sekundu (preto 100ms) 
     */

   while(1)  
    {
     unsigned char inputValue =0;
	 
     if bit_is_set(PINB,PB0)
       inputValue = 1;
     else
       inputValue = 0;
	 
     printf("Input D8: %u\r",inputValue); 
     _delay_ms(100);

    }

 return(0); 
}
#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h>

#define LED1  PB5          // Arduino D13 - zabudovana dioda 
#define RCinput PB3        // Arduino D8

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

void hw_init(void);
void timer0_init(void);
#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h>

#define LED1  PB5             // Arduino D13 - zabudovana dioda 
#define inputPulse PB0        // Arduino D8

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

unsigned volatile static int timer0ext = 0;


ISR (TIMER0_OVF_vect)     
{  
   timer0ext++;	      // pomocne pocitadlo

   if (timer0ext>20)
       set_bit(PORTB,LED1);
	
   if (timer0ext>64)  // po 61 preruseniach zmeni stav
     {
	   timer0ext = 0;
       clear_bit(PORTB,LED1); //predtym len toggle a zmenilo to 50:50
	  }	 
}

void timer0_init(void)  /* CTC match mode */
{
    /* Timer 0 Normal mode with clock = I/O clock / 1024 */    
	TCCR0A = 0x00;                 // Mode 0: normal
	TCCR0B = (1<<CS02)|(1<<CS00);  // Clock :1024  
	 TCNT0 = 0x00;                 // 8-bit Counter reset
	 TIFR0 = (1 << TOV0);          // Clear interrupt flag 
	TIMSK0 = (1 << TOIE0);         // Enable Overflow Interrupt 
	  sei();					   // Enable interrupts 
	
}

void hw_init(void)
{
   cli();                     // zakaz vsetky prerusenia

   set_bit(DDRB,LED1);        // set pin LED1 as output
   clear_bit(DDRB,inputPulse);     // set RC input as input
   timer0_init();
}
 /* použite vlastný z predošlého cvičenia */
 /* použite vlastný z predošlého cvičenia */



Tento program preložte, nahrajte do procesora a pripojte sa cez sériový terminál. LED dióda na doske by mala začať blikať cca 1x za sekundu a vo výpise by ste mali vidieť, že na vstupe je stále log. 0.

Chceme najskôr zmerať, s akou frekvenciou sa mení výstup s LED diódou (teda PB5, na doske D13). Na to použijeme to najpresnejšie počítadlo, ktoré na procesore máme k dispozícii, t.j. 16-bitové počítadlo T1. Necháme ho len samovoľne počítať s nejakou frekvenciou a vždy, keď príde nábežná hrana, odchytíme aktuálny stav počítadla TCNT1 do záchytného (capture) registra ICR1 (Input Capture Register). Toto odchytenie by sme síce mohli spraviť aj softvérovo, teda kontrolovať stav na vstupe PB5 a pri zmene sa pozrieť do TCNT1 a odpamätať si aktuálny stav. Ale to je nepohodlné a nepresné, preto na to využijeme možnosť spraviť to automaticky - počítadlo T1 to umožňuje spraviť signálom na vstupe PB0. Preto musíte prepojiť káblikom výstup D13 (PB5) so vstupom D8 (PB0).

V demonštračnom programe by ste už mali vidieť meniaci sa stav na vstupe.

Ready to measure...

Input D8: 0 
Input D8: 0 
Input D8: 1 
Input D8: 1 


Ďalším krokom bude nakonfigurovanie počítadla T1 tak, aby jednak samostatne počítalo od 0 po 65 535 a zároveň aby sa aktuálny stav počítadla odchytil do registra ICR1. Pri konfigurácii sa dá vybrať, či sa odchytávanie uskutoční pri nábežnej, alebo dobežnej hrane.

Zvolíme spúšťanie ICR nábežnou hranou, počítadlo bude počítať s frekvenciou 16 MHz:1024 (prescaler 1024), a do výpisu si pridáme aj stavy všetkých zúčastnených registrov

Input D8 = 1  TCNT1 =   353  ICR =     0 
Input D8 = 1  TCNT1 =  1543  ICR =     0 
Input D8 = 1  TCNT1 =  2749  ICR =     0 
Input D8 = 1  TCNT1 =  3956  ICR =     0 
Input D8 = 1  TCNT1 =  5163  ICR =     0 
Input D8 = 0  TCNT1 =  6369  ICR =  6070  D = 6070  T = 388.4800 ms
Input D8 = 0  TCNT1 =  7706  ICR =  6070  
Input D8 = 0  TCNT1 =  8961  ICR =  6070  
Input D8 = 0  TCNT1 = 10216  ICR =  6070  
Input D8 = 0  TCNT1 = 11488  ICR =  6070  
Input D8 = 0  TCNT1 = 12759  ICR =  6070  
Input D8 = 1  TCNT1 = 14031  ICR =  6070  
Input D8 = 1  TCNT1 = 15303  ICR =  6070  
Input D8 = 1  TCNT1 = 16574  ICR =  6070  
Input D8 = 1  TCNT1 = 17846  ICR =  6070  
Input D8 = 1  TCNT1 = 19117  ICR =  6070  
Input D8 = 1  TCNT1 = 20389  ICR =  6070  
Input D8 = 1  TCNT1 = 21661  ICR = 21591  D = 15521  T = 993.3441 ms
Input D8 = 0  TCNT1 = 23046  ICR = 21591  
Input D8 = 0  TCNT1 = 24334  ICR = 21591  
Input D8 = 0  TCNT1 = 25622  ICR = 21591  
Input D8 = 0  TCNT1 = 26910  ICR = 21591  
Input D8 = 0  TCNT1 = 28197  ICR = 21591  
Input D8 = 1  TCNT1 = 29485  ICR = 21591  
Input D8 = 1  TCNT1 = 30773  ICR = 21591  
Input D8 = 1  TCNT1 = 32061  ICR = 21591  
Input D8 = 1  TCNT1 = 33349  ICR = 21591  
Input D8 = 1  TCNT1 = 34636  ICR = 21591  
Input D8 = 1  TCNT1 = 35924  ICR = 21591  
Input D8 = 1  TCNT1 = 37212  ICR = 37110  D = 15519  T = 993.2161 ms
Input D8 = 0  TCNT1 = 38597  ICR = 37110  
Input D8 = 0  TCNT1 = 39885  ICR = 37110  
Input D8 = 0  TCNT1 = 41173  ICR = 37110  
Input D8 = 0  TCNT1 = 42461  ICR = 37110  
Input D8 = 0  TCNT1 = 43749  ICR = 37110  
Input D8 = 1  TCNT1 = 45037  ICR = 37110  
Input D8 = 1  TCNT1 = 46324  ICR = 37110  
Input D8 = 1  TCNT1 = 47612  ICR = 37110  
Input D8 = 1  TCNT1 = 48900  ICR = 37110  
Input D8 = 1  TCNT1 = 50188  ICR = 37110  
Input D8 = 1  TCNT1 = 51476  ICR = 37110  
Input D8 = 1  TCNT1 = 52763  ICR = 52630  D = 15520  T = 993.2800
Input D8 = 0  TCNT1 = 54149  ICR = 52630  
Input D8 = 0  TCNT1 = 55437  ICR = 52630  
Input D8 = 0  TCNT1 = 56724  ICR = 52630  
Input D8 = 0  TCNT1 = 58012  ICR = 52630  
Input D8 = 0  TCNT1 = 59300  ICR = 52630  
Input D8 = 1  TCNT1 = 60588  ICR = 52630  
Input D8 = 1  TCNT1 = 61876  ICR = 52630  
Input D8 = 1  TCNT1 = 63163  ICR = 52630  
Input D8 = 1  TCNT1 = 64451  ICR = 52630  
Input D8 = 1  TCNT1 =   203  ICR = 52630  
Input D8 = 1  TCNT1 =  1458  ICR = 52630  
Input D8 = 1  TCNT1 =  2730  ICR =  2619  D = 15525  T = 993.6000
Input D8 = 0  TCNT1 =  4083  ICR =  2619

Ak chceme merať aj striedu, musíme meranie realizovať s prerušením a v obsluhe prerušenia preklopiť konfiguračný bit, ktorý rozhoduje o prepise TCNT do ICR registra. Je to bit ICES1, ktorý je v TCCR1B.6.

#include <avr/interrupt.h>  

volatile int newTick = 0;   // The variable for interrupt should be declared as a volatile one!
                  
ISR(TIMER1_CAPT_vect)       // Timer 1 Capture Interrupt Service Routine
{
  TCCR1B = ??               // toggle Edge Select bit
  newTick = ICR1;
}; 

main()
{

   DDRB = ??                // Set ICR - Port B, pin0  as INPUT
 TCCR1B = ??                // T1 clk = F_CPU : 1024, falling edge pin ICP1,
 TCCR1A = ??                // T1 in timer mode !! Note: if You omit this, TCNT1 will be only 8-bit !!
  TCNT1 = 0x0000;           // initialize the counter (16-bit! Low+High bytes)
  TIFR1 = ??                // (1<<ICF1);   if a 1 is written to a ICF1 bit
                            //              - the ICF1 bit will be cleared
                      
 TIMSK1 = ??                // Enable ICR interrupt
  sei();                    // Enable ALL interrupts                      

  ....                      // TODO: display measured value somewhere
  
}


Ukážka pre Arduino využíva zabudovaný príkaz PulseIn:

#define SWITCH 8                // select the pin for Switch
unsigned long duration;

void setup()
{
 pinMode(SWITCH, INPUT);        // this pin is an INPUT
 Serial.begin(9600);
 Serial.println("PulsIn test:");
}

void loop()                      // endless loop
{
 duration = pulseIn(SWITCH, HIGH);
 Serial.print(" T1 = ");
 Serial.print(duration,DEC);
 Serial.print(" [us]");

 duration = pulseIn(SWITCH, LOW);
 Serial.print(" T0 = ");
 Serial.print(duration,DEC);
 Serial.println(" [us]");
}


Literatúra