Go Down

Topic: Impulsgenerator? (Read 528 times) previous topic - next topic

Kay19

Hallo Forum,

nach zwei Jahren Pause möchte ich mein altes Tachoprojekt nochmal neu aufsetzen. Dazu hab ich für Testzwecke eine Art Impulsgenerator gebaut. Zuerst hatte ich tone() verwndet, bis ich gelesen hatte das ich damit nur Frequenzen >30Hz erzeugen kann. Für mein Tachoprojekt reicht das aber nicht, also dachte ich, ich könnte mittels Timer einfach einen Pin zwischen HIGH und LOW hin- und herschalten lassen. Zusätzlich noch ein Poti um die Frequenz zu verändern...
Leider scheint das Ganz nicht zu funktionieren, das Programm läuft zwar, nach einfügen der Serial.print-Funktionen sehe ich auch das das Poti funktioniert, jedoch scheint an PIN2 kein Signal anzukommen. Habe für Testzwecke mal PIN13 verwendet um anhand der verbauten LED etwas zu erkennen, aber auch hier scheinbar keine Funktion. Ich vermute die Interruptroutine wird nicht aufgerufen, warum?
Code: [Select]

int impuls=0;
volatile byte b_mode=0;
volatile int dauer_neu=0;


ISR(TIMER1_COMPA_vect) { // will be called when an interrupt occurs at timer 1
    if (b_mode==1) {
    digitalWrite(2, HIGH);
    b_mode=1;
  } else {
    digitalWrite(2, LOW);
    b_mode=0;
  }
  OCR1A=dauer_neu;
 
}

void setup() {
  // put your setup code here, to run once:
  pinMode(2,OUTPUT);
  Serial.begin(19200);
  digitalWrite(2, LOW);

  cli(); //Lösche globales Interrupt-Enable-Bit
  //CTC-Mode aktivieren
  TCCR1A = 0; //Löschen des TCCR1A-Registers
  TCCR1B = 0; //Löschen des TCCR1B-Registers
  TCNT1  = 0; // reset counter value
  OCR1A=32500;  //countervergleichsregister
  TCCR1B |= (1 << CS11) | (1 << CS10);  //Setze CS11 und CS12 (Clock Select) Takt/64
  TCCR1B |= (1 << WGM12);  //Setze CTC-Mode
  TIMSK1 |= (1 << OCIE1A); //Bit Output Compare A Match Interrupt Enable setzen
 
 
}

void loop() {
  // put your main code here, to run repeatedly:
  impuls = analogRead(A2);
  if (impuls>0){
      sei();
      dauer_neu=impuls <<5; //mit 32 multiplizieren
     
  } else {
    cli();
    dauer_neu=0;
    digitalWrite(2,LOW);
  }
  Serial.print("dauer_neu: ");Serial.println(dauer_neu);



}


Viele Grüße

combie

Code: [Select]
if (impuls>0){
      sei();
     
     
  } else {
    cli();
 
  }

*gekürzt*
Was soll denn das unsymetrische Zeug?
Wer seine Meinung nie zurückzieht, liebt sich selbst mehr als die Wahrheit.

Quelle: Joseph Joubert

Kay19

ich bin unsicher ob ich die Frage richtig verstanden habe, der If-Teil sorgt dafür das keine 0 ins OCR1A geschrieben wird.

MicroBahner

#3
Dec 08, 2019, 02:49 pm Last Edit: Dec 08, 2019, 02:55 pm by MicroBahner
Es geht um deine etwas willkürlich verstreuten sei() und cli(). Du kannst nicht einfach beliebig die Interrupts generell ausschalten. Das darf immer nur kurzfristig gemacht werden, d.h. cli() und sei() müssen immer paarweise kurz hintereinander auftauchen. Es gibt schließlich auch noch andere Funktionen im Arduino, die auf Interrupts angewiesen sind.
Edit: Wenn die ISR nicht mehr aufgerufen werden soll, musst Du explizit diesen Interrupt im TIMSK1 wieder abschalten.

Zu deinem Problem: Das toggeln in der ISR funktioniert nicht, da Du dein b_mode nicht umschaltest. ( wird auf 1 gesetzt, wenn es schon 1 ist, ebenso wenn es 0 ist - es bleibt einfach wie es ist ).
Den aus Ausgang toggeln kannst Du aber auch einfach mit
Code: [Select]
  digitalWrite(2, !digitalRead(2) );
Gruß, Franz-Peter

postmaster-ino

Hi

Und?
Das entspräche 256.

Auch wird Dir das cli 'auf die Füße fallen' - lasse Dir Mal die millis() ausgeben - Die dürften von dem Dauer-cli durchaus beeindruckt sein.

MfG

combie

#5
Dec 08, 2019, 03:02 pm Last Edit: Dec 09, 2019, 11:27 am by combie
ich bin unsicher ob ich die Frage richtig verstanden habe,
Verwende besser ATOMIC_BLOCK Konstrukte.


Quote
der If-Teil sorgt dafür das keine 0 ins OCR1A geschrieben wird.
Den Teil habe ich extra raus geschnitten, da sich meine Aussage eben genau darauf NICHT bezieht.
Meinte schon die die unsymetrische Interrupt ein/aus schalterei.
Wer seine Meinung nie zurückzieht, liebt sich selbst mehr als die Wahrheit.

Quelle: Joseph Joubert

Doc_Arduino

Hallo,

du solltest dich vorher dringend mit dem Timer allgemein befassen.
Du möchtest dir im Grunde einen Frequenzgenerator bauen mit jederzeit änderbarer Frequenz.
Dabei gibts paar Dinge zu beachten hinsichtlich des aktualisierens der Compare-Match Register.
Lies den Abschnitt im Manual zum Timer. Sonst wird das nichts, glaube mir.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

MicroBahner

#7
Dec 08, 2019, 09:55 pm Last Edit: Dec 08, 2019, 09:56 pm by MicroBahner
Das macht er schon richtig, und das funktioniert auch.

Sein Problem ist der Fehler beim toggeln des Ausgangs ( wobei er das auch der HW überlassen könnte ), die falschen cli/sei und den nicht ATOMIC Zugriff beim Ändern des dauer_neu.
Auch wäre es sinnvoll, die Variable dauer_neu als 'unsigned int' zu deklarieren. Schließlich hat auch OCR1A kein Vorzeichen.
Dass er 'volatile' noch nicht richtig verstanden hat, ist dabei erstmal Nebensache.
Gruß, Franz-Peter

DrDiettrich

Mit dem richtigen Timer mode spielt die Hardware den Ton doch ganz von alleine ab, ohne ISR.

Doc_Arduino

Hallo,

ja okay, wenn er OCR1A in dessen ISR aktualisiert passt das, Entschuldigung.
Beim Rest muss der TO einfach nochmal seinen Code lesen.
Ich würde ja der Einfachheit vorschlagen immer eine bool Variable negieren und diese am Pin ausgeben.

Mit dem richtigen Timer mode spielt die Hardware den Ton doch ganz von alleine ab, ohne ISR.
Würde ich pauschal immer dafür plädieren. Wenn keine anderen Gründe vorliegen irgendeinen Mode mit OCRxn Buffer.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

MicroBahner

#10
Dec 09, 2019, 08:54 am Last Edit: Dec 09, 2019, 09:00 am by MicroBahner
Mit dem richtigen Timer mode spielt die Hardware den Ton doch ganz von alleine ab, ohne ISR.
Die ISR braucht er immer, um die Frequenz verändern zu können ( setzen von OCR1A ). Wie ich auch schon schrieb, kann er das Toggeln des Ausgangs der HW überlassen. Der Timer-Mode bleibt dabei aber derselbe (er will ja eine variable Frequenz, und kein PWM ), er muss nur den Ausgang entsprechend aktivieren ( in TCCR1A ). Allerdings ist er dann auf einen festen Pin ( hier 9 ) festgelegt. Macht er es per SW kann er den Pin selbst frei bestimmen.

Aber jetzt schau'n wer mal, was der TO zu dem Ganzen sagt  ;) .
Gruß, Franz-Peter

DrDiettrich

Mehr als einen Pin braucht man ja selten mit der gleichen Frequenz. Zum Ändern der Frequenz ist IMO kein ISR notwendig, die Zugriffe erfolgen bei 16 Bit Zählern synchronisiert.

Doc_Arduino

Hallo,

da muss ich nochmal einhaken. Man kann einen Frequenzgenerator ohne ISR inkl. Pulsweitenänderung bauen.
Hier in dem Fall müßte man nur die Pulsweite konstant auf 50% halten.
Das funktioniert zum Bsp. alles im Phase Correct Mode einwandfrei, weil die Compare Register gepuffert sind.
Dadurch kann man gefahrlos jederzeit die Einstellung ändern.
Ob das sich hier im Falle lohnt ist eine andere Frage. Möchte nur sagen es ginge auch ohne ISR.  ;)
Nach nochmaliger aktueller Überlegung würde ich an Stelle vom TO jedoch bei CTC bleiben.
Dann muss man sich nicht um die Pulsweitenanpassung kümmern.  :)


Mehr als einen Pin braucht man ja selten mit der gleichen Frequenz. Zum Ändern der Frequenz ist IMO kein ISR notwendig, die Zugriffe erfolgen bei 16 Bit Zählern synchronisiert.
:o :o :o   In Modi ohne gepufferte Compare Register macht der Timer Mist wenn du zufällig zur falschen Zeit den Comparewert änderst. Der Wert wird sofort übernommen. Wenn der TCNT zu dem Zeitpunkt schon drüber ist läuft der Timer kurzzeitig falsch. Deswegen ändert man hier im Fall CTC den Compare in der eigenen Compare ISR, da kann nichts schief gehen.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

DrDiettrich

Oder man löscht TCNT nach der Änderung des OCRx.

Doc_Arduino

Hallo,

Oder man löscht TCNT nach der Änderung des OCRx.
ich habe lange überlegt wie du das meinen könntest, komme jedoch immer zu der Überzeugung das die Aussage keinen Sinn macht. Egal welcher Timermode.

a) ich habe eine Konstellation nicht auf dem Schirm (kann was übersehen haben)
b) ich denke du hast dich gedanklich verrannt (passiert mir auch manchmal)

Du müßtest jetzt dazu sagen in welchen Mode du wann den OCR ändern und TCNT nullen möchtest.  ?
Dazu vielleicht noch ohne ISR?  Ich sehe wie gesagt keine Möglichkeiten.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

Go Up