Sicherer Programmaufbau für wiederkehrende Aufgaben

Gast #2698670
Lesenswert?

Ich möchte einem Programm schreiben, das alle x Sekunden einen Pin 
rücksetzt, dieser Pin kann mit Tastendruck wieder auf 1 gesetzt werden:

Bis jetzt habe ich es wie folgt versucht (mit Codevision):
1
unsigned int i=0; 
2
// Timer 0 overflow interrupt service routine
3
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
4
{
5
// Place your code here
6
    i=i+1; 
7
    if(i == 6250)  
8
    {   
9
    i=0;
10
    PORTA.1=0; 
11
    }
12
}
13

14
void main(void)
15
{
16
..Deklarationsteil
17

18
while (1) {
19
if(TASTER)
20
{
21
    delay_us(300);     
22
         #asm("CLI")    
23

24
    PORTA.1=1;     
25
    i=0;   
26
         #asm("SEI")    
27
}
28
}

Das funktioniert ja soweit (prinzipiell). Doch eigentlich dachte ich 
PORTA.1 müsste nachdem die Taste gedrückt wurde, immer x Sekunden lang 1 
sein um dann auf 0 zu wechseln.
Wenn ich den Taster kurz drücke (aber länger als 300us) geht der Pin 
gleich nach dem Loslassen wieder auf 0 zurück. Warum?
Gast #2698823
Lesenswert?

Ja, die Initialisierung des Timers:
[c]

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 1000,000 kHz
// Mode: 8bit top=FFh
TCCR0A=0x00;
TCCR0B=0x02;
TCNT0H=0x00;
TCNT0L=0x00;
OCR0A=0x00;
OCR0B=0x00;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x02;

#asm("sei")
[c/]
Gast #2700519
Lesenswert?

Vielen Dank für den "volatile-Tipp"!

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
+

Ich wenn mit dem Ozsi nachmesse, komm ich darauf, dass meine 
Interrupt-Routine alle 2ms aufgerufen wird.

Nur wie geht das rechnerisch?

1/(1 000 000 000Hz)*256=0.256us

Wie komme ich auf den Unterschied?
Gast #2700534
Lesenswert?

Ich verwende den internen Oszillatior, wobei

Das Fusebit CKDIV8 einen Hacken hat und SUT_CKSEL auf 
"INTRCOSC_8MHZ_6CK_14CK_64MS" steht.

Zudem habe ich im Code den Clock-Teiler eingestellt:
// Crystal Oscillator division factor: 8
#pragma optsize-
CLKPR=0x80;
CLKPR=0x03;
#ifdef OPTIMIZE_SIZE
#pragma optsize+
#endif

Ich habe gemessen wenn ich einen Ausgang auf 1 schalte und wieder 
zurück, so dauert es 2us, d.h. für jeden Schaltvorgang 1us = 1MHz.
Das wäre ja in Ordnung.
#2700635
Lesenswert?

Martin schrieb:
> Vielen Dank für den "volatile-Tipp"!
>
> //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +
>
> Ich wenn mit dem Ozsi nachmesse, komm ich darauf, dass meine
> Interrupt-Routine alle 2ms aufgerufen wird.
>
> Nur wie geht das rechnerisch?
>
> 1/(1 000 000 000Hz)*256=0.256us

Ich denke nicht, dass dein µC mit 1Ghz getaktet wird.
#2700639
Lesenswert?

Das ...
1
// Timer/Counter 0 initialization
2
// Clock source: System Clock
3
// Clock value: 1000,000 kHz
4
// Mode: 8bit top=FFh
5
TCCR0A=0x00;
6
TCCR0B=0x02;
7
TCNT0H=0x00;
8
TCNT0L=0x00;
9
OCR0A=0x00;
10
OCR0B=0x00;
11
// Timer(s)/Counter(s) Interrupt(s) initialization
12
TIMSK=0x02;
... ist genau das, was ich im Codevision Wizard hasse. Um rauszukriegen, 
was da tatsächlich eingestellt wird, muss man sich erst mal exzessiv 
durchs Datenblatt wühlen um zu entschlüsseln, welche Bits da eigentlich 
in den einzelnen Registern gesetzt werden und um dann weiter zu 
ergründen, was sie bedeuten.
Eines ist ziemlich sicher: das hier
TCCR0B=0x02;
ist kein Vorteiler von 1. Ich bin allerdings auch zu faul rauszusuchen, 
was das jetzt tatsächlich für ein Vorteiler ist.
Gast #2700666
Lesenswert?

Entschuldige, ich habe noch einen wichtigen Teil vergessen hier 
anzugeben.

// Crystal Oscillator division factor: 8
#pragma optsize-
CLKPR=0x80;
CLKPR=0x03;
#ifdef OPTIMIZE_SIZE
#pragma optsize+
#endif


TIMSK=0x02;
Heißt nur, dass der Timer Interrupt aktiviert wird.
#2700670
Lesenswert?

Martin schrieb:

> TIMSK=0x02;
> Heißt nur, dass der Timer Interrupt aktiviert wird.


Das weiß ich selber auch. Aber bei

  TIMSK |= ( 1 << TOIE0 );

kann ich direkt im Code sehen, dass hier das '_T_imer _O_verflow 
_I_nterrupt _E_nable bit vom timer _0_' gesetzt wird. Da steht also 
(mehr oder weniger) im Klartext, das hier der Overflow freigegeben wird. 
Es gibt nämlich im allgemeinen Fall auch noch andere Interrupts als nur 
den Overflow, die von einem Timer ausgelöst werden können.

Ausserdem geht es nicht um die Freigabe des Overflows, sondern darum, 
wie schnell eigentlich der Timer getaktet wird.
Dazu braucht man 2 Angaben
* die Taktfrequenz des µC
* welcher Vorteiler wird benutzt

aus diesen Angaben kann man errechnen, wie schnell der Timer getaktet 
wird und damit, und dem Wissen wie weit er zählt, errechnet sich dann, 
wie groß der zeitliche Abstand zwischen den Overflows ist.

Die µC Taktfrequenz musst du wissen. Welcher Vorteiler eingestellt ist, 
ist hier
TCCR0B=0x02;
codiert.
Und ich hab jetzt keine Lust rauszusuchen, welche CS-Bits in TCCR0B 
stecken und was sie bedeuten. Du bist der Programmierer, das ist dein 
Job.

http://www.mikrocontroller.net/articles/FAQ#Timer
Gast #2700840
Lesenswert?

Eigentlich sagt dir der CV-AVR in Kommentaren wie schnell dein Timer 
läuft,
vorausgesetzt du hast danach im "c" Text nichts verändert.

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 1000,000 kHz
// Mode: 8bit top=FFh


// Clock value: 1000,000 kHz bedeutet, dass der Timer mit 1MHz betrieben 
wird,das weiß der Compiler natürlich nur aus der Angabe des Systemtakts 
und dem Teiler, also 8Mhz/8-Teiler =1MHz.

Natürlich kann der Compiler nicht wissen wie die Fuses eingestellt sind 
und wie schnell der Quarz taktet, also bei 16Mhz Takt wäre der Timer mit 
oberen Einstellungen mit 2MHz gelaufen also 2 mal schneller.
Gast #2702535
Lesenswert?

OK, mein Problem war/ist mit dem "volatile" doch nicht gelöst.

Hier die Kurzfassung:
Vor dem Interrupt = als globale Variable
1
volatile unsigned int zaehler;

Timer-Interrupt:
1
interrupt [TIM0_OVF] void timer0_ovf_isr(void) 
2
{
3
    zaehler++;     
4
    if(zaehler==400)  
5
    {   
6
        zaehler=0;
7
        //Selbsthaltung lösen...
8
    }                        
9
}
1
void main(void)
2
{...
3
#asm("sei")
4
while (1) {
5
    if(TASTER)
6
    {
7
        delay_us(10); 
8
        //Selbsthaltung aktivieren    
9
        #asm("CLI")      
10
        zaehler=0;
11
        #asm("sei")
12
    }
13
}

Warum geht das Gerät meist bei Tastendruck aus?!?!
Gast #2703998
Lesenswert?

> Warum geht das Gerät meist bei Tastendruck aus?!?!

Das kann abartige Ursachen haben wie z.B. ein Kurzschluss durch die 
Tasterbetätigung und dadurch einen Reset (Power, Brownout) deiner ganzen 
Hardware. Denn nach dem Hochfahren des µC aus dem Reset heraus gilt ja 
auch PORTA.1=0;... Um diesen Fall zu Debuggen könntest du einen weiteren 
Portpin zu Beginn von main vor der while() Schleife schalten und mit 
einem Oszi oder einer LED überwachen, ob der µC resettet.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren