灰阶光立方 最少硬件资源 程序可扩展-Arduino中文社区 - Powered by Discuz! Archiver

createskyblue 发表于 2020-7-10 11:24

灰阶光立方 最少硬件资源 程序可扩展

本帖最后由 createskyblue 于 2020-7-10 19:05 编辑


说明亮点1 多阶灰度模拟,用最少的资源做出灰阶光立方
亮点2 可以使用串口通讯通过光立方的密度、亮度、闪烁频率直观地显示出CPU占用率(可惜视频拍不出这个效果,想感受得自己做一个)通过合理调整扫描间隔实现灰度显示,定时器不足采用软件模拟所以存在一定的缺陷:缺陷1 更精细的灰阶需要牺牲刷新率换取
缺陷2 使用了所有可以用的io驱动,只可以周期性地进行串口通讯交换数据
视频演示https://www.bilibili.com/video/BV1Vi4y137YX/

引脚定义


程序
/*
+创天蓝编写 1281702594@qq.com采用CC协议
+关于串口通讯
-当需要时,光立方驱动程序会向上位机发送指令“get”,当上位机收到get后可开始传送cpu使用率(0-100)
-默认2000ms光立方发送一次刷新请求
-串口通讯超时默认为1500ms
-请求状态下向光立方发送串口指令"120"会软重启光立方
+倘若通讯超时 将清空显示,如果希望通讯超时后显示随机内容请把SerialReadCMD()函数中最后一处出现的"p=0;"改为"p=random(0,100);"即可
+支持更改光立方大小 默认大小4x4x4 把4改为你想要的即可
-如果光立方分辨率高于4x4x4需要修改LightCube()函数,因为arduino某些型号并不能直接驱动高于4x4x4的光立方
-不过不用担心,修改方式很简单,把IO控制的两行代码改成控制所需要的控制寄存器的代码就好
*/
int cube;
int layer = {A5, A4, A3, A2}; //光立方的引脚
int column = {
A1, A0, 13, 12,
8,9,10, 11,
4,5,6,7,
0,1,2,3
};

byte LightCycle = 0;
int p = 0;
byte pw;
unsigned long DisplayerTime = 0;
unsigned long RandomCoolTime = 0;
unsigned long SerialReadCMDTimeOut = 0;
void (*resetFunc)(void) = 0;

void BootLogo() {
cube=255;

}

void setup() {
randomSeed(analogRead(A0));
SetupCubePin();
CleanCube();
BootLogo();
LightCube();
//Serial.begin(115200);
}

void loop() {
DisplayerTime = millis();
//                                  ↓ 默认的请求刷新时间 单位ms
while (millis() < DisplayerTime + 1000) {
    LightCube();
    //选择闪烁模式
    //byte RamTimePlusP = 100 - p + random(25, 75);//CPU使用率低时闪得慢,使用率高时闪得快
    byte RamTimePlusP = random(25, 85 + p); //CPU使用率高时闪得慢,使用率低时闪得快
    while (millis() > RandomCoolTime + RamTimePlusP) {
      RandomCube();
      //PrintCube();
      RandomCoolTime = millis();
    }
}
//CleanCube();
LightCube();
p = 1000.0/(5.3*random(1, 100)+10);
//SerialReadCMD();
}
void SetupCubePin() {
//Serial.println("SetupCubePin");
for (byte z = 0; z < 4; z++) pinMode(layer, OUTPUT);
for (byte y = 0; y < 4; y++)
    for (byte x = 0; x < 4; x++) pinMode(column, OUTPUT);
}
void CleanCube() {
//Serial.println("CleanCube");
for (byte z = 0; z < 4; z++)
    for (byte y = 0; y < 4; y++)
      for (byte x = 0; x < 4; x++) cube = 0;
}
void PrintCube() {
Serial.println("PrintCube");
for (byte z = 0; z < 4; z++) {
    for (byte y = 0; y < 4; y++) {
      //Serial.println();
      for (byte x = 0; x < 4; x++) Serial.print(cube + String(" "));
    }
    Serial.println();
}
}
void RandomCube() {
//Serial.println("RandomCube");
//CleanCube();
int NewLight;
pw = 0;
for (byte t = 0; t < 2; t++)
    for (byte z = 0; z < 4; z++)
      for (byte y = 0; y < 4; y++)
      for (byte x = 0; x < 4; x++) {
          if (cube > 0) cube -= 10;
          if (cube < 0) cube = 0;
          if (random(0, 100) < abs(p - 100 * t)) {
            NewLight = !t * random(15, 100) + cube;
            if (NewLight < 256) cube = NewLight; else NewLight = 255;
          };
          pw++;
      }
//Serial.println(float(pw) / 64);
}
void LightCube() {
//Serial.println("LightCube");
for (byte z = 0; z < 4; z++) {
    digitalWrite(layer, 0);
    for (byte y = 0; y < 4; y++)
      for (byte x = 0; x < 4; x++) {
      if (LightCycle < cube) digitalWrite(column, 1); else digitalWrite(column, 0);
      }
    digitalWrite(layer, 1);
}
LightCycle += 25;
}
void SerialReadCMD() {
pinMode(13, OUTPUT);
digitalWrite(13, 1);
Serial.begin(115200);
String inString = "";
SerialReadCMDTimeOut = millis();
delay(4);
while (1) {
    //Serial.println("Get");
    while (Serial.available() > 0) {
      char inChar = Serial.read();
      inString += (char)inChar;
    }
    if (inString != "" || millis() > SerialReadCMDTimeOut + 1500) break;//收到数据或者连接超时

}
//p = 0; //通讯超时后清空光立方
p = random(1, 10); //通讯超时后开启随机展示模式
if (inString != "") p = inString.toInt();
if (p == 110) resetFunc();
Serial.println(p);
Serial.end();//UNO IO不够通讯结束后防止显示异常必须关闭串口,如果你的串口IO与显示IO不是混用可以注释这一项
}

全部资料下载**** Hidden Message *****


Aron 发表于 2020-7-20 10:48

前来学习
页: [1]
查看完整版本: 灰阶光立方 最少硬件资源 程序可扩展