Forum: Mikrocontroller und Digitale Elektronik Modulation IR Signal - Interrupt oder Warteschleife?


von Mike (Gast)


Lesenswert?

Hallo zusammen,

ich möchte mit C auf dem ATtiny2313 ein IR-Signal (NEC) erzeugen. 
Folgenden Ansatz hab ich mir überlegt (bzw. aus diversen Forenbeiträgen 
etc. zusammengesucht):

- Frequenz von 38 kHz würde ich über PWM generieren. Muss/soll ich einen 
externen Quarz benutzen, um die notwendige Genauigkeit zu erreichen? 
Welcher ist zu empfehlen?

- Puls- und Pausephasen würde ich über einen Counter mit Prescaler 256 
terminieren. Bei Erreichen des Compare-Wertes dann PWM aktivieren (Puls) 
bzw. deaktivieren (Pause). Dazu sehe ich zwei Möglichkeiten:

--> Interrupt bei Erreichen Compare-Wert: Kann ich da einfach den 
Compare-Wert setzen, den Timer starten und dann in den Sleep-Modus, um 
das Programm "anzuhalten"? Oder entstehen bei Beginn sleep() und 
Unterbrechung durch Interrupt zu lange oder "ungenaue" Verzögerungen?

--> Warteschleife: Timer auf 0, Timer starten und dann Schleife, bis 
Counter = Anzahl Counts der entsprechenden Puls-/Pausephase

Die erste Möglichkeit fände ich etwas eleganter - aber funzt das? Was 
würdet Ihr empfehlen? Oder sind beide Ansätze "Quatsch" und es gibt 
einen besseren Weg?

VG Mike

von Falk B. (falk)


Lesenswert?

@  Mike (Gast)

>- Frequenz von 38 kHz würde ich über PWM generieren.

genau.

> Muss/soll ich einen
>externen Quarz benutzen, um die notwendige Genauigkeit zu erreichen?

Nein.

>- Puls- und Pausephasen würde ich über einen Counter mit Prescaler 256
>terminieren.

Geht viel einfacher. Über den OIverflow Interrupt des Vounter, der auch 
die PWM macht. Dann kann man sogar exakte Pulseanzahlen generieren.

>--> Interrupt bei Erreichen Compare-Wert: Kann ich da einfach den
>Compare-Wert setzen, den Timer starten und dann in den Sleep-Modus, um
>das Programm "anzuhalten"?

Warum?

> Oder entstehen bei Beginn sleep() und
>Unterbrechung durch Interrupt zu lange oder "ungenaue" Verzögerungen?

???

>--> Warteschleife: Timer auf 0, Timer starten und dann Schleife, bis
>Counter = Anzahl Counts der entsprechenden Puls-/Pausephase

Nein. Siehe Interrupt und Multitasking.

von Mike (Gast)


Lesenswert?

@Falk: Danke! Damit ich es richtig verstanden habe:

Also ich nutze einen einzelnen Timer abwechselnd im PWM-Modus (Puls) und 
im Normal-Zähl-Modus (Pause) und setze den Compare auf die jeweilige 
Anzahl der Flanken (nennt man das so?)? Also z. B. bei Startbit von 9000 
us setze ich den Compare auf 342 = 9.000 * 38.000 / 1.000.000?

Nach Setzen und Starten des Timers mach ich dann sleep(), damit das 
Programm auf den Interrupt wartet, und setze nach Rückkehr aus Interrupt 
den Timer (Modus und Compare-Wert) für das nächste Halbbit (Puls bzw. 
Pause)... usw.

Müsste gehen, oder?

VG Mike

von Falk B. (falk)


Lesenswert?

@  Mike (Gast)

>Also ich nutze einen einzelnen Timer abwechselnd im PWM-Modus (Puls) und
>im Normal-Zähl-Modus (Pause)

Nein, immer PWM. Die kann man ja zu Pin hin abschalten, mit den COMxy 
Bits. Der Zähler läuft immer durch, dadurch hat man eine Zeitbasis.

> und setze den Compare auf die jeweilige
>Anzahl der Flanken (nennt man das so?)?

Nein. Du zählst in der ISR die Anzahl Pulse, die gesendet werden sollen 
bzw. Pause sein soll.

>Müsste gehen, oder?

Naja, etwas aufgeräumter. Lies die Artikel und denk drüber nach.

von Falk B. (falk)


Lesenswert?

Man kann auch zwei Timer nehmen, wenn einem die 38 kHz Interruptfrequenz 
zuviel sind.

von Mike (Gast)


Lesenswert?

Danke, verstehe es (hoffentlich) langsam - Artikel hab ich gelesen und 
nochmal drüber nachgedacht :-) als Einsteiger fällt mir nur die Anwenung 
der Theorie auf's eigene Problem manchmal etwas schwer - also würde es 
dann so angehen:

- Phasenkorrekter PWM (damit An/Aus der IR LED gleich lange sind) mit 
Presclaler und Compare-Wert so, dass 38 kHz erzeugt werden - 
automatischer Toogle des Pin und Interrupt bei Compare Match geht beides 
"parallel", oder muss ich Pin in der ISR "manuell" umschalten?

- Hauptprogramm: Schleife über 32 Datenbits des NEC Befehls, pro 
Darenbit dann:
--> PWM an LED Pin für Pulsphase, an unbenutzten Pin für Pausephase
--> Variable für gewünschte Gesamtzahl der Pulse setzen
--> in ISR Anzahl der Pulse hochzählen
--> In Hauptprogramm warten, bis Anzahl Pulse = gewünchte Gesamtzahl
--> nächstes (Halb)Bit senden

Anmerkung: Während Senden müssen keine sonstigen Programmaktivitäten 
durchgeführt werden - dann ist die hohe Interruptfrequenz kein Problem, 
oder?

VG Mike

von Karl H. (kbuchegg)


Lesenswert?

Mike schrieb:

> - Phasenkorrekter PWM (damit An/Aus der IR LED gleich lange sind) mit
> Presclaler und Compare-Wert so, dass 38 kHz erzeugt werden -
> automatischer Toogle des Pin und Interrupt bei Compare Match geht beides
> "parallel", oder muss ich Pin in der ISR "manuell" umschalten?

Was habt ihr nur immer mit der Phasen korrekten PWM. Ist die sowas wie 
selig machend? Oder klingt die nur einfach gut? So von wegen "correct 
ist immer gut"

Fast-PWM mit Vorgabe des Top-Wertes
Den Compare Wert der PWM wird auf die Hälfte eingestellt.
Zusätzlich wird an diesen Compare Wert eine ISR geklemmt,
In der ISR wird ein SOftware-Zähler runtergezählt. Ist der bei 0 
angelengt, dann koppelt er mittels COM Bits die LED vom Timer weg und 
schaltet sie aus.

Hauptprogramm
Für jedes Bit
   ist es 1 (LED soll also leuchten)
       Mittels COM Bits die LED an den Timer koppeln
       LED einschalten

   Verzögerungszeit in den Softwarezähler schreiben
   warten bis der Softwarezähler auf 0 gefallen ist


> Anmerkung: Während Senden müssen keine sonstigen Programmaktivitäten
> durchgeführt werden - dann ist die hohe Interruptfrequenz kein Problem,
> oder?

Die ist sowieso kein Problem. IR-Übertragung ist doch keine 
Uhrmacher-Arbeit. Da gibt es Toleranzen. Die 38kHz sollten einigermassen 
genau passen (wegen dem optischen Filter vom Empfänger) aber in den 
Pulsen bzw. Pausen hast du genügend Toleranzen.

von Toralf W. (willi)


Lesenswert?

Mike schrieb:
> - Phasenkorrekter PWM (damit An/Aus der IR LED gleich lange sind) mit
> Presclaler und Compare-Wert so, dass 38 kHz erzeugt werden -
> automatischer Toogle des Pin und Interrupt bei Compare Match geht beides
> "parallel", oder muss ich Pin in der ISR "manuell" umschalten?

Wie Karl Heinz schon bemerkte, ist das nicht notwendig. Im Gegenteil, 
ich denke der Empfänger wird ein TSOP sein und die erlauben 
Tastverhältnisse von unter 20%. Das hat den Vorteil, das man die IR 
Diode mit einem höheren Strom senden lassen kann, was die Reichweite 
deutlich verbessert.

Gruß Willi

von Michael (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Die 38kHz sollten einigermassen genau passen (wegen dem optischen Filter
> vom Empfänger)

Was haben denn die 38kHz mit dem optischen Filter zu tun?

Zu dem optischen Filter muss die Wellenlänge der IR-LED passen. Bei 
einem TSOP31238 hat der Filter eine FWHM-Breite von etwa 180nm (im 
Datenblatt Fig. 10 - Sensitivity vs. Ambient Temperature).

Die 38kHz der IR-LED müssen zu der Mittenfrequenz des elektrischen 
Bandpassfilters im Empfänger passen. Die Bandbreite beträgt beim 
TSOP31238 z.B. Δf(3dB)=f0/10 (Fig. 5 - Frequency Dependence of 
Responsivity)

von Michael (Gast)


Lesenswert?

Michael schrieb:
> Fig. 10 - Sensitivity vs. Ambient Temperature

Sorry, Fig. 11 - Relative Spectral Sensitivity vs. Wavelength

von Karl H. (kbuchegg)


Lesenswert?

Michael schrieb:
> Karl Heinz Buchegger schrieb:
>> Die 38kHz sollten einigermassen genau passen (wegen dem optischen Filter
>> vom Empfänger)
>
> Was haben denn die 38kHz mit dem optischen Filter zu tun?
>
> Zu dem optischen Filter muss die Wellenlänge der IR-LED passen.

Autsch.
Ja, hast recht. Da hab ich nicht gut genug nachgedacht.
Ich brauch einen Kaffee.

von Mike (Gast)


Angehängte Dateien:

Lesenswert?

Ich habe einen ersten Testaufbau gemacht (siehe Foto). Links ist der 
Sender, rechts der Empfänger - wenn das IR-Signal blockiert wird, geht 
die blaue LED an (also eine Art Lichtschranke).

Hier der Code des Senders:

<c>int main(void)
{
  // PB0 und PB1 als Ausgang
  DDRB = (1<<PB0);

  // OC0A --> PIN PB0
  OCR0A = 8; // Dauer der Low-/High-Phase

  // PWM Modus konfigurieren
  TCCR0A = (1<<COM0A0) | (1<<WGM00);

  // T/C-Vorteiler = Clock
  TCCR0B = (1<<WGM02) | (1<<CS00);

  while(1)
  {}
}</c>

Und hier der Code des Empfängers:

<c>int main(void)
{
  // PB0 als Ausgang (blaue LED)
  DDRB = (1<<PB0);

  // PB1 als Eingang (IR LED)
  PORTB = (1<<PB1);

  while(1)
  {
    if (!(PINB & (1<<PB1))) // IR Signal empfangen
    {
      // blaue LED aus
      PORTB = (1<<PB1) | (1<<PB0);
    }
    else
    {
      // blaue LED an
      PORTB = (1<<PB1);
    }
  }
}</c>

Als erster Test funktioniert das soweit, aber ein paar Verstädnisfragen:

- Aktuell nutze ich phasenkorrekten PWM mit Vorteiler = 0 und Compare 
Wert = 8. Prozessortakt sollte 9,6 MHz sein, wobei bei den Fuses noch 
ein Flag "Divide clock by 8 internally" gesetzt ist. Es funktioniert, 
aber wie/warum komme ich auf die (annähernd) richtige Frequenz von 40kHz 
des IR-Empfängers?? Eine Messung ergibt übrigens 68kHz? Es geht, aber 
ich verstehs nicht....

- Wie mach ich das über Fast PWM genau?

Karl Heinz Buchegger schrieb:
> Fast-PWM mit Vorgabe des Top-Wertes
>
> Den Compare Wert der PWM wird auf die Hälfte eingestellt.
>
> Zusätzlich wird an diesen Compare Wert eine ISR geklemmt,
>
> In der ISR wird ein SOftware-Zähler runtergezählt.

Der TOP-Wert kommt doch in OCR0A (oder eben alternativ 0xFF). Aber ist 
das nicht auch der Compare-Wert? Mein Verständnisproblem ist wohl, wie 
ich den Top-Wert und den Compare-Wert getrennt setzen kann (Compare-Wert 
= 0,5 Top-Wert).

Den Rest über die ISR hab ich soweit verstanden, hoffe ich. Werde mal 
ans Programmieren gehen...

Karl Heinz Buchegger schrieb:
> Die 38kHz sollten einigermassen
>
> genau passen (wegen dem optischen Filter vom Empfänger) aber in den
>
> Pulsen bzw. Pausen hast du genügend Toleranzen.

Da ich den Empfänger auch selbst programmieren möchte, habe ich die 
Toleranzen eh in der Hand, oder? Anbei ein allererster, ungetesteter 
Code-Entwurf für die Entschlüsselung des NEC-Signals (habe da 20% 
Toleranz für die Phasenlängen versucht einzubauen) --> Interrupt bei 
Änderung am Eingangsport, dann Counter hochzählen und die einzelnen 
Status des Signals (Startbit, Datenbit, Endebit) durchlaufen - so 
zumindest die Theorie...

Karl Heinz Buchegger schrieb:
> Für jedes Bit
>
>    ist es 1 (LED soll also leuchten)
>
>        Mittels COM Bits die LED an den Timer koppeln
>
>        LED einschalten

Beim NEC-Signal sind m. W. Pulslänge bei 0- und 1-Bit gleich. Auf den 
Puls folgt bei 0-Bit eine kurze Pause, bei 1-Bit eine lange Pause - aber 
ändert ja nichts am Prinzip. "mittels COM Bits LED an Timer koppeln" 
heißt, TCCR0A = (1<<COM0A0), oder? Und zum Entkoppeln dieses Bit 
löschen, richtig?

Nochmal vielen Dank an alle! Ich geh jetzt an die Arbeit, könnte also im 
Laufe der Nacht noch die ein oder andere Frage kommen :-)

VG Mike

von Michael (Gast)


Lesenswert?

Mike schrieb:
> Da ich den Empfänger auch selbst programmieren möchte, habe ich die
> Toleranzen eh in der Hand, oder?

Wenn du als Detektor auf der Empfängerseite irgendetwas in Richtung 
TSOP31238 verwendest, was einem wegen der Umgebungslichtunterdrückung 
das Leben sehr vereinfacht, hat der µC mit den 38kHz gar nichts mehr zu 
tun. Da kommen das Signal schon ohne die Trägerfrequenz raus.

von Mike (Gast)


Lesenswert?

@ Michael: Ja, ich verwende einen TSOPxxx mit 40 kHz. Aber auf der 
Senderseite müsste ich ja annähernd auch auf die 40kHz kommen - komme 
ich aber weder rechnerisch (9,6 MHz  8  (2*8)??)

--> 8 wegen "Divide clock by 8 internally"
--> 2*8 wegen Rauf- und Runterzählen bis Compare-Wert = 8
--> da komme ich auf 75 kHz

noch gemäß Test mit Messgerät (~ 68 kHz)

Wenn ich Compare-Wert erhöhe (um Frequenz zu verringern), reagiert die 
LED (bei Unterbrechung der "Lichtschranke") nicht mehr. Und das versteh 
ich noch nicht ganz....

Empfängerseite ist mir klar, dass der TSOP die "Frequenz" bereits im 
Bauch hat. Ich hatte was gelesen, dass der TSOP ein invertiertes Signal 
ausgibt --> heißt das, wenn IR empfangen wird, ist Eingang am Pin (TSOP 
OUT) low - und umgekehrt?

von Mike (Gast)


Lesenswert?

Ich habe versucht, den von Euch vorgeschlagenen Ansatz (Zähler in ISR 
hochzählen, in Hauptprogramm LED an PIN koppeln bzw. entkoppeln bei 
Erreichen Schwellenwert) in ein kleines Programm umzusetzen:

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

volatile long int interrupt_count;

int main(void)
{
  // Flag zum Toogeln der IR LED
  unsigned char led_an_aus;

  // PB0 als Ausgang --> Anschluss IR LED
  DDRB = (1<<PB0);

  // OC0A --> PIN PB0 mit PWM
  OCR0A = 8; // Dauer der Low-/High-Phase

  // PWM Modus konfigurieren
  TCCR0A = (1<<COM0A0) | (1<<WGM00);

  // T/C-Vorteiler = Clock
  TCCR0B = (1<<WGM02) | (1<<CS00);

  // Interrupt bei T/C Compare Match
  TIMSK0 = (1<<OCIE0A);
  sei();

  while(1)
  {
    // IR LED zwischen Puls und Pause umschalten
    if (interrupt_count > 50000)
    {
      interrupt_count = 0;

      if (led_an_aus == 0)
      {
        TCCR0A = (1<<COM0A0) | (1<<WGM00); // LED an Timer koppeln
        led_an_aus = 1;
      }
      else
      {
        PORTB = (1<<PB0); // LED aus
        TCCR0A = (1<<WGM00); // LED vom Timer entkoppeln
        led_an_aus = 0;
      }

    }
  }
}

ISR(TIM0_COMPA_vect)
{
  interrupt_count++; // Interrupts zählen
}</c>

Allerdings sendet die IR LED ununterbrochen weiter... ich hätte 
erwartet, dass es zu einem Umschalten etwa jede Sekunde käme...

Habt jemand eine Idee, wo der Fehler ist?

von Mike (Gast)


Lesenswert?

HIIILLFEE --- i werd verrückt... jetzt check ich's gar nicht mehr.

Habe das Programm leicht modifiziert:

- Umstellung auf Fast PWM
- initial IR LED nicht an Timer hängen

Erwartetes Verhalten:

- Wechsel IR-Signal an/aus etwa im Sekundentakt

Tatsächliches Verhalten:

- IR-Signal zunächst ca. 1-2 Sekunden aus
- dann IR-Signal an --> aber bleibt dann auch "für immer" an, d. h. wird 
nicht mehr um-/ausgeschaltet

Es sieht so aus, als würde die Kopplung der IR LED an PWM über 
(1<<COM0A0) das Interruptverhalten verändern bzw. der Interrupt wird 
nicht mehr ausgeführt(???)

Ihr seid sicher, dass das Umschalten des PIN über PWM und Auslösen des 
Interrupts parallel gehen, oder?! Wo ist dann bloß der Fehler 
(wahrscheinlich ne dumme Sache, aber ich find's einfch nicht)... stöhn

Hier der aktualisierte Code:

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

volatile long int interrupt_count;

int main(void)
{
  // Flag zum Toogeln der IR LED
  unsigned char led_an_aus;

  // PB0 als Ausgang --> Anschluss IR LED
  DDRB = (1<<PB0);

  // Compare-Wert setzen (Dauer der Low-/High-Phase)
  OCR0A = 14;

  // PWM Modus konfigurieren (mit LED am Timer)
  TCCR0A = (1<<WGM00) | (1<<WGM01);
  TCCR0B = (1<<WGM02) | (1<<CS00);

  // Interrupt bei T/C Compare Match
  TIMSK0 = (1<<OCIE0A);
  sei();

  while(1)
  {
    // IR LED zwischen Puls und Pause umschalten
    if (interrupt_count > 30000)
    {
      cli();
      interrupt_count = 0;

      if (led_an_aus == 0)
      {
        // PWM Modus konfigurieren (ohne LED am Timer)
        TCCR0A = (1<<WGM00) | (1<<WGM01);
        TCCR0B = (1<<WGM02) | (1<<CS00);

        PORTB = (1<<PB0); // LED aus
        led_an_aus = 1;
      }
      else
      {
        // PWM Modus konfigurieren (mit LED am Timer)
        TCCR0A = (1<<WGM00) | (1<<WGM01) | (1<<COM0A0);
        TCCR0B = (1<<WGM02) | (1<<CS00);

        led_an_aus = 0;
      }
      sei();
    }
  }
}

ISR(TIM0_COMPA_vect)
{
  interrupt_count++; // Interrupts zählen
}</c>

von Ulrich (Gast)


Lesenswert?

Eine kleine Unschönheit - nicht mal ein echter Fehler ist noch im 
Programm - der sollte aber nicht den beschriebenen Effekt haben:

Die abfrage
"if (interrupt_count > 30000)"
ist nicht davor geschützt das der Wert gerade in der ISR geändert wird. 
Da könnte es also passieren das High und Low Wert nicht zusammenpassen. 
Der Fehler sollte aber hier nur eine eventuell minimal falsche Zeit 
sein.
Später kann dann der Interruptcount wohl auf den Typ Char geändert 
werden, weil die Impulse eher so im Bereich 30 Zyklen des 40 kHz Signals 
sind. Dann hat man das Problem nicht mehr.


Das Problem wird sein, dass die ISR zum hochzählen einfach zu lange 
bracht. So wie es konfiguriert ist, kommt alle 14 Zyklen ein Aufruf der 
ISR. Das ist einfach zu schnell, selbst wenn nur ein Bytewert 
hochgezählt werden soll.
Man kann die Zahl der Interrupts noch auf die Hälfe reduzieren, indem 
man den Timer bis 28 Zählen läßt, und das Signal als echtes PWM Signal 
am Ausgang OCR0B zu erzeugt. Man hat denn ggf. auch die Wahl das ein/aus 
Verhältnis für die LED anders (kürzer) zu wählen. Auch dann wird es mit 
nur 28 Zyklen sehr knapp und bräuchte wohl ASM für die ISR, oder halt 
einen höheren Takt von z.B. 2 MHz.
Wenn man mag, könnte man den Zähler vom USI-Teil nutzen um die Überläufe 
von Timer0 zu zählen, aber der hat nur 4 Bit und wird eher auch nicht 
ganz ausreichen. Erst mit Zählen der USI Überläufe ginge es dann.

Die einfachere Lösung wäre da wohl wirklich den Timer1 für die Länge der 
Pulse und Pausen zu nutzen. Schließlich gibt es für ungenutzte HW kein 
Geld zurück.

von Mike (Gast)


Lesenswert?

Es geht jetzt :-) "Empfangs-LED" (zeigt an, ob IR sendet oder nicht) 
blinkt jetzt im Sekundentakt - was auch mit dem Interrupt-Counter 
zusammen passt.

Grund für das "unerklärliche" Verhalten war wohl - ich trau mich's gar 
nicht zu sagen - der fehlende Stützkondensator (allmählich kapier auch 
ich, dass der wohl kein "nice-to-have" ist...) mann oh mann, wieder viel 
Lehrgeld bezahlt

Hoffe mal, dass es mit dem eigentlichen Ziel (Codierung/Decodierung NEC 
Signal) dann weniger schmerzvoll geht :-)

Danke für Euren Support & GUTE NACHT
Mike

von Mike (Gast)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

ich habe nun ein kleines Programm geschrieben (siehe Anhang), das eine 
4-Byte-Sequenz über IR sendet. Das Ganze funktioniert auch soweit (die 
Dauer von Puls und Pause sind extra lange gewählt, damit ich auf der 
Empfängerseite "mit dem Auge" sehe, ob es prinzipiell funktioniert).

Nur ein komisches Phänomen habe ich:

Wenn ich das Stopbit kurz einstelle (z. B. 500 Counts Puls / 500 Counts 
Pause), sendet die IR LED danach ununterbrochen weiter - das letzte 
"Abhängen" der LED über COM0A0=0 scheint also nicht zu funktionieren. 
Wenn ich eine längere Dauer wähle (z. B. 50.000 Puls / 50.000 Pause) 
geht es einwandfrei, und die Diode sendet dann am Schluss nicht mehr.

Hat jemand eine Idee, was das Problem sein könnte? Irgendwie scheint 
sich das Programm zu "verhaspeln"?

VG Mike

PS: Auch sonstige Kommentare/Verbesserungsvorschläge zum Programm sind 
natürlich willkommen...

von Mike (Gast)


Lesenswert?

PS: Noch komischer:

Wenn ich sendStopBit() im Hauptprogramm weglasse, und das letzte 
Datenbit sehr kurz (z. B. 500 Puls/500 Pause) geht es, d. h. nach Senden 
der Sequenz ist die LED "entkoppelt".

Wenn ich sendStupBit() mit der gleichen Länge (z. B. 500 Puls/500 Pause) 
am Schluss drin lasse, wird die LED nicht "entkoppelt" --> sendet munter 
mit 40 kHz "ewig" weiter

???

von Mike (Gast)


Lesenswert?

Um das Problem einzugrenzen und die Frage zu konkretisieren, habe ich 
das Programm von allem "überflüssigen" Balast befreit. Verhalten ist 
jetzt so:

sendBit(laengePulse, laengePause)

--> für laengePulese/laenge Pause > 40.000 funktioniert es - IR-Sender 
ist abwechselnd an und aus; die Empfangs-LED blinkt im Sekundentakt

--> für laengePulese/laenge Pause < 30.000 funktioniert es NICHT - 
IR-Sender ist ständig an; die Empfangs-LED entsprechend auch

Ich habe keinerlei Ahnung oder Ansatzpunkt, woran das liegen könnte... 
hat jemand eine Idee? Sonst verlier ich komplett den Glauben ;-)

Danke Mike
1
#include <avr/io.h>
2
#include <avr/delay.h>
3
#include <avr/interrupt.h>
4
5
// Zaehler fuer Anzahl Interrupts (= Anzahl LED-Impulse)
6
volatile long int interrupt_count;
7
8
void main(void)
9
{
10
  // Test
11
  unsigned char i;
12
  
13
  // PB0 als Ausgang (Toogle IR LED)
14
  DDRB = (1<<PB0);
15
  
16
  // Konfiguration Timer
17
  // Phasenkorrekter PWM / Vorteiler 1 / Compare-Wert = 55
18
  TCCR0A=(1<<WGM00);
19
  TCCR0B=(1<<WGM02)|(1<<CS00);
20
  OCR0A=55;
21
  
22
  // Interrupt definieren
23
  TIMSK0 = (1<<OCIE0A);
24
25
  for (i=0;i<10;i++)
26
  {
27
    sendBit(40000,40000);
28
  }
29
30
  // alles ausschalten
31
  TCCR0A = 0;
32
  TCCR0B = 0;
33
  TIMSK0 = 0;
34
35
  PORTB = (1<<PB0);
36
}
37
38
void sendBit(long int countPulse,long int countPause)
39
{
40
  // Pulse Phase
41
  cli();
42
  TCCR0A=(1<<COM0A0)|(1<<WGM00);  // LED an PWM gekoppelt
43
  TCCR0B=(1<<WGM02)|(1<<CS00);
44
  interrupt_count = 0;
45
  sei();
46
  
47
  while (interrupt_count < countPulse);
48
49
  // Pause Phase
50
  cli();
51
  TCCR0A=(1<<WGM00);        // LED nicht an PWM gekoppelt
52
  TCCR0B=(1<<WGM02)|(1<<CS00);
53
  interrupt_count = 0;
54
  sei();
55
  
56
  while (interrupt_count < countPause);
57
}
58
59
ISR(TIM0_COMPA_vect)
60
{
61
  interrupt_count++;        // Interrupts (= IR Pulse) zaehlen
62
}

von Karl H. (kbuchegg)


Lesenswert?

Das hier
1
  while (interrupt_count < countPulse);

ist keine atomare Abfrage des
1
volatile long int interrupt_count;

entweder du machst das atomar (d.h. interrupt_count unter Interrupt 
Sperre auslesen) oder du benutzt einen uint8_t zusätzlich, den du 
problemlos atomar auslesen kannst.
1
// Zaehler fuer Anzahl Interrupts (= Anzahl LED-Impulse)
2
volatile long int interrupt_count;
3
volatile uint8_t time_done;
4
5
....
6
7
  time_done = 0;
8
  interrupt_count = countPulse;
9
  sei();
10
  
11
  while (!time_done)
12
    ;
13
14
  ...
15
16
ISR(TIM0_COMPA_vect)
17
{
18
  if( interrupt_count > 0 )
19
  {
20
    interrupt_count--;        // Interrupts (= IR Pulse) zaehlen
21
    if( interrupt_count == 0 )
22
      time_done = 1;
23
  }
24
}


Beachte: Das spart dir auch das dauernde Timer ein/ausschalten. Denn 
solange interrupt_count auf 0 ist, macht die ISR de facto nichts.

Runterzählen von einem Vorgabewert bis auf 0 ist oft einfacher als 
raufzählen und gibt eine bessere Logik. Aber hier dürfte konkret das 
nicht atomare Abfragen von interrupt_count in main() das Problem sein.
Der Prozessor kann einen long int nicht in einem Aufwasch bearbeiten, 
sondern muss das in mehrere 8-Bit Häppchen zerlegen. Wenn da 
zwischendurch die ISR zum Zug kommt und dir den long int während der 
Abfrage verändert, dann kann da beim Vergleich alles mögliche passieren. 
Es ist wie wenn du eine Geschichte liest und während du aufs Klo gehst, 
tauscht dir jemand das Buch aus. Plötzlich stimmt in deiner Geschichte 
hinten und vorne nichts mehr.

Wieso eigentlich ein long? Können deine Wartezeiten auch negativ sein?

von Mike (Gast)


Lesenswert?

Hallo Karl Heinz,

erstmal vielen herzlichen Dank, dass Du Dir das Problem angeschaut hast!

Die Erklärung hört sich logisch an, wäre ich nicht drauf gekommen. Ich 
habe das jetzt so wie beschrieben umgesetzt (denke ich), aber immer noch 
das gleiche fehlerhafte Verhalten (bei Counts < ~40.000 bleibt die LED 
im Dauersende-Modus). Unten nochmal das vollständige aktualisierte 
Programm (zur Sicherheit, dass ich Deinen Ansatz auch richtig übernommen 
habe).

Hast Du noch eine Idee? Sicherheitshalber habe ich die Anweisungen in 
der ISR auch zwischen cli() und sei() gesetzt, damit während der ISR 
kein Interrupt auftritt... aber hilft auch nix... seufz :-(

Karl Heinz Buchegger schrieb:
> Wieso eigentlich ein long? Können deine Wartezeiten auch negativ sein?

nein, das ist eigentlich unnötig - zum Test benutze ich relativ große 
(aber stets positive) Wartezeiten - später müssten die Puls- und 
Pausephasen (gemäß NEC) so 560 us (= 22 Pulse/Interrupts) sein.
1
#include <avr/io.h>
2
#include <avr/delay.h>
3
#include <avr/interrupt.h>
4
5
// Zaehler fuer Anzahl Interrupts (= Anzahl LED-Impulse)
6
volatile long int interrupt_count;
7
volatile uint8_t time_done;
8
9
void main(void)
10
{
11
  // Test
12
  unsigned char i;
13
  
14
  // PB0 als Ausgang (Toogle IR LED)
15
  DDRB = (1<<PB0);
16
  
17
  // Konfiguration Timer
18
  // Phasenkorrekter PWM / Vorteiler 1 / Compare-Wert = 55
19
  TCCR0A=(1<<WGM00);
20
  TCCR0B=(1<<WGM02)|(1<<CS00);
21
  OCR0A=55;
22
  
23
  // Interrupt definieren
24
  TIMSK0 = (1<<OCIE0A);
25
26
  for (i=1;i<10;i++)
27
  {
28
    sendBit(10000,10000);
29
  }
30
31
  // alles ausschalten
32
  TCCR0A = 0;
33
  TCCR0B = 0;
34
  TIMSK0 = 0;
35
36
  PORTB = (1<<PB0);
37
}
38
39
void sendBit(long int countPulse,long int countPause)
40
{
41
  // Pulse Phase
42
  cli();
43
  TCCR0A|=(1<<COM0A0);    // LED an PWM gekoppelt
44
  time_done = 0;
45
  interrupt_count = countPulse;
46
  sei();
47
  while (!time_done);
48
49
  // Pause Phase
50
  cli();
51
  TCCR0A&=~(1<<COM0A0);    // LED nicht an PWM gekoppelt
52
  time_done = 0;
53
  interrupt_count = countPause;
54
  sei();
55
  while (!time_done);
56
}
57
58
ISR(TIM0_COMPA_vect)
59
{
60
  cli();
61
  if(interrupt_count > 0)
62
  {
63
    interrupt_count--;
64
    if (interrupt_count == 0)
65
      time_done = 1;
66
  }
67
  sei();
68
}

von Karl H. (kbuchegg)


Lesenswert?

Hat zwar mit dem Problem (wahrscheinlich) nichts zu tun, aber

> Hast Du noch eine Idee? Sicherheitshalber habe ich die Anweisungen
> in der ISR auch zwischen cli() und sei() gesetzt

Das machst du gleich wieder weg.
Das ist nicht 'sicherheitshalber'.
Denn mit dem Eintritt in die ISR werden die Interrupts sowieso gesperrt 
und beim Verlassen der ISR werden sie wieder aktiviert. Der cli() macht 
daher gar nichts, während dir der sei() einen Fehler einbrocken kann, 
weil die Interrupts zu früh wieder freigegeben werden.

So, jetzt studier ich mal das Programm.

von Karl H. (kbuchegg)


Lesenswert?

Schalte hier
1
  // Pulse Phase
2
  cli();
3
  TCCR0A|=(1<<COM0A0);    // LED an PWM gekoppelt
4
  time_done = 0;
5
  interrupt_count = countPulse;
6
  sei();
7
  while (!time_done);
8
9
  // Pause Phase
10
  cli();
11
  TCCR0A&=~(1<<COM0A0);    // LED nicht an PWM gekoppelt

sicherheitshalber die LED ab.
Nur weil du den Pin vom Timer wieder entkoppelst, heißt das nicht, dass 
der Pin danach 0 bzw. 1 ist. Du weißt nicht wie er steht, also sorg für 
gesicherte Verhältnisse
1
  // Pulse Phase
2
  cli();
3
  TCCR0A|=(1<<COM0A0);    // LED an PWM gekoppelt
4
  time_done = 0;
5
  interrupt_count = countPulse;
6
  sei();
7
  while (!time_done)
8
    ;
9
10
  // Pause Phase
11
  cli();
12
  TCCR0A&=~(1<<COM0A0);    // LED nicht an PWM gekoppelt
13
  PORTB |= ( 1 << PB0 );   // und LED ausschalten

ob du jetzt den Pin auf 0 oder 1 setzen musst, um die LED auszuschalten, 
weiß ich nicht. Hängt von deiner Verschaltung ab.

von Karl H. (kbuchegg)


Lesenswert?

PS:

Wo ist eigentlich deine Hauptschleife in main()?

von Karl H. (kbuchegg)


Lesenswert?

Wenn nach diesem hier
1
  // alles ausschalten
2
  TCCR0A = 0;
3
  TCCR0B = 0;
4
  TIMSK0 = 0;

der Timer immer noch eine PWM erzeugt, dann würde ich auch mal ins Auge 
fassen, dass der µC da zwischendurch abstürzt und das Programm wieder 
von vorne anfängt.

Du hast doch am µC 100nF Blockkondensatoren verbaut, oder nicht?

von Karl H. (kbuchegg)


Lesenswert?

Seh ich das richtig, dass dein IR-LED keinen Vorwiderstand hat?

von Mike (Gast)


Angehängte Dateien:

Lesenswert?

Karl Heinz Buchegger schrieb:
> Nur weil du den Pin vom Timer wieder entkoppelst, heißt das nicht, dass
>
> der Pin danach 0 bzw. 1 ist. Du weißt nicht wie er steht, also sorg für
>
> gesicherte Verhältnisse

ok, hab ich eingebaut. Wobei die IR LED ja komischerweise mit 40 kHz 
weiterflackert, so dass es vermutlich nicht so wichtig wäre, ob sie 
dauernd an oder aus wäre - aber sicher ist sicher - schalte ich aus.

Karl Heinz Buchegger schrieb:
> Denn mit dem Eintritt in die ISR werden die Interrupts sowieso gesperrt
>
> und beim Verlassen der ISR werden sie wieder aktiviert. Der cli() macht
>
> daher gar nichts, während dir der sei() einen Fehler einbrocken kann,
>
> weil die Interrupts zu früh wieder freigegeben werden.

danke für die Erklärung - hab ich auch rausgenommen

Karl Heinz Buchegger schrieb:
> Wo ist eigentlich deine Hauptschleife in main()?

Hatte ich keine - ich wollte nur senden und dann Schluss. Aber hast 
Recht, brauch natürlich eine Schleife - ich hab jetzt nach dem Senden 
ein while(1) ergänzt.

Karl Heinz Buchegger schrieb:
> Du hast doch am µC 100nF Blockkondensatoren verbaut, oder nicht?

Ja, nachdem mich dieser dumme Fehler Samstag Nacht ca. 3 h gekostet hat, 
werd ich es nicht mehr vergessen.

Karl Heinz Buchegger schrieb:
> Seh ich das richtig, dass dein IR-LED keinen Vorwiderstand hat?

Ja, die LED verträgt (angeblich) 5 V - werde ich nochmal prüfen - aber 
ohne Vorwiderstand sollte das Ding doch eher kaputt gehen, als korrekt 
40 kHz zu senden, obwohl es Ruhe geben sollte

Die 40 kHz habe ich übrigens auch mit dem Voltmeter nachgemessen.

Karl Heinz Buchegger schrieb:
> Wenn nach diesem hier  // alles ausschalten
>
>   TCCR0A = 0;
>
>   TCCR0B = 0;
>
>   TIMSK0 = 0;
>
> der Timer immer noch eine PWM erzeugt, dann würde ich auch mal ins Auge
>
> fassen, dass der µC da zwischendurch abstürzt und das Programm wieder
>
> von vorne anfängt.

Ja, vermutlich kommt das Programm nie an diese Stelle. Aber wo/warum 
kann es vorher abstürzen? Das Programm ist ja nun ziemlich 
"überschaubar", was kann da schief laufen?

Anbei ein Foto der aktuellen Schaltung und hier der aktuelle Code (immer 
noch der gleiche Fehler, Mist)... bin echt am Verzweifeln :-(

sehr komisch finde ich auch, dass es mit Pulse/Pause > 50000 geht, und 
bei kleineren Werten nicht... wofür könnte das ein Anhaltspunkt sein?


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

// Zaehler fuer Anzahl Interrupts (= Anzahl LED-Impulse)
volatile long int interrupt_count;
volatile uint8_t time_done;

void main(void)
{
  // Test
  unsigned char i;

  // PB0 als Ausgang (Toogle IR LED)
  DDRB = (1<<PB0);

  // Konfiguration Timer
  // Phasenkorrekter PWM  Vorteiler 1  Compare-Wert = 55
  TCCR0A=(1<<WGM00);
  TCCR0B=(1<<WGM02)|(1<<CS00);
  OCR0A=55;

  // Interrupt definieren
  TIMSK0 = (1<<OCIE0A);

  for (i=1;i<10;i++)
  {
    sendBit(50000,50000);
  }

  // alles ausschalten
  TCCR0A = 0;
  TCCR0B = 0;
  TIMSK0 = 0;

  PORTB |= (1<<PB0);

  while(1)
  {

  }
}

void sendBit(long int countPulse,long int countPause)
{
  // Pulse Phase
  cli();
  TCCR0A|=(1<<COM0A0);    // LED an PWM gekoppelt
  time_done = 0;
  interrupt_count = countPulse;
  sei();
  while (!time_done);

  // Pause Phase
  cli();
  TCCR0A&=~(1<<COM0A0);    // LED nicht an PWM gekoppelt
  PORTB |= (1<<PB0);
  time_done = 0;
  interrupt_count = countPause;
  sei();
  while (!time_done);
}

ISR(TIM0_COMPA_vect)
{
  if(interrupt_count > 0)
  {
    interrupt_count--;
    if (interrupt_count == 0)
      time_done = 1;
  }
}

von Mike (Gast)


Lesenswert?

PS: Noch ein Hinweis, um dem Problem (vielleicht) auf die Schliche zu 
kommen:

In dem Ursprungsprogramm (Senden Startbit, Senden 32 Datenbits, Senden 
Stopbit) hat es funktioniert (d. h. IR Signal nach Senden auch wirklich 
beendet), wenn ich das Senden des Stopbits weggelassen habe - und das 
obwohl das letzte Datenbit auch eine sehr kurze Pulse/Pause Dauer hat (< 
5000) - für mich bedeutet dieses Programmverhalten eigentlich nur noch 
mehr Verwirrung, aber vielleicht kannst Du damit was anfangen? ... danke 
...

von Karl H. (kbuchegg)


Lesenswert?

Mike schrieb:

>> Seh ich das richtig, dass dein IR-LED keinen Vorwiderstand hat?
>
> Ja, die LED verträgt (angeblich) 5 V - werde ich nochmal prüfen - aber
> ohne Vorwiderstand sollte das Ding doch eher kaputt gehen

Na, na, na. So schnell schießen die Preussen nicht!

Da gehören immer 2 dazu.
Der eine, der Verbraucher, der eine bestimmte Strommenge beziehen will. 
Und der andere, die Quelle, die diese Strommenge liefern können muss.

An einem idealen Netzgerät brennt deine LED ohne Vorwiderstand durch, 
weil zuviel Strom durchjagt. Ein ideales Netzgerät kann unendlich viel 
Strom liefern. Aber dein Tiny ist kein ideales Netzgerät. Der kann nur 
eine bestimmte Strommenge abgeben. Ist er an dieser Grenze angelangt, 
dann bricht die Ausgangsspannung ein. Irgendetwas wird überlastet. Und 
eine einbrechende Spannung ist prinzipiell nicht gut.

Du kannst ja auch Gegenstände hochheben, kannst also mit deinem Arm eine 
Kraft aufbringen. Kein Problem. Die Mineralwasserflasche kannst du 
problemlos um 20 Zentimeter anheben. Ist der Gegenstand aber zu schwer 
(ein PKW), dann wird das nichts mit dem Hochheben um 20 Zentimeter, 
sondern statt dessen bricht deine Hubhöhe auf 0 ein. Der PKW verlangt 
dir eine bestimmte Kraft zum Hochheben ab, du kannst aber nicht 
'liefern'.

> Ja, vermutlich kommt das Programm nie an diese Stelle. Aber wo/warum
> kann es vorher abstürzen? Das Programm ist ja nun ziemlich
> "überschaubar", was kann da schief laufen?

Spannungseinbruch in der Versorgungsspannung.
Lässt sich aber leicht feststellen. Verkabel eine 2.te LED (rot, grün, 
gelb. Aber bitte mit Vorwiderstand) an einen Portin und lass dir diese 
am Anfang in main() eine zeitlang einschalten. (kannst ruhig _delay_ms 
dafür nehmen).


( PortPin - LED - 330 Ohm - Vcc )
1
int main()
2
{
3
  ...
4
5
  DDRB |= ( 1 << PB1 );
6
  PORTB &= ~( 1 << PB1 );
7
  _delay_ms( 500 );
8
  PORTB |= ( 1 << PB1 );
9
  _delay_ms( 500 );
10
11
  ....

Diese LED darf nur ein einziges mal nach dem Flashen für kurze Zeit 
leuchten. Leuchtet sie auch zwischendurch irgendwann mal, dann wurde der 
µC resettet. Aus welchem Grund auch immer. Um den Grund kümmert man 
sich, wenn man weiß, dass es etwas gibt worum man sich kümmern muss. 
Erst mal muss man feststellen, ob ....

von Karl H. (kbuchegg)


Lesenswert?

Auf Deutsch:
Lass den µC dir helfen, zu verstehen was er eigentlich macht.

Man sollte nie unterschätzen, was man mit dem sinnvollen und überlegten 
Einsatz von ein paar zusätzlichen LED an Informationen gewinnen kann :-)

von Mike (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Diese LED darf nur ein einziges mal nach dem Flashen für kurze Zeit
>
> leuchten. Leuchtet sie auch zwischendurch irgendwann mal, dann wurde der
>
> µC resettet. Aus welchem Grund auch immer. Um den Grund kümmert man
>
> sich, wenn man weiß, dass es etwas gibt worum man sich kümmern muss.
>
> Erst mal muss man feststellen, ob ....

Habe die "Test-LED" in die Schaltung und ins Programm eingebaut: Sie 
blinkt tatsächlich nur am Anfang einmal kurz - und das bei einem 
Pulse/Pause-Wert von 50.000 (LED hört am Ende auf zu senden) und bei 
einem Pulse/Pause-Wert von 10.000 (LED hört am Ende nicht auf zu 
senden). Kann man daraus folgern, dass das Programm nicht abstürzt (da 
es nicht neu startet)?

Als zusätlichen Test habe ich das Blinken der "Test-LED" in die Schleife 
hinter sendBit() eingebaut

Mike schrieb:
> for (i=1;i<10;i++)
>
>   {
>
>     sendBit(50000,50000);
>
>   }

Da ist es nun so, dass bei 50.000 die LED 10 mal blinkt (1 mal am 
Anfang, 9 mal innerhalb Schleife) - und bei 10.000 nur 1 mal am Anfang. 
Das würde heißen, dass das Programm aus dem ersten Aufruf von 
sendBit(10000,10000) schon nicht mehr zurückkommt. "Nicht mehr 
zurückkommen" würde wohl bedeuten, dass time_done nie 1 wird. Und das 
wiederum, dass interrupt_count nie 0 wird. Und das wiederum, dass

1) die ISR nicht (häufig genug) angesprungen wird oder

2) das Runterzählen von interrupt_count die 0 "überspringt" (sozusagen 
von 1 direkt auf -1, z. B.) ????

Fall 1) Würde bedeuten, dass Timer (warum auch immer) nicht mehr 
weiterläuft oder der Interrupt bei Erreichen des Compare-Wertes nicht 
mehr ausgelöst wird bzw. ISR nicht mehr aufgerufen wird

Fall 2) Könnte es sein, dass interrupt_count--; zweimal (oder mehrmals) 
ausgeführt wird, ohne dass es zur Prüfung interrupt_count == 0 kommt? 
Aber wenn während ISR keine Interrupts möglich sind, sollte das 
ausgeschlossen sein.

Hast Du einen Erklärungsansatz?

Karl Heinz Buchegger schrieb:
> LED ohne Vorwiderstand

Als LED nutze ich "IR-Sendediode SFH 409 Osram Components SFH 409 
Gehäuseart T 1 Wellen-Länge 950 nm" - im Datenblatt steht etwas von 
Sperrspannung 5 V - ich betreibe die Schaltung aktuell an 4,5 V - 
brauche ich eventuell trotzdem Vorwiderstand oder sonstiges Bauteil?

von Falk B. (falk)


Lesenswert?

@  Mike (Gast)

>Als LED nutze ich "IR-Sendediode SFH 409 Osram Components SFH 409
>Gehäuseart T 1 Wellen-Länge 950 nm" - im Datenblatt steht etwas von
>Sperrspannung 5 V - ich betreibe die Schaltung aktuell an 4,5 V -

Ja und? Deine LED soll leuchten, nicht sperren.

>brauche ich eventuell trotzdem Vorwiderstand oder sonstiges Bauteil?

JA! Siehe LED!

von Karl H. (kbuchegg)


Lesenswert?

Ähm.
Mir fällt da gerade was anderes an deinem Code auf :-)

Du ignorierst die ganze Zeit eine Compiler-Warnung!

Hier
1
    sendBit(50000,50000);

müsste dir dein Compiler eine Warnung über eine implizit Deklaration 
geben. Wenn dich der Compiler nicht warnt, dann dreh die 
Compiler-Warnungen hoch auf -Wall. Du willst jede Hilfe haben, die du 
kriegen kannst.

Und wenn du die Warnung dann hast, dann 'entschärfst' du sie, in dem du 
für die Funktion einen Protoypen vor deine main() stellst oder die 
Funktion vor die main() ziehst.

Und dann schätze ich mal, wird dein Programm sogar funktionieren, weil 
du den Compiler nicht mehr angelogen hast bzw. ihm vorenthalten hast, 
dass die Funktion 2 long Werte nimmt (und bitte: spar dir das int in 
long int. long bzw. unsigned long oder noch besser uint32_t bzw. int32_t 
reicht) und er sich aus den Zahlenwerten 10000 zusammenreimt, dass die 
Funktion 2 int Werte nimmt.

Und wenn etwas nicht negativ sein kann, dann mach es, verdammt noch mal, 
auch unsigned. Du willst auf keinen Fall haben, dass irgendein 
Bitmuster, welches sich möglicherweise sogar auf momentan nicht 
verstandenen Wegen da einschmuggelt (zb aufgrund fehlerhafter 
Parameterlisten und/oder fehlendem Funktionsprotoyp), als negative Zahl 
aufgefasst wird, so dass so ein Vergleich

  if(interrupt_count > 0)

niemals wahr werden kann.

von Mike (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> bitte: spar dir das int in
>
> long int. long bzw. unsigned long oder noch besser uint32_t bzw. int32_t
>
> reicht

YES, es klappt :-)) das war der entscheidende Hinweis!! Werde mich mit 
den C Datentypen nochmal genauer auseinandersetzen müssen... jetzt bin 
ich erstmal super froh, dass das Problem gelöst ist (und einiges dabei 
gelernt hab ich auch noch) - VIELEN DANK!

Karl Heinz Buchegger schrieb:
> Wenn dich der Compiler nicht warnt, dann dreh die
>
> Compiler-Warnungen hoch auf -Wall.

Hmm, Compiler warnt mich da (trotz -Wall) nicht - aber werde zukünftig 
auf solch "dummen" Datentyp-Verwendungen achten

Falk Brunner schrieb:
>>brauche ich eventuell trotzdem Vorwiderstand oder sonstiges Bauteil?
>
>
> JA! Siehe LED!

ebenfalls danke. Baue ich ein (da habe ich den netten Herrn bei Conrad 
wohl missverstanden...)

VG Mike

von Karl H. (kbuchegg)


Lesenswert?

Mike schrieb:
> Karl Heinz Buchegger schrieb:
>> bitte: spar dir das int in
>>
>> long int. long bzw. unsigned long oder noch besser uint32_t bzw. int32_t
>>
>> reicht
>
> YES, es klappt :-)) das war der entscheidende Hinweis!!

Nö.
Das war nicht der entscheidende Hinweis.

Der entscheidende Hinweis ist der fehlende Funktionsprotoyp!

Und zwar auch nur dann, wenn du
1
    sendBit(10000,10000);
schreibst.

Denn jetzt muss der Compiler an dieser Stelle im Code (der Compiler 
liest den COde nur EINMAL von oben nach unten) davon ausgehen, nachdem 
er vorher noch nie irgendwas von einer Funktion sendBit im Code gesehen 
hat, dass diese Funktion so
1
int sendBit( int wert1, int wert2 )
2
{
3
  ...
4
}

aussieht.
Schreibst du
1
    sendBit(50000,50000);
dann muss sich der Compiler aufgrund der C-Regeln, die Funktion so 
annehmen
1
int sendBit( long wert1, long wert2 )
2
{
3
  ...
4
}
und das deckt sich, bis auf den falschen Returntyp (der sich hier aber 
nicht auswirkt), mit deiner tatsächlichen Funktion
1
void sendBit(long int countPulse,long int countPause)

im letzten Fall hat der COmpiler daher richtig 'geraten', bzw. haben ihn 
die C-Regeln zum richtigen Ergebnis geführt. Im ersten Fall (mit den 
10000) aber nicht!

Und das ist dein eigentlicher Fehler.

von Mike (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Nö.
>
> Das war nicht der entscheidende Hinweis.
>
>
>
> Der entscheidende Hinweis ist der fehlende Funktionsprotoyp!

Oh Mann, habe ich nicht mal das richtig "erkannt"... Aber jetzt versteh 
ich's (hoffentlich) --> ich muss entweder die gesamte Unterroutine vor 
das Hauptpgrogramm bringen oder den Funktionsprototyp (das ist 
Funktionsname inkl. Signatur/Parameter-Liste, richtig?)

Das hatte mir echt eine schlaflose Nacht bereitet und war ziemlich 
"verzweifelt" - aber im Nachhinein muss ich sagen, dass ich durch die 
Probleme/Fehler wieder einiges dazu gelernt habe...

Das Programm zum Senden der 32-Bit-Sequenz hab ich entsprechend 
überarbeitet - funktioniert jetzt (natürlich) auch. Heute Abend geh ich 
dann - mit gestärktem Wissen und Motivation ;-) an den entsprechenden 
Empfänger...

Also danke für die Hilfe und Hilfe zur Selbsthilfe!

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.