簡體   English   中英

在宏C中查找

[英]LUT in a macro C

我目前正在使用C建立框架,以便在多個微控制器之間使用。 該框架必須包含所有設備特定的代碼,因此該應用程序僅包含外圍設備的抽象用法(例如SerialPort_Read,write,SetBaudRate等)。

我努力尋找C語言解決方案的其中一件事情是I / O引腳圖。 我見過一些項目(例如非常受歡迎的Arduino),其中將引腳圖放置在運行時使用的LUT(查找表)中。 但是,此LUT永遠不會在運行時被修改,因此在內存中沒有使用它。 例如,此函數從某些“ const uint”表解析一些位索引和寄存器,然后置位或清除位:

void pinMode(uint8_t pin, uint8_t mode)
{
        uint8_t bit = digitalPinToBitMask(pin);
        uint8_t port = digitalPinToPort(pin);
        volatile uint8_t *reg;

        if (port == NOT_A_PIN) return;

        // JWS: can I let the optimizer do this?
        reg = portModeRegister(port);

        if (mode == INPUT) { 
                uint8_t oldSREG = SREG;
                cli();
                *reg &= ~bit;
                SREG = oldSREG;
        } else {
                uint8_t oldSREG = SREG;
                cli();
                *reg |= bit;
                SREG = oldSREG;
        }
}

由於這是在控制器上運行的實際C代碼,因此會浪費效率和速度。 我寧願定義某種功能相同的宏,但在編譯過程中已經將其解析為可以更高效地編譯的“單一代碼”:

GPIO_Write(PORTA, 5, 1); // Write '1' to pin 5 on PORTA
> LATA |= 1<<5; // Sets bit 5 high
GPIO_Tris(PORTA, 4, OUTPUT); // Set pin 4 on PORTA to output
> PORTA &= ~(1<<4); // sets pin 4 as output I/O type

有誰知道是否有可能(以及如何)在C語言中使用宏定義和使用查找表?

目前,我正在使用MicroChip C30編譯器,我相信它是基於GCC的。 它應該可以在不同的編譯器之間移植,包括MicroChip C18,C32以及ARM和AVR。

對於您的特定示例,遵循以下原則的方法將起作用:

#define WRITE_PORTA LATA
#define GPIO_Write(port, pin, value)         \
    (value ? WRITE_##port |=  (1U << (pin))  \        
           : WRITE_##port &= ~(1U << (pin)))

#define INPUT  0
#define OUTPUT 1
#define GPIO_Tris(port, pin, direction)                     \
     ((direction) == INPUT ? port |=  (1U << (pin))  \
                           : port &= ~(1U << (pin)))

您必須確保以系統可以理解的方式定義LATAPORTA ,尤其是嘗試重試其含義(如您的示例中所示)可能很難解決。

您定位到哪個處理器或微控制器? 您可能低估了LUT的用途。

對於許多處理器,LUT所做的不只是將“邏輯”引腳號映射到單個值(“物理”引腳號)。 LUT將“邏輯”引腳號映射到幾條信息。

通常,“邏輯”引腳映射到適當的讀/輸入或寫/輸出寄存器的端口地址,以及讀或寫寄存器內的位偏移。 因此,在許多MCU上,引腳值實際上已映射到結構。 它還可能包括到數據方向寄存器和其中的字段的映射,以及設置上拉或下拉電阻器狀態的寄存器。

例如,我有用於多路8x8顯示的代碼。 在運行時,我需要使用pinMode將引腳從輸出變為高阻抗輸入,以便信息需要以某種方式進行編碼。

可以在某些MCU上做一些巧妙的事情。 ARM MCU(我相信8051,盡管我從未使用過)使用“位帶尋址” http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dai0179b/CHDJHIDF html的

這會為每個端口引腳分配一個唯一的存儲器地址,固定偏移量可以得出其他數據寄存器和其他功能的引腳地址。 這不是魔術,代碼對經常存儲在LUT中的信息進行編碼。

對於其他MCU,它們確實確實需要端口和位的位置,因此每個引腳號都是兩個值。

如果您願意放棄使用整數作為引腳的想法,而是使用諸如P0,P1之類的名稱,那么您可以初始化很多const struct ,每個引腳名一個,並且您的函數將使用const struct值。 該結構將包含初始化的端口和位偏移或位掩碼值。 編譯器可能能夠優化速度。 這樣可以避免使用LUT,但仍會為所使用的引腳使用相似的空間。 您可能可以對其進行排列,從而無需在代碼中包括未使用的引腳,從而節省了空間。

編輯:如果您願意使用C ++,我建議使用C ++模板,它比宏可以提供更好的解決方案。 它們可以是類型安全的,並且通常更易於調試(如果您具有硬件調試功能,例如JTAG和gdb)

考慮以下宏:

#define write(port, pin, value) do { \
  if (value) \
    LAT##port |= 1 << pin; \
  else \
    LAT##port &= ~(1 << pin); \
} while (0)

用法:

write(A, 3, 1);   // compiles to LATA |= 1 << 3;
write(B, 2, 0);   // compiles to LATB &= ~(1 << 2);

那是你所追求的嗎?

我已經看到它通過幾個宏完成了( https://github.com/triffid/Teacup_Firmware/blob/Gen7/arduino.h ):

/// Read a pin
#define     _READ(IO)                   (IO ## _RPORT & MASK(IO ## _PIN))
/// write to a pin
#define     _WRITE(IO, v)           do { if (v) { IO ## _WPORT |= MASK(IO ## _PIN); } else { IO ## _WPORT &= ~MASK(IO ## _PIN); }; } while (0)

/// set pin as input
#define     _SET_INPUT(IO)      do { IO ## _DDR &= ~MASK(IO ## _PIN); } while (0)
/// set pin as output
#define     _SET_OUTPUT(IO)     do { IO ## _DDR |=  MASK(IO ## _PIN); } while (0)



//  why double up on these macros? see http://gcc.gnu.org/onlinedocs/cpp/Stringification.html

/// Read a pin wrapper
#define     READ(IO)                    _READ(IO)
/// Write to a pin wrapper
#define     WRITE(IO, v)            _WRITE(IO, v)
/// set pin as input wrapper
#define     SET_INPUT(IO)           _SET_INPUT(IO)
/// set pin as output wrapper
#define     SET_OUTPUT(IO)      _SET_OUTPUT(IO)

有:

#define DIO0_PIN       PIND0
#define DIO0_RPORT     PIND
#define DIO0_WPORT     PORTD
#define DIO0_PWM       &OCR0B
#define DIO0_DDR       DDRD

#define DIO1_PIN       PIND1
#define DIO1_RPORT     PIND
#define DIO1_WPORT     PORTD
#define DIO1_PWM       &OCR2B
#define DIO1_DDR       DDRD
...

您可以修改宏以使用直接整數而不是DIOn

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM