Question

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.

Était-ce utile?

La 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.

Autres conseils

Is PINB volatile? Isn't that the actual read of the port? If so, you read the value of the port in Button_init not in Button_instantRead.

In other words, button[id]->port contains the value of the port when you read it in Button_init, not some reference to PINB that can be used later.

Beware: It's been years since I've done atmega stuff.

You could recode it this way:

unsigned char Button_instantRead(int id){
    switch(id) {
        case ID_A: return PINA & (1 << button[id]->pin);
        case ID_B: return PINB & (1 << button[id]->pin);
        // etc
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top