Forum: Mikrocontroller und Digitale Elektronik Fehlersuche im Code:1/10 ms warten lassen mit Timer


von Seba (Gast)


Lesenswert?

Dieser Code soll genau wait_ms(10) soll den IC genau 1ms warten lassen, 
leider ist das nicht der Fall, kann mir einer sagen wodran es liegt, IC 
löuft mit 20mhz, es ist ein atmega 644.

#define F_CPU 20000000
#define IRQS_PER_SECOND   10000 /* 500 µs */ //jede microsekunde einen 
auslöser
#define IRQS_PER_10MS     (IRQS_PER_SECOND / 1000)

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

#if (F_CPU/IRQS_PER_SECOND > 65536) || (IRQS_PER_10MS < 1) || 
(IRQS_PER_10MS > 255)
#   error Diese Werte fuer F_CPU und IRQS_PER_SECOND
#   error sind ausserhalb des gueltigen Bereichs!
#endif


//Prototypen
void sleep_ms(uint16_t ms);

// Zähler-Variable. Wird in der ISR erniedrigt und in wait_10ms benutzt.
static volatile uint8_t timer_10ms;


//LED Defines
//Hier müssen die richtigen Angaben hin
#define LED_DDR    DDRB        //DDRA, DDRB...
#define LED_PORT  PORTB       //PORTA, PORTB...
#define LED_PORTPIN  PB3         //PA0, PA1..., PB0, PB1..., ...

// 
//////////////////////////////////////////////////////////////////////
// Die Interrupt Service Routine (ISR).
// In interrupt_num_10ms werden die IRQs gezählt.
// Sind IRQS_PER_10MS Interrups geschehen,
// dann sind 10 ms vergangen.
// timer_10ms wird alle 10 ms um 1 vermindert und bleibt bei 0 stehen.
SIGNAL (SIG_OUTPUT_COMPARE1A)
{
    static uint8_t interrupt_num_10ms;

    // interrupt_num_10ms erhöhen und mit Maximalwert vergleichen
    if (++interrupt_num_10ms == IRQS_PER_10MS)
    {
        // 10 Millisekunden sind vorbei
        // interrupt_num_10ms zurücksetzen
        interrupt_num_10ms = 0;

        // Alle 10ms wird timer_10ms erniedrigt, falls es nicht schon 0 
ist.
        // Wird verwendet in wait_10ms
        if (timer_10ms != 0)
            timer_10ms--;
    }
}


void timer1_init()
{
    // Timer1: keine PWM
    TCCR1A = 0;

    // Timer1 ist Zähler: Clear Timer on Compare Match (CTC, Mode #4)
    // Timer1 läuft mit vollem MCU-Takt: Prescale = 1
#if defined (CTC1) && !defined (WGM12)
   TCCR1B = (1 << CTC1)  | (1 << CS10);
#elif !defined (CTC1) && defined (WGM12)
   TCCR1B = (1 << WGM12) | (1 << CS10);
#else
#error Keine Ahnung, wie Timer1 fuer diesen AVR zu initialisieren ist!
#endif

    // OutputCompare für gewünschte Timer1 Frequenz
    // TCNT1 zählt immer 0...OCR1A, 0...OCR1A, ...
    // Beim überlauf OCR1A -> OCR1A+1 wird TCNT1=0 gesetzt und im 
nächsten
    // MCU-Takt eine IRQ erzeugt.
    OCR1A = 200;

    // OutputCompareA-Interrupt für Timer1 aktivieren
#if defined (TIMSK1)
    TIMSK1 |= (1 << OCIE1A);
#elif defined (TIMSK)
    TIMSK  |= (1 << OCIE1A);
#else
#error Keine Ahnung, wie IRQs fuer diesen AVR zu initialisieren sind!
#endif
}

// 
//////////////////////////////////////////////////////////////////////
// Wartet etwa t*10 ms.
// timer_10ms wird alle 10ms in der Timer1-ISR erniedrigt.
// Weil es bis zum nächsten IRQ nicht länger als 10ms dauert,
// wartet diese Funktion zwischen (t-1)*10 ms und t*10 ms.
void wait_ms (long int t)//wait_10ms (const uint8_t t)
{
    timer_10ms = t;
    while (timer_10ms);
}


int main(void){
  /*Den Pin wo die LED angeschlossen
      ist als Ausgang setzen
   */
//  LED_DDR |= (1<<LED_PORTPIN);


DDRD |= (1<<PD6);
PORTD |= (1<<PD6);

    // Timer1 initialisieren
    timer1_init();

    // Interrupts aktivieren
    sei();


DDRB |= (1<<PB0);
//PORTB |= (1<<PB0);
//wait_ms (50000);
PORTB |= (1<<PB0);
wait_ms (10000);
PORTB &= ~(1<<PB0);

int a = 0;

while(a != 1500){
  PORTB |= (1<<PB3);
//  LED_PORT |= (1<<LED_PORTPIN);  //Den Portpin auf high setzen
  sleep_ms(1);
  PORTB &= ~(1<<PB3);
//  LED_PORT &= ~(1<<LED_PORTPIN);  //Den Portpin auf low setzen
  sleep_ms(19);
  a++;
}

PORTD &= ~(1<<PD6);

//DDRD &= (1<<PD6);
int c = 0;
int d= 200 ;
  //Die LED die ganze Zeit an und aus schalten
  while(1){
  LED_PORT |= (1<<LED_PORTPIN);  //Den Portpin auf high setzen
  wait_ms(c);
  LED_PORT &= ~(1<<LED_PORTPIN);  //Den Portpin auf low setzen
  wait_ms(d);
  c++;
  d--;
  if(c==20){c=0;d=200;}
  }
}

/*  Diese Funktion lässt den Controller
    "ms" Millisekunden warten.
  Die while-Schleife wird so oft durchlaufen,
  wie der Funktion übergeben wurde.
  Bei jedem Duchlauf wir noch 1ms gewartet.
*/
void sleep_ms(uint16_t ms){
  while(ms){
    ms--;
    _delay_ms(1);
  }
}

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Seba wrote:
> Dieser Code soll genau wait_ms(10) soll den IC genau 1ms warten lassen,
                                 ^^                    ^^^

> leider ist das nicht der Fall, kann mir einer sagen wodran es liegt, IC
> löuft mit 20mhz, es ist ein atmega 644.
>
> #define F_CPU 20000000
> #define IRQS_PER_SECOND   10000 /* 500 µs */ //jede microsekunde einen
                            ^^^^^
> auslöser
> #define IRQS_PER_10MS     (IRQS_PER_SECOND / 1000)
                             ^^^^^^^^^^^^^^^^^^^^^^
1/ Passt irgendwie alles nicht.

// 1s sind 1000ms
// 1ms sind 1000s
// => 1s sind 1000x1000 µs also
#define IRQS_PER_SECOND 1000000L

// 1ms hat IRQS_PER_SECOND / 1000 IRQs
// 10ms haben 10x soviel
#define IRQS_PER_10MS ((IRQS_PER_SECOND / 1000) * 10)

2/ Für einen 10ms Timer einen 20 MHz µC bei Prescaler 1 laufen zu 
lassen... ist wie mit einem Ferrari nur im ersten Gang nach Maranello zu 
fahren.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

ADD:

Betreff ("1/10ms Timer") und Code ("Wartet etwa t*10 ms") widersprechen 
sich etwas.

>    OCR1A = 200;

Den Wert für den 1/10ms Timer1 halte ich um den Faktor 10 für zu klein.

Bei 20 MHz Takt und Prescaler 1 hast du 20.000.000 Takte pro Sekunde am 
Timer. Das sind 20.000 Takte pro Millisekunde. Das sind 2.000 Takte pro 
1/10 ms (= pro 100us).

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.