Kann ich ein Bitregister als Funktionsargument im Hi-Tech C-Compiler für PIC16 übergeben?

Gibt es eine Möglichkeit, ein Bit aus einem PIC-Register als Funktionsparameter zu übergeben?

Nehmen wir zum Beispiel den PIC16F887, dessen Register (SFRs) und einzelne Bits in der entsprechenden Header-Datei ( ...\HI-TECH Software\PICC\9.80\include\pic16f887.h) als Brachen definiert sind:

volatile       unsigned char    PORTB       @ 0x006;

volatile       bit  RB3     @ ((unsigned)&PORTB*8)+3;

Wie kann ich das RB3-Bit als Parameter in einer Funktion übergeben, damit ich die Funktion auf diese Weise aufrufen kann:

setBitHigh (RB3);

Was wäre der Prototyp der Funktion?

Ich verwende den HI-TECH C Compiler für PIC10/12/16 MCUs (PRO Mode) V9.80.

EDIT: Die Funktion setBitHigh ist nur ein vereinfachtes Beispiel. Eigentlich möchte ich Bits als Parameter an komplexere Funktionen übergeben und zur Laufzeit auswählen können, welche Bits die Funktion verwenden soll.

Ist "Bit im SFR-Register hoch setzen" nicht eine eingebaute PIC-Assembler-Anweisung?
@ pjc50 Ist es, aber ich möchte nicht nur ein bisschen hoch setzen. Siehe meine Bearbeitung..

Antworten (3)

Vielleicht würde das funktionieren, aber es ist kein Standard-C:

void setBitHigh( bit *b ){
   b = 1;
}
setBitHigh( & RB3 );

Wenn nicht, dann gibt es keine direkte Möglichkeit, das zu tun, was Sie wollen. Sie könnten natürlich den Wert aus der Funktion zurückgeben und ihn dann zuweisen:

RB3 = newBitValue();

oder Sie könnten der Funktion sowohl die Byteadresse als auch den Offset übergeben und es der Funktion überlassen, die Drecksarbeit zu erledigen:

void setBitHigh( unsigned char *a, bit_offset b ){
   *a |= ( 1 << b );
}
setBitHigh( & PORTB, 3 );
Danke Wouter. Eigentlich möchte ich dies in einer komplexeren Funktion als setBitHigh verwenden und zur Laufzeit auswählen können, welche Bits die Funktion verwenden muss. Das erste Stück Code könnte funktionieren. Ich muss es versuchen.
Probieren Sie meinen ersten Vorschlag aus, aber ich glaube mich zu erinnern, dass Hitec C keine Bitzeiger erlaubte. Wenn dies der Fall ist, müssen Sie ein Bit durch seine Byteadresse und seinen Offset darstellen. Sie können schmutzige Tricks anwenden, z. B. beide mit demselben Wert codieren. Oder wechsle zu C++ :)

Was Sie wirklich fragen, ist eine Compiler-Frage. Schauen Sie sich den PIC16-Befehlssatz an und Sie werden sehen, dass es keine Möglichkeit gibt, Bits im Datenspeicher direkt von zur Laufzeit berechneten Adressen zu adressieren. Adressen sind für ganze Bytes von 8 Bits.

Sie könnten jedoch eine Konvention zum Übergeben von Informationen festlegen, die ein bestimmtes Bit identifizieren. Was auch immer Sie tun, der PIC würde kein einzelnes Bit aus Ihrer Adressbeschreibung nativ adressieren, daher sind einige Anweisungen erforderlich, um ein zur Laufzeit ausgewähltes Bit zu lesen oder zu schreiben. Sie könnten Bitadressen so definieren, dass sie 3 extra niedrige Bits haben, was der Bit-Offset innerhalb des Bytes wäre, oder Sie könnten eine Maske des Bits innerhalb seines Bytes oder eine separate Byte- und Bitadresse übergeben, um nur 3 mögliche Konventionen zu nennen.

Überlegen Sie jedoch genau, warum Sie dies wirklich tun möchten. Angesichts des PIC-Befehlssatzes ist es besser, das Bit innerhalb eines Bytes zur Erstellungszeit zu kennen, da alle Bitadressierungsbefehle eine feste Bitnummer enthalten, die in ihnen codiert ist. Vielleicht ist die beste Antwort, einen Schritt zurückzutreten und darüber nachzudenken, was Sie wirklich zu erreichen versuchen, und sich ein Schema auszudenken, das den PIC-Befehlssatz vorteilhaft nutzt, anstatt dagegen anzukämpfen. Mit ein wenig Planung und fortgeschrittener Vorverarbeitung sind einige erstaunliche Dinge möglich. Erklären Sie, was Sie versuchen, zwei Ebenen höher zu erreichen, und vielleicht können wir Möglichkeiten vorschlagen, um die Bitadressierung zur Laufzeit unnötig zu machen.

Es gibt in HT-PIC keinen Mechanismus, um ein Registerbit als Parameter zu übergeben. Es gibt eine Vielzahl von Möglichkeiten, wie man ein solches Ergebnis erzielen kann, die verschiedene Kompromisse in Bezug auf Ausführungsgeschwindigkeit, Code der Aufrufstelle und Code der aufgerufenen Methode beinhalten.

Der einfachste Ansatz besteht wahrscheinlich darin, eine Bitmaske als einen Parameter und eine Adresse oder einen I/O-Adressoffset als zweiten zu übergeben. Wenn die Adresse immer in einer der oberen Bänke oder immer in einer der unteren Bänke sein wird, bedeutet dies, dass zwei Parameterbytes übergeben werden.

Wenn die interessierenden E/A-Bits immer innerhalb einer kleinen Gruppe von Registern (z. B. PORTA-PORTH) liegen, könnte man beide Informationsteile einigermaßen effizient in ein Byte komprimieren; Ich würde vorschlagen, dass zum Codieren der Bits 4-7 die oberen vier Bits eine Bitmaske darstellen, Bit 3 gesetzt ist und die Bits 0-2 einen E / A-Adressen-Offset darstellen. Für die Bits 0–3 sollen die oberen 4 Bits eine um 4 Bits nach links verschobene Bitmaske darstellen, Bit 3 gelöscht sein und die Bits 0–2 den Adressversatz darstellen. Wenn man sich ein paar globale Speicherorte leisten kann, um die Adresse und die Bitmaske zu speichern, könnte man eine Routine haben:

void calcIo(uint8_t portBit)
{
  ioPort = (&PORTA)+(portBit & 7);

  ioBit = portBit & 0xF0;
  if (!portBit & 8)
    ioBit = (ioBit << 4) | (ioBit >> 4); // Allow SWAPF
}

Die seltsam aussehende letzte Anweisung sollte es dem Compiler ermöglichen, wenn der Speicher reicht, eine bedingte SWAPF-Anweisung auf ioBit zu verwenden [der Ausdruck (ioBit << 4)wird immer Null sein, wenn er nicht vorhanden wäre, würde sich der Compiler verpflichtet fühlen, diese Bits zu maskieren].