在74HC595等串口转并口芯片接线的时候,我们会遇到两个问题:
74HC595
-
有时候按次序接线较困难。比如上图,我的我这样接线是方便,但是一些图形显示的库就不能直接用了,因为这些库需要按固定次序连线,当然,我们可以改造数码管字库数据,但太麻烦了。
-
我的74HC595某引脚连接的电路坏了,或者我只想使用部分引脚。比如我焊接的8个LED有3个坏了,我想在LED顺序点亮的时候只点亮5个。或者我只想用4个LED,传数据的时候,我只传0~15即可。
我写了两个函数来解决这些问题。这两个函数均是可变长参数,感觉还比较好用。
shiftOutQPins 这个函数可以用来解决问题2。用法和shirtOut相同,后面多了几个参数,表示你要使用的针脚。数字对应使用的Q引脚号。引脚使用的次序是按MSBFIRST
和LSBFIRST
来的,和输入的次序无关。
如果要们要使用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);
}
网友评论