Forum: Compiler & IDEs Signal auswerten, Probleme mit CTC


von Mike (Gast)


Lesenswert?

Hey leute.

Ich habe folgendes Problem.

Ich will ein Signal auswerten, das wie folgt aufgebaut ist.

Ein Bit ist jeweils 4ms lang.
Die Information ist 12 Bits lang.
Zwischen den Bits ist immer eine Pause von mehr als 14*4ms.

Ich lese das Signal mit einem Optokoppler später ein, von daher sind die 
Signale in meinem Code verdreht. Das heißt, ein High Pegel kommt als Low 
Pegel am µC an.

Ich bin so vorgegangen:

Verwendet habe ich einen Atmega8535

Ich habe den Timer 1 in den CTC Modus versetzt (ich denke mal nicht 
richtig, ich komm mit dem Datenblatt nicht zurecht...)
Prescaler auf 8 und er soll bei 124 einen Interupt machen.

Dort sehe ich dann nach, wenn 14 bits nacheinenader auf High sind (am µC 
also Low), dann wurde die Pause erkannt. Fällt nun der Wert auf Low, 
dann kanns losgehen mim einscannen.
So schreibt er mir alle 4ms einen bit.

Das Problem ist, das der Timer sich wohl nur ein einziges mal aufruft.
Wo könnte das Problem liegen?

Hier ist mal der Code
1
#include <stdlib.h>
2
#include <avr/pgmspace.h>
3
#include <lcd.h>
4
#include <avr/io.h>
5
#include <util/delay.h>
6
#include <stdint.h>
7
#include <avr/interrupt.h>
8
9
//Wählt wie oft auf high ohne unterbrechung
10
uint8_t count = 0;
11
//Steht auf 1, wenn mehr als 14 mal auf high (also 14*4ms vergangen sind, also eine Pause)
12
uint8_t watch = 0;
13
//das ist mein wert der verändert wird und ausgelesen werden soll, 12bit lang
14
uint16_t wert = 0b000000000000;
15
//bit muss ich rückwärts reinschreiben, das ist die position
16
uint8_t bit = 12;
17
uint8_t lcd = 0;
18
uint16_t wertbuffer;
19
20
///ACHTUNG  ACHTUNG ACHTUNG ACHTUNG ACHTUNG
21
///Pin auf Low heißt 1 und Pin auf High heißt 0 !!!!
22
///ACHTUNG  ACHTUNG ACHTUNG ACHTUNG ACHTUNG
23
24
ISR(TIMER1_COMPA_vect)
25
{
26
    //Wenn der counter unter 8 sein sollte, und ein low signal auftritt
27
    //Wird der counter auf 0 zurück gesetzt, weil da noch irgendwo ein
28
    //Signal ist, also keine pause
29
    if ((count < 15) && (PIND & (1<<PIND0))){count = 0;}
30
31
    //Wenn ein high signal da ist dann zählt der count eins hoch
32
    if (!(PIND & (1<<PIND0))){count++;}
33
34
    //Wenn der counter jetz größer ist als 7, war wohl ne pause.
35
    //Wenn zusätzlich noch ne flanke kommt, dann fängt das signal an
36
    //Das heißt watch ist auf 1, damit er unten bit schreibt
37
    if ((count > 14) && (PIND & (1<<PIND0))){watch = 1;}
38
39
    //Wenn watch auf high, ließt er den wert ein
40
    if (watch == 1){
41
        lcd = 0;
42
43
        //Wenn ein High kommt, dann soll er ne 1 schreiben an der stelle des Bits
44
        if (!(PIND & (1<<PIND0))){
45
            wert |= (1<<bit);
46
        }
47
    }
48
        //Springt jedesmal eine Bitposition zurück
49
         bit--;
50
51
         //Wenn das 0te Bit geschrieben ist, wird bit auf 12 zurückkgesetzt
52
         //watch auf 0, damit keine werte geschrieben werden
53
         //Wertbuffer übernimmt den wert, damit er immer aktuell abrufbar ist
54
         //wert wird auf 0 zurückgesetzt damit man ihn neu mit bits befüllen kann
55
         if (bit == 0){
56
             bit = 12;
57
             watch = 0;
58
             wertbuffer = wert;
59
             wert = 0x00;
60
             lcd = 1;
61
             }
62
63
64
65
66
}
67
68
int main(void)
69
{
70
71
72
    DDRD = 0x00;
73
    PIND = 0xff;
74
75
76
    TCCR1B = (1<<CS11) | (1<<WGM13) | (1<<WGM12) ;
77
      
78
    OCR1A = 124;
79
    TIMSK = (1<<OCIE1A);
80
    char buffer[14];
81
82
    lcd_init(LCD_DISP_ON);
83
    lcd_clrscr();
84
    sei();
85
86
  while(1)
87
  {
88
      //als Binärzahl ins Array schreiben
89
      itoa (wertebuffer, buffer, 2);
90
91
      if (lcd == 1)
92
      {
93
          lcd_clrscr();
94
          lcd_puts(buffer);
95
      }
96
97
98
  }
99
}

von Mike (Gast)


Lesenswert?

Ach ja, es geht um dieses Signal:

Beitrag "Signal auswerten"

von derderauchproblemehat (Gast)


Lesenswert?

Mike schrieb:
> TCCR1B = (1<<CS11) | (1<<WGM13) | (1<<WGM12) ;

du initialisiert als Vergleichsregistert ICR1, demnach vermute ich, dass 
bei dir im moment kein Compare Match auftritt
versuche es mal so
1
TCCR1B = (1<<CS11) | (1<<WGM12);
so wird OCR1A initialisiert
Prescaler 8 ist so korrekt

von Mike (Gast)


Lesenswert?

Mir fällt grad auf dass das vieleicht nicht das einzige Problem ist.

Ich hab vergessen dass es einen Overflow geben wird, wenn das Signal zu 
lange auf high ist. Das muss ich vorher zurücksetzen.

Und zweitens muss ich nachdem watch auf 1 steht, den Timer 
zurücksetzten, so das er von neuem anfängt zu zählen. Wie mache ich das?
Mit OCR1A = 124; setze ich ja fest wann der Overflow passiert, aber 
womit setze ich den Zähler auf 0 zurück?

von derderauchproblemehat (Gast)


Lesenswert?

Mit der genannten Einstellung läuft der Timer im CTC Modus (Clear on 
Compare Match).
Tritt ein Compare Match auf, wird der Timer zurücksetzet auf 0 (das 
Timer Zählregister TCNT1). Er zählt wieder von 0 bis eben zum Compare 
Match (OCR1A). Und das solange du ihm einen Takt vorgibst (Prescaler 
!=0).

Einen TimerOverflow gibt es nicht, da du kein Overflow Interrupt hast 
(der Timer OVF wurde nicht initialisiert und es gibt in deinem Programm 
auch keine ISR).

von Mike (Gast)


Lesenswert?

Wie meinst du es gibt keinen ISR??

Kann es vllt sein das meine Lösung (wenn sie mal funktionieren sollte) 
zu kompliziert ist?

Ich will dass er eine Pause von mehr als 14*4ms erkennt. Und dann wenn 
ne Flanke kommt, soll er alle 4ms dann immer ein bit einlesen, und das 
12 mal.

Gruß

von Mike (Gast)


Lesenswert?

Ich hab mal eben nur mal im Timer zählen lassen, aber der zählt ein 
einziges mal und danach nicht mehr.

Hab ne andere Einstellung versucht, geht aber nicht.
....
TCCR0 geht bei mir, hat aber kein CTC :/

von Mike M. (mikeii)


Lesenswert?

Jetz hab ichs mal so probiert, der Timer läuft.

Hab mal größere Werte genommen damit der Timmer ned so schnell läuft.

Das Problem ist, er schreibt mir keine Bits rein...

1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <avr/signal.h>
4
#include <stdint.h>
5
#include <lcd.h>
6
#include <stdlib.h>
7
8
9
//Count zählt wie oft ein High wert ohne unterbrechung da war
10
//Watch auf 1 bedeutet, er kann bits schreiben
11
//i ist meine Bitposition (muss rückwärts schreiben)
12
uint8_t count = 0, watch = 0, i = 12;
13
//Wert wird beschrieben, und wertb speichert das am ende zwischen
14
uint16_t wert = 0x00,wertb=0x00;
15
//Hat nur belang für die LCD ausgabe
16
uint8_t display=0;
17
//Setzt in der main nach ner Pause, wenn eine flanke auftaucht den Timer zurück um
18
//sich mit dem signal zu syncronisieren
19
uint8_t reset=1;
20
21
22
23
SIGNAL(SIG_OVERFLOW0)
24
{
25
    display++;
26
    if (display == 11){display = 0;}
27
28
    //Verhindert overflow
29
    if (count > 15){count = 15;}
30
    //Wenn eine flanke auftritt, wird count auf 0 zurückgesetzt
31
    if ((PIND & (1<<PIND0)) && (watch == 0)){count = 0;}
32
    //Solang auf low, wird count hochgezählt
33
    if ((!(PIND & (1<<PIND0))) && (watch == 0)){count++;}
34
    //Ist der wert 14 erreicht, wird watch auf 1 gestellt.
35
    if (count > 14){watch = 1;}
36
    //Kommt jetz ne flanke mit watch auf 1, geht das zählen los
37
    if ((watch == 1) && (PIND & (1<<PIND0))){
38
    //Wenn auf low, soll er mir ne 1 reinschreiben
39
    if (!(PIND & (1<<PIND0))){
40
    wert |= (1<<i);}
41
    //geht immer eine bitposition zurück
42
    i--;
43
    //Soll alle werte zurücksetzten, und den wert zwischenspeichern
44
        if (i==0){
45
            i=12;
46
            watch=0;
47
            reset=1;
48
            wertb = wert;
49
count = 0;
50
        }
51
52
53
    }
54
55
56
}
57
58
59
60
61
int main(void)
62
{
63
 DDRD = 0x00;
64
    PIND = 0xff;
65
    TIMSK = (1<<TOIE0) ;
66
    TCNT0 = 230        ;
67
    TCCR0 = 5;
68
    sei();
69
70
71
  char buffer[7];
72
73
74
    lcd_init(LCD_DISP_ON);
75
    lcd_clrscr();
76
  while(1) {
77
78
      //Syncronisiert den Timer mit dem Signal
79
if ((watch == 1) && (PIND & (1<<PIND0)) && (reset == 1)){TCNT0 = 230;reset = 0;}
80
//Displayausgabe
81
       wertb = wertb/2;
82
         itoa (wertb, buffer, 10);
83
84
      if (display == 10)
85
      {
86
          lcd_clrscr();
87
          lcd_puts(buffer);
88
      }
89
  }
90
}

von Stefan E. (sternst)


Lesenswert?

Aktuell fehlen da ein paar "volatile". Das Ganze kann aber auch ganz 
grundsätzlich so nicht funktionieren. Wenn du mit einem festen Raster 
abtastest, und dieses Raster nicht irgendwo auf das Eingangssignal 
synchronisiert wird, dann werden die Abtastpunkte auch mal im Bereich 
der Flanken liegen. Du musst bei jedem Datum das Raster neu auf die 
erste Flanke ausrichten, damit die Abtastpunkte ungefähr in der Mitte 
des Bits liegt.

von Mike M. (mikeii)


Lesenswert?

Stefan Ernst schrieb:
> Aktuell fehlen da ein paar "volatile". Das Ganze kann aber auch ganz
> grundsätzlich so nicht funktionieren. Wenn du mit einem festen Raster
> abtastest, und dieses Raster nicht irgendwo auf das Eingangssignal
> synchronisiert wird, dann werden die Abtastpunkte auch mal im Bereich
> der Flanken liegen. Du musst bei jedem Datum das Raster neu auf die
> erste Flanke ausrichten, damit die Abtastpunkte ungefähr in der Mitte
> des Bits liegt.


Ich hab einen kleinen Fehler im Code schon gefunden.

Aber wie richte ich das Signal den aus?
Ich muss ne Flanke erkennen, klar, aber das muss ja in der Main 
passieren, sonst kann ich das nicht anpassen.
Mir rauch langsam der Kopf, gibt es da nicht ne feste Vorgehensweiße um 
solche Signale einzulesen??

Danke

von Mike M. (mikeii)


Lesenswert?

Ok ich habs hinbekommen mit dem Timer 2

Das Problem ist nur, ich weiß nicht wie ich den Timer dazubringe, das er 
bei einer Flanke sich selbst zurücksetzt.

Ziemlich am Ende vom Code, da wo die vielen Fragezeichen sind:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <avr/signal.h>
4
#include <stdint.h>
5
#include <lcd.h>
6
#include <stdlib.h>
7
8
uint8_t flanke;
9
//Count zählt wie oft ein High wert ohne unterbrechung da war
10
//Watch auf 1 bedeutet, er kann bits schreiben
11
//i ist meine Bitposition (muss rückwärts schreiben)
12
uint8_t count = 0, watch = 0, i = 12;
13
//Wert wird beschrieben, und wertb speichert das am ende zwischen
14
uint16_t wert = 0x00,wertb=0x00;
15
//Hat nur belang für die LCD ausgabe
16
uint8_t display=0;
17
18
19
20
21
SIGNAL(SIG_OUTPUT_COMPARE2)
22
{
23
    flanke = PIND;
24
    display++;
25
    if (display == 50){display = 0;}
26
27
    //Verhindert overflow
28
    if (count > 15){count = 15;}
29
    //Wenn eine flanke auftritt, wird count auf 0 zurückgesetzt
30
    if ((PIND & (1<<PIND0)) && (count < 15)){count = 0;}
31
    //Solang auf low, wird count hochgezählt
32
    if ((!(PIND & (1<<PIND0))) && (watch == 0)){count++;}
33
    //Ist der wert 14 erreicht, wird watch auf 1 gestellt.
34
35
36
    if ((count > 14) && (PIND & (1<<PIND0))){watch = 1;}
37
38
39
    if (watch == 1){
40
41
42
    //Wenn auf low, soll er mir ne 1 reinschreiben
43
    if (!(PIND & (1<<PIND0))){
44
    wert |= (1<<i);
45
    }
46
    //geht immer eine bitposition zurück
47
    i--;
48
    //Soll alle werte zurücksetzten, und den wert zwischenspeichern
49
        if (i==0){
50
            i=12;
51
            watch=0;
52
            if (wert != 0){
53
            wertb = wert;}
54
            wert = 0x00;
55
            count = 0;
56
        }
57
58
59
    }
60
61
62
}
63
64
65
66
67
int main(void)
68
{
69
 DDRD = 0x00;
70
    PIND = 0xff;
71
TCCR2 = (1<<CS20) | (1<<CS22) | (1<<WGM21);  
72
OCR2  = 250;      
73
TIMSK |= (1<<OCIE2);    
74
75
76
  char buffer[7];
77
78
79
    lcd_init(LCD_DISP_ON);
80
    lcd_clrscr();
81
  while(1) {
82
83
// HIER Soll der Timer2 bei 0 wieder anfangen zu Zählen
84
if (PIND != flanke){????????}
85
86
87
         itoa (wertb, buffer, 10);
88
89
      if (display == 3)
90
      {
91
          lcd_clrscr();
92
          lcd_puts(buffer);
93
      }
94
  }
95
}

von derderauchproblemehat (Gast)


Lesenswert?

einfach einfügen TCNT2 = 0;

von Stefan E. (sternst)


Lesenswert?

Wenn du das Synchronisieren in main machen willst (ich würde einen 
externen Interrupt nehmen), dann könnte das ungefähr so aussehen:
1
// Pause detektieren
2
...
3
// Timer stoppen und vorbereiten
4
TCCR2 = (1<<WGM21);  
5
TCNT2 = 125;  // erster Interrupt nach der halben Zeit
6
// auf fallende Flanke warten
7
while (PIND & (1<<???));
8
// Timer starten
9
TCCR2 |= (1<<CS20) | (1<<CS22);
10
// warten bis Datum komplett
11
...
12
// Ausgabe
13
...

von Mike M. (mikeii)


Lesenswert?

Ok danke, wie meinst du das mit externem Interrupt, wie kann ich sowas 
bewerkstelligen??

von Mike M. (mikeii)


Lesenswert?

Keiner einen Tipp?
Bin immer noch nicht weiter....

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.