Forum: Mikrocontroller und Digitale Elektronik Zugriff auf Ports über einen Pointer od Ähnlichem für PIC18F (nicht Bit Addressierbar)


von Flo (Gast)


Lesenswert?

Hallo Leute,

nachfolgend ein beispiel zur erklärung:

Eine Funktion wird aufgerufen und eine Nummer übergeben (die Nummer gibt 
an welcher Port bzw. Bit abgefragt werden soll)

in MAIN:
value = receiver(1) ;

in FUNKTION:
unsigned int receiver (unsigned char Target)
{
    unsigned int Objective[17];
    .
    .
    .

 while(1)
 {
    Objective[1] = PORTCbits.RC1;
    Objective[2] = PORTCbits.RC2;
    .
    .
    . usw.
    if (Objective[Target] == 1)
    {
         ...
    }
    .
    .
    .
    return ...
 }
}
Heist also ich möchte abhängig vom Übergabeparameter an Receiver einen 
anderen Pin abfragen (Objective[Target]), jedoch direkt auf den Wert 
zugreifen über einen Pointer auf den Port. Ich nutze den PIC18F65K80, 
leider sind die Ports nicht Bit-addressierbar und es funktioniert evtl. 
nur über ein Makro, doch ich finde nicht wirklich hilfreiche Schnipsel.

Also wenn sich da jemand auskennt wäre eine kleine Hilfe wirklich super 
:-)!

PS: So wie es oben steht funktioniert es eigentlich, wenn es jedoch wie 
bei mir bis zu 16 Pins sind und ich nur einmal in der while Schleife die 
Abfrage mache, dann stimmen die Werte nicht mehr.

MFG

Flo

von Max H. (hartl192)


Lesenswert?

Poste vllt. mal den ganzen Code*, ich verstehe nicht ganz was du 
vorhast.

* Mit Formatierung:
1
[c]C-Code[/c]

von EGS T. (egs_ti)


Lesenswert?

Flo schrieb:
> jedoch direkt auf den Wert
> zugreifen über einen Pointer auf den Port.

Könntest du deinen Code bitte kommentieren?

Objective ist doch eine lokale Variable der Funktion receiver. Darauf 
kannst du doch garnicht in main zugreifen.

: Bearbeitet durch User
von EGS T. (egs_ti)


Lesenswert?

Flo schrieb:
> PS: So wie es oben steht funktioniert es eigentlich, wenn es jedoch wie
> bei mir bis zu 16 Pins sind und ich nur einmal in der while Schleife die
> Abfrage mache, dann stimmen die Werte nicht mehr.

Dann mach die Abfrage doch in der Funktion...

von Flo (Gast)


Lesenswert?

Hallo danke für die Antwort,

sorry aber der ganze Code ist viel zu kompliziert und aufgeblasen, im 
grunde geht es darum:

1. Wert zb. 2 wird in Main an die Funktion Receiver übergeben.
2. Der übergebene wert ist in der Receiver Funktion das hier z.B. zweite 
Element eines Arrays. Dieses Array beinhaltet Portzuweisungen also z.B.:

Objective[2] = PORTCbits.RC2;

3. Jetzt ist es so das über diesen Port ein Code eingelesen wird also 
mehrere High und Low Flanken, diese Werte werden dann in einem Array 
gebuffert und umcodiert etc.

4. Die Abfrage sieht dann so aus:
if (Objective[Target] == 1 && flag = 0)
{...}
if (Objective[Target] == 0 && flag = 1)
{...}

wobei Target der übergebene Wert (2) ist und hierbei der RC2 pin 
abgefragt werden soll.

Nun will ich aber bis zu 16 verschiedene Pins abfragen und würde ich es 
nach diesem Stil machen also in der while schleife zu schreiben:

//                Objective[1]  = PORTCbits.RC1;
//                Objective[2]  = PORTCbits.RC2;
//                Objective[3]  = PORTCbits.RC3;
//                Objective[4]  = PORTFbits.RF6;
//                Objective[5]  = PORTFbits.RF7;
//                Objective[6]  = PORTDbits.RD0;
//                Objective[7]  = PORTDbits.RD1;
//                Objective[8]  = PORTDbits.RD2;
//                Objective[9]  = PORTDbits.RD3;
//                Objective[10] = PORTEbits.RE6;
//                Objective[11] = PORTEbits.RE7;
//                Objective[12] = PORTCbits.RC4;
//                Objective[13] = PORTCbits.RC5;
//                Objective[14] = PORTCbits.RC6;
//                Objective[15] = PORTCbits.RC7;
//                Objective[16] = PORTDbits.RD5;

...

würde er bei jedem durchlauf erst mal alle Ports abfragen obwohl ich 
eigentlich aktuell nur den einen Wert also (2) möchte. Das führt zu 
Zeitverzögerungen und verursacht Fehler.

Deshalb möchte ich:

vorher einen pointer deklarieren der immer auf den Wert bzw. Adresse des 
aktuell gesuchten Elements zeigt und diesen dann in der if abfrage und 
in der while schleife verwenden.

also:

int receiver (unsigned char Target)
{
    unsigned char Objective[17];

    Objective[1]  = PORTCbits.RC1;    // Zuweisung der Elemente
    Objective[2]  = PORTCbits.RC2;
    Objective[3]  = PORTCbits.RC3;
    Objective[4]  = PORTFbits.RF6;
    ...

    unsigned char *pTR;               // Erstellen eines Pointers

    pTR = &Objective[Target];         // Auf adresse von gew. Wert

    while(1)
    {
        if(*ptr == 1 && flag == 0)    // Aktuellen Wert holen und prüfen
        {
         ...
        }
        if(*ptr == 0 && flag == 1)
        {
         ...
        }
    return irgendwas;
    }


Dies ist aber mit dem PIC nicht möglich da dieser nicht Bit Adressierbar 
ist, daher suche ich nach einer ähnlichen Alternative die mir diese 
Funktionalität ermöglicht!

MFG

FLO

PS: Ich hoffe da blickt noch wer durch :D

von EGS T. (egs_ti)


Lesenswert?

Müsste man dann nicht eher die Adresse des Ports in die Variable 
schreiben?
Also ungefähr so:

    Objective[1]  = &PORTCbits.RC1;    // Zuweisung der Elemente
    Objective[2]  = &PORTCbits.RC2;
    Objective[3]  = &PORTCbits.RC3;
    Objective[4]  = &PORTFbits.RF6;
    ...

Und dann halt ganz normal dereferenzieren:

    if ( *Objective[1] == 1 && flag == 0)
...

und du müsstest theoretisch den aktuellen Wert des Portbits erhalten. 
Theoretisch.

von reimay (Gast)


Lesenswert?

Also ich weiss nicht ob ich Dein Problem richtig verstanden habe und ich 
kenne auch den PIC C Compiler nicht.
Aber diese ganzen PortDbits.yxz scheinen Mitglieder einer struct zu 
sein.
Muss ja in einer Headerdatei deklariert sein.
Vlt hilfts die struct zurückzugeben und daraus den gewünschten Pin zu
lesen.
Aber gut möglich das ich das Problem nicht sehe, dann vergiss einfach 
meine Antwort.

von Volker S. (vloki)


Lesenswert?

Flo schrieb:
> PS: Ich hoffe da blickt noch wer durch :D

Nö ;-)

Warum willst du denn alle zuweisen, wenn dich nur eins interessiert ?
Was soll eigentlich die while(1) Schleife in einer Funktion ?

von EGS T. (egs_ti)


Lesenswert?

Volker SchK schrieb:
> Was soll eigentlich die while(1) Schleife in einer Funktion ?

Hehehe, das ist mir noch garnicht aufgefallen.

von Max H. (hartl192)


Lesenswert?

Ich denke, das einfachste wird sein wenn du dir eine Funktion getInput 
oder ähnliches schreibst:
1
uint8_t getInput(uint8_t pin_number)
2
{
3
  switch(pin_number) 
4
  {
5
    case  1: return PORTCbits.RC1;
6
    case  2: return PORTCbits.RC2;
7
    case  3: return PORTCbits.RC3;
8
    case  4: return PORTFbits.RF6;
9
    case  5: return PORTFbits.RF7;
10
    case  6: return PORTDbits.RD0;
11
    case  7: return PORTDbits.RD1;
12
    case  8: return PORTDbits.RD2;
13
    case  9: return PORTDbits.RD3;
14
    case 10: return PORTEbits.RE6;
15
    case 11: return PORTEbits.RE7;
16
    case 12: return PORTCbits.RC4;
17
    case 13: return PORTCbits.RC5;
18
    case 14: return PORTCbits.RC6;
19
    case 15: return PORTCbits.RC7;
20
    case 16: return PORTDbits.RD5;
21
    default: return 0;
22
  }
23
}

: Bearbeitet durch User
von EGS T. (egs_ti)


Lesenswert?

Gute Idee!

von Max H. (hartl192)


Lesenswert?

Wenn man sich den Funktionsaufruf bei jeder Abfrage sparen will, falls 
es so viele sind dass sie bei der Laufzeit ins Gewicht fallen, könnte 
man die getInput() auch inlinen lassen oder man versucht es so:
1
  // Untested
2
  #define INPUT_PIN (*port_ptr & bitmask)
3
  
4
  volatile uint8_t *port_ptr = NULL
5
  uint8_t bitmask = 0;
6
  switch(Target) 
7
  {
8
    case 1:  port_ptr = &PORTC; bitmask = 1 << 1;
9
    case 2:  port_ptr = &PORTC; bitmask = 1 << 2;
10
    case 3:  port_ptr = &PORTC; bitmask = 1 << 3;
11
    case 4:  port_ptr = &PORTF; bitmask = 1 << 6;
12
    case 5:  port_ptr = &PORTF; bitmask = 1 << 7;
13
    case 6:  port_ptr = &PORTD; bitmask = 1 << 0;
14
    case 7:  port_ptr = &PORTD; bitmask = 1 << 1;
15
    case 8:  port_ptr = &PORTD; bitmask = 1 << 2;
16
    case 9:  port_ptr = &PORTD; bitmask = 1 << 3;
17
    case 10: port_ptr = &PORTE; bitmask = 1 << 6;
18
    case 11: port_ptr = &PORTE; bitmask = 1 << 7;
19
    case 12: port_ptr = &PORTC; bitmask = 1 << 4;
20
    case 13: port_ptr = &PORTC; bitmask = 1 << 5;
21
    case 14: port_ptr = &PORTC; bitmask = 1 << 6;
22
    case 15: port_ptr = &PORTC; bitmask = 1 << 7;
23
    case 16: port_ptr = &PORTD; bitmask = 1 << 5;
24
  }
25
  if(port_ptr == NULL)
26
    return;
27
    
28
  //...
29
  
30
  // Abfrage dann mit
31
  if(INPUT_PIN)
32
  //...

: Bearbeitet durch User
von Flo (Gast)


Lesenswert?

Hey Leute,

vielen Dank für die Antworten!

Ich werde einige eurer Vorschläge ausprobieren!

Die while schleife in der Funktion kommt daher, das die Funktion selbst 
auch cases enthält (switch(state)...) und auch auf andere Funktionen 
noch zurückgreift.

Ums mal zu verdeutlichen:

Mein µC bekommt von 16 anderen µC Werte via Manchester Code auf GPIO 
rein. Nun frage ich jeden Pin nacheinander ab und beginne die 
Decodierung, an meine Mainfunktion gebe ich den Wert als Integer zurück. 
In meiner Main wird die Funktion in einer For-Schleife aufgerufen also 
so:

for (int i = 1; i < 17; i++)
{
    ReceiveBuffer[i] = Receiver(i);
}

Demnach werden die decodierten Werte als Integer im ReceiveBuffer mit 
dem jeweiligen Index gespeichert. Daher kommt das ganze mit den vielen 
Eingängen usw.

Natürlich könnte ich auch einen Multiplexer 16:1 davorschalten und das 
ganze über einen Pin machen, so werde ich es wenn es wirklich nicht 
anders funktioniert auch machen, jedoch war das Ziel hierbei so 
kostengünstig wie möglich ohne weitere benötigten Bauteile zu 
realisieren. Aber mal sehen was wird.

Auf jeden: Vielen Dank schon mal ich mach aber demnächst Feierabend und 
werde eure Vorschläge morgen ausprobieren!

LG

Flo

von Volker S. (vloki)


Lesenswert?

Ich fand deinen ersten Vorschlag eh besser aber hier fehlen breaks ;-)

von Max H. (hartl192)


Lesenswert?

Volker SchK schrieb:
> Ich fand deinen ersten Vorschlag eh besser aber hier fehlen breaks
> ;-)
Stimmt, hab ich ganz übersehen. Dann halt so:
1
  // Untested
2
  #define INPUT_PIN (*port_ptr & bitmask)
3
  
4
  volatile uint8_t *port_ptr = NULL
5
  uint8_t bitmask = 0;
6
  switch(Target) 
7
  {
8
    case 1:  port_ptr = &PORTC; bitmask = 1 << 1; break;
9
    case 2:  port_ptr = &PORTC; bitmask = 1 << 2; break;
10
    case 3:  port_ptr = &PORTC; bitmask = 1 << 3; break;
11
    case 4:  port_ptr = &PORTF; bitmask = 1 << 6; break;
12
    case 5:  port_ptr = &PORTF; bitmask = 1 << 7; break;
13
    case 6:  port_ptr = &PORTD; bitmask = 1 << 0; break;
14
    case 7:  port_ptr = &PORTD; bitmask = 1 << 1; break;
15
    case 8:  port_ptr = &PORTD; bitmask = 1 << 2; break;
16
    case 9:  port_ptr = &PORTD; bitmask = 1 << 3; break;
17
    case 10: port_ptr = &PORTE; bitmask = 1 << 6; break;
18
    case 11: port_ptr = &PORTE; bitmask = 1 << 7; break;
19
    case 12: port_ptr = &PORTC; bitmask = 1 << 4; break;
20
    case 13: port_ptr = &PORTC; bitmask = 1 << 5; break;
21
    case 14: port_ptr = &PORTC; bitmask = 1 << 6; break;
22
    case 15: port_ptr = &PORTC; bitmask = 1 << 7; break;
23
    case 16: port_ptr = &PORTD; bitmask = 1 << 5; 
24
  }

: Bearbeitet durch User
von Volker S. (vloki)


Lesenswert?

Flo schrieb:
> Ums mal zu verdeutlichen:
>
> Mein µC bekommt von 16 anderen µC Werte via Manchester Code auf GPIO
> rein. Nun frage ich jeden Pin nacheinander ab und beginne die
> Decodierung, an meine Mainfunktion gebe ich den Wert als Integer zurück.
> In meiner Main wird die Funktion in einer For-Schleife aufgerufen also
> so:
>
> for (int i = 1; i < 17; i++)
> {
>     ReceiveBuffer[i] = Receiver(i);
> }

Warum speicherst du nicht einfach die PortsC..F in ReceiveC..F ?
Die Dekodierung kannst du dann doch genauso machen ...

von Flo (Gast)


Lesenswert?

Hallo Volker,

ich kann deinem Vorschlag nicht ganz folgen, meinst du den Kompletten 
Port in jeweilige Buffer einlesen und diesen Buffer dann ausmisten?

Ich machs halt momentan so und es funktioniert auch wenn ich einzelne 
mache nur eben bei den vielen verzögert es sich:

1. Warte auf eine Reihe Nullen -> Statewechsel
2. Warte auf steigende Flanke -> Timer ein Statewechsel
3. Warte auf fallende Flanke -> Timer aus -> Wert = Synchronisationszeit 
-> Statewechsel
4. Warte auf eine Reihe Nullen -> Statewechsel
5. Warte auf steigende Flanke -> Timer ein
6. Warte auf fallende Flanke -> Timer aus wenn Zeit um einiges größer 
als erste Zeit dann dementsprechend eine 0 u. 1 ins Array oder eben 1 u. 
0. andernfalls wenn Zeit ungefähr gleich dann eben 1 oder 0 ins Array.
7. Wenn Message dann Fertig ist 8Bit ID + 10Bit daten wird das Array an 
eine Funktion übergeben die ID wegschneidet die Bits richtig hindreht 
und mir daraus den Binärwert in ein Integer schreibt --> return VALUE

von Volker S. (vloki)


Lesenswert?

Flo schrieb:
> Hallo Volker,
>
> ich kann deinem Vorschlag nicht ganz folgen, meinst du den Kompletten
> Port in jeweilige Buffer einlesen und diesen Buffer dann ausmisten?

Warum ausmisten, lass es einfach stehen bis zum nächsten mal.
Bei der Dekodierung greifst du einfach auf die jeweiligen Bits zu.

Von mir aus wieder über ein
   #define uCNr1_in    ReceiveC & 0x02

oder du definierst dir deine eigenen Bitfelder genau wie im PIC Header 
...

von Volker S. (vloki)


Lesenswert?

1
union whatever
2
{
3
  struct
4
  {
5
    unsigned char PC;
6
    unsigned char PD;
7
    unsigned char PE;
8
    unsigned char PF;
9
  };
10
  struct
11
  {
12
    unsigned C0  :1;
13
    unsigned O_01  :1;  //C1
14
    unsigned O_02  :1;  //C2
15
    unsigned O_03  :1;  //C3
16
    unsigned O_12  :1;  //C4
17
    ...
18
    unsigned O_04  :1;  //F6
19
    unsigned O_05  :1;  //F7
20
  };
21
};
22
23
...
24
25
union whatever newIn, flags;
26
27
...
28
29
  newIn.PC = PORTC;
30
  newIn.PD = PORTD;
31
  newIn.PE = PORTE;
32
  newIn.PF = PORTF;
33
34
  ...
35
36
  if(newIn.O_01 == flags.O_01){
37
  ...

von Peter D. (peda)


Lesenswert?

Am einfachsten ist es, wenn Du die 16 Eingänge auf 2 Ports legst und die 
dann als 16Bit einliest. Dann brauchst Du nur noch eine Maske 
drüberlegen, um den gewünschten Pin auszuwerten:
1
uint16_t read_pin( uint16_t mask ) // mask: 0x0001, 0x0002, 0x0004, ... 0x8000
2
{
3
  uint16_t val = (PORTE<<8) | PORTF;
4
  return val & mask;
5
}

von Volker S. (vloki)


Lesenswert?

Peter Dannegger schrieb:
> (PORTE<<8)

Wenn da mal nicht Null raus kommt ...

von Peter D. (peda)


Lesenswert?

Flo schrieb:
> Mein µC bekommt von 16 anderen µC Werte via Manchester Code auf GPIO
> rein.

Das ist natürlich die denkbar ungeeignetste Methode, mehrere MCs zu 
vernetzen.
Für sowas ist I2C oder CAN gedacht.

von Flo (Gast)


Lesenswert?

Hallo Leute,

weiterhin dickes Dankeschön für eure Bemühungen.

Leider hatte ich heute Vormittag einige Meetings und Telefonate und 
konnte deshalb noch nicht wirklich weiter machen. Ich hoffe ich finde 
Nachmittag noch Zeit an diesem MEETwoch! Dann versuche ich mal einige 
Methoden!

Mfg

Flo

von Flo (Gast)


Lesenswert?

Peter Dannegger schrieb:
> Das ist natürlich die denkbar ungeeignetste Methode, mehrere MCs zu
> vernetzen.
> Für sowas ist I2C oder CAN gedacht.

Ich weiß, jedoch kommt das nicht von mir und die 16microcontroller sind 
kleine 8-Füßler die nichts können ausser adc wert messen und über gpio 
als manchester ausgeben. Soll natürlich nahezu nichts kosten und deshalb 
der ganze aufwand, ein schöner Bus waere da natürlich was feines!

Mfg
Flo

PS: Habs heute nicht mehr geschafft, wies halt so oft ist man nimmt sich 
was vor und kommt zu gar nichts, aber morgen ;-)

von EGS T. (egs_ti)


Lesenswert?

Aber selbst so ein kleiner 8-Füßer müsste doch eine serielle 
Datenübertragung gebacken bekommen. Im "schlimmsten" Fall halt 
bitbanged.

: Bearbeitet durch User
von Flo (Gast)


Lesenswert?

Hallo Leute,

nach einem Kaffee und einem Whiteboard voll mit Code habe ich die Lösung 
gefunden.

Und zwar wie folgt:

Im DEFINITIONS.H Header:

typedef struct
{
    unsigned char *port;
    unsigned char mask;
}pin_pointer;

const pin_pointer pins[4] =
{
    &PORTC, 1 << 0,         // PORTC pin 0 RC0
    &PORTC, 1 << 1,         // PORTC pin 1 RC1
    &PORTC, 1 << 2,         // PORTC pin 2 RC2
    &PORTC, 1 << 3,         // PORTC pin 3 RC3
    ... etc...
};


Anschließend die Port/Pin Abfrage in der FUNKTION:

if(!((*pins[Target].port)&(pins[Target].mask)))
{
    jetzt liegt eine 0 am gewünschten über Target definierten Pin an
}

...

if(((*pins[Target].port)&(pins[Target].mask)))
{
    jetzt liegt eine 1 am gewünschten über Target definierten Pin an
}



So funktioniert es und er frägt immer nur den jeweilig gewünschten Port 
ab :-) ohne große Zeitverzögerung!

Vielen Dank für die Denkanstöße und bereigtestellten Codeschnipsel!!!

MFG

Flo


PS: Ja ich weiß aber dieser Weg wurde von Person "X" bestimt und von 
Person "Y" ausgeführt und "ich" also Person "Z" muss die Suppe 
auslöffeln :-D !

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.