Forum: Compiler & IDEs Programm verhält sich nicht wie geplant


von halllo (Gast)


Lesenswert?

Hallo,

irgendwie versteh ich nicht ganz das Verhalten des Programms. Der uC ist 
ein at90usb162.

Sobald das Programm ins ISR springt aktiviert es PB7. (Wieso)

Wenn es die Zeile PORTB = (PORTB<<1) | 1; ausführt springt das PORTB um 
eins weiter aber nicht PINB. PINB springt erst um eins weiter wenn es 
wieder in die Zeile der if-Bedingung springt.

Das nächste Problem ist auch das die if-Bedingung nicht ausgeführt wird.

Hoffe ihr könnt mir helfen.

MfG

1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <stdbool.h>
4
5
6
7
void init(void);
8
volatile bool bedingung;
9
10
11
int main (void)
12
{
13
  init();
14
15
  while(1)
16
  {
17
    if (bedingung == true)
18
    {
19
      PORTB = (PORTB<<1) | 1;
20
21
      if(PB1==1 && PB2==1 && PB3==1 && PB4==1 && PB5==1 && PB6==1 && PB7==0)
22
      {
23
        PORTB = 0xFE;
24
      }
25
26
      bedingung = false;
27
28
    }
29
  }
30
}
31
32
33
ISR(TIMER1_COMPA_vect)
34
{
35
  bedingung = true;
36
}
37
38
void init(void)
39
{
40
  DDRB = 0xFF;
41
  PORTB = 0xFF;
42
  
43
  DDRC = 0x04;
44
  PORTC = 0x04;
45
46
47
  TCCR1A |= (1<<COM1A1) | (1<<COM1A0);
48
  TCCR1B |= (1<<WGM12) | (1<<CS12);
49
  TIMSK1 |= (1<<OCIE1A);
50
51
  OCR1A = 1952;
52
53
  sei();
54
  
55
  PORTB = 0xFE;
56
}

von Uwe .. (uwegw)


Lesenswert?

halllo schrieb:
> Wenn es die Zeile PORTB = (PORTB<<1) | 1; ausführt springt das PORTB um
> eins weiter aber nicht PINB. PINB springt erst um eins weiter wenn es
> wieder in die Zeile der if-Bedingung springt.
Also im Simulator?
Das ist normales Verhalten der Hardware. Das PIN-Register gibt ja den 
Eingangspegel an den Pins wieder. Und da dieser erst synchronisiert 
werden muss, steht er nicht sofort, sondern erst verzögert zur 
Verfügung.

> Das nächste Problem ist auch das die if-Bedingung nicht ausgeführt wird.
Das liegt daran, dass PB0..PB7 anders definiert sind also du denkst. 
Mach dich mal schlau, wie man im avr-gcc die einzelnen Pins abfragt.

von halllo (Gast)


Lesenswert?

Danke.

Hast du noch eine Idee wieso PB7 aktiviert wird wenn es ins ISR springt.

Andere Frage: Wie kann man das Byte 11011101 getrennt shiften.

von Walter (Gast)


Lesenswert?

da fehlt ein while (1);

von Walter (Gast)


Lesenswert?

oops, verguckt

von Walter (Gast)


Lesenswert?

halllo schrieb:
> Hast du noch eine Idee wieso PB7 aktiviert wird wenn es ins ISR springt.
meinst du mit aktiviert auf 1 gesetzt?
Das hast du doch schon vorher gemacht
>
> Andere Frage: Wie kann man das Byte 11011101 getrennt shiften.
andere Frage: was meinst du damit?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

if(PB1==1 && PB2==1 && PB3==1 && PB4==1 && PB5==1 && PB6==1 && PB7==0)

Das ist eine umständliche Schreibweise der Anweisung


      if (1)

PB1 hat nämlich den Wert 1, damit ist bereits der erste Vergleich
wahr, der Rest interessiert nicht mehr.  Da das alles bereits zur
Compilezeit konstant ist, eliminiert der Compiler dann das "if"
auch noch.

      if (bedingung == true)

ist Humbug.  Noch "Boolscher" als "bool" gibt es nicht, und da
"bedingung" bereits vom Typ "bool" ist, kannst du einfach
schreiben:

      if (bedingung)

von halllo (Gast)


Lesenswert?

>> Hast du noch eine Idee wieso PB7 aktiviert wird wenn es ins ISR springt.
>meinst du mit aktiviert auf 1 gesetzt?
>Das hast du doch schon vorher gemacht

Sobald der Debugger ins ISR springt wird PB7 auf Low gesetzt. Nach der 
Zeile PORTB = (PORTB<<1) | 1; wirds durch das shiften wieder auf High 
gesetzt.

Aus irgendeinem Grund wird PB7 durch das Interrupt immer auf Low 
gesetzt.


Wenn ich 11011101 habe, würde ich zuerst gerne die 3 höchten Bits 
shiften und dann die unteren.

1101 1101
1011 1101
1011 1011
0111 1011
0111 0111

von Stefan E. (sternst)


Lesenswert?

Jörg Wunsch schrieb:
> if(PB1==1 && PB2==1 && PB3==1 && PB4==1 && PB5==1 && PB6==1 && PB7==0)
>
> Das ist eine umständliche Schreibweise der Anweisung
>
>
>       if (1)

Nö, "if (0)".

> PB1 hat nämlich den Wert 1, damit ist bereits der erste Vergleich
> wahr, der Rest interessiert nicht mehr.

Bei "&&"?

Nun ja, jeder hat mal einen schlechten Tag. ;-)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Stefan Ernst schrieb:

>> Das ist eine umständliche Schreibweise der Anweisung
>>
>>
>>       if (1)
>
> Nö, "if (0)".

OK, sehe ich jetzt auch. ;-)

von halllo (Gast)


Lesenswert?

Hat jemand noch einen Tipp für dieses Problem:

Wenn ich 11011101 habe, würde ich zuerst gerne die 3 höchten Bits
shiften und dann die unteren.

1101 1101
1011 1101
1011 1011
0111 1011
0111 0111

von Karl H. (kbuchegg)


Lesenswert?

Deine Beschreibung ist ein wenig mehrdeutig.

Kann es sein, dass du gar nicht 'shiften' willst, sondern im Kreis 
rotieren?
Das würde zumindest zu deinem Beispiel passen.

von halllo (Gast)


Lesenswert?

Bit 5-7 will ich immer von rechts nach links shiften und Bit 1-4 will 
ich zuerst nach links und dann nach rechts shiften. Die zwei Funktionen 
soll man aber getrennt ausführen können.

von ernst (Gast)


Lesenswert?

Du hast das Programm - bestimmt irrtümlich - versucht in der sog. 
"Sprache C" zu schreiben. Solche Kompilate sind hinlänglich dafür 
bekannt, genau - nicht das - zu tuen, für das sie geschrieben wurden!

von Johann (Gast)


Lesenswert?

ernst schrieb:
> Du hast das Programm - bestimmt irrtümlich - versucht in der sog.
> "Sprache C" zu schreiben. Solche Kompilate sind hinlänglich dafür
> bekannt, genau - nicht das - zu tuen, für das sie geschrieben wurden!


Schwachsinn. Assemblerprogramme sind auch berüchtigt dafür nicht das zu 
tun, wofür sie programmiert sind - wenn man keine Ahnung vom 
Programmieren hat. Das ist mit C nicht anders. Oder Pascal. Oder Java. 
Oder Python. Oder Wasauchimmer.

von halllo (Gast)


Lesenswert?

>Du hast das Programm - bestimmt irrtümlich - versucht in der sog.
>"Sprache C" zu schreiben. Solche Kompilate sind hinlänglich dafür
>bekannt, genau - nicht das - zu tuen, für das sie geschrieben wurden!

Was willst du damit sagen?

von Karl H. (kbuchegg)


Lesenswert?

halllo schrieb:
> Bit 5-7 will ich immer von rechts nach links shiften und Bit 1-4 will
> ich zuerst nach links und dann nach rechts shiften. Die zwei Funktionen
> soll man aber getrennt ausführen können.

Na dann mach das doch

Du hast einen Wert
Von dem holst du dir die Bits 5-7 in eine neue Variable und setzt alle 
anderen Bits auf 0 (damit sie dir beim nachfolgenden Shiften nicht in 
die Quere kommen)
die shiftest du um 1 stelle nach links
dann setzt du noch das Bit 5 (so willst du das anscheinend)
und überträgst das Ergebnis wieder zurück in die originale Variable
(dort die Bits 5-7 auf 0 setzen und mit dem geshifteten Ergebnis 
verodern)


Wie würdest du es denn von Hand machen, wenn du nur Operationen zur 
Verfügung hast, die auf alle 8 Bit gemeinsam wirken? Doch auch nicht 
anders.

von Karl H. (kbuchegg)


Lesenswert?

ernst schrieb:
> Du hast das Programm - bestimmt irrtümlich - versucht in der sog.
> "Sprache C" zu schreiben. Solche Kompilate sind hinlänglich dafür
> bekannt, genau - nicht das - zu tuen, für das sie geschrieben wurden!

Ziemlicher Unsinn.
Wenn man das Programm so formuliert, dass der Programmtext genau dem 
entspricht, was man eigentlich tun möchte, dann tun C Programme genau 
das was sie tun sollen. So wie Programme in anderen Programmiersprachen 
auch.

Die Krux liegt normalerweise an 4 Stellen
* der Programmierer weiß nicht, was er eigentlich will bzw. hat keine
  klare Vorstellung davon
* der Programmierer weiß nicht, wie er das Problem völlig losgelöst
  von einer Programmiersprache lösen will/kann.
* der Programmierer weiß nicht, wie er das in seiner Programmiersprache
  umsetzen kann. Dieser Punkt geht normalerweise Hand in Hand mit dem
  nächsten Punkt, der da lautet
* der Programmierer kennt seine Programmiersprache nicht oder nicht
  richtig.

Meistens ist das Hauptproblem schon im Punkt 1 oder 2 zu finden, bzw. an 
der Kombination aus Punkt 2 und Punkt 4. Da werden dann zur 
Problemlösungen 'Wunderoperationen' aus dem Hut gezaubert, die so gar 
nicht in der realen Programmiersprache vorhanden sind.
Im "Idealfall" sollte dann ein Schachprogramm so aussehen
1
int main()
2
{
3
  play( "Chess" );
4
}
und um alles andere hat sich der Compiler zu kümmern.
Aber so, wie ein Werkzeugkasten eben nicht von alleine die IKEA Möbel 
zusammenbaut, so muss man eben auch in einer Programmiersprache seinen 
Werkzeugkasten kennen um zu wissen, was man eigentlich alles zur 
Verfügung hat. Und dann muss man eben die gewünschte Operation Stück für 
Stück aus dem was man hat zusammensetzen.

von halllo (Gast)


Lesenswert?

Danke!

Habe noch eine Frage. :-)

Bei Timer1 verwende ich Channel A und B im CTC Mode. Wenn Channel A 
ausgeführt wird, setzt es den TCNT wieder auf 0 sodass Channel B nicht 
dran kommt.

Gibt es einen Weg dass Channel B trotzdem ausgeführt wird.

von Rolf Magnus (Gast)


Lesenswert?

halllo schrieb:
>>Du hast das Programm - bestimmt irrtümlich - versucht in der sog.
>>"Sprache C" zu schreiben. Solche Kompilate sind hinlänglich dafür
>>bekannt, genau - nicht das - zu tuen, für das sie geschrieben wurden!
>
> Was willst du damit sagen?

Ich vermute, er will sagen, daß er es nicht schafft, ein lauffähiges 
C-Programm zu schreiben und den Grund dafür nicht bei sich selbst, 
sondern bei der Sprache sucht.

von Karl H. (kbuchegg)


Lesenswert?

halllo schrieb:

> Bei Timer1 verwende ich Channel A und B im CTC Mode. Wenn Channel A
> ausgeführt wird, setzt es den TCNT wieder auf 0 sodass Channel B nicht
> dran kommt.
>
> Gibt es einen Weg dass Channel B trotzdem ausgeführt wird.


was soll 'Channel B wird ausgeführt' bedeuten?

Dein Timer zählt.  0, 1, 2, 3, 4, 5, .....

Im CTC Modus wird der momentane Wert des Timers (der Zählerstand) mit 
einem anderen Register verglichen. Sind sie gleich, dann wird der Zähler 
wieder auf 0 zurückgestellt und er beginnt wieder von vorne. 0, 1, 2, 3, 
...

Mit welchem Register verglichen wird, das findet sich im Datenblatt. Da 
gibt es eine schöne Tabelle, in der alle Modi aufgelistet sind und in 
der auch steht, welches Register für diesen Wert (den TOP Wert) 
zuständig ist.

Davon unabhängig (sofern die Register nicht für den jeweiligen Modus 
laut Tabelle eine bestimmte Bedeutung haben) sind die Compare Register 
OCR1A bzw. OCR1B. Wann immer der momentane Zählerstand mit einem der 
beiden Register übereinstimmt, hat man einen Compare Match und kann da 
eine Aktion daran binden.

Und das wars dann schon. Mehr gibt es dazu eigentlich fürs erste nicht 
zu sagen. Wenn du einen Compare Match beim Zählerstand 300 einstellst, 
der Timer aber immer nur von 0 bis 250 zählt, dann wird dieser Compare 
Match nie auftreten.

von halllo (Gast)


Lesenswert?

>was soll 'Channel B wird ausgeführt' bedeuten?


Ich verwende bei bei Timer1 OCR1A UND OCR1B. OCR1A ist zb. 30 und OCR1B 
zb. 60.

Wenn der Zählerstand 30 erfolgt ein COMPARE MATCH, das Interrupt wird 
ausgelöst und der Zählerstand wird wieder auf 0 gesetzt.

Da der OCR1B aber 60 und der Zählerstand bei 30 zurück gesetzt wird, ist 
die Folge dass OCR1B nie ausgelöst wird.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Du hast ein konzeptionelles Problem.  Man kann nicht "Kanal A und
Kanal B im CTC-Modus" benutzen.  (Gut, das hast du mehr oder weniger
gemerkt.)

Bitte gehe auf "Los!" zurück, ziehe nicht EUR 2000 ein und erzähle
uns die Aufgabe, die du lösen möchtest, statt einer halb angedachten
und dann doch nicht funktionierenden Lösung.

von halllo (Gast)


Lesenswert?

Mit Timer1 will ich zwei Lauflichter ansteuern und mit Timer0 will ich 
PWM ansteuern.

Somit sind alle Timer besetzt.

Wenn man Channel A;B;C bei Timer 1 nicht getrennt benützen kann, welchen 
nutzen haben sie dann.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

halllo schrieb:
> Mit Timer1 will ich zwei Lauflichter ansteuern und mit Timer0 will ich
> PWM ansteuern.

Bitte erzähle mehr darüber.

> Somit sind alle Timer besetzt.

Naja.  Vermutlich könnte man das alles mit einem einzigen Timer
machen.  Der macht dann in der Hardware die PWM, und per Software
organisiert er das Timing für die Lauflichter (bei dem es vermutlich
nicht auf 'ne Mikrosekunde ankommt).

> Wenn man Channel A;B;C bei Timer 1 nicht getrennt benützen kann, welchen
> nutzen haben sie dann.

Natürlich kann man diese getrennt benutzen, solange man nicht auf die
Idee kommt, alle für einen CTC-Modus benutzen zu wollen.  So eine
compare/match unit kann ja noch mehr machen als nur den Zähler zurück
zu setzen.

von halllo (Gast)


Lesenswert?

Bei PB1-PB4 läuft ein Lauflicht und bei PB5-PB7 läuft das andere 
Lauflicht mit unterschiedlicher Frequenz.
Bei PB0 wird eine Led über PWM gedimmt.

>Vermutlich könnte man das alles mit einem einzigen Timer machen.

Bei PWM ändert sich die Frequenz, deswegen bracht der ja einen extra 
Timer.


>Natürlich kann man diese getrennt benutzen

Für was kann man die Channel zb. benützen.  Was kann die compare/match 
unit noch machen.

von Karl H. (kbuchegg)


Lesenswert?

halllo schrieb:
> Bei PB1-PB4 läuft ein Lauflicht und bei PB5-PB7 läuft das andere
> Lauflicht mit unterschiedlicher Frequenz.
> Bei PB0 wird eine Led über PWM gedimmt.

Ist erst mal noch kein Hinernissgrund für nur einen Timer.

> Bei PWM ändert sich die Frequenz, deswegen bracht der ja einen extra
> Timer.

Bei PWM verändert sich keine Frequenz.

> Für was kann man die Channel zb. benützen.  Was kann die compare/match
> unit noch machen.

Das wofür sie designed wurde.

Stimmt Registerwert und Timerwert überein, dann kann man sich einen 
Interrupt auslösen lassen. Oder aber die Hardware so schalten, dass sie 
einen Pin toggelt.

von halllo (Gast)


Lesenswert?

>Ist erst mal noch kein Hinernissgrund für nur einen Timer.

Wenn sich das Duty Cicle ständig ändert, wie würdest du die Zeit messen. 
Am Overflow?

Wenn der Pin High toggelt, muss dann auch der Port toggeln?

Habe versucht per PWM die Led zu dimmen jedoch toggelt nur der PIN und 
nicht der Port. Die Folge ist dass die Led nicht die Helligkeit ändert.
1
include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <stdbool.h>
4
5
6
7
void init(void);
8
9
void pwm_helligkeit(void);
10
11
volatile bool bedingung;
12
13
14
int main (void)
15
{
16
  init();
17
18
19
  while(1)
20
  {
21
    if(bedingung==true)
22
    {
23
24
25
      pwm_helligkeit();
26
27
28
      bedingung = false;
29
    }
30
31
    
32
  }
33
}
34
35
36
ISR(TIMER1_COMPA_vect)
37
{
38
  bedingung = true;
39
}
40
41
42
43
void pwm_helligkeit(void)
44
{
45
  static bool modus;
46
47
  if (modus == true)
48
  {
49
    OCR0A += 5;
50
51
    if (OCR0A >= 250)
52
    {
53
      modus = false;
54
    }
55
  }
56
57
  if (modus == false)
58
  {
59
    OCR0A -= 5;
60
61
    if (OCR0A <= 5)
62
    {
63
      modus = true;
64
    }
65
  }
66
}
67
68
69
void init(void)
70
{
71
  DDRB = 0xFF;
72
  PORTB = 0xFF;
73
74
  //TCCR1A |= (0<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (0<<COM1B0);
75
  TCCR1B |= (1<<WGM12) | (1<<CS12);
76
  TIMSK1 |= (1<<OCIE1A);
77
78
  OCR1A = 50;
79
80
81
  TCCR0A |= (0<<COM0A1) | (1<<COM0A0) | (1<<WGM01)| (1<<WGM00) ;
82
  TCCR0B |= (1<<WGM02) | (1<<CS01);
83
84
  OCR0A = 0;
85
86
  sei();
87
  
88
}

von Karl H. (kbuchegg)


Lesenswert?

halllo schrieb:
>>Ist erst mal noch kein Hinernissgrund für nur einen Timer.
>
> Wenn sich das Duty Cicle ständig ändert, wie würdest du die Zeit messen.
> Am Overflow?

Was ist falsch daran?
Ja, genau so würde ich das machen.
Auch wenn sich der Duty Cycle dauernd ändert, die Overflows kommen 
weiterhin regelmässig. Die hängen ja nur davon ab, was der Top Wert der 
PWM ist. Und der bleibt auch bei einer PWM immer gleich. Nur sollte man 
auch eine PWM nehmen, bei der ein Overflow ausgelöst wird.

von halllo (Gast)


Lesenswert?

Beim letzten Bsp., wieso wird da das TCNT Register auf 0 gesetzt wenn es 
mit dem OCR übereinstimmt. Sollte das TCNT nicht weiter bis 255 zählen 
und nur den PIN toggeln.

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.