Forum: Mikrocontroller und Digitale Elektronik Marderschreck Selbstprogramm


von Adrian (Gast)


Angehängte Dateien:

Lesenswert?

hallo leute,

da ich mit dem Assembly-code vom Marderschreck ziemlich frustiert bin 
und denke mal nach einigen Posts keine lust mehr haben sicih weiter zu 
beschäftigen habe ich mich dazu entschlossen mir mein eigenes Programm 
zu schreiben. Zwar ist das ein optimales Programm hat aber noch seine 
kleinen Tücken. Ich weiss gerade nicht wie ich die frequenz stetig 
ändern kann dass ich am ende ne bandbreite zwischen 20- 40khz habe. Ich 
habs wenigstens geschafft am ausgang 31khz raus zu bekommen. Jedoch 
hängt es immer davon ab welchen wert ich pwm_max zuweise.

Ich versuche nach diesem assembler code auf der schreibe:( 
http://www.elektronik-labor.de/AVR/dds/Nightlight.html) eine frequenz 
von 20-40khz rauszubekommen. Das fürs erste :)

Was müsste ich dort noch ändern?

von Karl H. (kbuchegg)


Lesenswert?

Prinzipiell eine gute Idee.
Das Problem ist aber, dass du C anscheinend auch nicht kannst.

Wenn du haben willst, dass
1
ISR (TIMER1_COMPA_vect)
2
{
3
  int i_unten=0;
4
  int i_oben= 1;

i_unten bzw. i_oben ihren Wert von einem ISR AUfruf zum nächsten 
beibehalten, dann musst du die Variablen static machen, oder sie als 
globale Variablen ausführen.
So wie das jetzt ist, werden diese Variablen jedesmal neu erzeugt, wenn 
die ISR aufgerufen wird. Und damit ist klar, dass du damit keine 
Information von einem ISR Aufruf zum nächsten transportieren kannst.

Wozu eigentlich 2 Variablen? Eine alleine genügt doch völlig, denn 
i_oben ist immer das Gegenteil von i_unten. Wenn die eine 0 ist, ist die 
andere 1 und umgekehrt. D.h. was du dir in Wirklichkeit merkst, ist ja 
nichts anderes, als das die Frequenz größer bzw. kleiner werden soll, 
also die Richtung (engl. Direction) in die die nächste Frequenzänderung 
gehen soll, in dem der Top Wert für die PWM größer oder kleiner werden 
soll.
1
#define UP   0
2
#define DOWN 1
3
4
ISR (TIMER1_COMPA_vect)
5
{
6
  static uint8_t sweepDirection = UP;
7
8
  if( sweepDirection == UP )
9
  {
10
    maxpwm += 10;
11
    if( maxpwm > 190 )
12
      sweepDirection = DOWN;
13
  }
14
  else
15
  {
16
    maxpwm -= 10;
17
    if( maxpwm < 100 )
18
      sweepDirection = UP;
19
  }
20
21
  OCR1C = maxpwm;
22
}


> dass ich am ende ne bandbreite zwischen 20- 40khz habe
Ich hab jetzt dein OCR1C Werte bzw. die Grenzen 100 bzw. 190 nicht 
nachgerechnet, sondern die Zahlen einfach übernommen.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Das hier
1
    while(1)
2
    {
3
    
4
        if(PORTB|=(1<<PB3))
5
    {
6
  
7
      
8
      sei();
9
    }
10
  else
11
  cli();
12
  }

hilft dir nichts. Nur weil du die Interrupts abschaltest, hört der Timer 
nicht auf eine Hardware PWM zu erzeugen.

Wenn du einen Timer stoppen willst, dann ist (in deinem Fall) die 
einfachste Möglichkeit, einfach den Vorteiler auf 0 zu schalten. Soll er 
weiter laufen, dann schaltest du den Vorteiler wieder frei.

Das hier
1
        if(PORTB|=(1<<PB3))

ist keine Abfrage eines Portpins und das verblüfft mich eigentlich. Denn 
der sichere Umgang mit Portpins, sowohl in der Eingabe als auch in der 
Ausgabe, ist eigentlich Grundlage für alles weitere. Es ist sozusagen 
das, was in der Mathematik das kleine Einmaleins ist, oder für einen 
Werkzeugmacher der Umgang mit Feile und Schraubenzieher. In einem realen 
Projekt DARF es dabei keinerlei Unsicherheiten geben.


1
...
2
   sei();
3
4
   while(1)
5
   {
6
     if( PINB & (1<<PB3) )
7
       TCCR1 |= (1<<CS12);
8
     else
9
       TCCR1 &= ~(1<<CS12);
10
   }

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Wozu eigentlich ...
1
void  Timer1(){
2
  
3
  TCCR1 |=(1<<CTC1)|(1<<PWM1A)|(1<<COM1A1)|(1<<CS12);
4
...

das CTC Bit?
Alles was du brauchst ist PWM1A. Das erzeugt doch bereits eine PWM 
basierend auf OCR1A (Duty Cycle) und OCR1C (Frequenz).
CTC1 braucht niemand.

: Bearbeitet durch User
von Adrian (Gast)


Lesenswert?

Karl Heinz schrieb:
> Wozu eigentlich ...void  Timer1(){
>
>   TCCR1 |=(1<<CTC1)|(1<<PWM1A)|(1<<COM1A1)|(1<<CS12);
> ...
>
> das CTC Bit?
> Alles was du brauchst ist PWM1A. Das erzeugt doch bereits eine PWM
> basierend auf OCR1A (Duty Cycle) und OCR1C (Frequenz).
> CTC1 braucht niemand.

Im Datenblatt steht bei CTC1 wenn dieses bit gesetzt ist ist Timer1 
zurückgesetzt und zählt dannn bis es ein Match mit dem OCR1C register 
hat also mit mein maxpwm ...so hab ich gedacht

von Karl H. (kbuchegg)


Lesenswert?

Adrian schrieb:

> Im Datenblatt steht bei CTC1 wenn dieses bit gesetzt ist ist Timer1
> zurückgesetzt und zählt dannn bis es ein Match mit dem OCR1C register
> hat also mit mein maxpwm ...so hab ich gedacht

Und jetzt liest du dir auch noch die Beschreibung für das PWM1 Bit 
durch. Fällt dir was auf?

: Bearbeitet durch User
von Adrian (Gast)


Lesenswert?

Karl Heinz schrieb:
> Adrian schrieb:
>
>> Im Datenblatt steht bei CTC1 wenn dieses bit gesetzt ist ist Timer1
>> zurückgesetzt und zählt dannn bis es ein Match mit dem OCR1C register
>> hat also mit mein maxpwm ...so hab ich gedacht
>
> Und jetzt liest du dir auch noch die Beschreibung für das PWM1 Bit
> durch. Fällt dir was auf?

"Auf dem Kopf klatsch!" jaa Sie haben recht! Ist genau das selbe wie 
CTC1.. Toll-.-

von Karl H. (kbuchegg)


Lesenswert?

Adrian schrieb:

> ...  Sie ...

Unter uns Klosterschwestern sind wir automatisch "per du".

von Adrian (Gast)


Lesenswert?

Karl Heinz schrieb:
> Adrian schrieb:
>
>> ...  Sie ...
>
> Unter uns Klosterschwestern sind wir automatisch "per du".

Alles klar :D Entschuldigung:) Eigentlich müsste sich etwas an der 
Frequenz. Es schwanken von 16khz nur 100 hz umher

von Karl H. (kbuchegg)


Lesenswert?

Adrian schrieb:
> Karl Heinz schrieb:
>> Adrian schrieb:
>>
>>> ...  Sie ...
>>
>> Unter uns Klosterschwestern sind wir automatisch "per du".
>
> Alles klar :D Entschuldigung:) Eigentlich müsste sich etwas an der
> Frequenz. Es schwanken von 16khz nur 100 hz umher

Womit gemessen?

Denn um ehrlich zu sein, traue ich dem Messergebnis nicht. Die 
Frequenzänderung (durch Manipulation der Periodendauer) erfolgt nach 
JEDER EINZELNEN Schwingung. D.h. da sind keine 2 hintereinander 
liegenden Schwingen von gleicher Länge. Und ab ein Messgerät damit klar 
kommt, da bin ich mir nicht wirklich sicher. Ich würde es mal so machen, 
wenigstens (sagen wir mal) 1000 Schwingungen von der gleichen 
Periodendauer zu erzeugen und erst dann die Frequenz zu verändern. Bei 
30Khz sind das dann immer noch 30 Frequenzänderungen in der Sekunde.
1
ISR (TIMER1_COMPA_vect)
2
{
3
  static uint8_t  sweepDirection = UP;
4
  static uint16_t pulseCount = 0;
5
6
  pulseCount++;
7
  if( pulseCount == 1000 )
8
  {
9
    pulseCount = 0;
10
11
    if( sweepDirection == UP )
12
    {
13
      maxpwm += 10;
14
      if( maxpwm > 190 )
15
        sweepDirection = DOWN;
16
    }
17
    else
18
    {
19
      maxpwm -= 10;
20
      if( maxpwm < 100 )
21
        sweepDirection = UP;
22
    }
23
24
    OCR1C = maxpwm;
25
  }
26
}

: Bearbeitet durch User
von Adrian (Gast)


Lesenswert?

Mit einem Oszilloskop messe ich die Frequenz gerade. Leider sehe ich 
immer nur eine konstante Frequenz.

Vom marderschreck exampel sah ich auch dass die spannungen hin und her 
bewegten sprich sie dauerte mal länger mal kürzer. Wie kann ich dies im 
Porgramm beeinflussen? Mit delay vll?

von Karl H. (kbuchegg)


Lesenswert?

Adrian schrieb:
> Mit einem Oszilloskop messe ich die Frequenz gerade. Leider sehe ich
> immer nur eine konstante Frequenz.

Überprüf mal, ob die ISR überhaupt aufgerufen wird.

Mir ist nämlich auch aufgefallen, dass im Originalprogramm auf den 
Overflow Interrupt getriggert wird um die Frequenz zu verändern und laut 
Datenblatt wird in jedem Fall der Overflow am Ende eines PWM Zykluses 
aufgerufen (wenn der Timer zurück gesetzt wird).

Ansonsten poste mal den jetzigen Code.
Den sei() hast du vor die Hauptschleife gezogen?


> Vom marderschreck exampel sah ich auch dass die spannungen hin und
> her bewegten sprich sie dauerte mal länger mal kürzer. Wie kann ich
> dies im Porgramm beeinflussen? Mit delay vll?

Langsam. Eines nach dem anderen.
Jetzt kümmern wir uns mal darum, dass die Frequenz prinzipiell änderbar 
ist. Dann kommt das nächste. Aber wir werden hier jetzt nicht einen 
Mehrfrontenkrieg anfachen, indem wir neue Baustellen aufmachen noch ehe 
die erste (und wichtigste) Baustelle abgeschlossen ist. Sowas führt 
gerade bei Neulingen praktisch immer dazu, sich zu verzetteln.

: Bearbeitet durch User
von Adrian (Gast)


Angehängte Dateien:

Lesenswert?

ich habe es mal versucht zu debuggen aber eher mit einem Simulator da 
ich mit meinem Mikrokontroller nur auf ISP programmieren kann als auf 
JTAG.

In der Simulation hat der nicht die ISR aufgerufen. Ich denke mal ein 
Flag würde mir fehlen dass er weiß jetzt muss er die ISR ausführen.

von Karl H. (kbuchegg)


Lesenswert?

1
...
2
  TIMSK |=(1<<OCR1A);
3
  
4
  }
5
  
6
7
8
ISR (TIMER1_COMPA_vect)
9
{
10
...

geh mal auf den Overflow Interrupt

von Adrian (Gast)


Lesenswert?

Karl Heinz schrieb:
> ...
>   TIMSK |=(1<<OCR1A);
>
>   }
>
>
> ISR (TIMER1_COMPA_vect)
> {
> ...
>
> geh mal auf den Overflow Interrupt

bleibt irgendwie in der while schleife hängen obwohl der pin auf high 
ist.

von Dieter F. (Gast)


Lesenswert?

Ist das Teil noch im Kompatibilitäts-Modus? (FUSES ...)

von Adrian (Gast)


Angehängte Dateien:

Lesenswert?

Dieter Frohnapfel schrieb:
> Ist das Teil noch im Kompatibilitäts-Modus? (FUSES ...)


Komischer weisse sehe ich eig immer mit wieviel MHz mein Mikrocontroller 
läuft

von Dieter F. (Gast)


Lesenswert?

TIMSK |=(1<<OCR1A) ???

OCR1A finde ich nicht in TIMSK - OCIE1A aber schon ...

von Adrian (Gast)


Lesenswert?

Dieter Frohnapfel schrieb:
> TIMSK |=(1<<OCR1A) ???
>
> OCR1A finde ich nicht in TIMSK - OCIE1A aber schon ...

Da ist der Fehler!!!!!! Deswegen funktionierte es nicht! Danke *...*

Das Vergleichregister war falsch angelegt.

von Adrian (Gast)


Lesenswert?

Wie kann ich nun die Weite der Reckecksignale verändern und ist es 
möglich wenn ich jetzt den Timer0 zusätzlich programmiere dass er nach 
3min wieder anfängt zu klirren und 30sekunden anhält z.b?

von Dieter F. (Gast)


Lesenswert?

Ich sitze jetzt wieder am Tisch (Karl-Heinz weiß, wieso ich drunter lag 
... :-))

Falls sich niemand erbarmt wirst Du Dich wohl mit

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Die_Timer_und_Z%C3%A4hler_des_AVR

und

http://www.mikrocontroller.net/articles/Sleep_Mode

beschäftigen müssen.

Du könntest natürlich auch (böse, böse und ganz verpönt) delays in Deine 
WHILE-Schleife einbauen und den Timer entsprechend ein- und ausschalten 
(und dabei daran denken, den PWM-Pin jeweils auf low zu ziehen, wenn Du 
den Timer deaktivierst - ist besser für die Umwelt).

von Karl H. (kbuchegg)


Lesenswert?

Dieter Frohnapfel schrieb:
> Ich sitze jetzt wieder am Tisch (Karl-Heinz weiß, wieso ich drunter lag
> ... :-))


:-)

By the way. Danke für den Catch. Über den hab ich tatsächlich x-mal 
drüber gelesen.

> Falls sich niemand erbarmt wirst Du Dich wohl mit
>
> 
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Die_Timer_und_Z%C3%A4hler_des_AVR
>
> und
>
> http://www.mikrocontroller.net/articles/Sleep_Mode
>
> beschäftigen müssen.

Timer ja. Sleep Mode ist denke ich erst mal nicht so wichtig.


> Du könntest natürlich auch (böse, böse und ganz verpönt) delays in Deine
> WHILE-Schleife einbauen

finde ich jetzt nicht ganz so schlimm wie sich das hier anhört.
Man muss nicht päpstlicher als der Papst sein. Wenn die while Schleife 
per delay auf eine Durchlaufzeit von sagen wir mal 100 Millisekunden 
gebracht wird, dann ist ein zusätzliches Timing einfach nur eine Frage 
des abzählens von Schleifendurchgängen. Da der Tiny sowieso nichts 
anders zu tun hat, ist das m.M. akzeptabel. Mit einer Granulierung von 
100ms hat man immer noch eine ausreichend feine Zeitauflösung um 
nebenher noch Benutzerschalter oder LDRs in ausreichend kurzer Zeit 
berücksichtigen zu können.

Man kann das alles natürlich auch sauber mit einem Timer machen. Wenn 
man mal einen Sleep Mode aktivieren will, dann ist das auch 
unumgänglich.
FAQ: Timer


> (und dabei daran denken, den PWM-Pin jeweils auf low zu ziehen, wenn Du
> den Timer deaktivierst - ist besser für die Umwelt).

Das ist interessant. Das ist beim Tiny25 gut gelöst. Siehe Datenblatt. 
WEnn man mit dem Duty Cycle in den Extremwert 0 (bzw. Top geht, je nach 
COM Bit Einstellung), dann schaltet die Hardware den Pin auf stumm. D.h. 
das ganze Gefrickel mit Pin vom Timer abkoppeln ist beim T25 nicht 
notwendig.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Adrian schrieb:
> Wie kann ich nun die Weite der Reckecksignale verändern

was sagt dir 'duty cycle' und welche Variable bzw. damit verbunden 
welches Timer Register, klang im Originalprogramm ganz ähnlich?

von Adrian (Gast)


Lesenswert?

Karl Heinz schrieb:
> duty cycle

das war das OCR1A register ?

von Dieter F. (Gast)


Lesenswert?

Karl Heinz schrieb:
> WEnn man mit dem Duty Cycle in den Extremwert 0 (bzw. Top geht, je nach
> COM Bit Einstellung), dann schaltet die Hardware den Pin auf stumm. D.h.
> das ganze Gefrickel mit Pin vom Timer abkoppeln ist beim T25 nicht
> notwendig.

"When OCR1A contains $00 or the top value, as specified in OCR1C 
register, the output PB1(OC1A) is held low or
high according to the settings of COM1A1/COM1A0. This is shown in Table 
13-2."

Also einfach OCR1A = 0 setzen und bei der aktuellen Einstellung (COM1A1) 
ist der PIN dauerhaft low und es ist Ruhe. Zum Einschalten OCR1A einfach 
wieder auf den gewünschten Wert einstellen.

Ist das so korrekt?

von Adrian (Gast)


Lesenswert?

> Ist das so korrekt?

genau das ist richtig :) Jetzt hab ich es verstanden genau so wollte ich 
es haben^^
Ich denke mal ihr habt mir viel geholfen.

Ich hab mir jetzt den artikel sleep mode durchgelesen und jetzt den 
Eintrag von dir gelesen dass es nicht so sinnvoll bzw nicht nötig ist ?

Was kann ich stattdessen machen ? Mit delays ist es auch nicht getan das 
funktioniert nicht so wie ich es gern hätte.

von Dieter F. (Gast)


Lesenswert?

Adrian schrieb:
> Mit delays ist es auch nicht getan das
> funktioniert nicht so wie ich es gern hätte.

Wie sieht denn Dein Versuch konkret (Code ...) aus?

Hast Du den Hinweis von Karl-Heinz

>Wenn die while Schleife
>per delay auf eine Durchlaufzeit von sagen wir mal 100 Millisekunden
>gebracht wird, dann ist ein zusätzliches Timing einfach nur eine Frage
>des abzählens von Schleifendurchgängen.

berücksichtigt/umgesetzt?

von Adrian (Gast)


Lesenswert?

> berücksichtigt/umgesetzt?
1
 while(1){
2
    
3
   if(PINB &(1<<PB3)) 
4
  {
5
  TCCR1|=(1<<CS12);
6
  _delay_ms(100);
7
  TCCR1 &=~(1<<CS12);  
8
  _delay_ms(100);  
9
      
10
  }
11
  
12
  else
13
  TCCR1 &=~(1<<CS12);
14
      
15
  }
16
  
17
}
so hab ich das aus den zeilen heraus verstanden.

: Bearbeitet durch User
von Dieter F. (Gast)


Lesenswert?

Adrian schrieb:
> so hab ich das aus den zeilen heraus verstanden.

Da liegst Du aber schon etwas daneben ...

Wo zählst Du denn die Schleifendurchgänge?

Karl-Heinz meinte (vermutlich :-))

... bisheriges Programm bis zur Schleife ...

Zähler (groß genug für "Quietsch-Zeit" + "Stumm-Zeit" in 100 
mS-Einheiten definiert) auf Null setzen

Schleife Start.

   Delay 100 mS
   Zähler um eins erhöhen.

   Wenn der Zähler gleich der "Quietsch-Zeit" (in 100 mS-Einheiten) ist
      "Quietsch-Ausgang" deaktivieren

   Wenn Zähler gleich der "Stumm-Zeit" (in 100 mS-Einheiten)
   incl. "Quietsch-Zeit" ist (kannst sicherheitshalber auch größer oder
   gleich abfragen)
      "Quietsch-Ausgang" aktivieren
      Zähler auf Null setzen

   ... Deine Schalter-Abfragen ...

Schleife Ende

von Karl H. (kbuchegg)


Lesenswert?

Adrian schrieb:

> so hab ich das aus den zeilen heraus verstanden.

Die Zeilen sollten aber eher so etwas suggerieren
1
  while( 1 )
2
  {
3
    // erst mal brauchen wir eine Variable die bis 600 zählt.
4
    // 600 deshalb, weil wir 30 Sekunden Ruhe haben wollen und 30 Sekunden
5
    // gepiepse. D.h. nach 60 Sekunden (30 + 30), oder eben 600 mal
6
    // 100 Millisekunden wiederholt sich alles wieder.
7
8
    time++;
9
    if( time == 600 )
10
      time = 0;
11
12
    // nachdem das jetzt klar ist, ist auch klar, dass der Sender
13
    // eingeschaltet sein soll, wenn
14
    // a) die time Variable kleiner als 300 ist, denn dann befinden
15
    //    wir uns in den ersten 30 Sekunden dieses 60 Sekunden Zykluses
16
    // b) der externe Schalter so steht, dass vom Benutzer aus die
17
    //    Freigabe für das Gequietsche gegeben wurde
18
    //
19
    // wenn keins der beiden der Fall ist, dann soll sich auch nichts tun
20
21
    if( (PINB & (1<<PB3)) && time < 300 )
22
      TCCR1 |= (1<<CS12);
23
    else
24
      TCCR1 &= ~(1<<CS12);
25
26
    _delay_ms( 100 );
27
  }

Das hat natürlich den Nachteil, dass die Schaltung nach dem Betätigen 
des Schalters nicht sofort loslegt, sondern je nachdem auf welchem Wert 
der time-Zähler gerade steht eine Pause bis hinauf zu 30 Sekunden 
eingelegt wird. Da du das aber sowieso nicht hörst, spielt das aber IMHO 
eine eher untergeordnete Rolle.

Eine Einschalt-Kontrol LED kann man auch noch einbauen ....
1
    if( PINB & (1<<PB3) )    // grundsätzlich ist eingeschaltet
2
    {
3
      PORTB |= (1<<PB2);     // --> daher erst mal: LED an
4
5
      if( time < 300 )       // ob tatsächlich gedudelt wird, entscheidet die Zeit
6
        TCCR1 |= (1<<CS12);  // erste 30 Sekunden: ein
7
      else
8
        TCCR1 &= ~(1<<CS12); // zweite 30 Sekunden (eigentlich: die restliche Zeit): aus
9
    }
10
    else
11
    {                        // Nope. Da ist nichts eingeschaltet
12
      PORTB &= ~(1<<PB2);
13
      TCCR1 &= ~(1<<CS12);
14
    }
...
die natürlich sofort mit Betätigung des Schalters kommt.

PS. Für andere zeitliche Verteilungen müssen dann natürlich die Zahlen 
angepasst werden.

: Bearbeitet durch User
von proxyuser (Gast)


Lesenswert?

ihr wollt einen FUNKTIONIERENDEN Marderschreck? dann schicke ich euch 
ein bild und die unterwäsche von meiner nachbarin... da läuft ALLES 
freiwillig weg.......

von Karl H. (kbuchegg)


Lesenswert?

Gibt es eigentlich einen Grund dafür, warum du bei jedem einzelnen 
Posting immer eine Source Code Formatierung unter aller Sau hast?
Dabei bemüh ich mich immer, schönen Code herzuzeigen, in der Hoffnung, 
dass du siehst, um wieviel leichter vernünftig eingerückter Code, bei 
dem nicht alles in einer Wurscht dahin geschrieben ist, zu verstehen ist 
und dann auch ein wenig davon übernimmst.

von Adrian (Gast)


Lesenswert?

Entschuldigung daran werde ich jetzt arbeiten und versuchen es zu 
berücksichtigen:(

von Adrian (Gast)


Lesenswert?

Eine kleine Sache die ich nicht verstehe. Soweit funktioniert meine 
Software aber nur wenn ich am pin wo der schalter angeschlossen wird im 
Programm sage er soll low oder high werden.

Wenn er high ist führt er seinen Aufgabe aus also es kommt am ausgang 
was raus. Wenn er low eingestellt ist ist der Ausgang auf dauer high und 
nicht low.
Habs mit PORTB &=~(1<<PB0) versucht in der else Funktion wenn Pin3 nicht 
high ist aber bleibt tdem auf High.

Wenn ich das jetzt auf meine Schaltung übertrage und den Schalter 
verbinde dann ist die ganze zeit der Ausgang auf high. den Schalter habe 
ich von PB0 (High ganze zeit) auf pb3 verbunden. Und von Pb3 verläut ein 
pulldown widerstand zu Gnd.

Hoffe ihr habt vll eine idee woran es liegen kann?

von Karl H. (kbuchegg)


Lesenswert?

Adrian schrieb:

> was raus. Wenn er low eingestellt ist ist der Ausgang auf dauer high und
> nicht low.
> Habs mit PORTB &=~(1<<PB0) versucht in der else Funktion wenn Pin3 nicht
> high ist aber bleibt tdem auf High.

Solange der Pin an den Timer gekoppelt ist, ist er deinem direkten 
Einfluss entzogen.
Genau hier kommt jetzt der letzte Absatz meines Postings vom 13.5. 15:07 
ins Spiel, wonach man den Pin durch setzen des Duty Cycles auf Minimum 
bzw. Maximum auf Dauer-High bzw. Dauer-Low zwingen kann. Siehe 
Datenblatt

> verbinde dann ist die ganze zeit der Ausgang auf high. den Schalter habe
> ich von PB0 (High ganze zeit) auf pb3 verbunden. Und von Pb3 verläut ein
> pulldown widerstand zu Gnd.

?
Aus dem werde ich nicht schlau.
Was hast du mit wem verdunden?
Die Sprache des Elektronikers ist ein Schaltplan.

von Adrian (Gast)


Lesenswert?

Am PB3 habe ich ein ein widerstand nach Masse gelötet und zwischen Pb3 
und Pb0 ist ein Schalter verbunden. PB0 ist dauerhaft auf High 
beschaltet so dass wenn der Schalter geschlossen wird am Pb3 ein high 
signal gibt und wenn er schlossen ist soll er ein low signal haben.

von Adrian (Gast)


Lesenswert?

oder?

Karl Heinz schrieb:
> Adrian schrieb:
>
>> was raus. Wenn er low eingestellt ist ist der Ausgang auf dauer high und
>> nicht low.
>> Habs mit PORTB &=~(1<<PB0) versucht in der else Funktion wenn Pin3 nicht
>> high ist aber bleibt tdem auf High.
>
> Solange der Pin an den Timer gekoppelt ist, ist er deinem direkten
> Einfluss entzogen.
> Genau hier kommt jetzt der letzte Absatz meines Postings vom 13.5. 15:07
> ins Spiel, wonach man den Pin durch setzen des Duty Cycles auf Minimum
> bzw. Maximum auf Dauer-High bzw. Dauer-Low zwingen kann. Siehe
> Datenblatt


Auf Seite 87 finde ich eine Tabelle dazu indem ich die COM-Bit vom Timer 
einstellen muss damit ich mein Dauer-Low erzwingen kann. ich hab im 
TCCR1 Register COm1A1 bit 0 und Com1A0 bit 1 gegeben. Daraus folgt dass 
mein Output nun L sein sollte.

Aber die Zeilen verstehe ich dann nach nicht mehr so ganz

In PWM mode, the Timer Overflow Flag - TOV1 is set when the TCNT1 counts 
to the OCR1C value and the
TCNT1 is reset to $00. The Timer Overflow Interrupt1 is
executed when TOV1 is set
provided that Timer Overflow
Interrupt and global interrupts are enabled. This also app
lies to the Timer Output Compare flags and interrupts.
The PWM frequency can be derived from the timer/coun
ter clock frequency using the following equation:

Muss ich im Register TIFR das bit TOV1 und im Register TCNT1 das bit 
OCRIC beides setzen? Mehr zu duty cycles finde ich dazu nicht mehr

von Adrian (Gast)


Lesenswert?

> Muss ich im Register TIFR das bit TOV1 und im Register TCNT1 das bit
> OCRIC beides setzen? Mehr zu duty cycles finde ich dazu nicht mehr

Hatte einen kleinen Denkfehler

Wenn ich das so wie folgt einstelle
void  Timer1(){

  TCCR1 |=(1<<PWM1A)|(1<<COM1A1)|(1<<COM1A0)|(1<<CS12);

  OCR1C = maxpwm;
  OCR1A = dutypwm;
  TCNT1 |=(OCR1A);
  //OCR1A=80;  //Impulsbreite ändern

  TIFR |=(1<<TOV1);
  TIMSK |=(1<<OCIE1A);

  }

funktioniert es. Bekomme am Ausgang dauerhaft low Signal

von Adrian (Gast)


Lesenswert?

Ist es eigentlich nicht sinnvoll die Ausschaltzeit mit einem Timer 0 zu 
programmieren weil da der attiny genauer zählt als wenn ich das mit 
einem delay machen würde?

von Karl H. (kbuchegg)


Lesenswert?

Adrian schrieb:
> Ist es eigentlich nicht sinnvoll die Ausschaltzeit mit einem Timer 0 zu
> programmieren weil da der attiny genauer zählt als wenn ich das mit
> einem delay machen würde?

im allgemeinen: ja, natürlich.
im speziellen: ich denke, dein Marder wird nicht mit der Stoppuhr beim 
Auto stehen und den Kopf schütteln, wenn die 30 Sekunden um eine halbe 
Millisekunde zu lang sind.

von Adrian (Gast)


Angehängte Dateien:

Lesenswert?

> im allgemeinen: ja, natürlich.
ich bin gerade mal am ausprobieren und versuche es mit dem timer0 zu 
machen aber er kommt irgendwie nicht in der isr richtig rein. Habe ich 
hier was falsch gemacht?

von Karl H. (kbuchegg)


Lesenswert?

Humpf

Von vorne
1
void Timer0_setup (){
2
  //GTCCR |=(1<<TSM);
3
  
4
  //TCCR0A |=(0<<COM1A0)|(0<<COM1A1);
5
  TCCR0B |=(1<<CS01);
6
  
7
  TCNT0 |=(1<OCR0A);
8
9
  OCR0A = dutypwm;
10
11
  
12
  TIMSK |=(1<< OCIE0A);
13
  TIFR |=(1<<OCF0A);
14
  
15
}

du lässt dich da viel zu sehr von der Timer 1 initialisierung leiten. 
Mach das nicht. Überleg lieber: was will ich eigentlich.

ICh will letzten Endes, das eine bestimmte Funktion regelmässig vom 
Timer aufgerufen wird. Nicht mehr und nicht weniger. Sagen wir mal, dass 
die Zeit nicht auf den Taktzyklus genau sein muss. Denn dann kann man 
überlegen, ob man rein mit dem Timerumfang (8 Bit bzw. 16 Bit) und dem 
Vorteiler zum Ziel kommt.
Nehmen wir mal an, das geht tatsächlich. IN dem Fall hänge ich mich 
einfach an den Overflow Interrupt des Timers und gut ists.

Also: Ich brauch einen Timer, ohne Sonderspompanadeln, der einfach nur 
vor sich hinzählt und jedesmal wenn er den Überlauf 255 auf 0 hat (weil 
es ein 8 Bit Timer ist) soll eine Funktion (der Overflow-ISR) aufgerufen 
werden.

Also: das simpelste vom simplen
1
  TCCR0B |=(1<<CS01);
soweit klar. Der Timer braucht einen Vorteiler, sonst läuft er nicht.
1
  TCNT0 |=(1<OCR0A);
unsinnig. TCNTx ist immer das Zählregister. D.h. dort drinnen zählt der 
Timer. Dem brauch ich nichts zuweisen, den sobald der Timer einen 
Vorteiler hat, wird TNCTx hochgezählt.
1
  OCR0A = dutypwm;
OCR0A? Wozu brauch ich ein COmpare Register. Ich will doch einfach nur 
beim Wechsel des Zählerstandes von 255 auf 0 einen Overflow-Interrupt 
haben. Kein Mensch braucht dazu einen Compare Match.
dutypwm? was hat dutypwm da jetzt drinn verloren? Hier geht es doch gar 
nicht um eine PWM!
1
  TIMSK |=(1<< OCIE0A);
Nope. Overflow! Nicht Compare Match
1
  TIFR |=(1<<OCF0A);
abgesehen davon, dass es sich hier nicht um eine Compare Match Anwendung 
handelt: Man kann das Interrupt Flag löschen, muss es aber nicht 
wirklich tun. Den einen überflüssigen Interrupt ganz am Anfang wird man 
verschmerzen, sollte er wirklich auftreten.

1
ISR(TIM0_COMPA_vect){
2
  uint8_t time= 0;
3
     time++;
4
5
     if( time ==10 )
6
    {
7
8
    time = 0;
9
10
    if (time == 0)
11
12
    {
13
      TCCR1 &= ~(1<<CS12);
14
      _delay_ms(100);
15
   }
16
  }
17
  else
18
  TCCR1 |= (1<<CS12);
19
}

LASS DEN TIMER IN DER ISR IN RUHE!
Du brauchst ihm keinen Vorteiler setzen, du brauchst den Vorteiler nicht 
löschen, du willst vor allen Dingen keinen delay in der ISR (das war 
doch eigentlich der Sinn und Zweck der ganzen Übung - die delays los zu 
werden). Die ISR soll einfach nur die Zeit zählen
1
ISR( .... Timer Overflow )
2
{
3
  time++;
4
  if( time == 600 )   // oder was auch immer den 60 Sekunden entspricht
5
    time = 0;
6
}


FAQ: Timer

Du musst dich entscheiden:
entweder du schaltest den PWM-Timer (Timer1) in der ISR ODER du 
schaltest den in der Hauptschleife. Möglich ist beides. Aber nicht 
beides in einem Programm. Entweder so oder so.
Was spricht dagegen, die Zeitauswertung in der Hauptschleife zu machen. 
Funktioniert doch wunderbar
1
...
2
    while(1){
3
4
      if (time < 300)
5
        TCCR1 &= ~(1<<CS12);
6
      else
7
        TCCR1 |= (1<<CS12);
8
    }


man kann das alles natürlich noch in die ISR verlagern
1
ISR( .... Timer Overflow )
2
{
3
  time++;
4
5
  if( time == 600 )   // oder was auch immer den 60 Sekunden entspricht
6
    time = 0;
7
8
9
  if (time < 30)
10
    TCCR1 &= ~(1<<CS12);
11
  else
12
    TCCR1 |= (1<<CS12);
13
}

dann ist die Hauptschleife leer
1
int main()
2
{
3
  ...
4
5
    while(1){
6
    }

aber so wie es vorher war, ist es auch gut.

: Bearbeitet durch User
von Adrian (Gast)


Angehängte Dateien:

Lesenswert?

Wenn ich es so mache oder wie oben bekomme ich aufeinmal am ausgang 
nichts mehr raus sondern nur ein dauerhaftes low.

Jetzt funktioniert aufeinmal der Time1 nicht mehr.

von Karl H. (kbuchegg)


Lesenswert?

Das hier

>
>
1
> ISR (TIM1_COMPA_vect){
2
>

hätte eine Compilerwarnung geben müssen. Die Schreibweise ist falsch.

von Adrian (Gast)


Lesenswert?

hatte ich auch geändert... immer noch kein signal

von Adrian (Gast)


Angehängte Dateien:

Lesenswert?

ich verstehe gerade mein projekt ernsthaft nicht ich hab ein neues 
projekt erstellt und das nochmal drauf gemacht jetzt bekomme ich nur 
durchgehend die gleiche frequenz raus. Aber jetzt bewegt sich gar nichts 
mehr -.-

von Karl H. (kbuchegg)


Lesenswert?

1
  TIMSK |=(1<<TOIE0);
2
  
3
...
4
5
ISR(TIMER0_COMPA_vect){


Overflow freigegeben, Compare Match INterrupt installiert.

zweiteres wäre noch nicht so schlimm, aber ersteres ist schlimm. Ein 
freigegebener INterrupt für den es keine ISR gibt, führt zu einem 
Prozessor-Reset


Ich schätze, die Lektion die du gerade lernst lautet: Codequalität 
spiegelt sich nicht nur in der Funktion des Codes wieder sondern auch in 
der optischen Qualität bzw. wie man seinen Code organisiert. In einem 
gut organisiertem Code ist es leicht Fehler zu finden. In einem schlecht 
organisiertem Code ist es dagegen der reinste Horror. Überhaupt dann, 
wenn man keine oder kaum Übung darin hat, sich auch im schlimmsten Chaos 
zurecht zu finden.


Lass die Dinge thematisch beisammen!
ALles was zum Timer 0 gehört an einem Ort. Alles was zum Timer 1 gehört 
an einem Ort. Die ISR alle an einem Platrz zu sammelnb ist nur dann 
sinnvoll, wenn sie thematisch auch zusammengehören. Das tun sie in 
deinem Fall nicht. In deinem Fall ist der Zusammenhang zwischen Setup 
eines Timers und seinen ISR der wichtigere Zusammenhang.
1
void Timer0_setup ()
2
{
3
  TCCR0B |= (1<<CS01);
4
  TIMSK |= (1<<TOIE0);
5
}
6
7
ISR(TIMER0_OVF_vect)
8
{
9
  time++;
10
11
  if( time == 600 )   // oder was auch immer den 60 Sekunden entspricht
12
    time = 0;
13
}

Hier kann man leicht kontrollieren, ob die Konfiguration des Timers zum 
restlichen Timer Code (zb zu den ISR) passt. Es gibt keinen Grund, diese 
"Einheit" über Bord zu werfen. Es gibt aber viele Gründe das nicht zu 
tun. Die Verwendung des TOIE0 Bits im Register TIMSK erzwingt einen ISR 
Namen. Und den möchte ich finden und kontrollieren können, ohne mich zu 
Tode zu scrollen.


Das nächste was du lernen musst: Das exzessiv eingestreute Leerzeilen 
den Code einfach nur in die Länge ziehen. Sie erhöhen aber nicht die 
Übersicht. Das Gegenteil ist der Fall.

: Bearbeitet durch User
von Adrian (Gast)


Lesenswert?

ich musste das Timsk register vom Timer0 in
             TIMSK |=(1<<OCIE1A); umändern dann bekomme ich wieder meine 
frequenz raus leider zwischen 18 und 35khz?

von Adrian (Gast)


Lesenswert?

es regiert jedoch nicht auf meine beiden abfrage sofort und jetzt den 
Ausgang wieder auf high anstatt auf low?

von Adrian (Gast)


Angehängte Dateien:

Lesenswert?

sorry für meine unendlichlangen post aber ich glaube dass das letze mal 
dass ich jetzt mein kompletten quelltext rein machen werde. Sollte nur 
als Kontrolle dienen. Hab mein Programm überarbeitet hoffe das kommt dem 
was du mir oben schrieben hast endlich mal nahe. Kann es leider erst 
morgen test. Würde mich freuen wenn du mal ein kleinen Blick drüber 
werfen würdest. Hab es diesmal überall alles kommentiert.

von Walter (Gast)


Lesenswert?

wenn du Variablen hast die im Interrupt UND im Hauptprogramm verwendet 
werden solltest Du dich mal über volatile informieren

von Adrian (Gast)


Lesenswert?

Vielen dank funktioniert alles Wunderbar

von Adrian (Gast)


Lesenswert?

Kann ich beim attiny25 auch unter 20khz gehen z.b ich möchte nur 10khz 
eingestellt haben? Im Datenblatt finde ich nur eine Tabelle mit 
verschiednen Frequenzen die aber bei 20khz beginnen?

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.