www.mikrocontroller.net

Forum: Compiler & IDEs Problem: Stoppuhr in C (Interrupts und Pull-Ups)


Autor: Robert Knipp (mr_insanity)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich habe ein kleines Problem mit einem Programm. Und zwar habe ich eine 
Stoppuhr gebaut und der Prototyp funktioniert schon. Bei dem habe ich 
die Interrupt Pins mit einem Pull-Down Widerstand versehen und die 
Interrupts auf Rising Edge eingestellt. Nun habe ich das ganze mit 
großen 7-Segment-Anzeigen aufgebaut und dachte mir ich spare mir die 
Pull-Down Widerstände und nutze die internen Pull-Up widerstände. Also 
habe ich die Inetrrupts auf Falling Edge gestellt. Jetzt habe ich das 
Problem dass sich das Teil nicht mehr starten lässt. Ich habe schon viel 
rumprobiert, aber ich habe leider noch zu wenig Erfahrung mit C.

Vielen Dank schonmal für jegliche Hilfe!
//Stoppuhr

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


volatile unsigned char running;
volatile unsigned char zahl[10]; //Array in denen die Portausgaben für die Zahlen 0-9 gespeichert ist
volatile unsigned char sek[4];   //Parameter für zahl
volatile unsigned char i;        //Zählvariable für sek
volatile unsigned int counter;   // <- Zählervariable MUSS Integer sein, da > 255 gezählt wird


//Timer und Interrupt Initialisierung
int interrupt_init(void)
{
  TCNT0 = 0x00;  //Timer0 mit 0 initialisieren (00000000)
  TIMSK = 0x01;  //Timer0 Overflow Interrupt aktivieren (00000001)
  
  MCUCR = 0x02;  //Falling Edge Interrupt an INT0 aktivieren (00000011)
  MCUCSR = 0x00; //Falling Edge Interrupt an INT2 aktivieren (01000000)
  GICR = 0x60;   //Interrupt auf INT0 und INT2 aktivieren (01100000)
  
  return 0;
}
//-----------------------------------


//Konstanten und Portkonfiguration
int const_init(void)
{
                  //Pull-Up an
                  //      |
                  //     \|/
  zahl[0] = 0x7F; //(01111111)
  zahl[1] = 0x0E; //(00001110) 
  zahl[2] = 0xB7; //(10110111)
  zahl[3] = 0x9F; //(10011111)
  zahl[4] = 0xCE; //(11001110)
  zahl[5] = 0xDD; //(11011101)
  zahl[6] = 0xFD; //(11111101)
  zahl[7] = 0x0F; //(00001111)
  zahl[8] = 0xFF; //(11111111)
  zahl[9] = 0xDF; //(11011111)
  
  DDRA = 0xFF; //alle Pins Ausgang (11111111)
  DDRB = 0xFB; //Pin 2 (INT2) Eingang, Rest Ausgang (11111011)
  DDRC = 0xFF; //alle Pins Ausgang (11111111)
  DDRD = 0xFB; //Pin 2 (INT0) Eingang, Rest Ausgang (11111011)
    
  //alle Ports zeigen 0 an
  PORTA = zahl[0];  //Port für 10er Sekunden
  PORTB = zahl[0];  //Port für Sekunden
  PORTC = zahl[0];  //Port für 1/10 Sekunden
  PORTD = zahl[0];  //Port für 1/100 Sekunden
  
  running = 0;
  
  return 0;
}
//-----------------------------------


//Hauptprogramm
int main(void)
{
  interrupt_init();
  const_init();
  
  sei();

  while(1) {
  
    PORTA = zahl[sek[0]];
    PORTB = zahl[sek[1]]; 
    PORTC = zahl[sek[2]];
    PORTD = zahl[sek[3]];
  }
}
//-----------------------------------

//Funktion zum Tastenentprellen <- Ist für Tastendruck gegenüber GND programmiert.
inline unsigned char debounce(volatile unsigned char *port, volatile unsigned char pin)
{
    if (!(*port & (1 << pin)))  //Taste gedrückt --> Pin auf GND gezogen
    {
        /* Pin wurde auf GND-Potential gezogen, 100ms warten   */
        _delay_ms(50);  // max. 262.1 ms / F_CPU in MHz
        _delay_ms(50); 
        if (*port & (1 << pin))  //Taste losgelassen --> Pin wieder über Pull-Up aud 1
        {
            /* Anwender Zeit zum Loslassen des Tasters geben */
            _delay_ms(50);
            _delay_ms(50); 
            return 1;
        }
    }
    return 0;
}
//------------------------------------

//ISR für Timer
ISR(TIMER0_OVF_vect)
{          
  counter++;
  
  //if (counter > 625) //16MHz ohne Prescaler: (16000000/256)/625=100 --> 1/100sek Auflösung
  if (counter > 624)
  {
    sek[0]++;
    counter = 0;
  }
  
  for(i = 0; i < 4; i++)
  {
    if (sek[i] > 9)
    {
      sek[i]=0;
      sek[i+1]++;
    }
    if (sek[3] > 9)
    {
      sek[0] = 0;
      sek[1] = 0;
      sek[2] = 0;
      sek[3] = 0;
    }
  }
}
//-----------------------------------


//ISR für Start/Stop
ISR(INT0_vect)
{
  if (debounce(PIND, PD2))
  {
    if(running == 0)
    {
      TCCR0 = 0x01; //Timer ohne Prescaler (siehe S.80 im Datenblatt) (00000001)  
      running = 1;  //Indikator für "läuft"
    }
    else
    {
      TCCR0 = 0x00; //Timer0 aus (00000000)
      running = 0;  //Indikator für "läuft nicht"
    }
  }
}
//-----------------------------------


//ISR für Reset
ISR(INT2_vect)
{
  TCCR0 = 0x00; //Timer0 deaktivieren (00000000)
  
  //alle Anzeigen auf 0
  PORTA = zahl[0];
  PORTB = zahl[0];
  PORTC = zahl[0];
  PORTD = zahl[0];
  
  running = 0;  //Indikator für "läuft nicht"
}
//-----------------------------------

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

Bewertung
0 lesenswert
nicht lesenswert
Der Aufruf der debounce-Funktion hat in dem Interrupt Handler nichts zu 
suchen. Außerdem ist hoffentlich klar, dass die Taster bei der 
Konfiguration auch andersrum (gegen GND) angeschlossen werden müssen...

Autor: Matt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hast Du an den Tastern evtl. Kondensatoren, die Dir die Pins nach 
Systemstart zunächst auf GND ziehen? Wenn ja, bau vor dem global 
interrupt enable eine Verzögerung ein.

Autor: Marco G. (stan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Robert Knipp wrote:
>
> ...
>   MCUCSR = 0x00; //Falling Edge Interrupt an INT2 aktivieren (01000000)
> 

da passt Hex- und Binärdarstellung nicht zusammen, Absicht?

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

Bewertung
0 lesenswert
nicht lesenswert
Ich frage mich überhaupt, warum Du den Taster mit einem externen 
Interrupt abfragst. Das ist völlig unnötig, v.a. dann, wenn Du sowieso 
einen Timer laufen hast, der einen 10 ms-Takt macht. Taster-Abfrage über 
externe Interrupts ist unsinnig.

Autor: Robert Knipp (mr_insanity)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Außerdem ist hoffentlich klar, dass die Taster bei der
>Konfiguration auch andersrum (gegen GND) angeschlossen werden müssen...

Ist natürlich klar. Wurde auch entsprechend geändert.


>Hast Du an den Tastern evtl. Kondensatoren, die Dir die Pins nach
>Systemstart zunächst auf GND ziehen?

Nein, habe ich nicht.


>>   MCUCSR = 0x00; //Falling Edge Interrupt an INT2 aktivieren (01000000)
>da passt Hex- und Binärdarstellung nicht zusammen, Absicht?

Ups, das war keine Absicht. Habs vergessen in der Binärdarstellung zu 
ändern


>Ich frage mich überhaupt, warum Du den Taster mit einem externen
>Interrupt abfragst.

Wie macht man es denn sonst? Hatte aber bisher auch gut funktioniert.

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

Bewertung
0 lesenswert
nicht lesenswert
Robert Knipp wrote:
>>Ich frage mich überhaupt, warum Du den Taster mit einem externen
>>Interrupt abfragst.
>
> Wie macht man es denn sonst? Hatte aber bisher auch gut funktioniert.
Indem man alle 10-20 ms den betreffenden Pin auf seinen Zustand hin 
abfragt (z.B. mit Hilfe eines Timer-Interrupts, deshalb auch der Hinweis 
auf Deinen ohnehin laufenden 10-ms-Takt) und bei einer Änderung des 
Pinszustandes ein Flag setzt. Dann fallen auch die blödsinnigen 
Wartezeiten mit _delay_XX weg (die innerhalb eines Interrupt Handlers eh 
nix zu suchen haben). Ein Tasterdruck ist kein Ereignis, auf das der µC 
unverzüglich (d.h. innerhalb von wenigen CPU-Takten) reagieren können 
muss. Im Gegenteil: Externe Interrupts sind viel zu schnell dafür, 
weshalb man dann noch viel Aufwand für die Entprellung treiben muss. Bei 
einer zyklischen Abfrage alle paar 10 ms hat man die Wartezeit 
automatisch drin und der µC kann in der Zwischenzeit andere Dinge 
erledigen. Bei Deiner Version verlierst Du sogar bei jedem Tastendruck 
10 Timer-Overflow-Interrupts, weil das System durch die 
debounce-Funktion im Interrupt-Handler für 100 ms komplett blockiert 
ist! Und da der menschliche Bediener gar nicht in der Lage ist, eine 
Taste so kurz und schnell zu betätigen, dass der µC bei einer Abfrage 
z.B. alle 20 oder 30 ms das nicht mitbekommt, genügt das völlig.

Autor: Robert Knipp (mr_insanity)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habes jetzt mal so gemacht. Läuft aber auch nicht. Zeigt genau wie 
vorher nur 0 an.
//Stoppuhr

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


volatile unsigned char running;
volatile unsigned char zahl[10]; //Array in denen die Portausgaben für die Zahlen 0-9 gespeichert ist
volatile unsigned char sek[4];   //Parameter für zahl
volatile unsigned char i;        //Zählvariable für sek
volatile unsigned int counter;// <- Zählervariable MUSS Integer sein, da > 255 gezählt wird


//Timer und Interrupt Initialisierung
int interrupt_init(void)
{
  TCNT0 = 0x00;  //Timer0 mit 0 initialisieren (00000000)
  TIMSK = 0x01;  //Timer0 Overflow Interrupt aktivieren (00000001)
  
  return 0;
}
//-----------------------------------


//Konstanten und Portkonfiguration
int const_init(void)
{
  zahl[0] = 0x7F; //(01111111)
  zahl[1] = 0x0E; //(00001110) 
  zahl[2] = 0xB7; //(10110111)
  zahl[3] = 0x9F; //(10011111)
  zahl[4] = 0xCE; //(11001110)
  zahl[5] = 0xDD; //(11011101)
  zahl[6] = 0xFD; //(11111101)
  zahl[7] = 0x0F; //(00001111)
  zahl[8] = 0xFF; //(11111111)
  zahl[9] = 0xDF; //(11011111)
  
  DDRA = 0xFF; //alle Pins Ausgang (11111111)
  DDRB = 0xFB; //Pin 2 (INT2) Eingang, Rest Ausgang (11111011)
  DDRC = 0xFF; //alle Pins Ausgang (11111111)
  DDRD = 0xFB; //Pin 2 (INT0) Eingang, Rest Ausgang (11111011)
    
  //alle Ports zeigen 0 an
  PORTA = zahl[0];  //Port für 10er Sekunden
  PORTB = zahl[0];  //Port für Sekunden
  PORTC = zahl[0];  //Port für 1/10 Sekunden
  PORTD = zahl[0];  //Port für 1/100 Sekunden
  
  running = 0;
  
  return 0;
}
//-----------------------------------


//Hauptprogramm
int main(void)
{
  interrupt_init();
  const_init();
  
  sei();

  while(1) {
  
    PORTA = zahl[sek[0]];
    PORTB = zahl[sek[1]]; 
    PORTC = zahl[sek[2]];
    PORTD = zahl[sek[3]];
  }
}
//-----------------------------------


//ISR für Timer
ISR(TIMER0_OVF_vect)
{    
  if ( !(PINB & (1<<PINB2)) )
    {
        StartStop();
    }
    
  if ( !(PIND & (1<<PIND2)) )
  {
      Reset();
  }
    
  counter++;
  
  //if (counter > 625) //16MHz ohne Prescaler: (16000000/256)/625=100 --> 1/100sek Auflösung
  if (counter > 624)
  {
    sek[0]++;
    counter = 0;
  }
  
  for(i = 0; i < 4; i++)
  {
    if (sek[i] > 9)
    {
      sek[i]=0;
      sek[i+1]++;
    }
    if (sek[3] > 9)
    {
      sek[0] = 0;
      sek[1] = 0;
      sek[2] = 0;
      sek[3] = 0;
    }
  }
}
//-----------------------------------


inline StartStop(void)
{
  
    if(running == 0)
    {
        TCCR0 = 0x01; //Timer ohne Prescaler (siehe S.80 im Datenblatt) (00000001)  
        running = 1;  //Indikator für "läuft"
    }
    else
    {
        TCCR0 = 0x00; //Timer0 aus (00000000)
        running = 0;  //Indikator für "läuft nicht"
    }
}
//-----------------------------------


inline Reset(void)
{
  TCCR0 = 0x00; //Timer0 deaktivieren (00000000)
  
  //alle Anzeigen auf 0
  PORTA = zahl[0];
  PORTB = zahl[0];
  PORTC = zahl[0];
  PORTD = zahl[0];
  
  running = 0;  //Indikator für "läuft nicht"
}
//-----------------------------------

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

Bewertung
0 lesenswert
nicht lesenswert
Robert Knipp wrote:
>
> //ISR für Timer
> ISR(TIMER0_OVF_vect)
> {
>   if ( !(PINB & (1<<PINB2)) )
>     {
>         StartStop();
>     }
> 
>   if ( !(PIND & (1<<PIND2)) )
>   {
>       Reset();
>   }
> 
Das wird auch nicht so laufen, wie es soll. Du musst schon auf 
Änderungen abfragen (sprich: Du musst Dir den Zustand bei der jeweils 
vorherigen Abfrage merken). Auf die Weise wie oben wird bei einem 
Tastendruck die betreffende Funktion alle 10 ms aufgerufen, bis Du den 
Taster wieder loslässt (was möglicherweise nicht im Sinne des Erfinders 
ist).

Wenn Du nur wissen möchtest, ob ein Taster seit der letzten Abfrage 
gedrückt wurde (und das Wieder-Loslassen Dich nicht interessiert), dann 
genügt z.B. eine einfache UND-Verknüpfung des alten Zustandes mit dem 
Komplement des neuen.

Autor: Robert Knipp (mr_insanity)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also ich raffs nicht mehr. Es will immer noch nicht. So siehts jetzt 
aus:
volatile unsigned int start;
volatile unsigned int rst;

...

ISR(TIMER0_OVF_vect)
{    
  if ( (!(PINB & (1<<PINB2))) & (start == 0) )
    {
        StartStop();
        start = 1;
    }
    if ( (PINB & (1<<PINB2)) & start )
    {
        start = 0;
    }
    
    if ( (!(PIND & (1<<PIND2))) & (rst == 0) )
    {
        Reset();
        rst = 1;
    }
    if ( (PIND & (1<<PIND2)) & rst )
    {
        rst = 0;
    }

...

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

Bewertung
0 lesenswert
nicht lesenswert
Robert Knipp wrote:
>
>   if ( (!(PINB & (1<<PINB2))) & (start == 0) )
>     {
>         StartStop();
>         start = 1;
>     }
> 
Mit einem bitweisen UND an der zweiten Stelle wird das so auch u.U. 
nichts. Da musst Du schon ein logisches UND nehmen (ein "&&"). (Obwohl 
es in diesem Fall sogar funktionieren dürfte, weil beide Seiten 
Wahrheitswerte sind).

Autor: Robert Knipp (mr_insanity)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also langsam bin ich echt am verzweifeln. Habe das '&' durh ein '&&' an 
den besagten Stellen ersetzt und auch noch einen anderen Controller 
ausprobiert. Funktionieren tuts aber immer noch nicht.

Autor: Matthias Lipinsky (lippy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich mache Flankenerkennungen immer (ungefähr) so:
ISR(TIMER0_OVF_vect)
{    
  static _PINBLast;
  if (    (  ( PINB     & (1<<PINB2)) == 0 ) 
       && (  (_PINBLast & (1<<PINB2)) != 0 )  )
    {  // negative Flanke
        StartStop();
        start = 1;
    }
....


 _PINBLast = PINB;
}

Autor: Robert Knipp (mr_insanity)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also ich habe jetzt mal den Timer von Anfang an gestartet und dann läuft 
die Uhr auch erstmal. Was ich merkwürdig finde, ist dass dann Start/Stop 
und Reset genau einmal funktionieren und dann steht die Uhr. Wenn ich 
den Timer nich am Anfang starte lässt sich die Uhr auch nicht wenigstens 
starten.

Autor: Robert Knipp (mr_insanity)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielleicht noch jemand eine Idee?

Autor: Robert Knipp (mr_insanity)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Jetzt habe ich mal alle 4 Anzeigen an die Schaltung angeschlossen 
(hattees vorher nur mit einer ausprobiert), aber nun leuchten nicht alle 
Segmente. Woran kann das denn liegen. Bin ziemlich ratlos. An den 
Segmenten die nicht leuchten sind die Ports auch nicht geschaltet. Wie 
man im Programmtext sieht, sollten aber alle Anzeigen eine 8 anzeigen.
Hier der aktuelle Code und mal der Schalteplan.
//Stoppuhr

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


volatile unsigned char running = 0;
volatile unsigned char zahl[10]; //Array in denen die Portausgaben für die Zahlen 0-9 gespeichert ist
volatile unsigned char sek[4];   //Parameter für zahl
volatile unsigned char i;        //Zählvariable für sek
volatile unsigned int counter;   // <- Zählervariable MUSS Integer sein, da > 255 gezählt wird
volatile unsigned char start = 0;
volatile unsigned char rst = 0;


//Timer und Interrupt Initialisierung
int interrupt_init(void)
{
  TCNT0 = 0x00;  //Timer0 mit 0 initialisieren (00000000)
  TIMSK = 0x01;  //Timer0 Overflow Interrupt aktivieren (00000001)
  
  return 0;
}
//-----------------------------------


//Konstanten und Portkonfiguration
int const_init(void)
{
  zahl[0] = 0x7F; //(01111111)
  zahl[1] = 0x0E; //(00001110) 
  zahl[2] = 0xB7; //(10110111)
  zahl[3] = 0x9F; //(10011111)
  zahl[4] = 0xCE; //(11001110)
  zahl[5] = 0xDD; //(11011101)
  zahl[6] = 0xFD; //(11111101)
  zahl[7] = 0x0F; //(00001111)
  zahl[8] = 0xFF; //(11111111)
  zahl[9] = 0xDF; //(11011111)
  
  DDRA = 0xFF; //alle Pins Ausgang (11111111)
  DDRB = 0xFB; //Pin 2 (INT2) Eingang, Rest Ausgang (11111011)
  DDRC = 0xFF; //alle Pins Ausgang (11111111)
  DDRD = 0xFB; //Pin 2 (INT0) Eingang, Rest Ausgang (11111011)
    
  //alle Ports zeigen 0 an
  PORTA = zahl[8];  //Port für 10er Sekunden
  PORTB = zahl[8];  //Port für Sekunden
  PORTC = zahl[8];  //Port für 1/10 Sekunden
  PORTD = zahl[8];  //Port für 1/100 Sekunden
  
  running = 0;
  
  return 0;
}
//-----------------------------------


//Hauptprogramm
int main(void)
{
  interrupt_init();
  const_init();
  
  sei();
    //TCCR0 = 0x01;

  while(1) {
  
    PORTA = zahl[sek[0]];
    PORTB = zahl[sek[1]]; 
    PORTC = zahl[sek[2]];
    PORTD = zahl[sek[3]];
  }
}
//-----------------------------------

int StartStop(void)
{
  
    if(running == 0)
    {
        TCCR0 = 0x01; //Timer ohne Prescaler (siehe S.80 im Datenblatt) (00000001)  
        running = 1;  //Indikator für "läuft"
    }
    else
    {
        TCCR0 = 0x00; //Timer0 aus (00000000)
        running = 0;  //Indikator für "läuft nicht"
    }
    
    return 0;
}
//-----------------------------------


int Reset(void)
{
  TCCR0 = 0x00; //Timer0 deaktivieren (00000000)
  
  //alle Anzeigen auf 0
  PORTA = zahl[0];
  PORTB = zahl[0];
  PORTC = zahl[0];
  PORTD = zahl[0];
  
  running = 0;  //Indikator für "läuft nicht"
    
    return 0;
}
//-----------------------------------


//ISR für Timer
ISR(TIMER0_OVF_vect)
{    
  if ( (!(PINB & (1<<PINB2))) && (start == 0) )
    {
        StartStop();
        start = 1;
    }
    if ( (PINB & (1<<PINB2)) && start )
    {
        start = 0;
    }
    
    if ( (!(PIND & (1<<PIND2))) && (rst == 0) )
    {
        Reset();
        rst = 1;
    }
    if ( (PIND & (1<<PIND2)) && rst )
    {
        rst = 0;
    }
    
  counter++;
  
  //if (counter > 625) //16MHz ohne Prescaler: (16000000/256)/625=100 --> 1/100sek Auflösung
  if (counter > 624)
  {
    sek[0]++;
    counter = 0;
  }
  
  for(i = 0; i < 4; i++)
  {
    if (sek[i] > 9)
    {
      sek[i]=0;
      sek[i+1]++;
    }
    if (sek[3] > 9)
    {
      sek[0] = 0;
      sek[1] = 0;
      sek[2] = 0;
      sek[3] = 0;
    }
  }
}
//-----------------------------------

Autor: Robert Knipp (mr_insanity)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Und hier das Board.
Vielleicht liegts ja auch daran

Autor: johannes (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Naja, wenn du den Timer stoppst, dann wird natürlich auch kein 
Overflow-Interrupt mehr ausgelöst und somit funktioniert die 
Tastererkennung nicht mehr. Einfach einen zweiten Timer für die 
Tastenabfrage, der immer läuft. Oder die Tasterabfrage in die 
Main-Schleife, dann musst du dich allerdings noch um die Entprellung 
kümmern.

Autor: Robert Knipp (mr_insanity)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
OK, das macht Sinn. Danke für den Tip. Noch ne Idee warum die Ports 
nicht geschaltet werden?

Wie ist das denn bei so einer Stoppuhr überhaupt mit dem 
Tastenentprellen? Wenn die Entprellroutine erst nach 100ms meldet dass 
die Taste gedrückt ist, dann ist es doch gar nicht möglich auf 1/100 
Sekunde genau zu stoppen, oder?

Autor: johannes (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Natürlich kannst du auf 1/100 genau messen und noch viel genauer, 
letztendlich kannst du Genauigkeiten annähernd 1/Prozessor-Takt messen. 
Du kannst ja auf die erste Flanke des Tasters messen und dann musst du 
nur sicherstellen, dass durch das Prellen des Tasters, der Timer nicht 
dauernd ein und aus geschaltet wird, also darf der Timer erst nach 
einigen ms wieder eingeschaltet werden - was aber ja kein Problem 
darstellt, da ein Mensch sowieso nicht im ms-Bereich die Stoppuhr ein- 
und ausschaltet. Willst du schneller messen, dann kommt das Signal 
normalerweise sowieso von einer elektronischen Quelle (z.B. 
Lichtschranke) und die prellen nicht.

> Wie man im Programmtext sieht, sollten aber alle Anzeigen eine 8 anzeigen.
Nein, die Segmente zeigen das an, was beim initalisieren in dem 
sek-Array steht (siehe main-while) - die 8 bekommst du nie zu Gesicht.
Ich würde daher vorher das sek-Array und counter mit 0 initialisieren, 
da man bei C nie weiß was in den Variablen steht und somit ein sek[0]++ 
und counter++ nicht unbedingt das macht, was man erwartet.
(Die Zählvariable i kann man auch direkt in der for-Schleife 
daklarieren, muss nicht global, schon gar nicht volatile sein.)

Autor: Robert Knipp (mr_insanity)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Habe das sek-Array und den counter jetzt mit 0 initialisiert. Nun wird 
am Anfang auch eine 0 (oder was auch immer man will) zuverlässig 
angezeigt. Nur mit dem Start und Stop wills immer noch nicht. So siehts 
jetzt aus:
...

int main(void)
{
  interrupt_init();
  const_init();
  
  sei();

  while(1)
  {
    if ( (!(PINB & (1<<PINB2))) && (start == 0) )
    {
      StartStop();
      start = 1;
      _delay_ms(100);  //Tastenentprellung
    }
    if ( (PINB & (1<<PINB2)) && start )
    {
      start = 0;
    }
    
    if ( (!(PIND & (1<<PIND2))) && (rst == 0) )
    {
      Reset();
      rst = 1;
    }
    if ( (PIND & (1<<PIND2)) && rst )
    {
      rst = 0;
    }
  
    PORTA = zahl[sek[0]];  //Port für 10er Sekunden
    PORTB = zahl[sek[1]];  //Port für Sekunden
    PORTC = zahl[sek[2]];  //Port für 1/10 Sekunden
    PORTD = zahl[sek[3]];  //Port für 1/100 Sekunden
  }
}

...

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
du fragst immer noch nur den Pegel des Eingangs ab. Du darfst aber nur 
auf einen Wechsel des Pegels reagieren, sonst wir ununterbrochen 
StartStop aufgerufen, während du den Taster drückst.

Matthias Lipinsky (lippy) hats dir schon gezeigt, wies geht:
static _PINBLast;
  if (    (  ( PINB     & (1<<PINB2)) == 0 ) 
       && (  (_PINBLast & (1<<PINB2)) != 0 )  )
    {  // negative Flanke
        StartStop();
        start = 1;
    }
....


 _PINBLast = PINB;

Autor: Robert Knipp (mr_insanity)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also eigentlich läuft es jetzt. Um den Flankenwechsel festzustellen 
benutze ich doch die start und die rst Variable.

Autor: Robert Knipp (mr_insanity)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Habs jetz nochmal so geändert wie Matthias Lipinsky (lippy) es 
beschrieben hatte. Geht auch super und der Code ist noch etwas kürzer 
und übersichtlicher.

Vielen Dank nochmal an jeden der so gut weiter geholfen hat!

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.