74HC595等串列埠轉並口晶片的Arduino實用封裝

weixin_33728268發表於2018-01-14

在74HC595等串列埠轉並口晶片接線的時候,我們會遇到兩個問題:


228509-9195738a2892b227.jpg
74HC595
  1. 有時候按次序接線較困難。比如上圖,我的我這樣接線是方便,但是一些圖形顯示的庫就不能直接用了,因為這些庫需要按固定次序連線,當然,我們可以改造數碼管字型檔資料,但太麻煩了。

  2. 我的74HC595某引腳連線的電路壞了,或者我只想使用部分引腳。比如我焊接的8個LED有3個壞了,我想在LED順序點亮的時候只點亮5個。或者我只想用4個LED,傳資料的時候,我只傳0~15即可。

我寫了兩個函式來解決這些問題。這兩個函式均是可變長引數,感覺還比較好用。

shiftOutQPins 這個函式可以用來解決問題2。用法和shirtOut相同,後面多了幾個引數,表示你要使用的針腳。數字對應使用的Q引腳號。引腳使用的次序是按MSBFIRSTLSBFIRST來的,和輸入的次序無關。

如果要們要使用Q7,Q5,Q3,Q2,前幾個引數和shiftOut類似,後面加上4,7,5,3,2。4表示引數的個數。

shiftOutQPinsOrder 可以用來解決問題1和2。和shiftOutQPin不同的是,是按次序使用制定的引腳的,所以少了bitOrder引數。
shiftOutQPinsOrder(dataPin, clockPin, val, 8, 7, 6, 5, 4, 3, 2, 1, 0);
等同於shiftOut(dataPin, clockPin, MSBFIRST, val);
shiftOutQPinsOrder(dataPin, clockPin, val, 8, 0, 1, 2, 3, 4, 5, 6, 7);
等同於shiftOut(dataPin, clockPin, LSBFIRST, val);
上圖應該用shiftOutQPinsOrder(dataPin, clockPin, val, 8, 6, 7, 1, 2, 3, 5, 4, 0);

這兩個函式本質是對shiftOut的封裝,能用shiftOut的情況皆可用這兩個封裝。

// 只使用74HC595等晶片部分引腳輸出資料
//
// 和系統shiftOut函式引數對比
//     shiftOutQPins(dataPin, clockPin, bitOrder, value, count, pins...);
//          shiftOut(dataPin, clockPin, bitOrder, val);
// dataPin, clockPin, bitOrder:用法與shiftOut函式相同
// value:使用的針腳能表示的數值,如果用到n個針腳,數值最大應為2^n-1,若超過範圍,只擷取後面n位的資料
// count:要使用的QPin個數
// pins:使用的QPin針腳,次序可任意
//
// 使用範例
//     DS,SH_CP分別接在Arduino 11,12引腳,使用Q6, Q4, Q2, Q1, Q0五個引腳,使 Q6 與 Q2 輸出高電平:
//     shiftOutQPins(11, 12, MSBFIRST, B10100, 5, 6, 4, 2, 1, 0);
void shiftOutQPins(uint8_t dataPin, uint8_t clockPin, uint8_t order, uint8_t value, int count, ...) {
  int8_t pins[8] = { -1, -1, -1, -1, -1, -1, -1, -1};
  if (count <= 0) return;
  if (count > 8) count = 8;
  int8_t pin;
  va_list ap;
  va_start(ap, count);
  uint8_t index = 0;
  for (uint8_t i = 0; i < count; i++) {
    pin = va_arg(ap, int);
    if (pin < 0 || pin > 7) continue;
    pins[index] = pin;
    index++;
  }
  va_end(ap);

  qsort(pins, index, sizeof(int8_t), &ascending);
  if (order == LSBFIRST) {
    shiftOutQPinsOrder(dataPin, clockPin, value, 8, pins[0], pins[1], pins[2],
                       pins[3], pins[4], pins[5], pins[6], pins[7]);
  } else {
    shiftOutQPinsOrder(dataPin, clockPin, value, 8, pins[7], pins[6], pins[5],
                       pins[4], pins[3], pins[2], pins[1], pins[0]);
  }
}

// 使74HC595等晶片按指定的引腳次序輸出資料,可只使用部分引腳
//
// void shiftOutQPinsOrder(uint8_t dataPin, uint8_t clockPin, uint8_t value, int count, pins...)
// dataPin, clockPin:用法與shiftOut函式相同
// value:使用的針腳能表示的數值,如果用到n個針腳,數值最大應為2^n-1,若超過範圍,只擷取後面n位的資料
// count:要使用的QPin個數
// pins:使用的QPin針腳,有次序
//
// shiftOutQPinsOrder(dataPin, clockPin, val, 8, 7, 6, 5, 4, 3, 2, 1, 0);
// 等同於shiftOut(dataPin, clockPin, MSBFIRST, val);
//
// shiftOutQPinsOrder(dataPin, clockPin, val, 8, 0, 1, 2, 3, 4, 5, 6, 7);
// 等同於shiftOut(dataPin, clockPin, LSBFIRST, val);
//
// 使用範例(1)
//     DS,SH_CP分別接在Arduino 11,12引腳,要按照Q7, Q6, Q2, Q1, Q0,Q3, Q5, Q4次序輸出:
//     shiftOutQPinsOrder(11, 12, B11111111, 8, 7, 6, 2, 1, 0, 3, 5, 4);
// 使用範例(2)
//     DS,SH_CP分別接在Arduino 11,12引腳,使用Q6, Q4, Q2, Q1, Q0五個引腳,使 Q6 與 Q2 輸出高電平:
//     shiftOutQPinsOrder(11, 12, B10100, 5, 6, 4, 2, 1, 0);
void shiftOutQPinsOrder(uint8_t dataPin, uint8_t clockPin, uint8_t value, int count, ...) {
  int8_t pins[8] = { -1, -1, -1, -1, -1, -1, -1, -1};
  if (count <= 0) return;
  if (count > 8) count = 8;
  int8_t pin;
  va_list ap;
  va_start(ap, count);
  uint8_t index = 0;
  for (uint8_t i = 0; i < count; i++) {
    pin = va_arg(ap, int);
    if (pin < 0 || pin > 7) continue;
    pins[index] = pin;
    index++;
  }
  va_end(ap);

  // 7, 4, 6, 1, 2  // 引腳陣列pins(忽略未使用的引腳)
  // 1, 2, 4, 6, 7  // 排序後陣列pinsOrdered
  // 4, 2, 3, 0, 1  // 7,4,6,1,2在pinsOrdered中的索引(position)
  int8_t pinsOrdered[8];
  memcpy(pinsOrdered, pins, sizeof(pins));  // 複製pins資料到pinsOrdered
  qsort(pinsOrdered, index, sizeof(int8_t), &ascending);
  uint8_t val = 0;
  for (uint8_t i = 0; i < index; i++) {
    uint8_t position = 0;
    for (; position < index; position++) {
      if (pins[i] == pinsOrdered[position]) break;
    }
    uint8_t bitValue = (!!(value & (1 << position))) << (index - 1 - i);
    val += bitValue;
  }
  shiftOut(dataPin, clockPin, 1, val);
}

// 用於qsort函式,從小到大排列
int ascending(const void * a, const void * b) {
  return *((int8_t *)a) - *((int8_t *)b);
}

相關文章