Search code examples
cmicrocontrolleravr-gcc

How to define a pointer to a port address


I am having a bit of a problem with struct and defines from an atmega328p.

I have the following code:

typedef struct {
    char port;
    unsigned char pin;
    unsigned long timestamp;
} BUTTONS;

BUTTONS button_1;
BUTTONS button_2;
BUTTONS button_3;

BUTTONS* button[BUTTONS_ID_COUNT] = {&button_1,&button_2,&button_3};

void Button_init(void){

    button[BUTTONS_ID_1]->port = PINB;
    button[BUTTONS_ID_1]->pin = PINB4;
    button[BUTTONS_ID_1]->timestamp = 0;
}

unsigned char Button_instantRead(int id){
    //return PINB & (1 << PINB4);
    return button[id]->port & (1 << button[id]->pin);
}

I want to use my Button_instantRead() to be able to read any port by only giving it an ID number. I use my init function to set which pin is associated to which port. But for some reason when I call my Button_instantRead() function I do not get a 1 even when I press on my switch.

I tried my configuration in my main file using the commented line and everything works perfectly fine.

What am I doing wrong in my return line?

After some Googling I found that char is probably not the right type to reference a port. I think I would be better suited with a pointer to the first element of the address of the port, but again I don't know how to do it and could not find the answer either.


Solution

  • I would recommend looking up the definition of PINB first. I've found this link to a power point presentation that seems to have a reference to the right header files.

    Noteworthy files are:

    1. sfr_defs.h
    2. iom328p.h

    where all the information you need to define your own pointers to PINB resides.

    The following should work as you want it to:

    typedef struct {
        volatile uint8_t * port;
        uint8_t pin;
        unsigned long timestamp;
    } BUTTONS;
    
    BUTTONS button_1;
    BUTTONS button_2;
    BUTTONS button_3;
    
    BUTTONS* button[BUTTONS_ID_COUNT] = {&button_1,&button_2,&button_3};
    
    void Button_init(void){
        button[BUTTONS_ID_1]->port = &PINB;
        button[BUTTONS_ID_1]->pin = PINB4;
        button[BUTTONS_ID_1]->timestamp = 0;
    }
    
    unsigned char Button_instantRead(int id){
        //return PINB & (1 << PINB4);
        return *(button[id]->port) & (1 << button[id]->pin);
    }
    

    Note that the port is a pointer.

    Edit:

    I had to check myself for volatile struct member use and found this SO question and this other SO question quite interesting.

    Edit 2:

    If you are using gcc (which I think you are not since it is AVR but I could be wrong) you can skip the step of finding out what the exact type of PINB is and declare your struct as follows:

    typedef struct {
        typeof(PINB)* port;
        uint8_t pin;
        unsigned long timestamp;
    };
    

    The typeof operator is a gcc extension to the C language so you might not be able to use it but it is good to know about it.