Otáčkoměr - nevytvoří zálohu proměnné

Zdravím
dělám otáčkoměr pro pomalé frekvence, ale s větší přesností ±0.05Hz max 20Hz.

Když je “rychlost_hz=doba;” nezobrazí to nic, když to je “rychlost_hz=pocitadlo;” zobrazuje se počítadlo od 0 do maxima a při přerušení INT0 začne odznova. Nějaký nápad, proč se “pocitadlo” neokopíruje do “doba”

[code]

uint64_t pocitadlo=0, doba=0, doba_last=0,aaa=0;

// přerušení 2Hz pro zobrazení dat na LCD + výpočet frekvence
ISR(TIMER1_OVF_vect){
TCNT1H=0x87;
TCNT1L=0x00;
rychlost_hz=doba; ///**** problémový řádek
obnov=1; //obnoví údaj na displeji, zápis je ve while(1)… a zobrazí údaj “rychlost_hz”
}

//1KHz
ISR(TIMER0_OVF_vect){
TCNT0=0x83;
pocitadlo++;

    /// pro ověření frekvence - pin se připojí k multimetru na rozsah Hz
    /*if (neguj==0){
	neguj=1;
	SETBIT(PORTB,0);
 }else{
	neguj=0; 
	CLRBIT(PORTB,0);
 }*/

}

ISR(INT0_vect){
_delay_ms(5); //ošetření zákmitů
TIMSK0=0x00; //pokus, žádná změna
_delay_ms(1); //pokus, žádná změna
doba=pocitadlo; /// proč se pocitadlo neokopíruje do doba???******
pocitadlo=0;
TIMSK0=0x01;

}[/code]

Zobrazení informací

while(1){
                if(zobraz==1){
                  sprintf(buffer,"%u Hz", rychlost_hz);
		  lcd_puts("Frekvence:\n");
		  lcd_puts(buffer);
                  zobraz=0;
               }
......
}

Optimalizace kompilatortu ? Klicove promenne zadefinuj jako volatile. Pak se mi moc nelibi (ale to asi nepusobi ten poblem) ze mas v preruseni delay 5ms a 1ms. Udelej to jako stavovy automat (flagy) a casuj to v preruseni s nejrychlejsi casovou bazi (t.j. 1KHz)

Mozna bys mel zamykat rychlost_hz kdyz s ni pracujes v preruseni a soucasne v main.

V podstate by Ti na to cele stacilo jen jedno preruseni ( napr. T0) s periodou 1ms…

No urcite tam chyba volatile. O tom niet pochyb.
Na druhej strane co ma presne robit to nestastne delay_ms() v preruseni? Co si od toho konkretne slubujes?
Pises, ze sa jedna o nejake osetrenie zakmitov. To akoze aby sa prerusenie nevyvolalo viac krat rychlo za sebou?
Na co je tam delay_ms() dva krat? Ved za tym nic netestujes a nepodmienujes vysledkom testovania po oneskoreni 1ms.
Na filtraciu zakmitu tlacitka pouzi paralelne k tlacitku kondik 100n/1uf/… s casovou konstanou na tlacitko kludne aj 7-10ms. A mas to bezpecne.

Plne sa priklanam k navrhu ostanych pracovat s jednou casovou zakladnou 1ms a v ramci nej si testovat vsetky IO piny. Sledovat tlacitko cez interupt je uplne zbytocne.

filtracia tlacitka sa robi napriklad nasledovne:


// je to priklad, nech je tlacitko na porte B, pin 1, s odporom pullup

#define TLACITKO 1
#define FALSE 0x00
#define TRUE 0xff
#define CAS_TESTU_STAVU_TLACITKA 7

volatile uint8_t stav_tlacitka =  FALSE, stav_tlacitka_old = FALSE, cnt_tlacitko =  = CAS_TESTU_STAVU_TLACITKA;

 //1KHz
ISR(TIMER0_OVF_vect){
   // dost nepresna casova zakladna, ktora sa bude pomaly oneskorovavat.
// je omnoho lepsie pouzit mod casovaca s pocitanim do hodnoty OCRx s automatickym nulovanim hodnoty TCNTx
// v kazdom pripade toto funkcne bude
   TCNT0=0x83;
    pocitadlo++;
   
   if (PIND & (1<<TLACITKO) ) stav_tlacitka = FALSE;
   else stav_tlacitka = TRUE;
   if (stav_tlacitka_old ^ stav_tlacitka) {
      if (cnt_tlacitko) cnt_tlacitko--;
      else {
         stav_tlacitka_old = stav_tlacitka;
         if  (stav_tlacitka_old == TRUE) {
            // tu vykonaj cinnost pri stlaceni tlacitka
         } 
         else {
            // tu vykonaj cinnost pri pusteni tlacitka
         }
      }

   }
   else {
      cnt_tlacitko = CAS_TESTU_STAVU_TLACITKA;
   }
}

jsou tam dvě čidla (magnetické rele), musím ještě rozpoznat, jejich posloupnost (směr otáčení)

Za volatile děkuji. ve škole se o tom ani nezmínili :frowning:

Pokusil jsem se vytvořit program dle výše uvedeného návodu:
Přesto rychlost_hz je prázdná, na displeji 0

[code]
#define F_CPU 16000000UL // frekvence krystalu (nutné pro delay.h)

#define TL_CERNE 6
#define TL_MODRE 5
#define TLACITKA PIND

#define DDR(x) (*(&x - 1))
#define SETBIT(PORT, BIT) ((PORT) |= 1 << (BIT))
#define CLRBIT(PORT, BIT) ((PORT) &= ~(1 << (BIT)))
#define GETBIT(m) (_SFR_BYTE(TLACITKA) & _BV(m))
#define GETBITP(PORT, BIT) (_SFR_BYTE(PORT) & _BV(BIT))

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include “lcd.h”
#include <string.h>
#include <stdlib.h>
#include <avr/sleep.h>

int obnov=1;
char buffer[16];

volatile uint64_t rychlost_hz=0, pocitadlo=0,doba=0;
uint64_t doba_last=0;
int i=0;

volatile int d1 = 0,d2 = 0;
volatile float f2 = 0;

//1KHz
ISR(TIMER0_OVF_vect){
TCNT0=0x83;
pocitadlo++;
i++;
if(i>=1000){// půlsekunda
i=0;
obnov=1; //obnoví údaj na displeji
}
if(!GETBIT(2)){

	 //rozsekani na desetine cislo
	 rychlost_hz=pocitadlo;
	 d1 = pocitadlo;            
	 f2 = pocitadlo - d1;    
	 d2 = trunc(f2 * 10000);  
	 	
	 doba_last=pocitadlo;
	 doba=0;
	 obnov=1; //možná to tu smažu
	 pocitadlo=0;	
 }

}

void init(){
DDRA = 0b11111111;
PORTA = 0b11111111;

DDRB =  0b11111111;
PORTB = 0b11110000;

DDRC =  0b11111100;
PORTC = 0b00000000;

DDRD  = 0B00000000;
PORTD = 0b11111111;

TCCR0A=0x00;
TCCR0B=0x03;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;

TCNT1H=0x00;
TCNT1L=0x00; 
TCCR1A=0x00;  
TCCR1B=0x04; 

ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00; 
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

ASSR=0x00;
TCCR2A=0x00;
TCCR2B=0x00;
TCNT2=0x00;
OCR2A=0x00;
OCR2B=0x00;

EICRA=0x00;
EIMSK=0x00;
EIFR=0x00;
PCICR=0x00;

// Timer/Counter 0 Interrupt(s) initialization
TIMSK0=0x01;
TIMSK1=0x00;
TIMSK2=0x00;

ADCSRA=0x00;

SPCR=0x00;
SPSR=0x00;

TWCR=0x00;

sei();
_delay_ms(500);	

lcd_init(LCD_DISP_ON);  

}

int main(void){
init();

while (1){	
	if(obnov==1){
		lcd_clrscr();
		sprintf (buffer, "%d.%02d Hz  %d\n", d1, d2, rychlost_hz);
		lcd_puts(buffer);
		
		sprintf(buffer,"%d pocitadlo", pocitadlo);
		lcd_puts(buffer);
		obnov=0;
	}
}			

}[/code]