I am writing a module for other people which can output a PWM signal between 20 and 100Hz depending on the dutycycle.
For that I have written this code
void Weistra::begin() {
if( trackPin >= 13 && trackPin <= 8 ) {
port = &PORTB;
trackPin -= 8; // 13 becomes 5, 11, becomes 3 etc
}
else if( trackPin >= A5 && trackPin <= A0 ) {
port = &PORTC;
trackPin -= 14; // A5 becomes 5
}
else if( trackPin >= 13 && trackPin <= 8 ) {
port = &PORTD;
// trackPin needs no alterations for port D
}
else {
port = 0;
return; // invalid pin number
}
}
void Weistra::update() {
static byte counter = 0;
static uint16_t prevTime = 0;
if( port != 0 ) {
uint16_t currentTime = mircros() & 0x0000FFFF; // we only use the last 2 bytes of micros()
if( currentTime - prevTime >= intervalTime ) {
prevTime = currentTime;
counter++;
if( counter >= 100 ) { counter = 0; // if counter reaches 100, reset it to 0 and enable the track power pin
*port |= (1 << trackPin);
}
else if( counter == dutyCycle ) {
*port &= ~(1 << trackPin);
}
}
}
}
To make it more beginner syntax I thought I do it like this so one does not have to specify the port number or pin number for a direct port instruction. + my code only works for the atmega328P not for anything else. So I wanted to do the same as one does in digitalWrite.
In digitalWrite the make use of a macro called digitalPinToPort() to get the correct port back. But I am lost in that jungle of arduino libraries and tangled functions and macros.
extern const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[];
extern const uint8_t PROGMEM digital_pin_to_timer_PGM[];
// Get the bit location within the hardware port of the given virtual pin.
// This comes from the pins_*.c file for the active board configuration.
//
// These perform slightly better as macros compared to inline functions
//
#define digitalPinToPort(P) ( pgm_read_byte( digital_pin_to_port_PGM + (P) ) )
#define digitalPinToBitMask(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM + (P) ) )
I cannot find certain definitions and this does not make me happy
anyways. I have 3 questions.
- Am I doing this right? Can I use a pointer to control IO ports?
- Must this pointer be declared as volatile?
private:
uint16_t intervalTime;
byte dutyCycle;
byte trackPin;
byte *port; // < volatile needed?
};
- Can I simply use the macros digitalPinToBitMask and digitalPinToPort and suddenly have compatibility with the arduino mega and leonardo was well?
Kind regards,
Bas
Edit my topic is called wrong as I am talking about a macro