Tips and Tricks (3)
This one deals again with arguments passed to functions/commands. This time, I wanted to pass PORTx as an argument, and possibly use its value within the function/command in order to set data direction (DDRx).
The solution is pretty easy… once you know it 😉 . The exemples below illustrate two ways of achieving this.
Calling the blinkLed routine is performed with the next command:
blinkLed(PINB5, &PORTB);
Then the blinkLed routine
void blinkLed(uint8_t pin, volatile uint8_t *port){ volatile uint8_t *_port = port; volatile uint8_t *_direction; _direction = _port - 1; *_direction |= (1 << pin); for (int i = 0; i < 10; i++) { *_port ^= (1 << pin); delay(200); } }
Note that the data direction is set within the routine, by addressing the DDRx register (Address of the PORTx register minus 1)
Same routine, but in a more compact (and less self explicit) format:
void blinkLed(uint8_t pin, volatile uint8_t *port){ *(port - 1) |= (1 << pin); for (int i = 0; i < 10; i++) { *port ^= (1 << pin); delay(200); } }
The same result can be achieved in an elegant manner thanks to macros:
#define DDR(x) (*(&x - 1)) // address of data direction register of port x #define PIN(x) (*(&x - 2)) // address of input register of port x
And here commes the routine
void blinkLed(uint8_t pin, volatile uint8_t *port){ DDR(*port) |= (1 << pin); for (int i = 0; i < 10; i++) { *port ^= (1 << pin); delay(200); } }
HTH