Forum: Mikrocontroller und Digitale Elektronik interrupt nutzen


von Jürgen V. (derunglaubliche)


Lesenswert?

Hallo,

ich bin ziemlich neu in dem Thema und wollte eine 7 Segment anzeige dazu 
bringen, von 0 hochzuzählen mit einer Pause von jeweils 1000ms zwischen 
dem Wechsel.
Jedoch will ich keine Delay Funktion nutzen, sondern die Interrupts 
nutzen.
Ich habe jetzt einen Code geschrieben, jedoch funktioniert dieser nicht.

Die Bitmasken sind aufjedenfall richtig. Beim ausführen sehe ich 
garnichts, weshalb ich denke dass meine Interrupt Routine garnicht 
aufgerufen wird.

Edit: Es handelt sich um einen AtMega328PB
1
#include <avr/interrupt.h>
2
#include <avr/io.h> 
3
4
5
6
uint8_t PC_Bitmaske[10] = {0b00111,0b01111,0b00111,0b00111,0b01111,0b10111,0b10111,0b00111,0b00111,0b00111};
7
uint8_t PD_Bitmaske[10] = {0b11000011,0b11111011,0b10100111,0b10110011,0b10011011,0b10010011,0b10000011,0b11011011,0b10000011,0b10010011};
8
9
  
10
uint8_t timer_counter = 0;
11
uint8_t number = 0;
12
13
14
ISR(TIMER0_OVF_vect) 
15
  {
16
  
17
  number++;  
18
  
19
  while(timer_counter < 100){
20
    
21
    timer_counter++;
22
    
23
  }
24
    
25
  PORTC = PC_Bitmaske[number];    // 7 Segmentanzeige des Zählwerts (Ziffer) 
26
  PORTD = PD_Bitmaske[number];  
27
    
28
  if(number == 9){    // Rotierenden Ziffernwert für Anzeige 0..9 iterieren (inkrementiern, prüfen, bei Überlauf zurücksetzen)
29
  number = -1;
30
  }
31
    
32
  }
33
34
35
int main(void)
36
{
37
  // 7 Segment Anzeige initialisieren (Alle LEDs aus, restliche Bits passend für Input und Tristate)
38
  DDRC = 0x18;
39
  PORTC = 0xFF;
40
  DDRD = 0x7C;
41
  PORTD = 0x7C; 
42
  
43
  // Timer/Counter 0 initialisieren: CTC Modus, Prescaler 1/1024, Interrupt-Intervall 10 ms
44
  TCCR0A = (1<<WGM01); 
45
  TCCR0B =    (1<<CS02)|(1<<CS00) ; 
46
  OCR0A = 156;
47
  TIMSK0 = 0b00000010; 
48
  //Interrupts global freigeben
49
  sei();
50
  
51
  
52
    while (1) 
53
    {
54
  
55
    }

von Christoph db1uq K. (christoph_kessler)


Lesenswert?

avr steht ja wenigstens da, ist das ein Arduino?

von Jürgen V. (derunglaubliche)


Lesenswert?

Wie rufe ich denn genau eine ISR Funktion in C auf ? Ich dachte die 
Routine würde mit dem sei() aufgerufen werden.

von Jürgen V. (derunglaubliche)


Lesenswert?

Christoph db1uq K. schrieb:
> avr steht ja wenigstens da, ist das ein Arduino?

nein das ist ein AtMega328PB

von Hannes (Gast)


Lesenswert?

1
while(timer_counter < 100){
2
    
3
    timer_counter++;
4
    
5
  }

Was soll das? Das zählt im ersten Interrupt einmal bis 100 und verweilt 
dann da fröhlich. Wenn du die 10ms zählen willst um auf 1s zu kommen, 
solltest du das anders machen.

Und du benutzt einen Capturewert und rufst den Overflowvector auf.

von Hannes (Gast)


Lesenswert?

1
#include <avr/interrupt.h>
2
#include <avr/io.h> 
3
4
5
6
uint8_t PC_Bitmaske[10] = {0b00111,0b01111,0b00111,0b00111,0b01111,0b10111,0b10111,0b00111,0b00111,0b00111};
7
uint8_t PD_Bitmaske[10] = {0b11000011,0b11111011,0b10100111,0b10110011,0b10011011,0b10010011,0b10000011,0b11011011,0b10000011,0b10010011};
8
9
  
10
volatile uint8_t timer_counter = 0;
11
12
13
ISR(TIMER0_COMPA_vect){
14
  uint8_t number;
15
  timer_counter += 10; //10ms vergangen
16
  if(timer_counter == 10000) //nach 10s
17
    timer_counter = 0;
18
    
19
  number = (timer_counter - timer_counter%1000)/1000;  
20
  PORTC = PC_Bitmaske[number];    // 7 Segmentanzeige des Zählwerts (Ziffer) 
21
  PORTD = PD_Bitmaske[number];  
22
  
23
 }
24
25
26
int main(){
27
  // 7 Segment Anzeige initialisieren (Alle LEDs aus, restliche Bits passend für Input und Tristate)
28
  DDRC = 0x18;
29
    PORTC = 0xFF;
30
   DDRD = 0x7C;
31
    PORTD = 0x7C; 
32
  
33
    // Timer/Counter 0 initialisieren: CTC Modus, Prescaler 1/1024, Interrupt-Intervall 10 ms
34
    TCCR0A = (1<<WGM01); 
35
    TCCR0B =    (1<<CS02)|(1<<CS00) ; 
36
    OCR0A = 156;
37
    TIMSK0 = 0b00000010; 
38
    //Interrupts global freigeben
39
    sei();
40
 
41
    while (1) 
42
    {
43
  
44
    }
45
46
47
}



probier mal das

von Falk B. (falk)


Angehängte Dateien:

Lesenswert?

Jürgen V. schrieb:
> Hallo,
>
> ich bin ziemlich neu in dem Thema und wollte eine 7 Segment anzeige dazu
> bringen, von 0 hochzuzählen mit einer Pause von jeweils 1000ms zwischen
> dem Wechsel.
> Jedoch will ich keine Delay Funktion nutzen, sondern die Interrupts
> nutzen.

Prnzipiell richtig.

> Ich habe jetzt einen Code geschrieben, jedoch funktioniert dieser nicht.

Das oft der Fall ;-)

> Die Bitmasken sind aufjedenfall richtig. Beim ausführen sehe ich
> garnichts, weshalb ich denke dass meine Interrupt Routine garnicht
> aufgerufen wird.

Du hast einige grundlegende Dinge beim Thema Interrupt noch nicht 
verstanden. Lies den Artikel Interrput.
1
 while(timer_counter < 100){
2
    
3
    timer_counter++;
4
    
5
  }

Sowas ist sinnlos und hat in einer ISR nix zu suchen.

Das Multiplexen bzw. die Anzeige der Zahl macht man sinnvollerweise in 
der ISR, den Rest außerhalb. Für das einfache Beispiel kann man aber 
auch alles in der ISR machen. Siehe Anhang.

Dein wesentlicher Fehler ist der falsche Interrupt. Im CTC-Modus wird 
der Overflow praktisch NIE ausgelöst. Bei CTC muss man den COMPA nutzen.

von Falk B. (falk)


Lesenswert?

Hallo Admins, bitte mal die Diskussion ins richtige Unterforum 
verschieben. Danke.

von Hannes (Gast)


Lesenswert?

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

volatile uint8_t timer_counter = 0;

ISR(TIMER0_COMPA_vect){
  timer_counter += 10; //10ms vergangen
  if(timer_counter == 10000) //nach 10s
    timer_counter = 0;
 }

int main(){

  uint8_t PC_Bitmaske[10] = 
{0b00111,0b01111,0b00111,0b00111,0b01111,0b10111,0b10111,0b00111,0b00111 
,0b00111};
  uint8_t PD_Bitmaske[10] = 
{0b11000011,0b11111011,0b10100111,0b10110011,0b10011011,0b10010011,0b100 
00011,0b11011011,0b10000011,0b10010011};
    // 7 Segment Anzeige initialisieren (Alle LEDs aus, restliche Bits 
passend für Input und Tristate)
    DDRC = 0x18;
  PORTC = 0xFF;
  DDRD = 0x7C;
  PORTD = 0x7C;

    // Timer/Counter 0 initialisieren: CTC Modus, Prescaler 1/1024, 
Interrupt-Intervall 10 ms
    TCCR0A = (1<<WGM01);
    TCCR0B =    (1<<CS02)|(1<<CS00) ;
    OCR0A = 156;
    TIMSK0 = 0b00000010;
    //Interrupts global freigeben
    sei();

    while (1)
    {
  uint8_t number;
  number = (timer_counter - timer_counter%1000)/1000;
    PORTC = PC_Bitmaske[number];    // 7 Segmentanzeige des Zählwerts 
(Ziffer)
    PORTD = PD_Bitmaske[number];
    }
}


So ist es noch n ticken schöner, sofern die Anzeige asynchron umschalten 
darf.

von Falk B. (falk)


Lesenswert?

Hannes schrieb:
> So ist es noch n ticken schöner, sofern die Anzeige asynchron umschalten
> darf.

Sicher?

volatile uint8_t timer_counter = 0;
if(timer_counter == 10000) //nach 10s

von Jürgen V. (derunglaubliche)


Lesenswert?

Ich habe mir das Thema noch einmal neu angeschaut mit dem Interrupt und 
gemerkt dass ich die Funktion nicht richtig verstanden habe.
Jetzt habe ich das Thema verstanden und meinen Code verbessert. Jetzt 
klappt es auch mit dem hochzählen!
1
ISR(TIMER0_COMPA_vect)
2
  {
3
        
4
    if(timer_counter<100)
5
      {
6
        timer_counter++;
7
      } 
8
    
9
    else
10
    {
11
      timer_counter = 0;
12
      
13
      number++;  
14
      
15
      if(number == 10)
16
      {    
17
        number = 0;
18
      }
19
    }
20
    
21
  PORTC = PC_Bitmaske[number];    // 7 Segmentanzeige des Zählwerts (Ziffer) 
22
  PORTD = PD_Bitmaske[number];  
23
    
24
  
25
  }

als nächstes versuche ich mal ein numpad zu benutzen. wünscht mir glück 
:D

von Jürgen V. (derunglaubliche)


Lesenswert?

Ich will nun den PB2 Pin von meinem Knopf auslesen um eine Nummer 
anzeigen zu lassen. Wie lasse ich den Zustand von einem Pin abfragen. 
Ich habe einmal das unten und einmal mit PINB versucht aber beide male 
wird auch ohne den gedrückten Knopf die 1 angezeigt.


if(PORTB & (1<<3)){
        number = 1;
    }

von Purzel H. (hacky)


Lesenswert?

Ja, ein PORT wird auch nicht als PORT ausgelesen, sondern als PIN,
PIN ist der input buffer,
PORT ist der output buffer.

if ((PINB & 0x02)==0x02) {.. mach ..}

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.