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


亲,“电路城”已合并升级到更全、更大、更强的「新与非网」。点击查看「新与非网」
该项目/视频将展示如何在自制的8x8 LED矩阵上制作“太空侵略者”游戏。
组件:
原理图:
组装:
矩阵包含64个5毫米LED,这些LED安装在厚度为4毫米的Alumil板上。在矩阵的前面放置了一块厚度为1 mm的白色有机玻璃,用作光扩散器。
电位器用于左右移动武器,并通过按钮发射激光束。游戏伴随着适当的声音,类似于原始声音。它还包含几个级别,每增加一个新级别,速度就会提高。在这种情况下,电源是外部的,电池也可以安装。
将组件安装在合适的PVC盒子中,该盒子的厚度为3和5 mm,并涂有彩色的自粘墙纸。
代码(Arduino):
/ * ============================================ ============= * /
/ *
05-833 HCI中的应用小工具,传感器和活动识别
斯科特·哈德森(Scott Hudson)上课
卡内基·梅隆大学
2012年春季
*《太空客》 *,艾尔文·李(Elwin Lee)
娱乐技术中心
卡内基·梅隆大学
学分:
驱动器矩阵模式http://arduino.cc/playground/Main/DirectDriveLEDMatrix
通过扬声器播放音调http://arduino.cc/en/Tutorial/Tone
* /
/ * ================================================ ======== * /
#include "pitches.h"
/****测试****/
byte tempMatrix[8][8] = {
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0}
};
/*** 1级 ***/
#define level1_ani { \
{1, 1, 1, 0, 0, 1, 1, 1}, \
{1, 1, 0, 0, 0, 1, 1, 1}, \
{1, 1, 0, 0, 0, 1, 1, 1}, \
{1, 1, 1, 0, 0, 1, 1, 1}, \
{1, 1, 1, 0, 0, 1, 1, 1}, \
{1, 1, 1, 0, 0, 1, 1, 1}, \
{1, 1, 0, 0, 0, 0, 1, 1}, \
{1, 1, 0, 0, 0, 0, 1, 1} \
}
#define level1 { \
{0, 1, 0, 1, 0, 1, 0, 0}, \
{0, 0, 1, 0, 1, 0, 1, 0}, \
{0, 1, 0, 1, 0, 1, 0, 0}, \
{0, 0, 0, 0, 0, 0, 0, 0}, \
{0, 0, 0, 0, 0, 0, 0, 0}, \
{0, 0, 0, 0, 0, 0, 0, 0}, \
{0, 0, 0, 0, 0, 0, 0, 0}, \
{0, 0, 0, 0, 0, 0, 0, 0} \
}
/*** 2级 ***/
#define level2_ani { \
{1, 1, 1, 0, 0, 1, 1, 1}, \
{1, 1, 0, 0, 0, 0, 1, 1}, \
{1, 1, 0, 1, 1, 0, 0, 1}, \
{1, 1, 1, 1, 1, 0, 0, 1}, \
{1, 1, 1, 1, 0, 0, 1, 1}, \
{1, 1, 1, 0, 0, 1, 1, 1}, \
{1, 1, 0, 0, 0, 0, 0, 1}, \
{1, 1, 0, 0, 0, 0, 0, 1} \
}
#define level2 { \
{0, 1, 0, 1, 0, 1, 0, 1}, \
{0, 0, 1, 0, 1, 0, 1, 0}, \
{0, 1, 0, 1, 0, 1, 0, 1}, \
{0, 0, 1, 0, 1, 0, 1, 0}, \
{0, 0, 0, 0, 0, 0, 0, 0}, \
{0, 0, 0, 0, 0, 0, 0, 0}, \
{0, 0, 0, 0, 0, 0, 0, 0}, \
{0, 0, 0, 0, 0, 0, 0, 0} \
}
/*** 3级 ***/
#define level3_ani { \
{1, 1, 1, 0, 0, 0, 1, 1}, \
{1, 1, 0, 0, 0, 0, 0, 1}, \
{1, 1, 0, 1, 1, 0, 0, 1}, \
{1, 1, 1, 1, 0, 0, 1, 1}, \
{1, 1, 1, 1, 0, 0, 0, 1}, \
{1, 1, 0, 1, 1, 0, 0, 1}, \
{1, 1, 0, 0, 0, 0, 0, 1}, \
{1, 1, 1, 0, 0, 0, 1, 1} \
}
#define level3 { \
{0, 0, 0, 1, 1, 1, 0, 0}, \
{0, 0, 1, 1, 1, 1, 1, 0}, \
{0, 1, 1, 0, 1, 0, 1, 1}, \
{0, 1, 0, 1, 1, 1, 0, 1}, \
{0, 0, 0, 0, 0, 0, 0, 0}, \
{0, 0, 0, 0, 0, 0, 0, 0}, \
{0, 0, 0, 0, 0, 0, 0, 0}, \
{0, 0, 0, 0, 0, 0, 0, 0} \
}
/*** 赢 ***/
#define win { \
{1, 1, 1, 0, 0, 1, 1, 1}, \
{1, 1, 0, 0, 0, 0, 1, 1}, \
{1, 0, 1, 0, 0, 1, 0, 1}, \
{0, 0, 0, 0, 0, 0, 0, 0}, \
{0, 0, 0, 0, 0, 0, 0, 0}, \
{1, 0, 1, 0, 0, 1, 0, 1}, \
{1, 0, 0, 1, 1, 0, 0, 1}, \
{1, 1, 1, 0, 0, 1, 1, 1} \
}
/*** 一般的 ***/
const int cols[8] = { 12, 11, 10, 9, 8, 7, 6, 5 }; // Array of all the Column pin numbers
const int rows[8] = { 4, 3, 2, A0, A1, A2, A3, A4 }; // Array of all the Row pin numbers
// LED矩阵中的二维像素阵列:
int pixels[8][8];
int loopDelay = 2;
boolean levelAni = true; //真
boolean levelStart = false;
boolean levelComplete = false;
int levelsArrayIndex = 0;
const int _lvls = 7; //2 * 级数
byte levels[_lvls][8][8] = {
level1_ani, level1, level2_ani, level2, level3_ani, level3, win
};
//复制级别数组以进行重置
byte initial[_lvls][8][8] = {
level1_ani, level1, level2_ani, level2, level3_ani, level3, win
};
/*** 声音***/
int boom = NOTE_C4;
boolean loseSound = true;
int lose[] = { NOTE_F4, NOTE_A4, NOTE_C5 };
int loseNoteDurations[] = { 2, 4, 4};
/*** 计时器 ***/
unsigned long aniTime;
unsigned long completeTime;
unsigned long enemyTime;
unsigned long gameOverTime;
/*** 玩家 ***/
int bulletRow = 5;
int bulletCol;
byte bulletArray[6];
int bulletDelayCount = 0;
boolean fired = false;
/*** 控制 ***/
int btnPin = A5;
int potPin = A6;
int potVal;
boolean btnDown = false;
/*** 敌人 ***/
boolean enemyWon = false;
boolean enemyWaiting = false;
boolean enemyFired = false;
boolean enemyBulletCollision = false;
int enemyAttackSpeed[7] = {0, 150, 0, 100, 0, 25, 0};
int enemyBulletSpeed[7] = {0, 16, 0, 12, 0, 8, 0};
int enemyBulletRow;
int enemyBulletDelayCount = 0;
int enemyBulletArray[8][2] = { {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0} };
int enemyBottomCount = 0;
int randomBullet;
/*** 转换 ***/
boolean shiftLevel = false;
boolean shiftLeft = true;
boolean shiftDown = false;
boolean shiftRight = false;
boolean shiftUp = false;
int shiftCount = 0;
int shiftSpeed[2] = {70, 35};
void setup() {
Serial.begin(9600);
// 将I / O引脚初始化为输出:
//遍历图钉:
for (int thisPin = 0; thisPin < 8; thisPin++) {
//初始化输出引脚:
pinMode(cols[thisPin], OUTPUT);
pinMode(rows[thisPin], OUTPUT);
//将col引脚(即阴极)拉高,以确保
// LED熄灭:
//两者均为高电平,因此无连接
digitalWrite(cols[thisPin], HIGH);
digitalWrite(rows[thisPin], HIGH);
}
//将按钮和电位计设置为输入
pinMode(btnPin, INPUT);
pinMode(potPin, INPUT);
clearLeds(); //清除LED矩阵
aniTime = millis(); //开始级别#动画计时器
}
void loop() {
/ ***全部重置为无电路*** /
for (int i = 0; i < 8; i++) {
digitalWrite(rows[i], HIGH); //所有行都高
digitalWrite(cols[i], LOW);
}
/***行 0***/
for (int col = 0; col < 8; col++) {
if (pixels[0][col] == 1) {
digitalWrite(cols[col], HIGH);
} else {
digitalWrite(cols[col], LOW);
}
}
digitalWrite(rows[0], LOW);
delay(loopDelay);
digitalWrite(rows[0], HIGH);
setPattern(levelsArrayIndex); //创建关卡
/***行 1***/
for (int col = 0; col < 8; col++) {
if (pixels[1][col] == 1) {
digitalWrite(cols[col], HIGH);
} else {
digitalWrite(cols[col], LOW);
}
}
digitalWrite(rows[1], LOW);
delay(loopDelay);
digitalWrite(rows[1], HIGH);
if (levelAni) playLevelAni(); //播放动画
/***第 2行***/
for (int col = 0; col < 8; col++) {
if (pixels[2][col] == 1) {
digitalWrite(cols[col], HIGH);
} else {
digitalWrite(cols[col], LOW);
}
}
digitalWrite(rows[2], LOW);
delay(loopDelay);
digitalWrite(rows[2], HIGH);
if (levelStart) readPot(); //读取电位器值
/***第三行***/
for (int col = 0; col < 8; col++) {
if (pixels[3][col] == 1) {
digitalWrite(cols[col], HIGH);
} else {
digitalWrite(cols[col], LOW);
}
}
digitalWrite(rows[3], LOW);
delay(loopDelay);
digitalWrite(rows[3], HIGH);
if (levelStart) refreshPlayer(); //根据电位器值更新玩家的位置
if (levelStart) readBtn(); //读取按钮状态
/***第四行***/
for (int col = 0; col < 8; col++) {
if (pixels[4][col] == 1) {
digitalWrite(cols[col], HIGH);
} else {
digitalWrite(cols[col], LOW);
}
}
digitalWrite(rows[4], LOW);
delay(loopDelay);
digitalWrite(rows[4], HIGH);
if (levelStart && !enemyWon) readEnemy(); //获取敌人的最高排#号并发射子弹
/***第五行***/
for (int col = 0; col < 8; col++) {
if (pixels[5][col] == 1) {
digitalWrite(cols[col], HIGH);
} else {
digitalWrite(cols[col], LOW);
}
}
digitalWrite(rows[5], LOW);
delay(loopDelay);
digitalWrite(rows[5], HIGH);
if (levelStart && !levelComplete) checkLevelState(); //检查关卡的所有像素都消失了
if (levelComplete) levelFinished(); //胜利等级
/***第六行***/
for (int col = 0; col < 8; col++) {
if (pixels[6][col] == 1) {
digitalWrite(cols[col], HIGH);
} else {
digitalWrite(cols[col], LOW);
}
}
digitalWrite(rows[6], LOW);
delay(loopDelay);
digitalWrite(rows[6], HIGH);
if (levelStart && shiftLevel) shiftRow(); //在关卡中移动像素
/***Row 7***/
for (int col = 0; col < 8; col++) {
if (pixels[7][col] == 1) {
digitalWrite(cols[col], HIGH);
} else {
digitalWrite(cols[col], LOW);
}
}
digitalWrite(rows[7], LOW);
delay(loopDelay);
digitalWrite(rows[7], HIGH);
if (enemyWon) gameOver(); //被敌人击中则失败
updatePixels(); //更新LED矩阵的所有像素
}
void clearLeds() {
// 清除显示数组
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
pixels[i][j] = 0;
}
}
}
/*** 在LED矩阵上填充水平***/
void setPattern(int pattern) {
if (levelsArrayIndex < 7) { //如果不是最后一级
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
if ( levels[levelsArrayIndex][i][j] == 1 ) { //仅将“ 1”复制到临时矩阵
tempMatrix[i][j] = levels[levelsArrayIndex][i][j];
}
}
}
} else {
restart(); //如果已经结束游戏就重新开始
}
}
/***阅读句柄***/
void readPot() {
potVal = analogRead(potPin); //读取电位器值
potVal = map(potVal, 0, 1024, 0, 6); //将1023映射到6个LED矩阵值;
//仅0〜6列用于显示播放器
//将max_in和max_out提高1,以实现均匀的值分配http://arduino.cc/forum/index.php?topic=72153.0
}
/*** 刷新播放器 ***/
void refreshPlayer() {
byte _playerRows[2][8] = { //用于储存玩家位置的临时数组
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0}
};
//绘制玩家像素
_playerRows[0][potVal+1] = 1;
_playerRows[1][potVal] = 1;
_playerRows[1][potVal+1] = 1;
_playerRows[1][potVal+2] = 1;
for (int i = 6; i < 8; i++) { //第6-7行(玩家所在的位置)
for (int j = 7; j >= 0; j--) { //更新玩家位置
if(_playerRows[i-6][j] == 1) { //仅将“一个”复制到临时矩阵
tempMatrix[i][j] = _playerRows[i-6][j];
}
}
}
}
/***阅读按钮***/
void readBtn() {
int btnPress = digitalRead(btnPin); //读取按钮状态
if (btnPress == 1 && !fired && !btnDown){ //如果按下按钮
bulletCol = potVal+1; //矩阵上的项目符号列值
btnDown = true;
fired = true;
}
if (btnDown) {
if (btnPress == 0) {
btnDown = false;
}
}
if (fired) {
shoot(bulletCol); //播放拍摄动画
}
}
/*** 拍摄 ***/
void shoot(int _bulletCol) {
if (bulletDelayCount == 2) { //充当延迟并确定子弹的速度
bulletRow--;
if (bulletRow < 0) { //如果子弹到达顶部(行0)
bulletRow = 5; //重置子弹行位置
fired = false; //子弹射击完成
} else {
if (tempMatrix[bulletRow][_bulletCol] == 0) { //检查下一个像素位置是否为空
tempMatrix[bulletRow][_bulletCol] = 1; //新的项目符号像素位置并打开
} else {
collisionBullet(bulletRow, _bulletCol); //子弹与像素碰撞
}
}
} else {
tempMatrix[bulletRow][_bulletCol] = 1; //绘制子弹像素
}
bulletDelayCount = (bulletDelayCount+1) % 3; //子弹的速度计算器
}
/*** 子弹碰撞 ***/
void collisionBullet(int _row, int _col) {
int boomNoteDuration = 1000/4; //声音持续时间
tone(13, boom, boomNoteDuration); //播放时播放声音
// noTone(13);
levels[levelsArrayIndex][_row][_col] = 0; //删除从原始级别矩阵拍摄的1个像素
tempMatrix[_row][_col] = 0; //更新像素矩阵的温度矩阵
bulletRow = 5; //将原始项目符号行的位置设置回5
fired = false; //子弹射击完成
}
/*** 阅读敌人 ***/
void readEnemy() {
if (!enemyWaiting && !enemyFired && !enemyBulletCollision){ //如果敌人没有做任何事情 anything
enemyTime = millis(); //启动计时器
enemyWaiting = true;
}
if (enemyWaiting) {
if (millis() - enemyTime > enemyAttackSpeed[levelsArrayIndex]) { //根据数组对每个等级的攻击速度
int _row = 3; //临时行值
boolean dobreak = false; //用于两次休息;
//循环获取敌人的最高行像素(距离玩家最近)
for (int i = 3; !dobreak && i >= 0; i--) { //向后循环以获取最高行
for (int j = 0; j < 8; j++) {
if(levels[levelsArrayIndex][i][j] == 1) { //如果在行中找到“ 1”
_row = i; //保存行索引
enemyBulletRow = _row + 1; //将敌人子弹放在敌人下方1行的值
dobreak = true; //双破;
break;
}
}
}
enemyBottomCount = 0; ///计算最高行(距离播放器最近)中“一”像素的数量
for (int c = 0; c < 8; c++) { //循环遍历最高行
if(levels[levelsArrayIndex][_row][c] == 1) { //检查列是否包含“一个”
enemyBulletArray[enemyBottomCount][0] = _row;
enemyBulletArray[enemyBottomCount][1] = c;
enemyBottomCount++;
}
}
enemyWaiting = false;
enemyFired = true; //发射敌人子弹
randomBullet = random(enemyBottomCount); //随机选择列像素之一
}
}
if (enemyFired) {
if (enemyBulletDelayCount == (enemyBulletSpeed[levelsArrayIndex]-1)) { //敌人子弹速度(较高的值=慢)
enemyBulletArray[randomBullet][0]++; //行+ 1
if (enemyBulletArray[randomBullet][0] > 7) { //如果子弹到达底部
enemyBulletDelayCount = 0; ///重置并删除项目符号
enemyFired = false;
} else {
if (tempMatrix[enemyBulletArray[randomBullet][0]] [enemyBulletArray[randomBullet][1]] == 0) { //如果下一行为空
tempMatrix[enemyBulletArray[randomBullet][0]] [enemyBulletArray[randomBullet][1]] = 1; //子弹声明
} else { //子弹击中东西
if (!levelComplete) {
enemyBulletDelayCount = 0;
enemyFired = false;
enemyBulletCollision = true;
}
}
}
} else {
tempMatrix[enemyBulletArray[randomBullet][0]][enemyBulletArray[randomBullet][1]] = 1;
}
enemyBulletDelayCount = (enemyBulletDelayCount+1) % enemyBulletSpeed[levelsArrayIndex]; //enemy bullet speed
}
if (enemyBulletCollision) {
if (enemyBulletArray[randomBullet][0] == 6 || enemyBulletArray[randomBullet][0] == 7) { //check if enemy's bullet hit player
// digitalWrite(13, HIGH);
Serial.println("HIT!");
enemyWon = true;
gameOverTime = millis();
}
enemyBulletCollision = false;
}
}
/*** 转换级别***/
void shiftRow() { //测试目的
int _speed;
if (levelsArrayIndex == 3) {
_speed = shiftSpeed[0];
} else if (levelsArrayIndex == 5) {
_speed = shiftSpeed[1];
}
byte _levelTemp[5][8] = { //临时矩阵数组,用于储存级别像素位置
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0}
};
for (int i = 0; i < 5; i++) { //储存在临时数组中
for (int j = 0; j < 8; j++) {
_levelTemp[i][j] = levels[levelsArrayIndex][i][j];
}
}
if (shiftCount == (_speed-1)) { //移位前延迟(大约100 * 18ms)
if (shiftLeft == true) { //左移
//循环遍历矩阵的顶部5x8
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 8; j++) {
if (j == 7) { //防止移动不存在的列索引8
levels[levelsArrayIndex][i][7] = _levelTemp[i][0];
} else {
levels[levelsArrayIndex][i][j] = _levelTemp[i][j+1];
}
}
}
shiftCount = 0;
shiftLeft = false;
shiftDown = true;
} else if (shiftDown == true) { //下移
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 8; j++) {
if ( i == 0 ) { //防止不存在的行索引-1的移位
levels[levelsArrayIndex][i][j] = 0;
} else {
levels[levelsArrayIndex][i][j] = _levelTemp[i-1][j]; //降档
}
}
}
shiftDown = false;
shiftRight = true;
} else if (shiftRight == true) { //右移
for (int i = 0; i < 5; i++) {
for (int j = 7; j >= 0; j--) {
if (j == 0) { //防止移动不存在的列索引-1
levels[levelsArrayIndex][i][0] = _levelTemp[i][7];
} else {
levels[levelsArrayIndex][i][j] = _levelTemp[i][j-1];
}
}
}
shiftCount = 0;
shiftRight = false;
shiftUp = true;
} else if (shiftUp == true) { //向上移动
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 8; j++) {
if ( i == 4 ) { //防止移位行索引5
levels[levelsArrayIndex][i][j] = 0;
} else {
levels[levelsArrayIndex][i][j] = _levelTemp[i+1][j]; //降档
}
}
}
shiftUp = false;
shiftLeft = true;
}
}
shiftCount = (shiftCount+1) % _speed; //换挡延迟
}
/***播放级别数字动画***/
void playLevelAni() {
if (millis() - aniTime < 3000) { //从级别号转换到实际级别之前的时间
// if (levelsArrayIndex < 6 && millis() - aniTime > 3750) { //3000
// delay(500);
// }
} else {
levelAni = false; //结束动画
levelStart = true;
levelsArrayIndex++;
if (levelsArrayIndex == 3 || levelsArrayIndex == 5) {//如果级别2或3,则开始移位
shiftLeft = true;
shiftDown = false;
shiftRight = false;
shiftUp = false;
shiftLevel = true;
} else {
shiftLevel = false;
}
clearLeds();
}
}
void checkLevelState() { //检查所有关卡像素(敌人)是否都消失了
int _countLevelPixels = 0;
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 8; j++) {
if(levels[levelsArrayIndex][i][j] == 1){
_countLevelPixels++; //计算“一个”像素的数量
}
}
}
if((_countLevelPixels) == 0){ //如果什么都没有,恭喜!你打水平!
// digitalWrite(13,HIGH);
// digitalWrite(13, HIGH);
// Serial.println("COMPLETE!");
completeTime = millis();
levelComplete = true;
}
}
void levelFinished() {
if (millis() - completeTime > 2000) { //过渡到下一级别之前的时间
//重置布尔值
enemyWaiting = false;
enemyFired = false;
enemyBulletCollision = false;
levelStart = false;
levelComplete = false;
levelAni = true;
aniTime = millis();
levelsArrayIndex++;
}
}
/*** 更新像素矩阵 ***/
void updatePixels() {
/ //使用临时的8x8矩阵更新实际矩阵以防止任何错误
//当将值直接应用于pixel []矩阵时,往往会出现错误
//相反,将所有矩阵值都临时存储并立即将值应用于pixels []更稳定
//将所有临时矩阵值复制到实际显示矩阵
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
pixels[i][j] = tempMatrix[i][j];
}
}
//重置临时矩阵的所有值
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
tempMatrix[i][j] = 0;
}
}
}
void gameOver() {
if( loseSound) {
loseSound = false;
for (int thisNote = 0; thisNote < 3; thisNote++) {
//要计算音符持续时间,请花费一秒钟
//除以音符类型。
int noteDuration = 250/loseNoteDurations[thisNote];
tone(13, lose[thisNote],noteDuration);
//为了区分音符,请在它们之间设置最短时间。
//笔记的持续时间+ 30%似乎效果良好:
int pauseBetweenNotes = noteDuration * 1.30;
delay(pauseBetweenNotes);
//停止音调播放:
noTone(13);
}
}
if (millis() - gameOverTime < 3000) { / //重新启动之前的时间
延迟(250 );
delay(250);
} else {
restart();
}
}
void restart() {
//重置所以布尔值
enemyWon = false;
enemyWaiting = false;
enemyFired = false;
enemyBulletCollision = false;
levelAni = true;
levelStart = false;
levelComplete = false;
levelsArrayIndex = 0;
loseSound = true;
//重置所以级别
for (int level = 0; level<_lvls; level++) {
for (int x = 0; x<8; x++) {
for (int y = 0; y<8; y++) {
levels[level][x][y] = initial[level][x][y];
}
}
}
aniTime = millis(); //运行一级动画
};
基于Arduino的温控风扇
2021-07-06
如何将超声波传感器与 Arduino 连接
2021-07-02
基于esp8266的便携式无线PM2.5检测电路设计
2020-02-07
基于MEMS的惯性测量装置 (IMU) 检测电路设计
2020-02-06
硬实力,游戏机自己做,十个经典游戏机方案合集
2020-08-24
如何将按钮与 Arduino 连接起?
2021-07-13
基于树莓派和Arduino打造的PLC EtherCAT电路设计
2020-02-25
入门指南:TFT彩色显示屏,带Arduino和ESP8266
2020-04-23
Arduino最小系统板设计PCB板及原理图
2020-01-17
带有Arduino和ESP32的实时时钟
2020-04-17
讨论