mikrocontroller.net

Forum: Compiler & IDEs Signal auswerten, Probleme mit CTC


Autor: Mike (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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
#include <stdlib.h>
#include <avr/pgmspace.h>
#include <lcd.h>
#include <avr/io.h>
#include <util/delay.h>
#include <stdint.h>
#include <avr/interrupt.h>

//Wählt wie oft auf high ohne unterbrechung
uint8_t count = 0;
//Steht auf 1, wenn mehr als 14 mal auf high (also 14*4ms vergangen sind, also eine Pause)
uint8_t watch = 0;
//das ist mein wert der verändert wird und ausgelesen werden soll, 12bit lang
uint16_t wert = 0b000000000000;
//bit muss ich rückwärts reinschreiben, das ist die position
uint8_t bit = 12;
uint8_t lcd = 0;
uint16_t wertbuffer;

///ACHTUNG  ACHTUNG ACHTUNG ACHTUNG ACHTUNG
///Pin auf Low heißt 1 und Pin auf High heißt 0 !!!!
///ACHTUNG  ACHTUNG ACHTUNG ACHTUNG ACHTUNG

ISR(TIMER1_COMPA_vect)
{
    //Wenn der counter unter 8 sein sollte, und ein low signal auftritt
    //Wird der counter auf 0 zurück gesetzt, weil da noch irgendwo ein
    //Signal ist, also keine pause
    if ((count < 15) && (PIND & (1<<PIND0))){count = 0;}

    //Wenn ein high signal da ist dann zählt der count eins hoch
    if (!(PIND & (1<<PIND0))){count++;}

    //Wenn der counter jetz größer ist als 7, war wohl ne pause.
    //Wenn zusätzlich noch ne flanke kommt, dann fängt das signal an
    //Das heißt watch ist auf 1, damit er unten bit schreibt
    if ((count > 14) && (PIND & (1<<PIND0))){watch = 1;}

    //Wenn watch auf high, ließt er den wert ein
    if (watch == 1){
        lcd = 0;

        //Wenn ein High kommt, dann soll er ne 1 schreiben an der stelle des Bits
        if (!(PIND & (1<<PIND0))){
            wert |= (1<<bit);
        }
    }
        //Springt jedesmal eine Bitposition zurück
         bit--;

         //Wenn das 0te Bit geschrieben ist, wird bit auf 12 zurückkgesetzt
         //watch auf 0, damit keine werte geschrieben werden
         //Wertbuffer übernimmt den wert, damit er immer aktuell abrufbar ist
         //wert wird auf 0 zurückgesetzt damit man ihn neu mit bits befüllen kann
         if (bit == 0){
             bit = 12;
             watch = 0;
             wertbuffer = wert;
             wert = 0x00;
             lcd = 1;
             }




}

int main(void)
{


    DDRD = 0x00;
    PIND = 0xff;


    TCCR1B = (1<<CS11) | (1<<WGM13) | (1<<WGM12) ;
      
    OCR1A = 124;
    TIMSK = (1<<OCIE1A);
    char buffer[14];

    lcd_init(LCD_DISP_ON);
    lcd_clrscr();
    sei();

  while(1)
  {
      //als Binärzahl ins Array schreiben
      itoa (wertebuffer, buffer, 2);

      if (lcd == 1)
      {
          lcd_clrscr();
          lcd_puts(buffer);
      }


  }
}

Autor: Mike (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ach ja, es geht um dieses Signal:

Beitrag "Signal auswerten"

Autor: derderauchproblemehat (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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
TCCR1B = (1<<CS11) | (1<<WGM12);
so wird OCR1A initialisiert
Prescaler 8 ist so korrekt

Autor: Mike (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: derderauchproblemehat (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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).

Autor: Mike (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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ß

Autor: Mike (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 :/

Autor: Mike Mike (mikeii)
Datum:

Bewertung
0 lesenswert
nicht 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...

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <stdint.h>
#include <lcd.h>
#include <stdlib.h>


//Count zählt wie oft ein High wert ohne unterbrechung da war
//Watch auf 1 bedeutet, er kann bits schreiben
//i ist meine Bitposition (muss rückwärts schreiben)
uint8_t count = 0, watch = 0, i = 12;
//Wert wird beschrieben, und wertb speichert das am ende zwischen
uint16_t wert = 0x00,wertb=0x00;
//Hat nur belang für die LCD ausgabe
uint8_t display=0;
//Setzt in der main nach ner Pause, wenn eine flanke auftaucht den Timer zurück um
//sich mit dem signal zu syncronisieren
uint8_t reset=1;



SIGNAL(SIG_OVERFLOW0)
{
    display++;
    if (display == 11){display = 0;}

    //Verhindert overflow
    if (count > 15){count = 15;}
    //Wenn eine flanke auftritt, wird count auf 0 zurückgesetzt
    if ((PIND & (1<<PIND0)) && (watch == 0)){count = 0;}
    //Solang auf low, wird count hochgezählt
    if ((!(PIND & (1<<PIND0))) && (watch == 0)){count++;}
    //Ist der wert 14 erreicht, wird watch auf 1 gestellt.
    if (count > 14){watch = 1;}
    //Kommt jetz ne flanke mit watch auf 1, geht das zählen los
    if ((watch == 1) && (PIND & (1<<PIND0))){
    //Wenn auf low, soll er mir ne 1 reinschreiben
    if (!(PIND & (1<<PIND0))){
    wert |= (1<<i);}
    //geht immer eine bitposition zurück
    i--;
    //Soll alle werte zurücksetzten, und den wert zwischenspeichern
        if (i==0){
            i=12;
            watch=0;
            reset=1;
            wertb = wert;
count = 0;
        }


    }


}




int main(void)
{
 DDRD = 0x00;
    PIND = 0xff;
    TIMSK = (1<<TOIE0) ;
    TCNT0 = 230        ;
    TCCR0 = 5;
    sei();


  char buffer[7];


    lcd_init(LCD_DISP_ON);
    lcd_clrscr();
  while(1) {

      //Syncronisiert den Timer mit dem Signal
if ((watch == 1) && (PIND & (1<<PIND0)) && (reset == 1)){TCNT0 = 230;reset = 0;}
//Displayausgabe
       wertb = wertb/2;
         itoa (wertb, buffer, 10);

      if (display == 10)
      {
          lcd_clrscr();
          lcd_puts(buffer);
      }
  }
}






Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Mike Mike (mikeii)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Mike Mike (mikeii)
Datum:

Bewertung
0 lesenswert
nicht 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:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <stdint.h>
#include <lcd.h>
#include <stdlib.h>

uint8_t flanke;
//Count zählt wie oft ein High wert ohne unterbrechung da war
//Watch auf 1 bedeutet, er kann bits schreiben
//i ist meine Bitposition (muss rückwärts schreiben)
uint8_t count = 0, watch = 0, i = 12;
//Wert wird beschrieben, und wertb speichert das am ende zwischen
uint16_t wert = 0x00,wertb=0x00;
//Hat nur belang für die LCD ausgabe
uint8_t display=0;




SIGNAL(SIG_OUTPUT_COMPARE2)
{
    flanke = PIND;
    display++;
    if (display == 50){display = 0;}

    //Verhindert overflow
    if (count > 15){count = 15;}
    //Wenn eine flanke auftritt, wird count auf 0 zurückgesetzt
    if ((PIND & (1<<PIND0)) && (count < 15)){count = 0;}
    //Solang auf low, wird count hochgezählt
    if ((!(PIND & (1<<PIND0))) && (watch == 0)){count++;}
    //Ist der wert 14 erreicht, wird watch auf 1 gestellt.


    if ((count > 14) && (PIND & (1<<PIND0))){watch = 1;}


    if (watch == 1){


    //Wenn auf low, soll er mir ne 1 reinschreiben
    if (!(PIND & (1<<PIND0))){
    wert |= (1<<i);
    }
    //geht immer eine bitposition zurück
    i--;
    //Soll alle werte zurücksetzten, und den wert zwischenspeichern
        if (i==0){
            i=12;
            watch=0;
            if (wert != 0){
            wertb = wert;}
            wert = 0x00;
            count = 0;
        }


    }


}




int main(void)
{
 DDRD = 0x00;
    PIND = 0xff;
TCCR2 = (1<<CS20) | (1<<CS22) | (1<<WGM21);  
OCR2  = 250;      
TIMSK |= (1<<OCIE2);    


  char buffer[7];


    lcd_init(LCD_DISP_ON);
    lcd_clrscr();
  while(1) {

// HIER Soll der Timer2 bei 0 wieder anfangen zu Zählen
if (PIND != flanke){????????}


         itoa (wertb, buffer, 10);

      if (display == 3)
      {
          lcd_clrscr();
          lcd_puts(buffer);
      }
  }
}






Autor: derderauchproblemehat (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
einfach einfügen TCNT2 = 0;

Autor: Stefan Ernst (sternst)
Datum:

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


Autor: Mike Mike (mikeii)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok danke, wie meinst du das mit externem Interrupt, wie kann ich sowas 
bewerkstelligen??

Autor: Mike Mike (mikeii)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Keiner einen Tipp?
Bin immer noch nicht weiter....

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.