www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Ereignis innerhalb einer Zeit


Autor: Heinz der Heizer (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute!

Ich habe vor, mir eine Standheizung für mein Auto mittels ATmega8 und 
einem Handy zu bauen.
Das Handy wird an den PinB-1 angeschlossen.
Sobald jemand zwei mal innerhalb 10 sec. (warte_sec()) auf diesem Handy 
anruft, soll die Heizung (PinB-0) eingeschaltet werden und nach einer 
gewünschten Zeit (warte_minuten()) wieder ausgeschaltet werden.

Ich habe bei dem C-Programm das Problem, dass nicht abgefragt wird, ob 
bereits schon einmal innerhalb der 10 sec. angerufen hat.

Im Anhang findet ihr das gesamte Programm.


Könntet ihr mir helfen?


Vielen Dank!

Autor: Heinz der Heizer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nachtrag:

Der Prescaler war hier in meinem Upload falsch eingestellt. er müsste 
auf (CS00)|(CS02) stehen, damit er auf 1024 kommt. Das hat aber nicht 
zur Lösung beigetragen.

Autor: Matthias Lipinsky (lippy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie wäre es mit einer sauberen Lösung?
Eine Schrittkette:

Schritt1: Heizung aus
Transition1: Handyempfang => Schritt2

Schritt2: Heizung aus
Transition1: Handyempfang => Schritt3
Transition2: Timeout 10sek => Schritt1

Schritt3: Heizung ein
Transition1: Timeout x Minuten => Schritt1


So wird das sauber gelöst.
Unsetzung siehe mein Beitrag (Datum: 23.01.2008 11:36)
Beitrag "Programm bzw. Ablaeufe steuern"

Autor: Marcus W. (blizzi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das Programm compiliert bei mir gar nicht.

Du misshandelst den Timer:
Einen Timeroverflow fragt man gewöhnlich per Interrupt ab und das 
Overflowflag wird nicht per Hand gelöscht sondern automatisch wenn deine 
Interruptroutine ausgeführt wird.

return 2;  <--- return ist keine variable, die du später in
if ((AnrufAnzahl>1) && (return == 2))     abfragen kannst

Ich würde dir raten dich noch einmal in
- Timer und
- Funktionen und Rückgabewerte
einzulesen.

Kannst du den Code so überhaupt compilieren?

Der Vorschlag von Matthias ist langfristig gesehen auch sehr hilfreich, 
wenn dein Projekt mal größer wird blickst du sonst garnicht mehr durch.

Gruß Marcus

Autor: Heinz der Heizer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das Projekt wird nicht größer werden, mehr als die genannte Aufgabe soll 
der AVR garnicht machen...

Ja ich kann den Code so kompilieren. Wie mache ich denn dann den 
Rückgabewert für die Funktion, anstelle des "return 2"?


Wieso muss ich unbedingt mit Interrupts arbeiten? Das wird doch wohl 
auch ohne gehen ?!


Danke

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dein Programm ist ziemlich mies, und ehrlich gesagt hab ich
da jetzt keine Lust, das gross auf Interrupt Betrieb umzustellen.
Das grundelgende Handwerkszeug dazu findest du im GCC_Tutorial
hier.

Aber: Zu deinem generellen Code Stil
Wenn du 'while' meinst, dann schreib auch 'while'.
So was:
  for(;zuende==0;)
ist maximal ein Schuss ins eigene Knie. Und wenn du dich heute
nicht ins eigene Knie schiesst, dann eben morgen.

  while( zuende == 0 )
  {
  }

PS: Die andere 'while'-Schleife in deinem Code sieht mehr als
suspekt aus.
Aber wie gesagt: Besser wäre es, wenn du auf Interrupt umstellst.

Autor: Heinz der Heizer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ja, wie karl-heinz schon sagt, "groß" auf Interrupt-Betrieb 
umstellen....

Mir ist wiederum der Interrupt suspekt. Ich muss zugeben, dass ich sie 
noch nie verwendet habe.

Die for-Schleife ist zwar nicht elegant, aber die Funktion deiner 
genannten while-Schleife müsste sie auch machen oder?

Aber wie würde es denn OHNE Interrupts funktionieren?


Danke

Autor: Björn (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
wie macht man denn eig. dann einen rückgabe-wert, wenn das von mir 
programmierte "return" nicht klappen soll?!


danke

Autor: Heinz der Heizer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
bin übrigens nicht DER Björn mit dem Lichtschrankenzeug. ich bin ein 
anderer^^ nur zum Klarstellen ;)

Autor: Heinz der Heizer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
jetzt mal eine konkrete Frage:

Geht mein Projekt nur mit einem Interrupt-gesteuertem Programmablauf, 
oder würde es auch ohne gehen?

danke

Autor: Stefan Oberpeilsteiner (stefano)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Björn wrote:
> wie macht man denn eig. dann einen rückgabe-wert, wenn das von mir
> programmierte "return" nicht klappen soll?!
>
>
> danke


Du hast eine Funktion mit dem Funktionsprototypen in der Form:

Rueckgabedatentyp Funktionsname(Eingabedatentyp Variablenbezeichnung);


konkretes Beispiel:
int zaehleZweiDazu(int);

Der Funktionscode deiner Funktion:
int zaehleZweiDazu(int eingabewert)
{
 return eingabewert + 2;
}
Nun moechtest du angenommen die Funktion im Hauptprogramm verwenden:
void main(void)
{
 int zahl = 0;   // Eine Variable anlegen und auf 0 setzen
 
 zahl = zaehleZweiDazu(3);  
/* An dieser stelle wird die Funktion mit dem "Parameter" 3 aufgerufen. Die Zahl 3 wird an dieFunktion übergeben. Die Funktion zählt dieser Zahl 2 hinzu und gibt das Ergebniss (5) mit return zurück.*/

// Die Variable Zahl hat jetzt den Wert 5!

}

Autor: Heinz der Heizer (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
ok jetzt von der Funktionsrückgabewert abgesehen, hier mal der 
Code,soweit ich ihn nun habe , könntet ihr mal einen Blick draufwerfen 
ob es so funktionieren würde?



Danke

Autor: Heinz der Heizer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
das Abfragen des Rückgabewerts klappt aber trotzdem nicht:


if ((AnrufAnzahl==2) && (warte_sec()==1))   //wenn Anrufzahl=2 UND die Funktion warte_sec() den Rückgabewert 1 liefert...
      {
        AnrufAnzahl=0;
        PORTB = 0xFF;
        warte_minuten(1);
        PORTB = 0;
      }



Compiler meldet : ../standheizung.c:53: error: too few arguments to 
function `warte_sec'


Danke

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Heinz der Heizer wrote:
> das Abfragen des Rückgabewerts klappt aber trotzdem nicht:

Fehlermeldungen sind dazu da, dass man sie auch liest.
OK. Manchmal sind Fehlermeldungen auch mal verwirrend, aber
nicht in diesem Fall.

Was sagt der Compiler:

> Compiler meldet : ../standheizung.c:53: error: too few arguments to
> function `warte_sec'

Wenn man das mal Wort für Wort übersetzt.
Zu wenige Argumente an Funktion 'warte_sec'

Argumente sind die Dinger, die in eine Funktion hineingehen.
Also schaun wir mal. Hier ist der Aufruf

(warte_sec()==1

An warte_sec wird nichts übergeben.

Wie sieht die Funktion aus?

int warte_sec( int i )

Aha. warte_sec möchte ein Argument haben. Du übergibst aber keines.
Daher: Zuwenig Argumente

Autor: Heinz der Heizer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hier mal der jetzige Code:

das Programm funktioniert natürlich immer noch nicht....
#include <avr/io.h>
#include <util/delay.h>


//----------------------------------------------------------------------------------

short warte_sec(int);

short warte_sec(int i)
{
  TCNT0 = 0;
  TCCR0 |=  (1<<CS00)|(1<<CS02);                // Prescaler auf 1024
  int overflow=0;
  short zuende=0;

  for(;zuende==0;)
  {
    if (TIFR &(1<<TOV0))                   // wenn generell Überlauf, erhöhe Variable "uberlauf" um eins
      {
      while(overflow<(4*i))
      {
          overflow++;
          //TIFR &= ~(1<<TOV0);                  // Flag wieder auf NULL setzen
        }
    zuende=1;
    }
                            // Liefere 1 zurück, wenn gewünschte sec-Zeit verstrichen
  }
return 1;  
}
//----------------------------------------------------------------------------------
void warte_minuten(int y)
{
  int i;
  for(i=0;i<y;i++)
  warte_sec(60);
}
//----------------------------------------------------------------------------------

void main (void)
{
  short AnrufAnzahl=0;
  DDRC = 0xFF;        //PortB als Ausgang
  DDRB = 0x00;        //PortC als Eingang
  PORTC = 0;

  for(;;)
  {  
    if (PINB==0x01)
    {
      AnrufAnzahl++;                //erhöhe beim Anrufen AnrufAnzahl    
      warte_sec(10);                    
      if ((AnrufAnzahl==2) && (warte_sec(2)==1))  //wenn innerhalb der 10 sec. ein weiterer Anruf getätigt wird, dann schalte Heizung ein
      {
        AnrufAnzahl=0;
        PORTC = 0x00;
        warte_minuten(1);
        PORTC = 0xFF;
      }
    }

}
}


Wo liegt noch der Fehler?


Danke

Autor: Richard B. (rbrose)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich würde bei den Kommentaren Anfangen ;-)
  DDRC = 0xFF;        //PortB als Ausgang
  DDRB = 0x00;        //PortC als Eingang

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Warum schaust du dir nicht einfach mal an, wie das mit den
Interrupts funktioniert. Das hat doch so alles keinen
wirklichen Sinn.

Als Anfang:

#include <avr/io.h>
#include <avr/interrupt.h>

vvolatile uint8_t g_HaveOverflow;

ISR( TIMER2_OVF_vect )   // wird aufgerufen, wenn der Timer
                         // den Overflow generiert
{
  g_HaveOverflow = 1;
}

int main()
{
  TCCR0 |=  (1<<CS00)|(1<<CS02);                // Prescaler auf 1024

  TIMSK = ( 1 << TOIE0 );       // Interrupt bei Overflow erlauben

  sei();    // Interrupts generell zulassen  

  while( 1 ) {

    if( g_HaveOverflow == 1) {   // der Timer hat einen Overflow ausgelöst
                                 // als Folge davon wurde die ISR
                                 // aufgerufen. In der ISR wurde die Variable
                                 // g_HaveOverflow auf 1 gesetzt.
      cli();
      g_HaveOverflow = 0;        // Den Overflow wieder scharfstellen
      sei();

      ....
    }
  }
}


Wenn ich jetzt hier keinen Tippfehler gemacht habe, wird in der
Hauptschleife der Code im Bereich .... jedesmal ausgeführt, wenn
der Timer einen Overflow hat. Von dort weg kannst du dann zb.
mitzählen wie oft das passiert und einen Sekundenpuls zu generieren.

Autor: Heinz der Heizer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für den Interrupt-Anfang, aber ist ein Interrupt für den 
Tastendruck nicht wichtiger, als ein Interrupt wenn ein Überlauf 
stattfand?

Schade nur, dass im AVR-GCC-Tutorial nicht steht, dass IN der 
ISR-Funktion die Anweisung steht, die ausgeführt wird, wenn der 
Interrupt ausgelöst wird.

Danke

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Heinz der Heizer wrote:
> Danke für den Interrupt-Anfang, aber ist ein Interrupt für den
> Tastendruck nicht wichtiger, als ein Interrupt wenn ein Überlauf
> stattfand?

Der Witz ist der, dass du in derselben ISR beides machen kannst.

Oder meinst du einen Interrupt der ausgelöst wird, wenn eine
Taste gedrückt wird?
1) ist das sowieso keine gute Idee. Tasten prellen und müssen
   entprellt werden. Das kann man mit der PeDa Methode für
   Tastenentprellen wunderbar in einem Timer Overflow Interrupt
   machen.

2) Wer sagt, dass es nur eine ISR geben kann. Es gibt viele
   verschiedene Interrupts. Für jeden einzelnen kann man eine
   ISR angeben. Es ist nicht ungewöhnlich, wenn es in einem
   Programm mehrere ISR gibt.
   Genau aus dem Grund steht ja auch das TIMER0_OVF_vect bei
      ISR( TIMER0_OVF_vect )
   Dadurch wird diese ISR gekennzeichnet als: Wird aufgerufen
   wenn beim Timer 0 ein Overflow auftritt.

>
> Schade nur, dass im AVR-GCC-Tutorial nicht steht, dass IN der
> ISR-Funktion die Anweisung steht, die ausgeführt wird, wenn der
> Interrupt ausgelöst wird.

Na ja.
Das wäre dann in etwa so, als ob man extra betonen muss, dass
man in C innerhalb von Funktionen auch Anweisungen stehen haben
kann, die dann ausgeführt werden, wenn die Funktion aufgerufen
wird.
Eine ISR ist auch nichts anderes als eine Funktion, mit 3 Unter-
schieden:
* die Syntax der Funktionsdefinition ist ein wenig anders
* Der Aufruf der Funktion erfolgt nicht explizit durch einen
  Funktionsaufruf im Programm, sondern durch die Hardware indem
  irgendein Ereignis (in dem Fall: Timer ist übergelaufen)
  eintritt
* Da es keinen expliziten Funktionsaufruf gibt, kann man auch
  keine Argumente und keinen Returnwert haben. Jegliche Kommunikation
  mit der ISR muss über globale Variablen erfolgen (die dann auch
  volatile sein muessen)

Das wars. Mit diesen Punkten hast du den C-spezifischen Teil der
Interrupts erledigt. Der Rest ist Datenblattstudium: Welches
Bit in welchem Register muss wie gesetzt werden, damit welcher
Interrupt ausgelöst wird.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger wrote:

>
> #include <avr/io.h>
> #include <avr/interrupt.h>
> 
> vvolatile uint8_t g_HaveOverflow;
> 
> ISR( TIMER2_OVF_vect )   // wird aufgerufen, wenn der Timer
>                          // den Overflow generiert

Sorry, Copy&Paste Fehler.
Das muss natürlich
ISR( TIMER0_OVF_vect )

heissen. Du benutzt ja den Timer 0 und nicht den Timer 2

Autor: Heinz der Heizer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo nochmal!


Jetzt habe ich mal was mit Interrupt probiert, funktioniert aber auch 
nicht...-Wie solls auch anders sein .


Hier mal der Code



#include <avr/io.h>
#include <avr/interrupt.h>

volatile uint8_t gTimeCounter=0;

ISR( TIMER2_OVF_vect )   // wird aufgerufen, wenn der Timer
                         // den Overflow generiert
{
   gTimeCounter++;
}

int main()
{

DDRB = 0xFF;
DDRD = 0x00;


  TCCR0 |=  (1<<CS00)|(1<<CS02);                // Prescaler auf 1024

  
  sei();    // Interrupts generell zulassen  

  while( 1 ) {

     while(!(PIND == 0xFE));
       TIMSK = ( 1 << TOIE0 );       // Interrupt bei Overflow erlauben
    
   while( gTimeCounter < 10000)
   {
    if(PIND == 0xFE)
    {
       PORTB = 0x00;
         TIMSK = ~( 1 << TOIE0 );       // Interrupt bei Overflow sperren
         gTimeCounter=0;
     TIMSK = ( 1 << TOIE0 );  
    }
    while( gTimeCounter < 10000)
    {
    PORTB = 0xFF; 
      }
    
   }

    if( gTimeCounter == 1) {   // der Timer hat einen Overflow ausgelöst
                                 // als Folge davon wurde die ISR
                                 // aufgerufen. In der ISR wurde die Variable
                                 // g_HaveOverflow auf 1 gesetzt.
      cli();
      gTimeCounter = 0;        // Den Overflow wieder scharfstellen
      sei();

 
    }
  }
}




Autor: Heinz der Heizer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Habt ihr eine Lösung wie man den Interrupt so setzt, dass während der 10 
sec. der Controller auf erneute Tastendrücke wartet und diese auswertet?

Danke

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Heinz der Heizer wrote:
> Hallo nochmal!
>
>
> Jetzt habe ich mal was mit Interrupt probiert, funktioniert aber auch
> nicht...-Wie solls auch anders sein .

Hast du die Korrektur gesehen?

> [c]
>
>
>
> #include <avr/io.h>
> #include <avr/interrupt.h>
>
> volatile uint8_t gTimeCounter=0;
>
> ISR( TIMER2_OVF_vect )   // wird aufgerufen, wenn der Timer
>                          // den Overflow generiert


Du arbeitest mit Timer 0, nicht Timer 2.
Daher muss die ISR TIMER0_OVF_vect heissen und nicht TIMER2_OVF_vect

Autor: Heinz der Heizer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ja ich habe die Änderung vorgenommen, hat aber auch nix gebracht....

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mit welcher Taktfrequenz läuft dein µC eigentlich?

Ich kann dir leider jetzt dein Programm nicht komplett
fertig machen. Bin selber im Stress.
Aber ich kann dir ein Programm schreiben, welches bei einer 0 am
Pin D0 den Ausgang PB0 auf 1 setzt, eine gewisse Wartezeit abwartet
und danach den PB0 wieder auf 0 setzt.

Damit die Zeit aber einigermassen stimmt, brauch ich die Taktfrequenz
des µC.

Autor: Heinz der Heizer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also meine Taktfrequenz ist bei 1 MHz, da ich damit am leichtesten auf 
eine Sekunde komme.

Echt nett von dir, dass du dich für mich einsetzt, ich erläutere jedoch 
nochmal kurz, was das Programm machen soll.

Wenn ein H-Pegel an PinD0 anliegt, soll das Programm prüfen, ob nach 
einer gewünschten Zeit ein weiterer H-Pegel anliegt. Wenn dies der Fall 
ist, soll PortB0 für eine bestimmte Zeit auf H gesetzt werden, danach 
wieder auf 0 zurückkehren und von vorne beginnen...


Vielen Dank!

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
#include <avr/io.h>
#include <avr/interrupt.h>

volatile uint16_t g_Delays;
volatile uint8_t  g_TimeReached;

ISR( TIMER0_OVF_vect )
{
  if( g_Delays > 0 ) {
    g_Delays--;

    if( g_Delays == 0 )
      g_TimeReached = 1;
}

int main()
{
  DDRD = 0x00;     // PortD auf Eingang
  DDRB = 0xFF;     // PortB auf Ausgang

  TCCR0 |=  (1<<CS00)|(1<<CS02);                // Prescaler auf 1024
  TIMSK = ( 1 << TOIE0 );       // Interrupt bei Overflow erlauben

  sei();    // Interrupts generell zulassen  

  while( 1 ) {

    if( ( PIND & ( 1 << PD0 ) == 0 )    // PinD0 auf 0 ?
      PORTB = 0x01;

      g_TimeReached = 0;
      g_Delays = 300;       // ********
    }

    if( g_TimeReached == 1 ) {
      PORTB = 0x00;
    }
  }
}


Die mit // ******* markierte Zeile muesste angepasst werden.
Keine Anhnung wie lange 300 Overflows auf deinem µC bei einem
Vorteiler von 1024 dauern. Hängt von deiner Taktfrequenz ab.


Der Code war noch nicht im Simulator. Sollte aber ziemlich stimmen.

Autor: Heinz der Heizer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich habe noch paar Sachen wie Klammern-Setzen verbessert:

er meldet nun "undefined reference to 'main' ". Was bedeutet das?

Hier nochmal der "verbesserte" Code:

#include <avr/io.h>
#include <avr/interrupt.h>

volatile uint16_t g_Delays;
volatile uint8_t  g_TimeReached;

ISR( TIMER0_OVF_vect )
{
  if( g_Delays > 0 ) {
    g_Delays--;

    if( g_Delays == 0 )
      g_TimeReached = 1;
}

int main()
{
  DDRD = 0x00;     // PortD auf Eingang
  DDRB = 0xFF;     // PortB auf Ausgang

  TCCR0 |=  (1<<CS00)|(1<<CS02);                // Prescaler auf 1024
  TIMSK = ( 1 << TOIE0 );       // Interrupt bei Overflow erlauben

  sei();              // Interrupts generell zulassen  

  while( 1 ) {

   if( ( PIND & ( 1 << PD0 ) == 0 ))    // PinD0 auf 0 ?
   {
    PORTB = 0x01;

      g_TimeReached = 0;
      g_Delays = 300;       // ********
    }
  }

    if( g_TimeReached == 1 ) {
      PORTB = 0x00;
    }
  }
}



Danke fürs Posten , das ging ja irre schnell!

Autor: Der Leser (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielleicht sind meine Augen nicht mehr die Besten, aber ich glaube zum 
schluß ist eine } zuviel

Autor: Heinz der Heizer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nee, Die klammer ist nicht zuviel, dann meldet er "syntax error at end 
of input"...

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Da ist nicht nur eine Klammer zu viel! Da stimmt alles Mögliche mit 
der Klammerung nicht. In der ISR ist eine offene Klammer, zu der es in 
der ISR keine geschlossene gibt. Dementsprechend ist main für den 
Compiler in die ISR eingebettet, und das haut nicht hin!

Gewöhne Dir generell eine saubere Einrückung an. Dann passiert sowas 
nicht. Also ungefähr so:
int main()
{
    while(1)
    {
        if(bedingung)
        {
            machwas();
            undnochwas();
        }
        else
        {
            machwasanderes();
            undvielleichtnochwasanderes();
        }
    }
}
Grundsätzlich sollten der Übersichtlichkeit halber Klammern, die 
zusammengehören, immer direkt untereinander stehen.

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So, ich hab Dein Programm mal neu formatiert. Jetzt müsste zumindest die 
Klammerei passen.
#include <avr/io.h>
#include <avr/interrupt.h>

volatile uint16_t g_Delays;
volatile uint8_t  g_TimeReached;

ISR( TIMER0_OVF_vect )
{
    if( g_Delays > 0 )
        g_Delays--;

    if( g_Delays == 0 )
        g_TimeReached = 1;
}

int main()
{
    DDRD = 0x00;     // PortD auf Eingang
    DDRB = 0xFF;     // PortB auf Ausgang

    TCCR0 |=  (1<<CS00)|(1<<CS02);                // Prescaler auf 1024
    TIMSK = ( 1 << TOIE0 );       // Interrupt bei Overflow erlauben

    sei();              // Interrupts generell zulassen  

    while( 1 ) 
    {
        if( ( PIND & ( 1 << PD0 ) == 0 ))    // PinD0 auf 0 ?
        {
            PORTB = 0x01;
            g_TimeReached = 0;
            g_Delays = 300;       // ********
        }

        if( g_TimeReached == 1 ) 
            PORTB = 0x00;
    }
}
Und auf die Weise sieht man immer sofort, wenn irgendwo eine Klammer 
zu viel ist! Alle mir bekannten Editoren machen die Einrückungen 
automatisch, so dass man sich da praktisch keine Gedanken machen muss.

Autor: Heinz der Heizer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ok danke erstmal fürs formatieren, ich werds dann vll heut abend noch 
austesten....


gruß

Autor: Heinz der Heizer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ähm ist das nun der Code von Karl-Heinz Buchegger, welcher - wie ich 
geschrieben habe - die gewünschte Zeit wartet und dementsprechend den 
Port-PinD auf H-Pegel setzt?

Oder ist das der:

Karl-Heinz Buchegger wrote: Aber ich kann dir ein Programm schreiben, 
welches bei einer 0 am
Pin D0 den Ausgang PB0 auf 1 setzt, eine gewisse Wartezeit abwartet
und danach den PB0 wieder auf 0 setzt.



Vielen Dank!

Autor: Marcus W. (blizzi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Code ist doch wirklich schön übersichtlich.
Glaubst du nicht du könntest mal versuchen den selber zu analysieren?
Dabei lernt man unheimlich viel, vielleicht brauchst du dann auch nicht 
bei jedem kleinsten Schritt eine Hilfestellung.

Falls du einen der Befehle nicht verstehst und nicht in den Tutorials 
findest kannst du gerne nachfragen.

Autor: Heinz der Heizer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
vielmehr meinte ich eigentl. ob ich den Code von Karl-Heinz so umbauen 
kann, dass er meinen Ansprüchen gerecht wird.

Autor: Marcus W. (blizzi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Heinz der Heizer wrote:
> vielmehr meinte ich eigentl. ob ich den Code von Karl-Heinz so umbauen
> kann, dass er meinen Ansprüchen gerecht wird.

Klar kannst du das.
Der Code zeigt dir ein funktionierendes Beispiel wie man mit einem Timer 
arbeitet. Du brauchst jetzt nur noch deine gewünschte Funktionen in den 
Code einbauen.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Johannes M. wrote:
> Da ist nicht nur eine Klammer zu viel! Da stimmt alles Mögliche mit
> der Klammerung nicht.

Das muss ich auf meine Kappe nehmen. Ich war unter Zeitdruck und
habe den Code direkt im Forumseditor runtergetippt. Da sind
dann wohl einige Klammern auf der Strecke geblieben.

Wenn er sich allerdings an der Einrückung orientiert hätte und
ein bischen analysiert hätte was wohl die Idee hinter so manchem
Codestück ist, dann sollte man das aber schon sehen können, wo
welche Klammer fehlt :-)

Und ja. Der Code ist nicht als Vorstufe zu deiner Lösung zu
sehen sondern als Anschungsbeispiel, wie man mit einem Timer
Zeitsteuerungen machen kann. Wenn du verstanden hast, wie das
funktioniert, ist dein eigentliches Problem nicht mehr so schwer.

Autor: Heinz der Heizer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Leider ist mir das mit den Interrupts noch nicht so klar. Die einzelnen 
Befehle vielleicht schon, aber wie ich das jetzt speziell auf mein 
Problem, bzw Programm, anwenden kann, verstehe ich noch nicht.

Autor: Kanzler Gorkon (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn Du es (bis jetzt) noch nicht verstanden hast, dann schlage ich Dir 
(gut gemeint) vor, dass Du Dich zuerst einmal mit den Sachen 
beschäftigst, die Du verstehst und Dich dann selbstständig und 
schrittweise an Deine Problemstellung annäherst.

Autor: Heinz der Heizer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das würde ich ja gerne, aber ich stehe nunmal vor dieser 
Problemstellung, und komme mit meinem bisherigen Wissensstand nicht 
weiter. Zudem ist mir ja nahegelegt worden, dass hier Interrupts 
unverzichtbar sind, ergo stecke ich momentan in einer Sackgasse :)

Autor: Marcus W. (blizzi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Heinz der Heizer wrote:
> Das würde ich ja gerne, aber ich stehe nunmal vor dieser
> Problemstellung, und komme mit meinem bisherigen Wissensstand nicht
> weiter. Zudem ist mir ja nahegelegt worden, dass hier Interrupts
> unverzichtbar sind, ergo stecke ich momentan in einer Sackgasse :)

Wir sind hier keine Dienstleister, die dir eine funktionierende Software 
schreiben. Sowas kostet in der Regel Geld.
Hier bekommst du nur Tipps und Hilfestellungen, wie du selber deine 
Software schreiben kannst.

> Leider ist mir das mit den Interrupts noch nicht so klar.

Was ist unklar?
Das die Interruptroutine jedesmal aufgerufen wird, wenn der Interrupt 
ausgelöst wird is doch klar oder? Und in deinem Fall benutzt du den 
Timer-Overflow Interrupt, der wird also jedes mal aufgerufen, wenn der 
Timer überläuft.

> aber wie ich das jetzt speziell auf mein
> Problem, bzw Programm, anwenden kann, verstehe ich noch nicht.

Tja, Programmieren muss man erlernen. Dazu braucht man Erfahrung. Das 
Handwerkszeug haben wir dir erklärt. Du weißt jetzt wie du eine LED per 
Knopfdruck eine bestimmte Zeit lang leuchten lassen kannst.
Wie man jetzt die LED erst beim zweiten Knopfdruck leuchten lassen kann 
ist jetzt deine Aufgabe.

Vom Prinzip is der Ablauf so:

Signal kommt an (High), dann wartest du bis es wieder auf Low geht.
Im Anschluss startest du einen Timer und lässt ihn z.B. 10 Sekunden 
laufen.
Damit schaltest du deine Schaltung quasi für 10 Sekunden scharf.
Wenn dann jemand anruft bevor der Timer überläuft wird die Heizung 
angeschalten. (Ein Timer steuert dann im Anschluss wie lange die Heizung 
anbleiben soll)
Läuft der Timer vorher über "entschärft" er die Schaltung wieder und die 
Heizung geht nicht an.

Auch wenn du jetzt vor dieser Problemstellung stehst:
Wenn du es nicht hinbekommst muss deine Problemstellung eben warten und 
du musst mit kleineren Sachen anfangen. Programmieren lernt man nicht 
von heute auf morgen. Dein Problem ist wirklich Programmiertechnisch, 
das hat nichts mit Elektronik oder Mikrocontrollern zu tun.
Die Alternative ist natürlich sich jemand zu suchen der dir für nen 
Kasten Bier die Software schreibt, das is vielleicht ne Sache von 15 
Minuten.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das nächste Problem, um das du dich kümmern musst ist die Erkennung
des Anrufsignals. Es reicht nicht, wenn du nur die Information hast,
dass der Eingang eine 0 aufweist. Denn diese 0 wird ein paar
Millisekunden da stehen. Du musst die Flanke erkennen, wann
das Signal den Pegel wechselt!

Und von dort weg ist es dann eigentlich einfach.
Kommt eine Flanke herein gibt es 3 Möglichkeiten

* Läuft die 10 Sekunden Zeitmessung bereits und ist die noch
  nicht abgelaufen, dann war das die zweite Flanke
  -> der Ausgang wird geschaltet und eine zweite Zeitmessung
     startet nach deren Ablauf der Ausgang wieder in seine
     Ruheposition zurückkommt
     Die 10 Sekunden Zeitmessung wird abgestellt

* Läuft die 10 Sekunden Zeitmessung noch nicht und läuft auch
  die zweite Zeitmessung noch nicht, dann war das die erste Flanke
  -> die 10 Sekunden Zeitmessung wird gestartet

* Läuft die 10 Sekunden Zeitmessung noch nicht, wohl aber die
  zweite Zeitmessung, so liegt der Fall vor, dass während der
  Heizperiode ein weiterer Anruf kam. Du musst entscheiden
  was in diesem Fall passieren soll. Zb. Könnte man die Heizung
  dann vorzeitig abschalten
  -> Ausgang in den Ruheszustand zurückschalten
     zweite Zeitmessung abschalten.

Zusätzlich gibt es noch die Fälle

* die 10 Sekunden laufen ab, ohne dass das Eintreffen einer
  zweiten Flanke die Heizung eingeschaltet hat.
  -> Es muss nichts weiter gemacht werden. Die 10 Sekunden
     Zeitmessung schaltet sich ab

* die zweite Zeitmessung, die die Heizperiode steuert läuft ab
  -> der Heizausgang wird wieder in seinen Ruhezustand zurückgesetzt.
     die zweite Zeitmessung schaltet sich ab.


Du musst anfangen in Form von "Ereignis tritt ein" zu denken und
nicht in Form von "erst mach dies, dann mach das"

Autor: Heinz der Heizer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also, jetzt habe ich den Code mal soweit es ging auf meine Bedürfnisse 
angepasst:

Folgendes macht das Programm (im Simulator) bisher, so wie es sein soll: 
Wenn ich PIND0 zweimal drücke, dann kriegt PortB H-Pegel. Ansonsten 
nicht.
Außerdem schaltet er dann den PortB wieder nach einer gewissen Zeit aus. 
-Soweit sogut!

Nun habe ich noch das Problem, dass ich nicht weiß, ob er mit meinem 
Code die Zeit berücksichtigt, in der die Taste mind. 2x gedrückt werden 
soll.

Außerdem weiß ich nicht, wie ich "AnrufAnzahl" auf NULL setzen kann, 
damit nach dem Ausschalten des PortB der Mikrocontroller auf erneute 
Tastendrücke wartet.
Bisher muss ich nach Ausschalten von PortB lediglich EINMAL PinD 
betätigen, damit PortB wieder aktiv wird.
#include <avr/io.h>
#include <avr/interrupt.h>

volatile uint16_t g_Delays;
volatile uint8_t  g_TimeReached;


ISR( TIMER0_OVF_vect )
{
    if( g_Delays > 0 )
        g_Delays--;

    if( g_Delays == 0 )
  {
        g_TimeReached = 1;
  }
}

int main()
{
    DDRD = 0x00;     // PortD auf Eingang
    DDRB = 0xFF;     // PortB auf Ausgang

  int AnrufAnzahl=0;

  
    TCCR0 |=  (1<<CS00);                // Prescaler auf 1024
    TIMSK = ( 1 << TOIE0 );       // Interrupt bei Overflow erlauben

    sei();              // Interrupts generell zulassen  

    while( 1 ) 
    {
        if( (AnrufAnzahl == 0) &&( PIND & ( 1 << PD0 ) == 1 ))    // PinD0 auf 0 ?
        {
      AnrufAnzahl = 1;
      PIND = 0;
    }
        if ((AnrufAnzahl == 1) && ( PIND & ( 1 << PD0 ) == 1 ))
    {
      AnrufAnzahl=2;
            g_TimeReached = 0;
            g_Delays = 30;       // ********
        }  
    if (AnrufAnzahl == 2)
    {  
      PORTB = 0xFF;
      g_Delays = 20;
      //g_Delays--;
      AnrufAnzahl =0;
    }    
    

        if( g_TimeReached == 1 ) 
            PORTB = 0x00;
      
    }
}


Vielen Dank!

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ach was solls. Mein Service Techniker in Hongkong ist mit dem
Programmupdate glücklich und ich hab ein bischen Zeit.

Aber versprich mir, dass du den Code studierst und nicht einfach
nur in einen µC brennst und gut ists.

Der Code überwacht den Pin PD0.
Kommt dort ein 0 Signal an, dann beginnt eine Torzeit von 10
Sekunden (einstellbar mit TIME_1) zu laufen. Gleichzeitig wird
eine Kontrollled eingeschaltet um anzuzeigen, dass die Schaltung
scharf ist und auf den zweiten Puls wartet. Kommt innerhalb
dieser Zeit ein zweites 0 Signal, dann wird die Kontrolled wieder
abgeschaltet, die Heizung eingeschaltet und die Heizzeit
(einstellbar mit TIME_2) beginnt.
Nach Ablauf der Heizzeit wird die Heizung wieder abgeschaltet.
Kommt innerhalb der Heizzeit ein weiterer Impuls, so wird die
Heizung vorzeitig abgeschaltet.

PORTB:    Heizung         am Pin HEATER_PIN
          Kontrolled      am Pin LED_PIN

PORTD:    Signaleingang   am Pin INPUT_PIN

Programm ist auf einem Mega16 getestet. Die Makros LED_ON, LED_OFF,
HEATER_ON, HEATER_OFF musst du anpassen, je nachdem ob ein gesetztes
Bit die Led/Heizung ein oder aus schaltet. Ich habs aber einfach
gemacht den jeweiligen Zustand zu verstehen. Im Moment sind alle
Ausgänge so benutzt, dass eine 0 die jeweilige Funktionalität
(Heizung, Led) einschaltet.

Ob du den Pullup am PortD brauchst, musst du selbst eintscheiden.
Im Moment ist der auskommentiert.
#include <avr/io.h>
#include <avr/interrupt.h>

// Taktfrequenz des Controllers
#define F_CPU  1000000

// wo sind Heizelement und Kontrollampe am Port B angeschlossen
#define HEATER_PIN   PB0
#define LED_PIN      PB1

// an welchem Eingang am Port D kommt das Signal herein
#define INPUT_PIN    PD0

#define TIME_1   10   /* 10 Sekunden - Torzeit  */
#define TIME_2   60   /* 60 Sekunden - Heizzeit */

#define WAIT_10    F_CPU / 1024 * TIME_1 / 256
#define WAIT_HEAT  F_CPU / 1024 * TIME_2 / 256

#define SET_BIT(p,b)    p |= ( 1 << b )
#define CLR_BIT(p,b)    p &= ~( 1 << b )

#define LED_ON     CLR_BIT( PORTB, LED_PIN )
#define LED_OFF    SET_BIT( PORTB, LED_PIN )
#define HEATER_ON  CLR_BIT( PORTB, HEATER_PIN )
#define HEATER_OFF SET_BIT( PORTB, HEATER_PIN )

volatile uint16_t g_10SecTimer;      // verbleibende Wartezeit - 10 Sekunden
volatile uint16_t g_HeatTimer;       // verbleibende Wartezeit - Heizzeit

volatile uint8_t  PrevInput;         // der vorhergehende Zustand des Input Pins
volatile uint8_t  Signal;            // 1 wenn ein Anruf erkannt wurde

ISR( TIMER0_OVF_vect )
{
  if( g_10SecTimer > 0 )
    g_10SecTimer--;

  if( g_HeatTimer > 0 )
    g_HeatTimer--;

  // kann am Eingangspin eine Flanke 1->0 erkannt werden?
  uint8_t Input = PIND & ( 1 << INPUT_PIN );
  if( PrevInput != Input && Input == 0 )
    Signal = 1;
  PrevInput = Input;
}

int main()
{
  DDRB = ( 1 << HEATER_PIN ) | ( 1 << LED_PIN );

  DDRD = 0x00;
//  PORTD = ( 1 << INPUT_PIN );   // ev. Pullup einschalten

  TCCR0 = ( 1 << CS02 ) | ( 1 << CS00 );
  TIMSK = ( 1 << TOIE0 );

  // zur Zeit läuft kein Timer
  g_10SecTimer = 0;
  g_HeatTimer = 0;
 
  PrevInput = 1;
  Signal = 0;

  LED_OFF;
  HEATER_OFF;

  sei();

  while( 1 ) {

    if( Signal ) {                   // Am Eingang ist ein Signal gekommen
      cli();

      Signal = 0;

      if( g_10SecTimer > 0 ) {       // läuft der 10 Sekunden Timer noch?
        g_10SecTimer = 0;            // 10 Sekunden abschalten

        HEATER_ON;                   // Heizung ein
        g_HeatTimer = WAIT_HEAT;     // Heizzeit beginnt
      }

      else {                         // 10 Sekunden laufen nicht

        if( g_HeatTimer > 0 ) {      // läuft die Heizung bereits?
          HEATER_OFF;                // Wenn ja, dann vorzeitig abschalten
          g_HeatTimer = 0;           // und Timer stoppen
        }

        else {
          g_10SecTimer = WAIT_10;    // Starte das 10 Sekunden Intervall
          LED_ON;                    // Kontrolllampe an
        }
      }

      sei();
    }

    if( g_HeatTimer == 0 )           // wenn die Heizzeit nicht läuft
      HEATER_OFF;                    // die Heizung auf jeden Fall abschalten

    if( g_10SecTimer == 0 )          // wenn die Torzeit nicht läuft
      LED_OFF;                       // die Kontrolllampe auf jeden Fall abschalten
  }
}

Autor: Heinz der Heizer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ok. Vielen Dank!

Echt nett von dir, dass du dir so eine Arbeit machst. Es hätte auch eine 
Verbesserung meines bereits geschriebenen Codes gereicht.

Ich versuche deinen Code zu verstehen.


Danke!

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.