74HC595等串口转并口芯片的Arduino实用封装

在74HC595等串口转并口芯片接线的时候,我们会遇到两个问题:


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);
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,392评论 5 470
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,258评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,417评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,992评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,930评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,199评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,652评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,327评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,463评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,382评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,432评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,118评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,704评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,787评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,999评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,476评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,057评论 2 341