Forum: Compiler & IDEs uint32_t avr gcc Problem


von Alexander (Gast)


Lesenswert?

Hey,
zur Zeit spiele ich mit 4x74HC595 an einem Atmega 168 rum. Soweit so 
gut, die Pins 1 bis 16 leuchten nacheinander auf, so wie ich mir das 
vorstelle. Doch 16 leuchtet dann alleine genauso lange wie der gesamte 
Durchlauf, 17 bis 32 leuchten nie auf.
1
uint32_t old_data = 1UL;
2
int main(void){
3
4
5
  DDRB |= (1 << SER_PIN) | ( 1 << CLK_PIN) | (1<< RST_PIN);
6
  PORTB &= ~( 1 << RST_PIN);
7
  PORTB &= ~( 1 << CLK_PIN);
8
  PORTB &= ~( 1 << SER_PIN);
9
10
  while(1){
11
    for(uint8_t i=0; i< 32; i++){
12
      send_32_bits();
13
      old_data = old_data + old_data;
14
      _delay_ms(100);
15
    }
16
    old_data = 1UL;
17
  }
18
19
}
Das ist mein Code soweit.

Meine Theorie wäre jetzt, das Pin 16 als Wert ja 2^15 hat (also 32768), 
Pin 17 jedoch 65536, was größer als der uint16_t ist. Ich nutze jedoch 
einen uint32_t, sodass ich es halt merkwürdig finde, dass genau an 
dieser Grenze ein Fehler auftritt.

Habe ich irgendwas übersehen ?

Viele Grüße & vielen Dank im vorraus

Alexander

von g457 (Gast)


Lesenswert?

> Habe ich irgendwas übersehen ?

Ja, den Rest des Codes.

von Loocee L. (loocee)


Lesenswert?

- Wie schaut denn send_32_bits() aus?

- sind alle 595 korrekt verkettet?
- bekommen alle einen Clock und einen Strobe?
- alle Reset-Pins inaktiv?

von Alexander (Gast)


Lesenswert?

Hallo,
Ja alle sind richtig verkettet, da die 32 Bit verkehrt herum 
rausgeschifftet werden (LSB vom uint32_t ist praktisch MSB der 74HC595 
Ausgänge).
Wie gesagt die Ausgänge 17-32 leuchten nacheinander auf (das sind die 
letzten beiden 74HC595 die in der Reihe hängen), bei den vorderen beiden 
passiert nichts. Q0 vom 3ten 74hc595 (also Anschluss 17 oder Bit 16 von 
old_value) leuchtet nach dem Durchlauf von 32 bis 17 noch einmal genauso 
lang, wie der Durchlauf gedauert hat.

Wie gesagt es läuft einwandfrei, die Schaltung hatte ich vorher schonmal 
genutzt (mit einem Beaglebone), dort liefen alle 32 Ausgänge...

Da Clk und Latch(bei mir im code reset) durchgeschleift werden und es 
bei den letzten beiden Funktioniert, nehme ich an, dass das alles okay 
ist.

von Loocee L. (loocee)


Lesenswert?

Alexander schrieb:
> Hey,
> zur Zeit spiele ich mit 4x74HC595 an einem Atmega 168 rum. Soweit so
> gut, die Pins 1 bis 16 leuchten nacheinander auf, so wie ich mir das
> vorstelle. Doch 16 leuchtet dann alleine genauso lange wie der gesamte
> Durchlauf, 17 bis 32 leuchten nie auf.

Alexander schrieb:
> Wie gesagt die Ausgänge 17-32 leuchten nacheinander auf (das sind die
> letzten beiden 74HC595 die in der Reihe hängen), bei den vorderen beiden
> passiert nichts. Q0 vom 3ten 74hc595 (also Anschluss 17 oder Bit 16 von
> old_value) leuchtet nach dem Durchlauf von 32 bis 17 noch einmal genauso
> lang, wie der Durchlauf gedauert hat.

Du willst hier aber niemand verarschen ?

Solang du nicht ein anständiges (authentisches) Schaltbild und
eine Routine send_32_bits() lieferst hörst du von mir nichts mehr.

Ausser vielleicht dass ein Latch- und ein Clock-Impuls nicht
"durchgeschleift" werden können, die 595 haben keine Ausgänge dafür.
Wäre auch voll der Käse da sonst wild Laufzeiten dazukommen.

: Bearbeitet durch User
von Alexander (Gast)


Angehängte Dateien:

Lesenswert?

1
void send_32_bits(void) {
2
  for (uint8_t i = 0; i < 32; i++) {
3
    if (old_data & (1 << i)) {
4
      PORTB |= ( 1 << SER_PIN);
5
    } else {
6
      PORTB &= ~( 1 << SER_PIN);
7
    }
8
    generate_clock();
9
  }
10
  reset_register();
11
}
12
13
void generate_clock(){
14
  PORTB |= (1 << CLK_PIN);
15
  _delay_us(40);
16
  PORTB &= ~(1<< CLK_PIN);
17
}
18
19
void reset_register(){
20
  PORTB |= (1 << RST_PIN);
21
  _delay_us(40);
22
  PORTB &= ~( 1 << RST_PIN);
23
24
}

Anbei die Schaltung.

Wie Eberhard so schön festgestellt hab, schleife ich den CLK und Latch 
natürlich nicht durch, sondern er wird zentral verteilt.
Auf dem Steckbrett ist jedoch immer von einem clk input zum nächsten 
eine Drahtbrücke, deshalb war das für mich wie "durchgeschleift".
Die unteren beiden 595er tun was sie sollen.
Die oberen beiden tun nicht was sie sollen, stattdessen bleibt Q0 vom 
vorletzten 595er dauerhaft an, bis ein neuer Durchlauf beginnt.

von Detlev T. (detlevt)


Lesenswert?

Alexander schrieb:
> if (old_data & (1 << i))

Hier ist dein Problem. Per Standard rechnet der avg-gcc nur mit 16 Bit!. 
(1<<16) ist null. Setze hier doch einmal 1UL ein.

: Bearbeitet durch User
von Loocee L. (loocee)


Lesenswert?

Vermutlich macht in der Zeile

if (old_data & (1 << i))

der Shift einen Cast auf einen signed int16
sodass das Ergebnis nur für die ersten 16 Bit true sein kann.

Vergleiche old_data mit einer uint32_t bitmask dann sollte
es funktionieren.

also

(uint32_t)bitmask = (1 << i);
if (old_data & bitmask ) .....


(war jemand schneller als ich)

von chris (Gast)


Lesenswert?

Eberhard F. schrieb:
> (uint32_t)bitmask = (1 << i);

auch das hilft nicht.
1 ist ein int und somit auf AVRs 16bit breit.
Die 1 muss direkt in einen breiteren Datentyp gecastet werden und dann 
geshiftet.

Abgesehen davon kann man die Funktion optimieren, damit nicht so viele 
Shifts nötig sind (die muss der AVR mangels Barrelshifter alle einzeln 
durchführen):
1
void send_32_bits(void) {
2
  for (uint8_t i = 0; i < 32; i++) {
3
    if (old_data & 0x01) {          // immer das LSB prüfen
4
      PORTB |= ( 1 << SER_PIN);
5
    } else {
6
      PORTB &= ~( 1 << SER_PIN);
7
    }
8
     old_data = old_data >> 1;   // nur ein Shift pro Durchlauf
9
    generate_clock();
10
  }
11
  reset_register();
12
}


lg
Chris

von Alexander (Gast)


Lesenswert?

Vielen Dank euch beiden !
Jetzt funktioniert es.

von g457 (Gast)


Lesenswert?

> (uint32_t)bitmask = (1 << i);

Nö, das ist das selbe in grün. detlevt hat das richtig(tm) gelöst.

Ne menge Rechenzeit kann man übrigens sparen wenn man das Rumgeschiebe 
nicht in jedem Schleifendruchlauf wiederholt sondern die Maske speichert 
(ählich wie loocee schrub, allerdings ausserhalb der Schleife 
deklariert) und in jedem Durchlauf jeweils nur um ein Bit schiebt.

von Loocee L. (loocee)


Lesenswert?

chris schrieb:
> auch das hilft nicht.

Ich habe mich ungenau ausgedrückt. Natürlich muss man die
Variable als uint32 definieren.

Das Aufrufen von reset_register() ist übrigens unnötig.

von Karl H. (kbuchegg)


Lesenswert?

Eberhard F. schrieb:
> chris schrieb:
>> auch das hilft nicht.
>
> Ich habe mich ungenau ausgedrückt. Natürlich muss man die
> Variable als uint32 definieren.
>
> Das Aufrufen von reset_register() ist übrigens unnötig.

unnötig würde ich nicht sagen.
Eher: Die Funktion ist falsch benannt.
Der RCLK Pin eines 595 hat nichts mit einem Reset zu tun.

Im übrigen würde ich nach dem Muster 'Teile zund Herrsche' vorgehen.
Eine Funktion, die nur 8 Bit rausschiftet ist trivial. Sowohl für den C 
Programmierer als auch für den AVR. 8 Bit kann er wunderbar durch die 
Gegend shiften, ohne dass er Stress kriegt.
Diese Funktion 4 mal mit je einem anderen Byte aus dem uint32_t 
aufzurufen ist ebenfalls trivial.
1
void clock_8_bits( uint8_t value )
2
{
3
  for (uint8_t i = 0; i < 8; i++) {
4
    if (value & 0x01) {          // immer das LSB prüfen
5
      PORTB |= ( 1 << SER_PIN);
6
    } else {
7
      PORTB &= ~( 1 << SER_PIN);
8
    }
9
    value >>= 1;
10
    generate_clock();
11
  }
12
}
13
14
void send_32_bits( uint32_t value )
15
{
16
  clock_8_bits(   value         & 0xFF );
17
  clock_8_bits( ( value >>  8 ) & 0xFF );
18
  clock_8_bits( ( value >> 16 ) & 0xFF );
19
  clock_8_bits( ( value >> 24 ) & 0xFF );
20
21
  reset_register();
22
}

von Loocee L. (loocee)


Lesenswert?

Karl Heinz schrieb:
> unnötig würde ich nicht sagen.
> Eher: Die Funktion ist falsch benannt.
> Der RCLK Pin eines 595 hat nichts mit einem Reset zu tun.

In der Tat ... ich nahm in der Eile an er führt nach jedem
32-Bit Write einen Reset aus, aber das ist ja der Latch-Puls,
der auf jeden Fall kommen muss .....

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.