mikrocontroller.net

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


Autor: Matthias Nagel (mat81927)
Datum:

Bewertung
0 lesenswert
nicht 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.
void check_active_port_gpi(void)
{
  unsigned char gpi_ports_high, gpi_ports_low;
  unsigned char i,openport=1;  

  gpi_ports_low  = PINB;
  gpi_ports_high = PING;
  
  for(i=0; i<8; i++)
  {
    if(bit_is_set(gpi_ports_low,i))
    {
      i=8;
    }
    else
    {
      openport += 1;
    }
  }
if((openport == 8) && (bit_is_set(gpi_ports_high,0)))
{
  openport += 1;
}
else
{
  openport = 0;
}
}

Vielen Dank für eure Hilfe

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Matthias Nagel (mat81927)
Datum:

Bewertung
0 lesenswert
nicht 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/func...

meinst du diese Funktion ?

Autor: MNR (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Matthias Nagel (mat81927)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke euch,

werde mir die Doku nun mal anschauen.

Grüsse, Matthias

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie wäre es damit:

byte check_active_port_gpi(void)
{
 word input = 0;

 input = PINB;
 input |= (PING<<8);

 switch( input )
 {
  case 1:return 1;break;
  case 2:return 2;break;
  case 4:return 3;break;
  case 8:return 4;break;
  case 16:return 5;break;
  case 32:return 6;break;
  case 64:return 7;break;
  case 128:return 8;break;
  case 256:return 9;break;
  default: return 0;break;
 }

}

Autor: Matthias Nagel (mat81927)
Datum:

Bewertung
0 lesenswert
nicht 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 ?
unsigned char check_active_port_gpi(void)
{
 unsigned char input, eeprom_port;

 input = PINB;

 switch( input )
 {
  case 1: input=1;
  case 2: input=2;
  case 4: input=3;
  case 8: input=4;
  case 16: input=5;
  case 32: input=6;
  case 64: input=7;
  default: input=0;
 }
 
 eeprom_port = eeprom_read_byte(EEP_OFFSET_SWITCH_PORT);

 if(input != eeprom_port)
 {
  eeprom_write_byte(EEP_OFFSET_SWITCH_PORT, input);
  enable_port(input);
 }

 return input;
}

Vielen Dank

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Matthias Nagel (mat81927)
Datum:

Bewertung
0 lesenswert
nicht 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 ?

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, ein Thread für ein Problem, damit auch die Überschrift passt.

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:

// PC = Aktuelle Position in der Befehlsverarbeitung
// Wird entweder als "Instruction Pointer" (IP) od. auch als 
// "Program counter" (PC) bezeichnet.

Adresse   Pseudocode

00        Springe zu PC+x;// switch (value) - value ist hier 2; x = 0;
01        
02         Tue Prozedur 1;// wird bei value = 2 angesprungen
03         springe zu 07;
04         Tue Prozedur 2;// wird bei value = 4 angesprungen
05         springe zu 07;
06         ....
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!)

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 ;)

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.