Forum: Compiler & IDEs bit_is_set Abfrage in Software i2c auf Atmega8


von Matthias (Gast)


Lesenswert?

hi

ich bin grade mit dem Versuch beschäftigt, für einen Atmega8 mit 
Winavr/GCC eine Software i2c-routine zu schreiben. Dummerweise treibt 
mich dabei aber eine kleine if-Abfrage so langsam aber sicher in den 
Wahnsinn. Das Ding wehrt sich schon seit tagen:
1
#define SCL_PORT PORTC
2
#define SCL_DDR  DDRC
3
#define SCL_PINREG PINC
4
#define SCL_PIN PC5
5
#define SDA_PORT PORTC
6
#define SDA_DDR DDRC
7
#define SDA_PINREG PINC
8
#define SDA_PIN PC4
9
10
unsigned char i2c_readNak(void)
11
{
12
    unsigned char data;
13
    unsigned char i = 1;
14
    // sicherstellen dass alle zustände auf richtigem ausgangspunkt sind
15
    SDA_DDR &= ~(1<<SDA_PIN);  // SDA: Datenrichtung: in
16
    SDA_PORT &= ~(1<<SDA_PIN);   // SDA: low
17
    SCL_DDR |= (1<<SCL_PIN);  // SCL: Datenrichtung: out
18
    SCL_PORT &= ~(1<<SCL_PIN);  // SCL: low
19
    // empfangen einleiten 
20
    data = 0;
21
    i = 1;
22
    while( i <= 8)    
23
    {
24
       i2c_wait_quaterpuls();
25
       SCL_DDR &= ~(1<<SCL_PIN);  // SCL: Datenrichtung: in (clockstreching)
26
       SCL_PORT |= (1<<SCL_PIN);   // SCL: high
27
       while( bit_is_clear(SCL_PINREG,SCL_PIN) )
28
       {
29
         asm volatile ("nop");
30
       }
31
       SCL_DDR |= (1<<SCL_PIN);  // SCL: Datenrichtung: out
32
       i2c_wait_quaterpuls();
33
       if( bit_is_set(SDA_PINREG,SDA_PIN) )
34
       {
35
          data = ( (data<<1) | 0x01);    // neue information einschreiben
36
       }
37
       else
38
       {
39
          data = ( (data<<1) | 0x00);
40
       }
41
       i2c_wait_quaterpuls();
42
       SCL_PORT &= ~(1<<SCL_PIN);  // SCL: low
43
       i2c_wait_quaterpuls();    // lowpuls abwarten  
44
       i = i + 1;
45
    }
46
    SDA_DDR |= (1<<SDA_PIN);  // SDA: Datenrichtung: out
47
    SDA_PORT |= (1<<SDA_PIN);   // SDA: high = NO ACK
48
    i2c_wait_quaterpuls();    // lowpuls fertig warten
49
    SCL_DDR &= ~(1<<SCL_PIN);  // SCL: Datenrichtung: in (clockstreching)
50
    SCL_PORT |= (1<<SCL_PIN);   // SCL: high
51
    while( bit_is_clear(SCL_PINREG,SCL_PIN) )
52
    {
53
      asm volatile ("nop");
54
    }
55
    SCL_DDR |= (1<<SCL_PIN);  // SCL: Datenrichtung: out
56
    i2c_wait_quaterpuls();    // highpuls abwarten
57
    i2c_wait_quaterpuls();
58
    SCL_PORT &= ~(1<<SCL_PIN);  // zurück auf "warten auf Aufgabe"
59
60
    return data;        // Daten ausgeben    
61
}/* i2c_readNak */
die dabei spinnende Abfrage ist die Zeile: 
if(bit_is_set(SDA_PINREG,SDA_PIN) )
die spricht immer an, egal ob der Pin gesetzt ist oder nicht, was zur 
Folge hat, dass der Code immer 0xff als Ergebniss zurückgibt.

hat mir da irgendjemand eine idee, woran es liegen könnte?

gruß und Danke
Matthias

von Timo B. (Firma: MicroForge) (timob)


Lesenswert?

Total doof, ich habe momentan das gleiche Problem mit meinem Mega2560!

Egal wie ich mit einem if-Statement einen Port abfrage, es ist immer 
true!
1
SIGNAL(PCINT2_vect){
2
  if(bit_is_set(PINK, PORTK0)){
3
    doSomeFineStuff();
4
  }
5
  if(PINK & (1 << PORTK1)){
6
    doSomeThingElse();
7
  }
8
  if(PINK & _BV(PORTK2)){
9
    doSomeNastyCrap();
10
  }
11
}

Es werden immer alle funktionen ausgeführt, aber eigentlich will ich ja 
nur eine der drei ausführen...

Bug im Compiler, oder Bug im Kopf? Der IRQ feuert und dann frage ich ab, 
welche meiner Tasten diesen IRQ abgesetzt hat und vor allem mit welcher 
Flanke. Das geht ja mit den PCINT nicht anders. Aber aus einem mit nicht 
ersichtlichen Grund geht das nicht :(

Gruß
Timo

von Timo Birnschein (Gast)


Lesenswert?

Das beste ist eigentlich, dass wenn ich
1
  
2
if(PINK & (1 << PORTK1)){
3
   doSomeThingElse();
4
}

durch
1
if((PINK & 0x02)){
2
   doSomeThingElse();
3
}

dann GEHTS!.... Aber warum? Nach folgendem stardard-Include
1
#include <avr/io.h>

welche wiederum
1
#include <avr/iom2560.h>

und von da aus
1
#include <avr/iomxx0_1.h>

steht:
1
# define PORTK  _SFR_MEM8(0x108)
2
# define PK7 7
3
# define PK6 6
4
# define PK5 5
5
# define PK4 4
6
# define PK3 3
7
# define PK2 2
8
# define PK1 1
9
# define PK0 0

Dann gehts wieder zurück zur io.h welche anschließend dann
1
#include <portpins.h>

includiert wird, worin steht:
1
#if defined(PK1)
2
#  define PORTK1 PK1
3
#endif

also frage ich gern nochmal: wo ist der Unterschied zwischen (1 << 
PORTK1) und 0x02? Oder anders:
1
if ((1 << PORTK1) != 0x02)
2
   burnAVR();

Gruß
Timo

von A. F. (artur-f) Benutzerseite


Lesenswert?

if(PINK & (1 << PK1))
sollte definitiv den Zustand der Leitung abfragen können. Datenrichtung 
richtig gesetzt? Pull-Ups aus?

von Timo B. (Firma: MicroForge) (timob)


Lesenswert?

Datenrichtung steht auf
1
DDRK = 0x00;
2
PORTK = 0xFF; // Pull-ups an

Die Pullups sind an, da ich mit meinem Taster auf Lowpegel ziehe. Da 
aber auch die Abfrage auf High nicht klappt, habe ich hier das Beispiel 
mit dem HighPegel gemacht.

Im Code steht also eigentlich:
1
SIGNAL(PCINT2_vect){
2
  if(~bit_is_set(PINK, PORTK0)){
3
    doSomeFineStuff();
4
  }
5
  if(~(PINK & (1 << PORTK1))){
6
    doSomeThingElse();
7
  }
8
  if(~(PINK & _BV(PORTK2))){
9
    doSomeNastyCrap();
10
  }
11
}

Oder klappt das nicht?

von Jean P. (fubu1000)


Lesenswert?

Moin,
probier doch mal if(!(PINK & (1 << PK0)) oder if(!(PINK & 0x01)) .

Gruß

von Werner B. (werner-b)


Lesenswert?

Welche Version des Compiler?

Ich frage weil die "frühen" WinAVR mit GCC 4.3 alle möglichen Käfer 
haben.

Wenn AVR-GCC 4.3 auf Linux kann es das gleiche Problem sein.


(Noch) Aktuell ist WinAVR20080610 von 
http://sourceforge.net/projects/winavr/

P.S.
Es häufen sich in letzter Zeit wieder die "alter 4.3er WinAVR" Probleme.
Wer verteilt die?

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.