2015-03-25 39 views
1

目前我遇到一個技術問題,這讓我想改善以前的實現,該情況是:如何使3D面膜

我有5個GPIO引腳,我需要使用這些引腳作爲硬件標識符,例如:

pin1: LOW 
pin2: LOW 
pin3: LOW 
pin4: LOW 
pin5: LOW 

這意味着我的一個硬件變體,所以我們可以有很多組合。在以往的設計中,開發人員使用if-else實現這一點,就像:

if(PIN1 == LOW && ... && ......&& PIN5 ==LOW) 
{ 
    HWID = variant1; 
} 
else if(...) 
{ 
} 
... 
else 
{ 
} 

,但我認爲這是不好的,因爲這將有超過200點的變體,並且代碼將變得很長,我想改變它掩飾。我的想法是將這5個引腳視爲一個5位寄存器,並且由於我可以根據GPIO狀態來預測需要分配哪個變體(這已由硬件團隊定義,它們提供了一個變體列表,以及所有這些GPIO引腳配置)因此,代碼可能是這樣的:

enum{ 
    variant 0x0 //GPIO config 1 
    ... 
    variant 0xF3 //GPIO config 243 
} 

話,我可以先閱讀這五個GPIO引腳的狀態,並比較了一些面具,看看他們是否相等。

問題

然而,GPIO,它有三種狀態,即:低,高,OPEN。如果有一個好的計算方法來製作3D掩模?

+0

什麼常量'LOW','HIGH'和'OPEN'對應? – 2015-03-25 02:31:51

+0

據我瞭解,你將有125種組合(5L * 5H * 5O)或者我正在失去一些東西? – CrApHeR 2015-03-25 02:32:53

+0

@CrApHeR不會,它會是pow(3,5)= 243的組合。 – kibibu 2015-03-25 02:55:49

回答

1

你有5只腳各3個狀態。你可以用幾種方法來表達這一點。

首先,設想利用這種框架:

#define LOW (0) 
#define HIGH (1) 
#define OPEN (2) 

uint16_t config = PIN_CONFIG(pin1, pin2, pin3, pin4, pin5); 

if(config == PIN_CONFIG(LOW, HIGH, OPEN, LOW, LOW)) 
{ 
    // do something 
} 

switch(config) { 
    case PIN_CONFIG(LOW, HIGH, OPEN, LOW, HIGH): 
     // do something; 
     break; 
} 

uint16_t config_max = PIN_CONFIG(OPEN, OPEN, OPEN, OPEN, OPEN); 
uint32_t hardware_ids[config_max + 1] = {0}; 

// init your hardware ids 
hardware_ids[PIN_CONFIG(LOW, HIGH, HIGH, LOW, LOW)] = 0xF315; 
hardware_ids[PIN_CONFIG(LOW, LOW, HIGH, LOW, LOW)] = 0xF225; 

// look up a HWID 
uint32_t hwid = hardware_ids[config]; 

此代碼只是那種東西你想和引腳配置做。留下來實施的唯一的一點是PIN_CONFIG


方法1

第一種方法是使用它作爲一個位字段保留,但每銷,而不是1位使用2個比特來表示每個引腳的狀態。我認爲這是最乾淨的,即使你爲每個銷釘「浪費」了一半。

#define PIN_CLAMP(x) ((x) & 0x03) 
#define PIN_CONFIG(p1, p2, p3, p4, p5) \\ 
    (PIN_CLAMP(p1) &      \\ 
    (PIN_CLAMP(p2) << 2) &    \\ 
    (PIN_CLAMP(p3) << 4) &    \\ 
    (PIN_CLAMP(p4) << 6) &    \\ 
    (PIN_CLAMP(p5) << 8)) 

這是一種不錯的,因爲它留下餘地「不關心」或「無效」值,如果你打算以後做搜索。


方法2

或者,你可以用算術來做到這一點,並確保您使用的必要位的最小量。也就是說,〜1.5位來編碼3個值。正如預期的那樣,這從0到242共計3^5 = 243個狀態。 不知道你的情況,我相信這是你的針狀態最小的完整編碼。 (實際上,你必須使用8位編碼243個值,所以它的每個引腳的1.5位)

#define PIN_CLAMP(x) ((x) % 3) /* note this should really assert */ 
#define PIN_CONFIG(p1, p2, p3, p4, p5) \\ 
    (PIN_CLAMP(p1) &      \\ 
    (PIN_CLAMP(p2) * 3) &     \\ 
    (PIN_CLAMP(p3) * 9) &     \\ 
    (PIN_CLAMP(p4) * 27) &    \\ 
    (PIN_CLAMP(p5) * 81)) 

方法1.1

如果你不喜歡預處理的東西,你可以使用函數有點像這樣:

enum PinLevel (low = 0, high, open); 

void set_pin(uint32_t * config, uint8_t pin_number, enum PinLevel value) { 
    int shift = pin_number * 2; // 2 bits 
    int mask = 0x03 << shift; // 2 bits set to on, moved to the right spot 
    *config &= ~pinmask; 
    *config |= (((int)value) << shift) & pinmask; 
} 

enum PinLevel get_pin(uint32_t config, uint8_t pin_number) { 
    int shift = pin_number * 2; // 2 bits 
    return (enum PinLevel)((config >> shift) & 0x03); 
} 

這跟隨第一(每值2位)的方法。


方法1.2

YET用C的冷靜位域語法另一種方式:

struct pins { 
    uint16_t pin1 : 2; 
    uint16_t pin2 : 2; 
    uint16_t pin3 : 2; 
    uint16_t pin4 : 2; 
    uint16_t pin5 : 2; 
}; 

typedef union pinconfig_ { 
    struct pins pins; 
    uint16_t value; 
} pinconfig; 

pinconfig input; 
input.value = 0; // don't forget to init the members unless static 

input.pins.pin1 = HIGH; 
input.pins.pin2 = LOW; 

printf("%d", input.value); 

input.value = 0x0003; 
printd("%d", input.pins.pin1); 

工會允許您查看位域爲一個數字,反之亦然。

(注:所有的代碼經過充分測試)

+0

我不想用'位field'(進一步的移植問題),我也不想用很多'如果-else'條件 – 2015-03-25 09:52:54

+0

@HowChen Kikibu給您更多的選擇很好的解釋。我在夜間思考,另一種方式,我雖然是從kikibu職位的第二個(使用8位而不是10位)。用這個例子你可以得到你想要的枚舉。也許我們不明白你的要求,你可以在你的文章中添加更多關於他們的信息嗎? – CrApHeR 2015-03-25 11:31:07

+0

@HowChen你預計什麼移植問題?在某些時候,您想要發現您的pin是否處於三種狀態之一,則此答案假定您已經完成該操作並將其編碼爲0,1或2. 。 關於if-else,我會添加一些示例東西 – kibibu 2015-03-25 21:44:56

1

這是我的建議,解決問題

#include<stdio.h> 

#define LOW 0 
#define HIGH 1 
#define OPEN 2 

#define MAXGPIO 5 

int main() 
{ 
    int gpio[MAXGPIO] = { LOW, LOW, OPEN, HIGH, OPEN }; 

    int mask = 0; 

    for (int i = 0; i < MAXGPIO; i++) 
     mask = mask << 2 | gpio[i]; 

    printf("Masked: %d\n", mask); 
    printf("Unmasked:\n"); 

    for (int i = 0; i < MAXGPIO; i++) 
     printf("GPIO %d = %d\n", i + 1, (mask >> (2*(MAXGPIO-1-i))) & 0x03); 

    return 0; 
} 

對代碼做一點解釋。

掩蔽
我使用2位保存每個GPIO值。的組合是:

  • 00: LOW
  • 01: HIGH
  • 02: OPEN
  • 03是無效

我迭代所述陣列GPIO(其中,i具有所獲取的值)以及創建在掩模mask變量左移2位並應用or操作。

取消屏蔽
要獲得的初始值我只是使相反的操作右移2位乘以GPIO的量 - 1,並用0×03

掩蔽我將掩模施加與×03因爲這些是我感興趣的一點。

這是該計劃的結果

$ cc -Wall test.c -o test;./test 
Masked: 38 
Unmasked: 
GPIO 1 = 0 
GPIO 2 = 0 
GPIO 3 = 2 
GPIO 4 = 1 
GPIO 5 = 2 

希望這有助於

+0

這隻適用於每個引腳由兩位定義,可能並非如此。 – 2015-03-25 03:32:23

+0

是的,的確如此。你只需要2位來保存3個狀態。 – CrApHeR 2015-03-25 11:22:40