einfacher C-Code -> Denkfehler??

Gast #1333141
Lesenswert?

Hallo Leute,

habe ich in meinem Code ein Denkfehler?
Ein Unterprogramm wird immer wieder in main aufgeruffen.

>>int main(void) {
>>    while(1) {
>>        Code();
>>    }
>>}

Wenn ich den Taster (E0,1) drücke, dann soll die LED (A0,3) angehen und 
auch wenn der Taster (E0,1) nicht mehr gedrückt wird soll die LED 
leuchten.

>>void Code(void){
>>    If(E0 & ( 1 << 1) ) {
>>        A0 |= ( 1 << 3 );
>>    }
>>}

Leider ist es so, dass sobald ich den Taster los lasse, wird auch die 
LED gelöscht.

Was mache ich falsch? Wo liegt mein Fehler? Ich teste das Programm auf 
STK500 (ATmega8)

Gruß
#1333172
Lesenswert?

>Dein Fehler besteht darin, dass du nicht das komplette Programm postest.
>Sprich: der Fehler befindet sich in dem Teil, den du hier nicht zeigst.

Möglicherweise liegt der Fehler aber auch in deinem Versuchsaufbau.
Sicher das du die led nicht ausversehen direkt mit dem schalter 
schaltest, weil du irgend eine Brücke falsch gesetzt hast?


>allerdings mag ich hier gerne ein einfaches Makro:
>#define BIT(n) (1 << (n))
>dann wirds vernünftig lesbar.

Geschmackssache. Auf jeden Fall sollte man sich auf eine Variante 
festlegen und auf jeden Fall die von den avr-Headern bereitgestellten 
Kosntanten benutzen.
Gast #1333179
Lesenswert?

funky schrieb:
> gehts nur mir so, das ich 0x08 einleuchtender finde als 1 << 3 ??

Ja.

"1 << 3" ist zwar auch nicht das Gelbe vom Ei, aber immer noch besser 
als "0x08".

Besser wäre es so:
1
#define DDR_LED    DDRA
2
#define PORT_LED   PORTA
3
#define LED0       (1<<0)
4
#define LED1       (1<<1)
5
#define LED2       (1<<2)
6
#define LED3       (1<<3)
7

8
void main (void)
9
{
10
   DDR_LED = LED0|LED1|LED2|LED3;
11
   PORT_LED = 0;
12

13
   // tu irgendwas...
14

15
   while (1)
16
   {
17
      if(irgendeine Bedingung)
18
         PORT_LED |= LED3;
19
   }
20
}
#1333310
Lesenswert?

Maxxie schrieb:
> @Mark,
>
> na auch deine #defines muss jemand anderes in angemessener Zeit lesen
> können. Code-Reviews mit lauter 0xDEADBEEF sind meist nicht die
> Angenehmsten ;-)

Hehe, ich kenn DEBB und AFFE...
Naja aber die Zweierpotenzen sollte man schon drauf haben, oder? Zumal 
wenn da sowas steht wie:

#define LED0 (0x01)
#define LED1 (0x02)
#define LED2 (0x04)
#define LED3 (0x08)
#define LED4 (0x10)
#define LED5 (0x20)
#define LED6 (0x40)
#define LED7 (0x80)

Also das sollte man vielleicht gerade noch so vom Verständnis hinkriegen 
:-)
#1333521
Lesenswert?

Lothar Miller schrieb:
>> ...du schaltes den Interrupt des Timer0 frei, hast aber
>> keine Routine, welche den Interrupt abarbeiten kann.
> Deshalb wird der Reset-Vektor angesprungen
> --> das Programm startet neu
> --> die LED ist wieder aus.

Womit wir wieder bei dem Punkt wären, den Magnus 10 Minuten nach 
Fragestellung angemerkt hat:

> Sprich: der Fehler befindet sich in dem Teil, den du hier nicht zeigst.
#1333650
Lesenswert?

1
// Schaltplan nachschaun wie mans angehaengt hat
2
#define LED_PORT PORTA
3
#define LED_DDR DDRA
4
#define LED1 (1<<PA0)
5
#define LED2 (1<<PA1)
6
// oder
7
#define LED3 PA5
8
#define LED4 PA6
9
...
10
int main(void)
11
{
12
  LED_DDR |= LED1 | LED2;
13
  LED_PORT &= ~(LED1 | LED2);
14
  // bzw
15
  LED_DDR |= (1<<LED3) | (1<<LED4);
16
  LED_PORT &= ~((1<<LED3) | (1<<LED4));
17
  ...
18
  return 0;
19
}
20
...
Prost!
0xDeadBeefBadF00d
#1333772
Lesenswert?

Mark Brandis schrieb:
> Warum aber
>
> #define LED3       (1<<3)
>
> besser sein soll als
>
> #define LED3       (0x08)

Weil ich bei 0x08 wieder nachdenken muss, welches Bit denn nun gesetzt 
ist. Bei (1<<3) brauch ich das nicht. Es steht schon dort: Bit 3 ist 
gesetzt. Wenn die Led aus irgendeinem Grund von Pin 3 auf Pin 6 versetzt 
werden muss, schreib ich einfach

#define LED3       (1<<6)

und fertig.
Bei deiner Version muss ich wieder überlegen, welche Hexzahl sich 
ergibt, wenn Bit 6 gesetzt ist.

Lass den Compiler die Routinearbeiten erledigen. Der macht das 
zuverlässiger. Die Kunst beim Programmieren besteht auch darin, sich den 
Source Code so zu organisieren, dass man Änderungen einfach machen 
kann ohne grossartig nachdenken oder analysieren zu müssen.

> ich benutze dann ja eh keine "magic numbers" mehr im Code, dafür hab
> ich ja das define.

"magic numbers" zu vermeiden ist das eine. Aber es ist nur die halbe 
Miete.
1
#define NR_ENTRIES  5
2
int Entries[NR_ENTRIES] = { 10, 80, 100, 40, 80 };
3

4
int main()
5
{
6
  for( i = 0; i < NR_ENTRIES; ++i )
7
    // mach was mit Entries[i]
8
}
benutzt auch keine direkten 'magic numbers' im Code.
Trotzdem hast du dir unnötigerweise einen möglichen Stolperstein 
eingehandelt. NR_ENTRIES und die Anzahl der Initialisierungen müssen 
übereinstimmen.
1
int Entries[] = { 10, 80, 100, 40, 80 };
2
#define NR_ENTRIES  (sizeof(Entries) / sizeof(*Entries))
3

4
int main()
5
{
6
  for( i = 0; i < NR_ENTRIES; ++i )
7
    // mach was mit Entries[i]
8
}

Hier passt sich alles von selbst an. Will ich einen Wert mehr im Array, 
schreibe ich ihn einfach hin. Der Compiler erledigt den Rest
1
int Entries[] = { 10, 80, 100, 40, 80, 400 };
2
#define NR_ENTRIES  (sizeof(Entries) / sizeof(*Entries))
3

4
int main()
5
{
6
  for( i = 0; i < NR_ENTRIES; ++i )
7
    // mach was mit Entries[i]
8
}

(Und nein: Beides ist gleich effizient. Nur um gleich dem Einwand der 
erhöhten Laufzeit vorzubeugen. Die paar Hunderstel Sekunden, die der 
Compiler zum Parsen und Bewertung des konstanten Ausdrucks benötigt, 
können wir getrost vergessen. Spätestens wenn du nur ein einziges mal 
einen 2.ten Compilerlauf benötigst, weil der Compiler warnt, dass die 
Anzahl der Initialisierungen nicht mit der Array-Size übereinstimmt, 
hast du mehr Zeit unnötig verbrutzelt als das Schreiben und die 
zusätzliche Compilerlast in vielen Tausend Compilerdurchgängen benötigt)

> Also das sollte man vielleicht gerade noch so vom Verständnis hinkriegen

Klar sollte man das. Aber wozu, wenn es eine Schreibweise gibt, bei der 
die Bitnummer direkt dort steht? Und an dieser Stelle interessiert mich 
die Bitnummer viel mehr als alles andere, weil sie mir sagt, nach 
welchem Pin ich auf dem µC suchen muss, wenn ich ein Multimeter 
draufhalten will. Die Hex-Zahl bringt dagegen keinen Vorteil an dieser 
Stelle, ausser den, den Programmierer geistig beweglich zu halten und 
seine Fertigkeit im Erkennen von gesetzten Bits in einer Hexzahl zu 
trainieren.

In der alternativen Schreibweise muss ich mir lediglich merken, dass das 
Muster  1 << x  ein Datenwort ergibt, welches an der Stelle x ein 1-Bit 
aufweist. Diese Erkentniss brauchst du aber in der µC-Programmierung 
sowieso alle Nase lang.
Moderator (Firma: Titel) Persönliche Seite #1333814
Lesenswert?

> Weil ich bei 0x08 nachdenken muss, welches Bit denn nun gesetzt ist.
Nachdenken schadet nicht...

Wenn ich z.B. ein Kommandoregister initialisiere, dann sagt mir
1
 kreg = 0x47;
dass ich alle Bits angeschaut, bewertet und anschliessend auf 1 oder 0 
gesetzt habe. Wenn ich dagegen
1
 kreg = (1<<6)|(1<<2)|(1<<1)|(1<<0);
ansehe, dann könnte man ja meinen, ich hätte nur die Bits angefasst, von 
denen ich meinte, sie wären wichtig. Hier könnte der geneigte Leser des 
Programms den Verdacht hegen, dass ich eines einfach vergessen habe. 
Ausführlich müsste ich also schreiben
1
 kreg =  (0<<7)|(1<<6)|(0<<5)|(0<<4)|(0<<3)|(1<<2)|(1<<1)|(1<<0);
Leserlich ist das jetzt nicht mehr.

> Die Hex-Zahl bringt dagegen keinen Vorteil an dieser Stelle, ausser den,
> den Programmierer geistig beweglich zu halten und seine Fertigkeit im
> Erkennen von gesetzten Bits in einer Hexzahl zu trainieren.
... und kompakter zu Schreiben und zu Lesen zu sein. Es ist doch nur ein 
klitzekleiner Mehraufwand, sich neben all dem anderen Zeug noch die 
Hexzahlen anzulernen.

> Die Hex-Zahl bringt dagegen keinen Vorteil an dieser Stelle...
Aber an anderer Stelle doch? Dann muß ich sie auch lesen können, und 
Übung macht bekanntlich den Meister   ;-)
#1333840
Lesenswert?

Lothar Miller schrieb:
> Wenn ich z.B. ein Kommandoregister initialisiere, dann sagt mir
>
1
 kreg = 0x47;
> dass ich alle Bits angeschaut, bewertet und anschliessend auf 1 oder 0
> gesetzt habe. Wenn ich dagegen
>
1
 kreg = (1<<6)|(1<<2)|(1<<1)|(1<<0);
> ansehe, dann könnte man ja meinen, ich hätte nur die Bits angefasst, von
> denen ich meinte, sie wären wichtig. Hier könnte der geneigte Leser des
> Programms den Verdacht hegen, dass ich eines einfach vergessen habe.
> Ausführlich müsste ich also schreiben
>
1
 kreg =  (0<<7)|(1<<6)|(0<<5)|(0<<4)|(0<<3)|(1<<2)|(1<<1)|(1<<0);
2
>
> Leserlich ist das jetzt nicht mehr.
Falsch!
Du hast bei der HEX Schreibweise vergessen 0xB8 mal 0x00 zu addieren!
Moderator (Firma: Titel) Persönliche Seite #1333879
Lesenswert?

> Gut, dann denke mal nach was (0<<3) | (0<<7) ergibt.
Ich weiß das schon, glaubs mir   ;-)
Aber ich könnte mir gut vorstellen, dass das einige ins Schleudern 
bringt.

> Hex oda Shift sagt genau nichts darüber aus, ob man die ganze Funktion
> des Registers beachtet!
Nein, aber in Hex habe ich jedem Bit explizit einen Wert zugewiesen, ich 
kann nicht einfach eines vergessen.

BTW: was ist eigentlich in C der Wert 0987 als Hex-Zahl dargestellt?


@  Jochen64:
Das eigentliche Problem ist schon lange gelöst:
Interrupts verwendet, ohne eine Interruptroutine zu haben.
Beitrag "Re: einfacher C-Code -> Denkfehler??"
#1333905
Lesenswert?

Lothar Miller schrieb:
> Nein, aber in Hex habe ich jedem Bit explizit einen Wert zugewiesen, ich
> kann nicht einfach eines vergessen.
Bei
1
FOO = (1<<3);
 habe ich auch jedem Bit einen Wert zugewiesen.
Bei
1
FOO |= (1<<3); //bzw &= ~(..);
 siehts anders aus, tortzdem heisst es bei Hex nicht, dass man alles 
beachtet hat.

> BTW: was ist eigentlich in C der Wert 0987 als Hex-Zahl dargestellt?
Ich verstehe die Frage nicht. 0987 ist eine Oktalzahl in C, da sie mit 0 
beginnt. Als Hex wäre es einfach 0x987 (bzw 0x0987 wennst die führende 0 
willst).
#1333911
Lesenswert?

HB schrieb:
> Einfacher gehts nicht
>
> #define LED1_ON            (PORTA &= ~0x01)
> #define LED1_OFF            (PORTA |=  0x01)
> #define TASTER1            (PINE &  0x01)
>
>
> While(1)
> {
>  if(TASTER1)LED1_ON
>        .
>        .
>        .
>        .
>  irgendwo...LED1_OFF


Ich finde Bitvariablen einfacher.
Man kann sie auf 0 oder 1 testen bzw. setzen, wie jede andere Variable 
auch.
Und man kann ihnen vor allem aussagekräftige Namen geben:
1
#include <avr\io.h>
2

3
struct bits {
4
  uint8_t b0:1;
5
  uint8_t b1:1;
6
  uint8_t b2:1;
7
  uint8_t b3:1;
8
  uint8_t b4:1;
9
  uint8_t b5:1;
10
  uint8_t b6:1;
11
  uint8_t b7:1;
12
} __attribute__((__packed__));
13

14
#define SBIT_(port,pin) ((*(volatile struct bits*)&port).b##pin)
15
#define SBIT(x,y)       SBIT_(x,y)
16

17

18

19

20
#define LED_GREEN       SBIT( PORTB, PB0 )
21
#define LED_GREEN_DDR   SBIT( DDRB,  PB0 )
22

23
#define KEY_ON_PIN      SBIT( PINB,  PB1 )
24
#define KEY_ON_PULL     SBIT( PORTB, PB1 )
25

26

27
int main( void )
28
{
29
  LED_GREEN_DDR = 1;    // output
30
  KEY_ON_PULL = 1;      // input with pullup
31

32
  for(;;){
33
    if( KEY_ON_PIN == 1 )
34
      LED_GREEN = 1;
35
    else
36
      LED_GREEN = 0;
37
  }
38
}


Peter
Gast #1334840
Lesenswert?

Programmierer schrieb:
>> #define SECS_PER_HALF_HOUR     60*60
>>
>> #define SECS_PER_HALF_HOUR     3C*1C
>
> Ist aber Müll... Klammern vergessen... Kann also häßliche Seiteneffekte
> haben. Ausserdem ist "3C" kein gültiges C...
>
> Besser ist:
>
>
1
> #define SECS_PER_HALF_HOUR     (60 * 60)
2
> 
3
> #define SECS_PER_HALF_HOUR     (0x3C * 0x1C)
4
>

Veto!

1. Eine halbe Stunde hat 30 * 60 Sekunden.

2. 0x1C sind 28 und passen nun gar nicht ins Schema ;)

Ansonsten stimme ich der Aussage von "Programmierer" zu.
#1335043
Lesenswert?

Magnus Müller schrieb:

> Ansonsten stimme ich der Aussage von "Programmierer" zu.


Recht hat er.
Ich bin beim Schreiben gestört worden (Achtung: Chef kommt!) und habe 
kurzfristig auf Senden gedrückt :-)

Der Sinn dürfte aber rübergekommen sein.
Ob Hex oder Dezimal oder Binär oder die 1<<x Schreibweise:
Es kommt auf den Verwendungszweck an, welche Darstellung vernünftiger 
ist.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren