Hallo!
Ik ben bezig meteen projectje en het gaat om het volgende:
Ik wil de tijd meten tussen 2 nul-detecties. Kortom hoeveel tijd er zit tussen 2 nulpunten van een sinus signaal.

De code voor de nul-detectie heb ik al, maar ik kan weinig infomatie of voorbeelden vinden over tijd meten. Ik werk zelf met de Atmega32 en programmeer in C met CodeVision.

Ik heb het volgende gevonden:

void timer0_init(void)
{
TCCR0 = 0x00; //stop
TCNT0 = 0x83; //set count
TCCR0 = 0x02; //start timer
}

Het gedeelte met timer start en stop snap ik nog wel, maar hoe kan je nu zien hoelang de timer gelopen heeft?

Kan iemand mij verder helpen met het maken van een stukje code om tijd te meten door een timer te starten en eventueel weer te laten stoppen?

Alvast bednakt!

Je werkt hier puur met de registers van de timer. Dat is niet zozeer aan c gerelateerd, maar aan de hardware. Met behulp van het hoofdstuk over de timer in de datasheet zou je een heel eind moeten komen.

Ik zou in elk geval TCNT0 op 0 zetten voordat je de timer start. Op het moment dat je de timer stop kan je daar uitlezen hoeveel pulsen deze verder is. Uiteraard moet je rekening houden met het bereik. Een 8-bit timer telt bijvoorbeeld maar tot 255 en begint daarna opnieuw. Het is ook maar net afhankelijk van hoe nauwkeurig je wilt meten en hoe groot de tijdsverschillen zijn tussen de nuldoorgangen. Wil je nauwkeurig over relatieve lange tijd dan zal je zelf moeten gaan bijhouden hoe vaak je teller opnieuw begint (timer overflow interrupt).

TCCR0 = 0x02; //start timer

Het is trouwens veel netter daar bit definities te gebruiken, want weet jij zo welk bit je zet met 0x02?

[Bericht gewijzigd door Marcel op ]

Bedankt voor je antwoord:) dat over TCNT wist ik niet, en daar was ik nou juist naar opzoek :)

Ik heb de datasheet erbij gepakt maar ik snap hier niet heel veel van :(

Zou iemand mij wat meer uitleg kunnen geven over hoe het precies werkt? Of mss een voorbeeld met uitleg kunnen showen?

Geef eens concreet aan wat je er niet van snapt. TCNT0 is het timer register waarin de timer telt. Bij elke timer puls wordt de waarde in het register met 1 verhoogt.

Is het trouwens een schoolproject?

Een minimalistische aanpak zou zo iets kunnen zijn:


unsigned int T0_loops;

ISR(SIG_OVERFLOW0)
{
    T0_loops++;				       // Overflow-teller met 1 verhogen
    // Test ook T0_loops voor overflow!
}

void T0_init(void)
{
    TCCR0 = 0;				       // Counter0 stilleggen
    TIMSK |= _BV(TOIE0);		       // Enable counter0 overflow interrupt
    sei();				       // Global interrupts on
}

void T0_start(void)
{
    TCNT0 = 0;				       // Counter0 = 0
    T0_loops = 0;			       // Overflow-teller = 0
    TCCR0 = _BV(CS00);			       // CLK = max.
}

unsigned long T0_stop(void)
{
    TCCR0 = 0;				       // Counter0 stilleggen
    return (((unsigned long) T0_loops * 256) + TCNT0);
}

Als het te snel gaat, gebruik je een prescaler voor de klok (TCCR0). Het starten en stoppen kan je best via een externe interrupt doen, waar je de nuldoorgangsdedector op aansluit.

Het is inderdaad voor school, we zijn met een project bezig waarvoor we een vermogensmeter moeten ontwerpen/maken.

Ik begin er al wat meer van te snappen, in TCNT0 worden dus het aantal klokslagen bij gehouden met als maximum 255(8-bit).

Wij zijn van plan een comperator aan te sluiten op de INT0 . Het is dan dus mogelijk om in de interrupt de timer te laten starten door middel van: TCCR0 = 0x02;? of is dit stukje code wat ik gevonden heb niet juist?

wat doet dit stukje code precies:
ISR(SIG_OVERFLOW0) ?
en (((unsigned long) T0_loops * 256) + TCNT0);?

Op 26 april 2007 23:41:40 schreef MarcoNehmelman:

Ik wil de tijd meten tussen 2 nul-detecties. Kortom hoeveel tijd er zit tussen 2 nulpunten van een sinus signaal.

ik dacht dat je dit voor de lol wilde doen, maar je meent het.
De tijd is toch altijd hetzelfde ?
Is je vraag wel juist ?

Ja, je kan in de INT0-ISR de timer starten met "TCCR0 = _BV(CS01);".
Er wordt naar ISR(SIG_OVERFLOW0) gesprongen, zodra TCNT0 van 255 terug naar 0 springt. Bij een overflow van counter0, dus.
(((unsigned long) T0_loops * 256) + TCNT0) berekent het totaal aantal klokpulsen tussen het starten en het stoppen van timer0 en plaatst dat in een unsigned int. Als dat meer is dan je denkt nodig te hebben, kan je voor T0_loops een unsigned char gebruiken, dat met 256 vermenigvuldigen en er TCNT0 bij tellen. Of je gebruikt een 16-bits timer.

Ik heb nu het volgende toegevoegd:

(de interrupt heb ik aangepast om het in CodeVision te laten werken)


interrupt [TIM0_OVF] void timer0_ovf_isr(void){
    T0_loops++;				       // Overflow-teller met 1 verhogen
    // Test ook T0_loops voor overflow!
}

void T0_init(void)
{
    TCCR0 = 0;				       // Counter0 stilleggen
    TIMSK=0x00;		       // Enable counter0 overflow interrupt
    #asm("sei")				       // Global interrupts on
}

void T0_start(void)
{
    TCNT0 = 0;				       // Counter0 = 0
    T0_loops = 0;			       // Overflow-teller = 0
    //TCCR0 = _BV(CS00);			       // CLK = max.
}

unsigned long T0_stop(void)
{
    TCCR0 = 0;				       // Counter0 stilleggen
    return (((unsigned long) T0_loops * 256) + TCNT0);
}

alleen het volgende werkt niet in CodeVision: TCCR0 = _BV(CS00);

CodeVision kent _BV() niet.
Wat moet hier staan ipv _BV(CS00) ?

Ik heb nu een code gemaakt die de timer op een lcd scherm zou moeten weergeven, hier volgt de code:


/*****************************************************
This program was produced by the
CodeWizardAVR V1.25.3 Evaluation
Automatic Program Generator
© Copyright 1998-2007 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project : 
Version : 
Date    : 27-4-2007
Author  : Freeware, for evaluation and non-commercial use only
Company : 
Comments: 


Chip type           : ATmega32
Program type        : Application
Clock frequency     : 16,000000 MHz
Memory model        : Small
External SRAM size  : 0
Data Stack size     : 512
*****************************************************/

#include <mega32.h>

// Alphanumeric LCD Module functions
#asm
   .equ __lcd_port=0x18 ;PORTB
#endasm
#include <lcd.h>
#include <stdlib.h>
#include <delay.h>

int teller;
char buffer[30]; 
unsigned int T0_loops;


interrupt [TIM0_OVF] void timer0_ovf_isr(void){
    T0_loops++;				       // Overflow-teller met 1 verhogen
    // Test ook T0_loops voor overflow!
}

void T0_init(void)
{
    TCCR0 = 0;				       // Counter0 stilleggen
    TIMSK=0x00;		       // Enable counter0 overflow interrupt
    #asm("sei")				       // Global interrupts on
}

void T0_start(void)
{
    TCNT0 = 0;				       // Counter0 = 0
    T0_loops = 0;			       // Overflow-teller = 0
    //TCCR0 = _BV(CS00);			       // CLK = max.
}

unsigned long T0_stop(void)
{
    TCCR0 = 0;				       // Counter0 stilleggen
    return (((unsigned long) T0_loops * 256) + TCNT0);
}


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

// 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=T 
PORTB=0x00;
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: System Clock
// Clock value: 15,625 kHz
// Mode: Normal top=FFh
// OC0 output: Disconnected
TCCR0=0x05;
TCNT0=0x00;
OCR0=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer 1 Stopped
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2 output: Disconnected
ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;

// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// INT2: Off
MCUCR=0x00;
MCUCSR=0x00;

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

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

// LCD module initialization
lcd_init(16);
        
T0_init();

	     
     
     
while (1)
      {
      T0_start();				    
      delay_ms(30);
      teller = T0_stop();
      itoa(teller, buffer); // zet int om in char;
      lcd_puts(buffer);     // geeft buffer weer op lcd
      lcd_clear(); 
    
      
      
      };
}

Deze code zou dus een getal op het scherm moeten weergeven van de timer maar ik zie alleen een 0 verschijnen omdat TCNT0 = 0; de timer nul maakt.

Ziet iemand wat ik fout doe?

Je kan "_BV(CS00)" vervangen door "1 << CS00". Die _BV() is een typisch gcc-ding.

Verder ben ik zelf zo dom geweest om T0_loops te declareren als


unsigned int T0_loops;

Terwijl dat voor gcc moet zijn:


volatile unsigned int T0_loops;

Weet niet of dat met CodeVision ook noodzakelijk is.

Het TOIE0-bit van TIMSK moet hoog gemaakt worden, wil je dat een counter0-overflow voor een interrupt zorgt:


TIMSK |= (1 << TOIE0);

En dan die itoa() functie: kan die met een unsigned long overweg?

Na wat knutselen is het mij gelukt :)


#include <mega32.h>

// Alphanumeric LCD Module functions
#asm
   .equ __lcd_port=0x18 ;PORTB
#endasm
#include <lcd.h>
#include <stdlib.h>
#include <delay.h>

int timerloops;
int teller;
char buffer[30];
char bufferloop[30];
int j=0;

// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
timerloops++;
}

void main(void)
{
PORTB=0x00;
DDRB=0x00;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 125,000 kHz
// Mode: Normal top=FFh
// OC0 output: Disconnected
TCCR0=0x03;
TCNT0=0x00;
OCR0=0x00;

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


// LCD module initialization
lcd_init(16);

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

while (1)
      {
      teller = TCNT0;
      itoa(teller, buffer);
      itoa(timerloops, bufferloop);
      lcd_puts(buffer);
      lcd_putsf("  loop: ");
      lcd_puts(buffer);
      lcd_clear();

      };
}

ik heb nu TCNT0 steeds tellent van 0 t/m 255 op mijn lcd en daarnast het aantal loops.

Hoe kan je berekenen hoelang hij er over doet om van 0 tot 255 te tellen?
En hoe kan ik er voor zorgen dat de timer niet zo snel loopt? Ik kan de timer ook rond de 7kHz laten draaien met codevision maar dat is alsnog snel?

zijn hier truckjes voor?

Alvast bedankt! :D

Je kan een tweede timer starten, die in zijn overflow-ISR zichzelf en counter0 stopt. Die tweede timer hoeft niet absoluut van 0 tot MAX te tellen; je kan z'n counter (TCNTx) bij het starten een waarde geven, zodat hij korter telt.

Voor een ATmega32 is het gebruik van counter2 interessant, omdat die zijn klok kan betrekken uit een extern horlogekristal. Handig voor frequentiemetingen, en onafhankelijk van de systeem-klok.

-Ik heb nu een timer lopen op 125kHz(=125000Hz)
-De timer telt steeds tot 255 op de Frequentie en bij 255 is er een overflow interrupt en gaat timerloops +1;

Dit zou betekenen als ik secondes wil tellen:
-125000Hz per sec= 0,000008sec per Hz=0,00204sec per 255 Hz
-125000 / 255 = 490 keer tot 255 tellen per seconden(toch?)
Dit betekend dat als timerloops(variabel die +1 gaat bij elke overflow interrupt) 490 is, dat er 1 seconde voorbij zou zijn gegaan?

Of komt er meer bij kijken om een seconde teller te maken?

De werkwijze lijkt me OK. Je berekening niet. De teller telt van 0 tot 255, dat zijn 256 stapjes! Dat betekent dus:
488 maal van 0 tot 255 (124928 klokpulsen)
1 maal van 183 tot 255 (72 klokpulsen)

Dat laatste doe je door de 489e maal TCNTx op 183 te zetten.

Oke, maar hoe bereken ik dan hoeveel stapjes er nodig zijn voor 1 seconde?

Als je timer-klok 125000Hz bedraagt, zou het bovenstaande mi. moeten werken. Anders:
CLK / 256 = volledige meet-lussen
CLK - (volledige meet-lussen * 256) = extra-meetpulsen.
Bij laatste meting: TCNTx = 255 - extra-meetpulsen
Controleren kan altijd, door een bekende frequentie te meten en na te gaan of het resultaat overeenstemt met de verwachtingen.