Tips and Tricks (3)

Previous T&T

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

Next T&T

Leave a Reply

You must be logged in to post a comment.