Лет 6 работаю с gpio только на шаблонах(compile-time) и интерфейсах (рантайм).
Compile-time:
CODE
template<char GPN> static inline LPC_GPIO_TypeDef* GetGpioByName();
template<> inline LPC_GPIO_TypeDef* GetGpioByName<'0'>(){ return LPC_GPIO0; }
template<> inline LPC_GPIO_TypeDef* GetGpioByName<'1'>(){ return LPC_GPIO1; }
...
template<char GPN> class GpioPort{
public:
static LPC_GPIO_TypeDef* gpio(){ return GetGpioByName<GPN>(); }
static void set(uint32_t msk){ gpio()->FIOSET = msk; }
static void clear(uint32_t msk){ gpio()->FIOCLR = msk; }
//....
};
template<char PORT, int PIN> class GpioPin{
public:
static LPC_GPIO_TypeDef* gpio(){ return GetGpioByName<PORT>(); }
static void set(){ GpioPort<PORT>::set(msk); }
static void clear(){ GpioPort<PORT>::clear(msk); }
// ....
enum{ Pin=PIN, msk=1<<PIN};
static const char Port = PORT;
};
// usage:
#define LED1_pin GpioPin<'0',10>
LED1_pin::set();
//....
LED1_pin::clear();
Runtime:
CODE
class IGpioPin{
public:
virtual ~IGpioPin(){}
virtual void set()=0;
virtual void clear()=0;
// ....
};
template<class T> class IGpioPin_T;
template<char PORT, int PIN>
class IGpioPin_T<GpioPin<PORT,PIN> > : public IGpioPin{
public:
virtual void set(){
GpioPin<PORT, PIN>::set();
};
virtual void clear(){
GpioPin<PORT, PIN>::clear();
}
// .....
};
// usage:
#define LED1_pin GpioPin<'0',10>
IGpioPin_T<LED1_pin> LED1_pin_rt;
//...
IGpioPin* const array[3] = {&LED1_pin_rt, &LED2_pin_rt, &LED3_pin_rt};
void f(){
for(int i=0; i<3; i++)array[i]->set();
}
В итоге при переходе на совершенно другой контроллер софт править не нужно, правится только платформо-зависимый код драйвера.