8

Is it possible to use an AVR port as a variable which can be passed around?

For example

LED myLed(PORTA,7);   //myLED hooked to PORTA, Pin 7

I would like to make LED be able to take any PORT / Pin combination, so I would rather not hard code it in.

Note that the PORTs are defined as:

#define PINA  _SFR_IO8(0x00)
#define DDRA  _SFR_IO8(0x01)
#define PORTA _SFR_IO8(0x02)    

PORTA symbol resolves to (*(volatile uint8_t *)((0x02) + 0x20))

I believe this would allow me to do something like the following, but I am unsure whether I would need the volatile keyword or not, nor whether it will actually work as expected

class LED{
public:
    LED(volatile uint8_t* port, uint8_t pin);
    {
        Port=port;
        Pin=pin;
    }
    void write(bool val)
    {
        if(val) (*Port) |= 1 << Pin;
        else    (*Port) &= ~(1 << Pin);
    }

private:
    uint8_t  Pin
    volatile uint8_t* Port;
}

Finally, is there a way to set Port / Pin as an Output from the LED Constructor? This would involve finding the relative DDR# register for the Given PORT#. Can I assume &DDR# will always be &PORT#-1?

3
  • you can use also a bit struct... Commented Dec 4, 2012 at 13:31
  • would you mind expanding on this? I'm not sure what you mean by bit struct Commented Dec 5, 2012 at 15:58
  • struct port{ UINT8 _port_1_0:1; UINT8 _port_1_2:1; ... }; - this is better/nicer in C. But if you have C++ and templates avakar example is better. Commented Dec 5, 2012 at 16:17

3 Answers 3

6

The register macros are basically pointers to the memory location, where the appropriate register resides, so yes, you can use uint8_t volatile *. However, the compiler will not generate the most efficient code this way -- it will use indirect addressing instead of direct writes.

This is what I do instead, using avrlib.

#include <avrlib/porta.hpp>
#include <avrlib/pin.hpp>
using namespace avrlib;

typedef pin<porta, 4> led_pin;

Then you can use the led_pin typedef, e.g.

led_pin::set();
Sign up to request clarification or add additional context in comments.

1 Comment

The link to the library no longer works (the site is down).
6

This is how I did it, im not very experienced in AVR,

#include <avr/io.h>

void LED(volatile uint8_t* port, uint8_t pin)
{
    // First set DDRx ; DDRx on ATmega32 is one address below port address
    *(port -1) |= (1<< pin);
    // Now set the pin high
    *port |= (1<< pin);
}

int main(void)
{
   LED(&PORTB,1);
   LED(&PORTC,2);
   LED(&PORTD,3);
    while (1) 
    {
    }
}

Comments

0

Ports are nothing more than I/O addresses, so all you have to do is pass the address of the I/O port to you LED constructor:

LED *light = new LED(&PORTA, 4);

Why does this work? PORTA resolves, as you already mentioned, to the dereferencing of a pointer:

(*(volatile uint8_t *)((0x02) + 0x20))

So adding an address of operator in front creates

&(*(volatile uint8_t *)((0x02) + 0x20))

which can be simplified to

(volatile uint8_t *)((0x02) + 0x20)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.