Jak zprovoznit čítač pomalé frekvence(cca 0-200Hz)?

Ahoj, snažím se udělat obyčejný čítač frekvence, na ATmega 644p, ale pořád se mi nedaří, zobrazuje mi to pořád nějaké šílené čísla. Mám zapnutej 16bit čítač/časovač, kterej mi počítá 1s a pomocí čítače/časovače 0 chci počítat pulzy (5V) a ty zobrazovat na displeji. Jsem začátečník a moc tomu nerozumím, tak nevím kde mám chybu. Prosím o radu. Program je psán v codevisionu pomocí codewizardu.

float a;
unsigned char b[8];
// Declare your global variables here
interrupt [TIM1_OVF] void timer1_ovf_isr(void)
{
// Reinitialize Timer1 value
TCNT1H=0xC2F6 >> 8;
TCNT1L=0xC2F6 & 0xff;
 
a = TCNT0;
TCNT0 = 0;
 
}
void main(void)
{

/// Timer/Counter 0 initialization
// Clock source: T0 pin Rising Edge
// Mode: Normal top=0xFF
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=0x00;
TCCR0B=0x05;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 15,625 kHz
// Mode: Normal top=0xFFFF
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer1 Overflow Interrupt: On
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x05;
TCNT1H=0xC2;
TCNT1L=0xF6;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;


lcd_init(16);
lcd_gotoxy(0,0);
lcd_putsf("IR SNIMAC ");

#asm("sei")


while (1)
      {
       lcd_gotoxy(0,1);
        lcd_putsf(" ");
         
        ftoa(a,1,b);
         lcd_gotoxy(3,1);
        lcd_puts(b);

      }
}

Díky za pomoc nebo návrh nějakého jiného řešení

Pro začátek:
před “float a;” chybí “volatile” (s “a” se pracuje v přerušení).
Proč je “a” jako float??? Vždyť počítáš pulzy ne? Tedy celá čísla, navíc pouze kladná => “unsigned int a” nebo “unsigned long int a”.

řádky “TCNT1H=0xC2F6 >> 8;” a “TCNT1L=0xC2F6;” jsou špatně ikdyž možná udělají co potřebuješ. Registry jsou pouze 8bitové, tedy 2 hexa číslice na 1 registr.

Tak ‘a’ jsem si upravil na ‘volatile unsigned int a’ , jinak ty řádky si udělal Codevision sám, když jsem ve wizardu zadal hodnotu dopočítanou na jednu sekundu. Ale ani po opravení to nefunguje.

Předpokládám, že jsi “ftoa” změnil na “utoa” (nebo jak se ta funkce v CV jmenuje).

TCNT1H=0xC2;
TCNT1L=0xF6;

jj, změnil na ‘itoa’ , a pořád to ukazuje nějaké měnící se hodnoty, ale mění se po sekundě, takže myslím že časovač bude v pořádku…
komplet celej kod :

#include <mega644p.h>
#include <stdlib.h>
#include <alcd.h>

volatile int a;
unsigned char b[8];

interrupt [TIM1_OVF] void timer1_ovf_isr(void)
{
// Reinitialize Timer1 value
TCNT1H=0xC2;
TCNT1L=0xF6;

a=TCNT0;
TCNT0=0;

}

// Declare your global variables here

void main(void)
{
// Declare your local variables here

// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

// Input/Output Ports initialization
// Port A initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T 
PORTA=0x00;
DDRA=0x00;

// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=P 
PORTB=0x01;
DDRB=0x00;

// Port C initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T 
PORTC=0x00;
DDRC=0x00;

// Port D initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In 
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T 
PORTD=0x00;
DDRD=0x00;

// Timer/Counter 0 initialization
// Clock source: T0 pin Rising Edge
// Mode: Normal top=0xFF
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=0x00;
TCCR0B=0x07;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 15,625 kHz
// Mode: Normal top=0xFFFF
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer1 Overflow Interrupt: On
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x05;
TCNT1H=0xC2;
TCNT1L=0xF6;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer2 Stopped
// Mode: Normal top=0xFF
// OC2A output: Disconnected
// OC2B output: Disconnected
ASSR=0x00;
TCCR2A=0x00;
TCCR2B=0x00;
TCNT2=0x00;
OCR2A=0x00;
OCR2B=0x00;

// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// INT2: Off
// Interrupt on any change on pins PCINT0-7: Off
// Interrupt on any change on pins PCINT8-15: Off
// Interrupt on any change on pins PCINT16-23: Off
// Interrupt on any change on pins PCINT24-31: Off
EICRA=0x00;
EIMSK=0x00;
PCICR=0x00;

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

// Timer/Counter 1 Interrupt(s) initialization
TIMSK1=0x01;

// Timer/Counter 2 Interrupt(s) initialization
TIMSK2=0x00;

// USART0 initialization
// USART0 disabled
UCSR0B=0x00;

// USART1 initialization
// USART1 disabled
UCSR1B=0x00;

// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
ADCSRB=0x00;
DIDR1=0x00;

// ADC initialization
// ADC disabled
ADCSRA=0x00;

// SPI initialization
// SPI disabled
SPCR=0x00;

// TWI initialization
// TWI disabled
TWCR=0x00;

// Alphanumeric LCD initialization
// Connections are specified in the
// Project|Configure|C Compiler|Libraries|Alphanumeric LCD menu:
// RS - PORTC Bit 5
// RD - PORTC Bit 7
// EN - PORTC Bit 4
// D4 - PORTC Bit 0
// D5 - PORTC Bit 1
// D6 - PORTC Bit 2
// D7 - PORTC Bit 3
// Characters/line: 16
lcd_init(16);
lcd_gotoxy(0,0);
lcd_putsf("Snimac");

// Global enable interrupts
#asm("sei")

while (1)
      {
      
      lcd_gotoxy(0,1);  
      itoa(a,b);
      lcd_puts(b);
      lcd_gotoxy(5,1);
      lcd_putsf("Hz"); 

      }
}
  1. Je zbytečné zobrazovat hodnotu nepřetržitě.
    Uprav kód takto

[code]volatile unsigned char a,flag;
char b[8];

interrupt [TIM1_OVF] void timer1_ovf_isr(void)
{
// Reinitialize Timer1 value
TCNT1H=0xc2; //16MHz
TCNT1L=0xf6;

a=TCNT0;
TCNT0=0;
flag=1;
}

while (1)
{
if(flag == 1)
{
flag = 0;
itoa(a,b);

  lcd_gotoxy(0,1); 
  lcd_puts(b);
  lcd_gotoxy(5,1);
  lcd_putsf("Hz");
}

}
[/code]
2. Nedávej pull-up na vstup (vynech řádek "PORTB=0x01; ").
Když se pak dotkneš vstupu (portb.0) prstem, ukáže 50 Hz.

Nepíšeš taky jaký zdroj signálu měříš - máš nějaký generátor s kontrolou, co z něj leze. Víš tedy určitě, že ty nesmysly, co ti to ukazuje na tom vstupu opravdu nemáš?

Všechny navrhované úpravy jsou samozřejmě k lepšímu, ale i bez nich v tom původním by to mělo chodit .

špatně to určitě není - párkrát už jsem se s takovým zápisem, nebo obdobným TCNT1H=0xC2F6/256;intu do dvou 8b registrů setkal a CV stejně jako třeba MPlab s tím vůbec problém nemá - prostě se zapíše jen spodní byte a zbytek ignoruje.

Ok, tak je to tak, na vstupu jsem měl nesmysly. Tak to funguje. Jen mě napadlo, nešlo by to nějak zpřesnit na desetiny Hz?

A další věc, můžu si nějak sám udělat jednoduše nějakej generátor frekvence s možností měnit rozsah? Co je k tomu potřeba? PWM?

Na zpřesnění máš 2 cesty.
První je prodloužení doby měření (když budeš měřit 10s, změříš desetiny Hz), druhá je měření periody a následný výpočet frekvence.

scienceprog.com/avr-dds-sign … rator-v20/ niekde na nete je aj lepšia vrerzia.

Záleží jesli potřebuje DDS nebo stačí obdélník a jesli to má být vůbec s procesorem.

Ok, to zpřesnění provedu aspon na pul Hz změnou doby čítání na 2s, pujde to tak, že? :slight_smile:

Stačí jen obdélník, právě mě napadlo pustit pwm na timeru0 se střídou 1:1 a tuto sřídu měnit, měl by k tomu sloužit registr 0CR1, ale nějak nevím co za hodnotu do toho registru ukládám?

Změnou střídy nezměníš frekvenci.
Pwm mód se hodí pouze protože u něj jde nastavit délka timeru, samotné generování pwm tě nezajímá pokud chceš pouze měnit frekvenci se stálou střídou 50%.
Na timeru 0 můžeš s 1MHz hodinama generovat frekvence od zhruba 4Hz.

At si s tím hraju jakkoliv, tak žádnou frekvenci negeneruju… co mám zapnout a kde bude ten signál výstupní?

Jako zdroj pro timer nastav děličku 1024, mód třeba 2 (CTC, délku timeru určuje OCR0A, WGM2:0 = 010). Jako výstup použij třeba pin OC0A(PB3 - nastavit jako výstup) a nastav ho na “Toggle OC0A on Compare Match” (COM0A1:0 = 01).

Při 1MHz, děličce 1024, OCR0A=0xFF bude na výstupu frekvence f=1e6/(10242562) = 1.9Hz

Snížením děličky nebo TOP (OCR0A) zvýšíš frekvenci.