赞
踩
这两天重新来玩74HC595,因为前一段时间为了点亮led 像素屏用了查理复用,但是查理复用的GPIO占用实在太高,而且接线其实也非常不方便;因此打算重新用74HC595来点灯,毕竟595的价格喜人啊。
之前一直不愿意用595的原因是它的文档实在看起来头疼的很,什么sclk,rclk,sclr,stcp ,shcp,ds,si 等等,同样是595 芯片,不同文档介绍的时候,pin的名称是两套,不论是那一套都让人容易晕头转向。
同时为了更深入理解595的运行机制,加上前端时间用了tm1637,学习了异或和对应的二进制转换,所以打算手工来驱动595 ,不使用shiftout函数。
布线如下:
代码如下:
-
- int latchPin = D8; //Pin connected to ST_CP(pin 12) of 74HC595 //ST
- int clockPin = D6; //Pin connected to SH_CP(pin 11) of 74HC595 //这个pin居然可以没有 SH
- int dataPin = D7; //Pin connected to DS(pin 14) of 74HC595
- int r = 8;
- unsigned char sequence[8] = {B00000001, B00000010, B00000100, B00001000, B00010000, B00100000, B01000000, B10000000,};
-
- void setup() {
- Serial.begin(115200);
- pinMode(latchPin, OUTPUT);
- pinMode(clockPin, OUTPUT);
- pinMode(dataPin, OUTPUT);
- }
- uint8_t cur = 0;
- void loop() {
- for (int a = 0; a < 8; a++) {
- cur = sequence[a];
- digitalWrite(latchPin, LOW);
- for (int c = 0; c < 8; c++) {
- digitalWrite(clockPin, LOW);
- if (cur & 0x01)digitalWrite(dataPin, HIGH);
- else digitalWrite(dataPin, LOW);
- digitalWrite(clockPin, HIGH);
- cur >>= 1;
- }
- digitalWrite(latchPin, HIGH);
- delay(800);
- }
- delay(2000);
- }
这样的代码就是从8->1输出流水灯,结果8->2都运行起来正常,但是2->1的时候出了问题,本来应该是2灭1亮,结果2和1 一期亮了,如下图:
代码问题找了无数遍找不出原因,各种测试和尝试,找不出原因。
按照595的手册:
1、SI(DS)输入数据;
2、CLK(SHCP)上升沿,输入数据到移位寄存器;
3、重复上面过程到数据输入结v束;
4、RCLK(STCP) 上升沿,移入数据到锁存器并行输出Q0-Q8并行输出;
所以上面的代码是没有错的,网上搜到过由于电压不对,导致输出不对的情况,595 的电压是5V,SI(DS)的电压是3.3V这种情况导致输出不对,于是就试了一下,结果在3.3V 的情况下,8->1确实输出正常。
由于3.3V 下,LED不够亮,重新回到了5V折腾,于是开始怀疑是不是各种接线不对,于是把MR接到了GND,之前没有接,如下图
这次调整后,MR接了GND, 5.5V下8-1输出正常,这其实已经是最标准的做法,因为之前没有接MR.
然而这件事并没有完,后来在MR没有接入GND的情况下,为了对比一下效果,使用了shiftout函数,发觉MR没有接入GND,同样意图8->1输出,我自己的代码2->1 同时亮,而shiftout函数又是完全正常的,代码如下:
-
- int latchPin = D8; //Pin connected to ST_CP(pin 12) of 74HC595 //ST
- int clockPin = D6; //Pin connected to SH_CP(pin 11) of 74HC595 //这个pin居然可以没有 SH
- int dataPin = D7; //Pin connected to DS(pin 14) of 74HC595
- int r = 8;
- unsigned char sequence[8] = {B00000001, B00000010, B00000100, B00001000, B00010000, B00100000, B01000000, B10000000,};
-
- void setup() {
- Serial.begin(115200);
- pinMode(latchPin, OUTPUT);
- pinMode(clockPin, OUTPUT);
- pinMode(dataPin, OUTPUT);
- }
- uint8_t cur = 0;
- void loop() {
- for (int a = 0; a < 8; a++) {
- cur = sequence[a];
- digitalWrite(latchPin, LOW);
- for (int c = 0; c < 8; c++) {
- digitalWrite(clockPin, LOW);
- if (cur & 0x01)digitalWrite(dataPin, HIGH);
- else digitalWrite(dataPin, LOW);
- digitalWrite(clockPin, HIGH);
- cur >>= 1;
- }
- digitalWrite(latchPin, HIGH);
- delay(800);
- }
- for (int m = r - 1; m >= 0; m--) {
- digitalWrite(latchPin, LOW);
- shiftOut(dataPin, clockPin, MSBFIRST, sequence[m]);
- digitalWrite(latchPin, HIGH); delay(800);
- }
- delay(2000);
- }
视频对比如下:
WeChat_20221108223820
于是又各种找原因,怀疑是不是各种上升沿出了问题,各种怀疑,各种调试,反正就是觉得奇怪:
1、在MR接入GND的情况下,都正常;
2、在MR没有GND的情况下,3.3V电压 一切正常;5V电压,为啥shiftout函数亮灯正常,而我自己的函数亮灯前面正常,最后两位出了问题,如果说我的代码有问题,那么为啥有的情况下工作正常,有的不正常?
一直到最后实在不行,祭出了终极大法,查看shiftout的源代码:
- void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val) {
- uint8_t i;
-
- for(i = 0; i < 8; i++) {
- if(bitOrder == LSBFIRST)
- digitalWrite(dataPin, !!(val & (1 << i)));
- else
- digitalWrite(dataPin, !!(val & (1 << (7 - i))));
-
- digitalWrite(clockPin, HIGH);
- digitalWrite(clockPin, LOW);
- }
- }
这一下就对比出来了,shiftout对于时钟线的上升沿用的是:
- digitalWrite(clockPin, HIGH);
- digitalWrite(clockPin, LOW);
而我自己用的是:
- digitalWrite(clockPin, LOW);
-
- digitalWrite(clockPin, HIGH);
当把代码重新修改后,在MR不接GND的情况下,5V电压,从8->1 shiftout和我自己的代码都工作正常。
在网上其他人的代码也是同我最初的情况一样:
应该说很多人都是这么写的,先low后high.
一般情况下,MR接入GND,这段代码都会工作正常,但是我上面的经历说明了某些情况下如果不按照shiftout所示的先high后low,会存在难以找到原因的异常,包括网上流传的5V电压74HC595不稳定要用到3.3V电压的谣传大概也是因为这个原因。
不过最后还是没有搞明白为啥是先high后low,而不是先low和high呢?
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。