ИМХО, не привязываясь к архитектуре не получится. В аналогичной задаче для MB90 сделал так:
В таблице
static const INT8U Tests_Pins[]на этапе компиляции кодируется информация о пине: номер порта, номер бита, значение активного уровня. Макросы и функция для удобства манипулирования:
#define TESTS_PIN_VAL_MASK (1<<3)
#define tests_pinH(port, bit) ((0x0##port<<4) + TESTS_PIN_VAL_MASK + ##bit)
#define tests_pinL(port, bit) ((0x0##port<<4) + 0 + ##bit)
#define tests_pin(port, bit, val) tests_pin##val(port, bit)
#define TESTS_PIN(x) tests_pin(x)
/* производит упаковку данных о пине в байт: */
/* port3 port2 port1 port0 val bit2 bit1 bit0 */
/* port = номер и одновременно адрес порта, 4 бита */ /* (pin >> 4) */
/* bit = номер бита в байте порта , 3 бита */ /* (pin & 0x07) */
/* val = 0, если в описании пина L */ /* (pin & TESTS_PIN_VAL_MASK) */
#define TESTS_PIN_ON_H(pin) *(__io unsigned char *)(pin >> 4) |= (1<<(pin & 0x07))
#define TESTS_PIN_ON_L(pin) *(__io unsigned char *)(pin >> 4) &= ~(1<<(pin & 0x07))
#define tests_pinO(pin) *(__io unsigned char *)(0x10 + (pin >> 4)) |= (1<<(pin & 0x07))
#define tests_pinI(pin) *(__io unsigned char *)(0x10 + (pin >> 4)) &= ~(1<<(pin & 0x07))
#define TESTS_PIN_DIRECT(pin, mode) tests_pin##mode(pin)
//...
#pragma inline Tests_PinOn
static void Tests_PinOn (INT8U pin)
{
if (pin & TESTS_PIN_VAL_MASK) /* val == H */
{
TESTS_PIN_ON_H(pin);
}
else /* val == L */
{
TESTS_PIN_ON_L(pin);
}
}
Мне надо было сделать бегущий огонек. Собственно манипуляция в цикле:
for (i = 0; i < sizeof(Tests_Pins); i++)
{
pin_code = Tests_Pins[i];
TESTS_PIN_DIRECT(pin_code, O);
Tests_PinOn(pin_code);
OSTimeDly(TESTS_PIN_ON_DURATION);
TESTS_PIN_DIRECT(pin_code, I);
}