Forum: Mikrocontroller und Digitale Elektronik portpin in strukt arrey


von Marcel Tschannen (Gast)


Lesenswert?

Hallo Leute.

Ich bastle hier eine Terrariensteuerun mit einem pic18f4550 im C18.

USB, DS1307 und feuchtesensor HYT221 habe ich zum laufen gebracht(bin 
noch am lernen).

Nun scheitere ich aber an der "Zeitschaltuhr"! eigentlich nur am 
speichern eines portpins in einer variable. Wen ich in der Function 
chek_jops() den pin pseudo: PORTx.bits.XX = 1; funzt das super. nur 
brauche ich das "dynamisch".
Habe eine strukt arrey mit jops erstellt:
Die Kanäle für die Relais habe ich mit #define KANAL1 LATEbits.LATE0 be 
named:
1
typedef struct jop{
2
      unsigned char hpts;
3
      unsigned char ehr;
4
      unsigned char emin;
5
      unsigned char ahr;
6
      unsigned char amin;
7
      unsigned char aktion;
8
      unsigned char kanal;
9
      unsigned char status;
10
} jop_t;
11
12
13
jop_t testjop[15];
14
15
testjop[0].hpts=1;
16
testjop[0].ehr=18;  // einschalten
17
testjop[0].emin=0;
18
testjop[0].ahr=18; //ausschalten
19
testjop[0].amin=12;
20
testjop[0].aktion=1;
21
testjop[0].kanal = KANAL1;  // hier scheiterts wohl!????!!
22
testjop[0].status=0;


In der Funktion chek_jops() wollte ich mit testjop[i].kanal = 1 den 
Kanal einschalten -> funzt nicht, weil ich damit ja nur den wert 1 an 
die variable zuweise!
leider übe ich schon eine Woche an dem Problem aber find keine lösung! 
geht das überhaubt in der art oder bin ich total auf dem holzwg?
Hier noch die Funktion
1
void check_jops (void){
2
unsigned char i;
3
for(i=0;i<14;i++){  
4
   if (testjop[i].ehr == aktime.hr && aktime.min == testjop[i].emin){
5
      if (testjop[i].aktion == 1){
6
         if(testjop[i].status == 0){
7
                     testjop[i].kanal = 1;
8
                     testjop[i].status = 1;
9
                     testjop[i].aktion = 0;
10
           
11
         }
12
      }
13
   }
14
   if (testjop[i].ahr == aktime.hr && aktime.min == testjop[i].amin){  
15
      if(testjop[i].aktion == 0){
16
         if(testjop[i].status == 1){
17
                     testjop[i].kanal=0;
18
                     testjop[i].status = 0;
19
                     testjop[i].aktion = 1;
20
         }  
21
      }
22
   }
23
}
24
25
26
}

Währe sehr froh um etwas input.
Gruss Marcel.

von Karl H. (kbuchegg)


Lesenswert?

Du musst rausfinden, was genau sich hinter LATEbits verbirgt. Der Syntax 
nach wird das wohl irgendeine Struktur sein, die auf nicht-Standard-C 
Art mit dem realen physischen Port verknüpft wird.

In deine Struktur muss dann ein Pointer auf genau so eine Struktur rein. 
Allerdings: mit dem Pin an sich wird das höchst wahrscheinlich nichts 
werden. D.h. du wirst mit Byte vom Port holen und ausmaskieren arbeiten 
müssen.

Ich kenn den C18 nicht.
Aber auf einem AVR mit GCC würde das so gehen.

ein Port hat den Datentyp *(volatile unsigned char*)

in eine Struktur muss also rein

struct PortKonfig {
  volatile unsigned char* pPort;
  unsigned char           PortMask;
}

eine derartige Konfiguration wäre zb

struct PortKonfig LedPort = { &PORTA, 0x01 };   // Pin 0 am Port A

normalerweise würde man so den Pin auf 1 setzen
    PORTA |= 0x01;

in der indirekten Variante ist das dann

    *(LedPort.pPort) |= (LedPort.Mask);

von Marcel Tschannen (Gast)


Lesenswert?

Hallo Karl Heinz

Danke für Deine super schnelle Antwort.

Habe es auch schon mit pointer versucht. Nur unterstüzt der C18 keine 
Pointer auf einzelne bit's(wie Du erwartet hast:-))
1
extern volatile near unsigned char       PORTE;
2
extern volatile near union {
3
  struct {
4
    unsigned RE0:1;
5
    unsigned RE1:1;
6
    unsigned RE2:1;
7
    unsigned RE3:1;
8
    unsigned :3;
9
    unsigned RDPU:1;
10
  };
11
  struct {
12
    unsigned CK1SPP:1;
13
    unsigned CK2SPP:1;
14
    unsigned OESPP:1;
15
  };

Die Idee mit maske und pointer auf port bin ich nicht gekommen! Werde 
das mahl probieren.

Ist mir noch ne andere Idee gekommen:-)
Habe mir überlegt ob es nicht einfacher währe nur die Nr des Kanals
zu speichern und mit switch auszuwerten:
1
#define KANAL1_ON() KANAL1 = 1;
2
#define KANAL1_OFF() KANAL1 = 0;
3
4
switch testjop[i].kanal:
5
                        case 1:
6
                              KANAL1_ON(); 
7
                              break;
8
//usw für jeden kanal

Dies nur weil nicht alle Kanäle auf einem Port liegen.
Weis nur nicht wie "elegannt" das ist und ob das nicht mein code extrem 
aufbläst?

von Klaus (Gast)


Lesenswert?

Die PIC Leute machen das etwas anders.

Da schreibt man in C:
1
     _RB0 = 1;       // Port B bit 0 = 1

Was sich dahinter verbirgt hier als Beispiel aus einem der Header Files, 
ist zwar vom C30, sollte aber bei C18 das Gleiche sein
1
extern volatile unsigned int  PORTB __attribute__((__sfr__));
2
typedef struct tagPORTBBITS {
3
  unsigned RB0:1;
4
  unsigned RB1:1;
5
  unsigned RB2:1;
6
  unsigned RB3:1;
7
  unsigned RB4:1;
8
  unsigned RB5:1;
9
  unsigned RB6:1;
10
  unsigned RB7:1;
11
  unsigned RB8:1;
12
  unsigned RB9:1;
13
  unsigned RB10:1;
14
  unsigned RB11:1;
15
  unsigned RB12:1;
16
  unsigned RB13:1;
17
  unsigned RB14:1;
18
  unsigned RB15:1;
19
} PORTBBITS;
20
extern volatile PORTBBITS PORTBbits __attribute__((__sfr__));

Damit würde man dann folgendes schreiben können:
1
   PORTBbits.RB0 = 1;

Und für die Schreibfaulen gibts dann noch das:
1
#define _RB0 PORTBbits.RB0

Für alle Special Function Register gibts solche Einträge in den Header 
Files, auch für Felder mit mehr als einem Bit. Die Bezeichnungen 
entsprechen den im Datenblatt.

MfG Klaus

von Karl H. (kbuchegg)


Lesenswert?

Klaus schrieb:
> Die PIC Leute machen das etwas anders.

Das war mir schon klar.
Nur: wie machst du das indirekt?

zb wie übergibst du einer Funktion eine Referenz auf den Portpin, den 
sie schalten soll.
Da klappt das dann nicht mehr.

von Klaus (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> zb wie übergibst du einer Funktion eine Referenz auf den Portpin, den
> sie schalten soll.

Ich bin da nicht so der C-Experte, deshalb hab ich ja den Ausschnitt aus 
dem Headerfile gepostet. Sollte es nicht möglich sein, einen Pointer auf 
ein Strukturelement aus einer Portstruktur zu bekommen?

MfG Klaus

von Karl H. (kbuchegg)


Lesenswert?

Klaus schrieb:
> Karl Heinz Buchegger schrieb:
>> zb wie übergibst du einer Funktion eine Referenz auf den Portpin, den
>> sie schalten soll.
>
> Ich bin da nicht so der C-Experte, deshalb hab ich ja den Ausschnitt aus
> dem Headerfile gepostet. Sollte es nicht möglich sein, einen Pointer auf
> ein Strukturelement aus einer Portstruktur zu bekommen?

Genau da liegt das Problem. Sowas ist in C nicht vorgesehen.
Die kleinste addressierbare Einheit ist das Byte (vulgo unsigned char).

von gänzi (Gast)


Lesenswert?

Klaus schrieb:
> Sollte es nicht möglich sein, einen Pointer auf
> ein Strukturelement aus einer Portstruktur zu bekommen?
Ist denn ein dein PIC bitadrtessierbar?

von Klaus (Gast)


Lesenswert?

gänzi schrieb:
> Klaus schrieb:
>> Sollte es nicht möglich sein, einen Pointer auf
>> ein Strukturelement aus einer Portstruktur zu bekommen?
> Ist denn ein dein PIC bitadrtessierbar?

Ich glaube, das sind sie. Seit ich die größeren (PIC24) benutze, habe 
ich aber noch keinen Blick auf den Assemblercode geworfen. Wichtig ist 
aber eigentlich, daß der Compiler den passenden Code generiert, ob 
direkt oder mit Maske.

Karl Heinz Buchegger schrieb:
> Genau da liegt das Problem. Sowas ist in C nicht vorgesehen.
> Die kleinste addressierbare Einheit ist das Byte (vulgo unsigned char).

Ich glaube zu verstehen was du meinst. Ist aber nicht inzwischen soetwas 
wie:
1
  unsigned RB0:1;
2
  unsigned RB1:1;
auch Standard C mit der Garantie, daß die beiden Bits hintereinander im 
selben Byte liegen?

MfG Klaus

von Karl H. (kbuchegg)


Lesenswert?

Klaus schrieb:


> Ich glaube zu verstehen was du meinst. Ist aber nicht inzwischen soetwas
> wie:
>
1
>   unsigned RB0:1;
2
>   unsigned RB1:1;
3
>
> auch Standard C mit der Garantie,

natürlich sind Bitfelder schon lange Standard

> daß die beiden Bits hintereinander im
> selben Byte liegen?

Das ist IMHO nicht definiert. Spielt aber auch keine so grosse Rolle in 
diesem Fall. Der springende Punkt ist: Du kannst keinen Pointer bilden, 
der auf einen derartigen Member zeigt. Es gibt schlicht und ergreifend 
keinen Datentyp dafür.

(UNd das zeigt auch wo das Problem beim Bitfield liegt: Ein Bit in einem 
Bitfield wird durch eine Zusatzinfo 'erzeugt', die aber nicht Teil des 
Datentyps ist. Damit kann man auch keinen Pointer daraus bilden)

von Klaus (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
>> auch Standard C mit der Garantie,
>
> natürlich sind Bitfelder schon lange Standard
>
>> daß die beiden Bits hintereinander im
>> selben Byte liegen?

Du hast meinen Satz elegant in zwei Teile geteilt. Na klar sind 
Bitfelder Standard, ich habe sie aber selten verwendet, weil der 
Compiler die Freiheit hat, aus jedem Bitfeld ein int zu machen und ich 
damit nicht die Kontrolle über eine bestimte Bitposition habe.

Wenn ich dich also richtig verstehe, funktioniert dieses Konstruct aus 
dem C30 Header File
1
typedef struct tagPORTBBITS {
2
  unsigned RB0:1;
3
  unsigned RB1:1;
4
.
5
.
nur beim GCC für PICs.

MfG Klaus

von Karl H. (kbuchegg)


Lesenswert?

Klaus schrieb:
> Karl Heinz Buchegger schrieb:
>>> auch Standard C mit der Garantie,
>>
>> natürlich sind Bitfelder schon lange Standard
>>
>>> daß die beiden Bits hintereinander im
>>> selben Byte liegen?
>
> Du hast meinen Satz elegant in zwei Teile geteilt. Na klar sind
> Bitfelder Standard, ich habe sie aber selten verwendet, weil der
> Compiler die Freiheit hat, aus jedem Bitfeld ein int zu machen und ich
> damit nicht die Kontrolle über eine bestimte Bitposition habe.
>
> Wenn ich dich also richtig verstehe, funktioniert dieses Konstruct aus
> dem C30 Header File
>
1
> typedef struct tagPORTBBITS {
2
>   unsigned RB0:1;
3
>   unsigned RB1:1;
4
> .
5
> .
6
>
> nur beim GCC für PICs.

Dieses Konstruct wird schon überall funktionieren (wenn wir mal 
unterstellen, dass Compilerbauer das naheliegenste tun, an den Stellen 
an denen der C-Standad Freiräume lässt)


Aber das hier
1
void foo( ###### * bitPos )
2
{
3
  *bitPos = 1;
4
}
5
6
int main()
7
{
8
  struct tagPORTBITS myBits;
9
10
  foo( &myBits.RBO );
11
}
kriegst du nicht gebacken, weil es in C keinen Datentyp gibt, den man an 
der Stelle ###### einsetzen könnte. Und was damit zusammenhängt: Der 
Adressoperator in &myBits.RBO kann nicht bis in das Bitfeld hinein 
adressieren. So gesehen hat das Bit RBO innerhalb der Struktur keine 
Adresse, die es von RB1 unterscheidbar machen würde.

von Klaus (Gast)


Lesenswert?

Danke, mal wieder was gelernt.

MfG Klaus

von Karl H. (kbuchegg)


Lesenswert?

Der Krampf ist, dass mir ausser sowas

struct PortKonfig {
  volatile unsigned char* pPort;
  unsigned char           PortMask;
}


nix zu dem Thema einfällt.

C++ wär gut, dann könnte man das alles, samt Zuweisung, wenigstens in 
einer Klasse verstecken und kann die Syntax auf das Gewünschte 
hindrehen.

void foo( const BitAddr& bit )
{
  bit = 1;
}

kein Problem. Aber in C .... hmmmm .... und dann auch noch elegant .... 
hmmm

von Marcel Tschannen (Gast)


Lesenswert?

Hallo Leute

Habe da etwas rumgetestet. Pointer auf einzelne bit's funzt definitif 
nicht!
Steht so sogar irgendwo im C18 manual(finds grad nicht mehr).


Das mit der switch anweisung geht wunderbahr, gefählt mir aber nicht so 
toll.

Schreibe am week mahl die andere variante und versuche den generierten 
code zu vergleichen (gröse).
Danke für eure Ausführungen. Wieder etwas gelernt!


ANDERE FRAGE

Irgendwie geht mir der Schpeicher aus!
Wen ich schreibe jop_t testjop[20]; für 20 jop's, erhalte ich 
Linkerfehler:
Error - section '.udata_main.o' can not fit the section. Section 
'.udata_main.o' length=0x00000116

mit ...[15]; gehts dan tip tip
Hat das was mit #pragma udata zu tun;

währe es besser das in die user_init() zu paken -> bringt das überhaubt 
was?
Etwas mehr jops wären schon anzustreben!
1
#pragma udata
2
char USB_In_Buffer[64];
3
char USB_Out_Buffer[64];
4
unsigned char temphigh;
5
unsigned char templow;
6
unsigned char feuchtehigh;
7
unsigned char feuchtelow;
8
jop_t testjop[15];   Hier gerne mehr wen irgendwie möglich

Sorry proge hobbymäsig und erst ca 1 jahr. Habe noch nicht so den 
überblick
über die speicher.
Grus Marcel

von Karl H. (kbuchegg)


Lesenswert?

Marcel Tschannen schrieb:

>
1
> #pragma udata
2
> char USB_In_Buffer[64];
3
> char USB_Out_Buffer[64];
4
> unsigned char temphigh;
5
> unsigned char templow;
6
> unsigned char feuchtehigh;
7
> unsigned char feuchtelow;
8
> jop_t testjop[15];   Hier gerne mehr wen irgendwie möglich
9
>

rechne dir halt mal aus, wieviel Speicher das alles verbraucht.
Dann vergleichst du noch mit dem Speicher, den dein µC in Form von SRAM 
hat und denkst daran, dass du den nicht komplett mit Variablen anfüllen 
kannst, weil du ja auch noch SRAM zur Laufzeit für Stack und lokale 
Variablen brauchst.

Aber wenn diese Variablen da oben schon mal mehr als, sagen wir mal, 80% 
deines SRAM ausmachen, dann wirds sowieso schon eng.


Und PS:
Das Wort im Englischen heißt "Job". mit weichem b.

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.