Forum: Compiler & IDEs Port Binärzahl in Dezimalzahl umwandeln


von Matthias N. (mat81927)


Lesenswert?

Hallo erstmal,

bin ein Neuling in Sachen uC-Progarmmierung und habe C im ersten 
Semester vor 2 Jahren "gelernt". Meine erste Frage mag deshalb für die 
erfahrenen unter uns sehr einfach klingen, ich scheitere jedoch bereits 
hieran.

Ich verwende einen AT90CAN128. Es geht um folgendes C-Problem.
AN PORTB sind alle Pins auf Eingang geschalten. PIN G0 dient ebenfalls 
als Eingang. Aufgrund von schaltungsspezifischen Vorgaben ist nur 
jeweils ein PORT high. Wäre z.B. Port B2 High sollte ich folgendes 
Bitmuster bekommen.

PB0 PB1 PB2 PB3 PB4 PB5 PB6 PB7 PG0
0   0   1   0   0   0   0   0   0

Nun möchte ich diese Information in eine dezimale Zahl umwandeln und 
zwar folgendermassen,

PB0 PB1 PB2 PB3 PB4 PB5 PB6 PB7 PG0
0   0   1   0   0   0   0   0   0
1   2   3   4   5   6   7   8   9

und in diesem Fall würde die unsigned char Variable "openport" den Wert 
3 bekommen. Ist kein Port High, dann soll die Variable den Wert 0 
erhalten. Diese Variable steht für den PORT der High ist. Nun mache ich 
das derzeit mit einer "hässlichen" For-Schleife und ich glaube das man 
das wesentlich schöner hinkriegt.
1
void check_active_port_gpi(void)
2
{
3
  unsigned char gpi_ports_high, gpi_ports_low;
4
  unsigned char i,openport=1;  
5
6
  gpi_ports_low  = PINB;
7
  gpi_ports_high = PING;
8
  
9
  for(i=0; i<8; i++)
10
  {
11
    if(bit_is_set(gpi_ports_low,i))
12
    {
13
      i=8;
14
    }
15
    else
16
    {
17
      openport += 1;
18
    }
19
  }
20
if((openport == 8) && (bit_is_set(gpi_ports_high,0)))
21
{
22
  openport += 1;
23
}
24
else
25
{
26
  openport = 0;
27
}
28
}

Vielen Dank für eure Hilfe

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


Lesenswert?

Die Funktion ffs() macht genau das, was du willst.  Im Großen und
Ganzen ist sie aber auch sehr ähnlich zu deiner Variante
implementiert.

von Matthias N. (mat81927)


Lesenswert?

Vielen Dank erstmal für die schnelle Hilfe,

leider kann ich in meinen C-Büchern und im Web nichts über die Funktion 
finden (Deklaration etc.). Vielleicht könntest du mir eine gute 
Internetseite nennen, wo ich mehr über die Funktion bzw. die Bibliothek 
dazu erfahre.

Vielen Dank

! Nachtrag:

Habe gerade diese Seite gefunden:
http://www.opengroup.org/onlinepubs/009695399/functions/ffs.html

meinst du diese Funktion ?

von MNR (Gast)


Lesenswert?

Er meint die Funktion ffs aus der avr_libc, dessen Doku du erhalten 
hast, als du deinen ggc für avr installiert hast.

Gruß, Matthias

von Matthias N. (mat81927)


Lesenswert?

Danke euch,

werde mir die Doku nun mal anschauen.

Grüsse, Matthias

von Matthias (Gast)


Lesenswert?

Wie wäre es damit:

1
byte check_active_port_gpi(void)
2
{
3
 word input = 0;
4
5
 input = PINB;
6
 input |= (PING<<8);
7
8
 switch( input )
9
 {
10
  case 1:return 1;break;
11
  case 2:return 2;break;
12
  case 4:return 3;break;
13
  case 8:return 4;break;
14
  case 16:return 5;break;
15
  case 32:return 6;break;
16
  case 64:return 7;break;
17
  case 128:return 8;break;
18
  case 256:return 9;break;
19
  default: return 0;break;
20
 }
21
22
}

von Matthias N. (mat81927)


Lesenswert?

Finde ich eine sehr gelungene Darstellung.
Allerdings habe ich mal gehört, dass Operationen mit "goto()" und 
"break" alte Programmierweise ist und aufgrund des harten Eingriffs in 
den Ablauf des Programms nicht mehr eingesetzt werden. Die Funktion 
müsste aber doch auch ohne dem break funktionieren.

Die nun vorläufige Funktion habe ich nochmal ein bisschen abgeändert. 
Habe nun nur noch 7 Eingänge. Und der alte Wert, steht im EEPROM und 
wird gegebenenfalls aktualisiert. Müsste doch so funktioieren oder ?
1
unsigned char check_active_port_gpi(void)
2
{
3
 unsigned char input, eeprom_port;
4
5
 input = PINB;
6
7
 switch( input )
8
 {
9
  case 1: input=1;
10
  case 2: input=2;
11
  case 4: input=3;
12
  case 8: input=4;
13
  case 16: input=5;
14
  case 32: input=6;
15
  case 64: input=7;
16
  default: input=0;
17
 }
18
 
19
 eeprom_port = eeprom_read_byte(EEP_OFFSET_SWITCH_PORT);
20
21
 if(input != eeprom_port)
22
 {
23
  eeprom_write_byte(EEP_OFFSET_SWITCH_PORT, input);
24
  enable_port(input);
25
 }
26
27
 return input;
28
}

Vielen Dank

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


Lesenswert?

Matthias Nagel wrote:

> Allerdings habe ich mal gehört, dass Operationen mit "goto()" und
> "break" alte Programmierweise ist und aufgrund des harten Eingriffs
> in den Ablauf des Programms nicht mehr eingesetzt werden.

Kokolorus.

Donald E. Knuth hat in der Zeit, in der die sogenannte ,,strukturierte
Programmierung'' ihre politische Hochkonjunktur hatte, mal ein Buch
geschrieben, das heißt: ``Structured Programming with GOTO''.  Darin
hat er sehr detailliert beide Seiten der (eher politischen) Diskussion
beleuchtet und begründet, warum absolutistisch vertretene Meinungen
nicht automatisch zu einem gesunden Programmierstil führen.

> Die Funktion müsste aber doch auch ohne dem break funktionieren.

Nein, du hast die Funktion der switch-Anweisung von C noch nicht
verstanden.

von Matthias N. (mat81927)


Lesenswert?

> Donald E. Knuth hat in der Zeit, in der die sogenannte ,,strukturierte
> Programmierung'' ihre politische Hochkonjunktur hatte, mal ein Buch
> geschrieben, das heißt: ``Structured Programming with GOTO''.  Darin
> hat er sehr detailliert beide Seiten der (eher politischen) Diskussion
> beleuchtet und begründet, warum absolutistisch vertretene Meinungen
> nicht automatisch zu einem gesunden Programmierstil führen.

Interessant, so habe ich das noch nie gehört. Jetzt kenn ich wenigstens 
mal den Background dahinter.

>> Die Funktion müsste aber doch auch ohne dem break funktionieren.
>
> Nein, du hast die Funktion der switch-Anweisung von C noch nicht
> verstanden.

Richtig, habe ich verwechselt. SRY

Ich hätte eine Frage zu UART. Wäre wahrscheinlich besser einen neuen 
Beitrag aufzumachen oder ?

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


Lesenswert?

Ja, ein Thread für ein Problem, damit auch die Überschrift passt.

von Matthias (Gast)


Lesenswert?

Gruß an Meister "Matthias Nagel":


Wenn Du das brak bei einer Switch case Anweisung weglässt, dann erlebst 
du
dein blaues Wunder.

Die switch(value) Anweisung sollte vom Compiler in eine Sprungtabelle 
übersetzt werden. Dabei wird der Wert value so ausgewertet, dass daraus 
ein
Sprungoffset berechnet wird.

Beispiel:
1
// PC = Aktuelle Position in der Befehlsverarbeitung
2
// Wird entweder als "Instruction Pointer" (IP) od. auch als 
3
// "Program counter" (PC) bezeichnet.
4
5
Adresse   Pseudocode
6
7
00        Springe zu PC+x;// switch (value) - value ist hier 2; x = 0;
8
01        
9
02         Tue Prozedur 1;// wird bei value = 2 angesprungen
10
03         springe zu 07;
11
04         Tue Prozedur 2;// wird bei value = 4 angesprungen
12
05         springe zu 07;
13
06         ....
14
07         Tue was anderes;// ist das Ende der Switch case.

Ich garantiere hier nicht für Fehlerfreiheit, aber das Prinzip dürfte 
klar sein.

Eine stapel if-Anweisung erzeugt einen etwas komplexeren und dadurch 
langsameren code. Währen die switch-Anweisung schnelleren code 
produziert.
(Intelligente OPtimierungen eines Compilers mal vernachlässigt!)

von Matthias (Gast)


Lesenswert?

Zusatz:

Hab ne Kleinigkeit vergessen:

Das "break" übersetzt der Compiler dabei in die Anweisungen an Adresse 
03 und 05. Wenn man die weglässt läuft das Programm linear durch!

von Matthias (Gast)


Lesenswert?

REM ** Wer lesen kann ist klar im Vorteil ***

Sorry, hab wohl den Thread zu schnell überflogen.
Ich hab noch einen Tip für "Matthias Nagel":

>Und der alte Wert, steht im EEPROM und
>wird gegebenenfalls aktualisiert. Müsste doch so funktioieren oder ?

Wie oft ändert sich der Wert? BEdenke dass das EEPROM nur eine begrenzte 
Anzahl an Schreibzyklen hat! Ausserdem ist die read_eeprom() Funktion 
relativ langsam. Ich empfehle eine Kombination aus Hardware- und 
Softwarelösung.

IN die Schaltung einen "dicken" Elko einbauen, der dem Controller noch 
für einige hundert Milisekunden Strom liefern kann.
Den alten Wert einmal in eine globale VAriable laden und dann bei jeder 
Änderung nur diese Aktualisieren. Wenn die Spannungsversorgung ausfllt 
sollte der Controller einen INterrupt bekommen, die globale Variable ins 
EEPROM sichern und dann solang in einer Schleife (bitte mit Zähler, 
falls wieder Strom kommt) warten, bis der Elko entladen ist!

Das spart Rechenzeit und eeprom-Zyklen ;)

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.