本网页已闲置超过3分钟,按键盘任意键或点击空白处,即可回到网页

带移位寄存器的发光二极管
发布时间:2021-05-10
分享到:
带移位寄存器的发光二极管
发布时间:2021-05-10
分享到:

该项目主要是为带有移位寄存器的发光二极管立方体(4*4)编写代码,为立方体创造不同的模式。

硬件组件:

  • Arduino Nano R3
  • 移位寄存器75HC595
  • 瞬时按钮开关
  • 发光二极管

 4*4立方体:

该立方体有16条腿和4排的立方体。Les s把这些行叫做层。如何将这16条支路连接到Arduino而不占用其所有引脚的最简单方法是使用移位寄存器75HC595。

(移位寄存器75HC595)

将立方体的前8个引脚(1-8)连接到第一个移位寄存器(引脚Q0-Q7),并将其他8个引脚(9-16)连接到另一个引脚,如俯视图中的表格所示:

(俯视立方体的腿)

下一步是用Arduino连接移位寄存器的引脚,如下所示:

  • 引脚8(两个移位寄存器/ GND)至阿尔杜伊诺的接地引脚
  • 第一移位寄存器的引脚9 (Q7)至第二移位寄存器的引脚14(数据)
  • 引脚10(两个移位寄存器/复位)至Arduino的引脚8
  • 引脚11(两个移位寄存器/时钟)至Arduino的引脚9
  • 引脚12(两个移位寄存器/锁存器)至Arduino的引脚10
  • 引脚14(第一个移位寄存器/数据)至Arduino的引脚11
  • 引脚16(两个移位寄存器/ VCC)至Arduino的5V引脚

最后一步是用Arduino连接立方体的层:

  • 引脚4 -第0层(通过100欧姆电阻)
  • 引脚5 -第1层(通过100欧姆电阻)
  • 引脚6 -第2层(通过100欧姆电阻)
  • 引脚7 -第3层(通过100欧姆电阻)

(立方体的底部)

控制led: 

一层中的每个led都由一个数字表示,如下表所示:

(打开指示灯的值)

所以要打开图层第二行的第二个led,就会设置layer = 32。要打开前两个led,layer = 1 + 2 = 3。要打开第一行led,layer = 1 + 2 + 4 + 8 = 15。

如果想将循环中的光穿过层中的所有LED,在第一步中,设置layer=b000000000000001=1,然后在循环中,将通过设置layer=layer<<1来移动该位。或者可以设置layer=(1<<count)并在循环中增加“count”。

主回路:

当知道如何在一层中设置led时,想要控制4层。虽然只能向我们的2个移位寄存器发送关于1层的信息,但使用Arduino的主循环来非常快速地打开和关闭循环中的层,它们将在同一时刻全部改变。显示图层值的代码非常简单:

 SetShiftReg(layer[k]);    //将层数据发送到移位寄存器
 bitClear(PORTD, 4 + k);   //启用“层k”
 delay(1);                 //对LED亮度很重要
 PORTD |= B11110000;       //关闭图层
 k++; if (k > 3) k = 0;    //在循环中再增加一层

在该项目中,使用按钮(与接地和Arduino的引脚2连接)来改变创建的模式。按下按钮设置“开始”。这个开始采用并初始化下一个模式。

然后,循环在“速度时间”值中设置的每一个时间(以毫秒为单位)后启动选定的模式。

关于主循环和按钮的标签:

#define buttonPin 2
unsigned int layer[4] = {0, 0, 0, 0};   //65535填充层
byte k = 0;
bool start = true;
unsigned long delayTime;
int speedTime = 0;
int count;
void setup() {
 InitializeShiftReg();
 InitializeMyLedCube();
}
void InitializeMyLedCube() {
 DDRD = B11110000;         //引脚D0-D3作为输入,D4-D7作为输出
 PORTD |= B11110000;       //关闭图层
 pinMode(buttonPin, INPUT_PULLUP);
 attachInterrupt(digitalPinToInterrupt(buttonPin), PushButton, FALLING);
 delayTime = millis();
}
byte patternNum = 28;
byte pattern = patternNum - 1;
void loop() {
 if (start) {
   detachInterrupt(digitalPinToInterrupt(buttonPin));
   delay(500);   //等待释放按钮
   pattern++; 
   if (pattern > patternNum) pattern = 1;
   attachInterrupt(digitalPinToInterrupt(buttonPin), PushButton, FALLING);
   count = 0;
 }
 if (((millis() - delayTime) > speedTime) || start) { 
   switch (pattern) {
     case 1: LayersUpDown(); break;
     case 2: FallingDot(); break;
     case 3: Rain(); break;
     case 4: AllCube(); break;
     case 5: Cut(); break;
     case 6: Cube(); break;
     case 7: Diagonal(); break;
     case 8: Mixer(); break;
     case 9: Random(); break;
     case 10: FallingLayer(); break;
     case 11: LayerCut(); break;
     case 12: Circle(); break;
     case 13: RandomWay(); break;
     case 14: SmallCube(); break;
     case 15: RandomWayCube(); break;
     case 16: GrowingCube(); break;
     case 17: FallingLayers(); break;
     case 18: GrowingLine(); break;
     case 19: CircleEdges(); break;
     case 20: CircleSide(); break;
     case 21: RandomWayLine(); break;
     case 22: RandomWaySide(); break;
     case 23: DJCube(); break;
     case 24: FillingCube(); break;
     case 25: NanoBuilding(); break;
     case 26: Curve(); break;
     case 27: Snake(); break;
     case 28: Julka(); break;
     default: break;
   }
   delayTime = millis();
 }
 //此部分显示在函数中设置的图层
 SetShiftReg(layer[k]);    //将层数据发送到移位寄存器
 bitClear(PORTD, 4 + k);   //启用“层k”
 delay(1);                 //对LED亮度很重要
 PORTD |= B11110000;       //关闭图层
 k++; if (k > 3) k = 0;    //在循环中再增加一层
}
void PushButton() {
 start = true;
}

“移位寄存器”标签:

#define latchPin 10   //端口 B2
#define clockPin 9    //端口 B1
#define dataPin 11    //端口B3
#define resetPin 8    //端口 B0
void InitializeShiftReg() {
 DDRB |= B1111;  //引脚D8-D11作为输出
 PORTB |= B0001; //将引脚重置为高
}
void SetShiftReg(unsigned int value) {
  bitClear(PORTB, 2);   //数字写入(latchPin, LOW);
  shiftOut(dataPin, clockPin, MSBFIRST, value >> 8); 
  shiftOut(dataPin, clockPin, MSBFIRST, value);      
  bitSet(PORTB, 2);    //数字写入(latchPin, HIGH);
}

创建模式:

每次在“速度时间”值中设置模式的开始后,Arduino的主循环都会启动选定的模式。换句话说,一个模式的函数总是只改变一次层,但是主循环会重复多次。

以Rain()模式为例:

void Rain() {
 if (start) {
   start = false; speedTime = 200;
   ClearLayers();
 }
 layer[0] = layer[1];
 layer[1] = layer[2];
 layer[2] = layer[3];
 layer[3] = 1 << random(16);
}

只有当打开模式时,“开始”部分才会启动一次。它设置速度时间并关闭所有led。然后,总是随机打开顶层16个led中的一个,在这个循环中,把它移到底层。

项目演示:

 

加入微信技术交流群

技术交流,职业进阶

关注与非网服务号

获取电子工程师福利

加入电路城 QQ 交流群

与技术大牛交朋友

讨论