Hallo,

ich habe gerade ein grundlegendes Verständnisproblem bei der Definition einer Structure und zwar möchte ich für ein Projekt eine RS485 "Klasse" erstellen.
Dabei habe ich gerade das Problem, dass ich nicht genau weiß, an welcher Stelle im Code bzw in welcher Datei, ich die Structure platzieren soll.

Ein Tutorial zu den Structures habe ich hier gefunden: zuvor wurde bei einem Multi-Datei-Projekt folgende Programmstruktur vorgestellt:
Wie ist jetzt das richtige Vorgehen?


Variante A:
Header
Code:
// RS485.h
#ifndef RS485_H
#define    RS485_H

#include <xc.h>

#ifdef    __cplusplus
extern "C" {
#endif

    #define bufferlen 46

    #define TXDIR TRISBbits.TRISB5
    #define TXDP  PORTBbits.RB5

    typedef struct RS485_STRUCT { 
        uchar  use_interrupt;
        uchar  loopback;
        uchar  ownAddress;
        volatile uint16 txcounter;
        volatile uint16 txLength;
        volatile uint16 rxcounter;
        volatile uint16 readcounter;
        volatile uchar RxBuffer[bufferlen];
        volatile uchar TxBuffer[bufferlen];
    } RS485_STRUCT;


    extern RS485_STRUCT RS485;

    void  RS485_RC_INT(void);
    void  RS485_TX_INT(void);

    void  RS485_open(uchar sirq);
    void  RS485_close(void);
    
    uchar RS485_read(void);
    void  RS485_writeBytes(const uchar *bytes, uint16 len);

#ifdef    __cplusplus
}
#endif

#endif    /* RS485_H */
Source
Code:
// RS485.c
#include "RS485.h"

RS485_STRUCT RS485; // ???
// oder
volatile RS485_STRUCT RS485; // ???

// ... CODE ...

oder Variante B:
Header
Code:
// RS485.h
#ifndef RS485_H
#define    RS485_H

#include <xc.h>

#ifdef    __cplusplus
extern "C" {
#endif

    #define bufferlen 46

    struct { 
        uchar  use_interrupt;
        uchar  loopback;
        uchar  ownAddress;
        volatile uint16 txcounter;
        volatile uint16 txLength;
        volatile uint16 rxcounter;
        volatile uint16 readcounter;
        volatile uchar RxBuffer[bufferlen];
        volatile uchar TxBuffer[bufferlen];
    } RS485;

    void  RS485_open(uchar sirq);
    void  RS485_close(void);
    
    uchar RS485_read(void);
    void  RS485_writeBytes(const uchar *bytes, uint16 len);

    void  RS485_RC_INT(void);
    void  RS485_TX_INT(void);


#ifdef    __cplusplus
}
#endif

#endif    /* RS485_H */
Source
Code:
// RS485.cpp
#include "RS485.h"
// Ohne Lokale Deklaration
// RS485_STRUCT RS485;
Variante B wurde bereits verwendet allerdings ohne die volatile deklarationen innerhalb des Struct.
Dies hat auch irgendwie funktioniert allerdings bin ich mir bei dieser Version nicht sicher ob durch complier optimierung oder der Verwendung mehrerer Interrupts daten verfälscht werden.

Damit der Controller genügend Zeit für die weiteren Aufgaben bekommt findet die Kommunikation ebenfalls über Interrupts statt. Der Tx-Interrupt sendet die Daten im TxBuffer solange bis der TxCounter = txLength ist.
Bei einem Rx-Interrupt werden die Daten solange am RxBuffer angehängt, bis dieser Voll ist... ab einem RxCounter-Wert von 8 schaut das Hauptprogramm den RxBuffer an und beginnt diesen Abzuarbeiten.

Code:
//-----------------------------------------------------------------------
void RS485_TX_INT(void)    // Interrupt Methode Senden
{
    if (TRMT)
    {
        RS485.txcounter++;
        TXREG = RS485.TxBuffer[RS485.txcounter];    //TXIF is cleared by loading TXREG
        RS485.TxBuffer[RS485.txcounter] = 0x00;
        ClrWdt();
        if (RS485.txcounter >= RS485.txLength-1)
        {
            RS485.txLength  = 0;
            RS485.txcounter = 0;
            TXEN = 0;
            TXIE = 0;
            TXDP = 0;         // Dataenable am MAX 491 Baustein
        }
    }
}
//-----------------------------------------------------------------------
void RS485_RC_INT(void)    // Interrupt Methode Empfangen
{
    uchar input = RCREG;
    
    if (RS485.rxcounter >= bufferlen-1)
    {
        //RS485.rxcounter = 0x00;
        RS485_writeBytes("RS485.RxBuffer: Overrun!",24);
    }

    if (RS485.rxcounter < bufferlen-1)
    {
        RS485.RxBuffer[RS485.rxcounter] = input; //RCREG;
        RS485.rxcounter++;
    }
}
//-----------------------------------------------------------------------
void RS485_writeBytes(const uchar *bytes, uint16 len)
{
    if (len < bufferlen)
    {
        RS485.txcounter = 0;
        RS485.txLength  = 0;
        for (uint16 i = 0; i <= len; i++)
        {
            RS485.TxBuffer[RS485.txLength] = bytes[i];
            RS485.txLength++;
            ClrWdt();
        }
        PIE1bits.TXIE   = 1;
        TXDP            = 1;
        TXREG           = RS485.TxBuffer[RS485.txcounter]; //TXIF is cleared by loading TXREG
        TXSTAbits.TXEN  = 1; // Wenn TX eingeschaltet wird ist TXIF == 1
                            // Darum springt uC gleich in Interrupt routine.
    }    
}
//-----------------------------------------------------------------------
Falls jemand grobe Fehler an der Struktur erkennt oder Verbesserungsvorschläge hat nehme ich diese gerne entgegen.
Wichtig wäre mir vor allem eine saubere und stabile Programmierung. Vor allem bei der Definition der Struktur.

Viele Grüße