Sida 1 av 1

Använda ADC som timer?

Postat: 10 augusti 2010, 01:27:37
av Korken
Sitter i leran och har märkt att jag behöver en timer till, då 2 st redan är upptagna och har inga fler.
De som då slog mig är om jag kan använda ADCns ISR som timer? Då jag har 128 i prescaler så borde frekvensen blir FCPU/128.
Eller är det något mer som påverkar frekvensen på ADCns ISR? Vet att beräkna värdet tar 13.5 cykler men de borde få plats pga prescalern.

Samt koden som ska in i ADCn är mycket liten, en variabel som behöver räknas samt en if-sats som tillåter en grej att köras i main-programmet, så det borde få plats.
Och det jag mer gör i ADCn är att ta ut ADC värden, så inget tungt där sen förut.

Kan detta fungera? :humm:

Re: Använda ADC som timer?

Postat: 10 augusti 2010, 06:43:43
av Swech
Det är en AVR? Vilken modell?
Vad använder du de andra timrarna till då som gör att de är helt upptagna?

Frekvensen blir FCPU/(128*13.5) det går 13.5 cykler oavsett prescalerns värde.

Swech

Re: Använda ADC som timer?

Postat: 10 augusti 2010, 09:26:44
av dangraf
Du skulle annars kunna skriva om din kod lite och använda en timer till flera olika grejjer. Såg i din tidigare tråd att du lagt togglingen inne i timer-interruptet. Det finns ett annat alternativ ifall det inte är så tidskritiska grejjer som t.ex att blinka med en lysdiod.

Timer drivrutin: (fattas lite delar som init osv men denna är skriven mest för att du ska förstå prinsipen.

Kod: Markera allt

#define TIMER_INST_PER_MILLISEC		             BOARD_FOSC/(1000*4)
#define U16MS_TO_TICK(time)			(uint16)((TIMER_INST_PER_MILLISEC*time)/(256ull))

uint16 timerRead16(void)
{
                          uint16 tick = 0;
                          INTCONbits.TMR0IE = 0;		// Disable interrupt
	
                          tick = TMR0H;
                          tick <<=8;
                          tick |= TMR0L;

		
                          INTCONbits.TMR0IE = 1;
                          return tick;
}

uint16 timerGetDiff16( uint16 timestamp )
{
	uint16 diff;
	diff = timerRead16();
	diff = diff - timestamp;
	
	return diff;
}
void timerInit(void)
{
      TMR0H = 0;
      TMR0L = 0;

    INTCONbits.TMR0IE = 0;		// Disable interrupt

    // Timer0 on, 16-bit, internal timer, 1:256 prescalar
    T0CON = 0x86;
}
För att använda ovanstående kod på ett bra sätt kan du skriva:

Kod: Markera allt

void blinkLed(void)
{
   static uint16 myTimestamp;

  // LEDPIN är en bitmask för din diod

  if( PORTB & LEDPIN)
  {
       // lysdioden är tänd 
        if( timerGetDiff16( myTimestamp) > U16MS_TO_TICK( 100 )
        {
            // låt den vara tänd i 100 ms därefter släck
            myTimestamp = timerRead16();
            PORTB &= ~LEDPIN;
        }
  }else
  {
        if( timerGetDiff16( myTimestamp) > U16MS_TO_TICK( 20 )
        {
            // låt den vara släckt 20 ms därefter tänd
            myTimestamp = timerRead16();
            PORTB |= LEDPIN;
        }
  }

}
På detta sättet får möjlighet att hålla koll på tiden i flera små applikationer samtidigt. Nackdelen är att du får inte samma exakthet i tidmätningen jämfört med att använda en timer för varje grejj. Detta pga att det finns risk för att en annan applikation gör något som tar lite längre tid, t.ex räknar ut ett värde på en vektor, läser ett SD-kort etc. Men i ditt fall verkar det hur lungt som helst.

Re: Använda ADC som timer?

Postat: 10 augusti 2010, 15:30:57
av Korken
Tackar för tipset!

Det som gör dom upptagna är att ena timer kör som hw PWM och den andra har jag just nu "blink-led" rutinen.
Jag kan trycka in det i den timern, men jag funderade om det gick att använda ADCn då den kör redan i en väldigt bra frekvens för de jag vill köra i main loopen sen, vilket ger mig mindre jobb än att bygga om min ena timer. :)

µC: Just nu för test tiny45, men ska sedan petas in i en tiny24. (hade ingen tiny24 i DIP-kapsel)

Re: Använda ADC som timer?

Postat: 10 augusti 2010, 16:02:21
av jesse
det ska väl gå bra, du läser av flaggan (alternativt låter ett interrupt sätta en flagga), läser av ADC, och sedan gör du det du ska göra.

Re: Använda ADC som timer?

Postat: 10 augusti 2010, 20:11:19
av dangraf
Risken med att använda ADCn jämfört med ett vanligt timer-interrupt är att du startar din timer varje gång du hoppar in i interruptet vilket kan medföra att du får en drift i tid beroende på vart du befinner dig i din kod. låt säga att du får ett ADC interrupt samtidigt(eller lite efter) som du får ett timer interrupt. Då kommer koden köra i timer interruptet och kan inte hoppa till ADC interruptet direkt (antar att du inte ADCn som högsta prioritet).

Om man jämför detta med t.ex ett timer interrupt så gör det inget ifall det blir en liten fördröjning eftersom timern fortsätter att snurra i bakgrunden och behöver inte startas varje gång du hoppar in i interruptet.

Lycka till!

Re: Använda ADC som timer?

Postat: 10 augusti 2010, 21:26:51
av Korken
Precis, har tänkt på det också.
Som tur är så är inte det jag gör så tidskritiskt, mer så att det blir ungefär lika lång tid (och att det tar tid) mellan varje gång.
För det jag bestämmer är hur ofta jag uppdaterar PWMens Dutycycle. För jag styr en Buck-converter med PWMen och vill inte stiga/sjuka för fort så kondensatorerna inte hinner med.
För nu när jag testar utan att kontrollera hur snabbt de får stiga/sjuka utan bara kontrollerar vart jag vill hamna, så hamnar systemet i svängning, därför jag ändrar lite. :)

Re: Använda ADC som timer?

Postat: 11 augusti 2010, 09:57:18
av bearing
Jag har för mig att man kan köra ADC i "free running mode", vilket borde göra att ADC-interruptet kommer i jämn takt likt en timer.

Re: Använda ADC som timer?

Postat: 11 augusti 2010, 11:19:15
av Korken
Japp, det är rätt de!
Jag gör just de, för då ska man få frekvensen FCPU/prescaler Hz.

Jag har testat detta lite nu och jag måste säga att det fungerar över förväntningar!
Tog lite tid och tester att hitta hur lång paus jag behövde, men nu fungerar det som det ska.
Från svängningar på ca 3V till mindre än 0.1V, de är godkänt! :D