以下是对这段代码的错误分析与修正建议: 1. `CS_PIN` 定义可能有误 在注释里提到 `D8` 对应 `GPIO15`,但代码里把 `CS_PIN` 定义成了 `12`。若使用 `D8` 引脚,`CS_PIN` 应定义为 `15`。 ```cpp #define CS_PIN 15 // D8 对应 GPIO15 ``` 2. `mx.setRow` 函数使用有误 在 `gameOver` 函数里,`mx.setRow(0, i, 0b11111111);` 这行代码存在问题。`mx.setRow` 函数的参数顺序为 `setRow(device, row, value)`,这里的 `device` 是设备编号,`row` 是行号,`value` 是要设置的值。从代码来看,这里想逐行点亮显示屏,不过参数传递有误。正确的做法是把 `device` 设为 `0`,`row` 设为 `i`。 ```cpp void gameOver() { mx.clear(); for (int i = 0; i < 8; i++) { mx.setRow(0, i, 0b11111111); // 修正参数顺序 delay(100); } delay(1000); snakeLength = 3; dirX = 1; dirY = 0; for (int i = 0; i < snakeLength; i++) { snakeX[i] = 2 - i; snakeY[i] = 0; } generateFood(); } ``` 3. 缺少按键消抖处理 在 `readKey` 函数中,对于按键值的读取没有做消抖处理,这样可能会造成按键误触发。可以添加简单的消抖逻辑,例如在读取按键值后延时一小段时间再读取一次,两次结果一致才认定为有效按键。 ```cpp // 读取AD按键并设置方向 void readKey() { int keyVal = analogRead(KEY_PIN); delay(20); // 消抖延时 int keyVal2 = analogRead(KEY_PIN); if (keyVal == keyVal2) { if (keyVal < 50) { dirX = 0; dirY = -1; } // 上 else if (keyVal < 200) { dirX = 0; dirY = 1; } // 下 else if (keyVal < 400) { dirX = -1; dirY = 0; } // 左 else if (keyVal < 600) { dirX = 1; dirY = 0; } // 右 } } ``` 完整修正后的代码 ```cpp #define USE_FC16_HW 1 #include <MD_MAX72xx.h> #include <SPI.h> #define FC16_HW 1 #define HARDWARE_TYPE FC16_HW #define MAX_DEVICES 1 #define CS_PIN 15 // D8 对应 GPIO15 MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, CS_PIN, MAX_DEVICES); // 蛇定义 #define WIDTH 8 #define HEIGHT 8 int snakeX[64], snakeY[64]; int snakeLength = 3; int dirX = 1, dirY = 0; int foodX = 3, foodY = 3; // 按键 A0 #define KEY_PIN A0 void setup() { mx.begin(); mx.clear(); randomSeed(analogRead(0)); // 初始化蛇身体 for (int i = 0; i < snakeLength; i++) { snakeX[i] = 2 - i; snakeY[i] = 0; } generateFood(); } void loop() { readKey(); // 获取方向 moveSnake(); if (checkCollision()) { gameOver(); return; } if (snakeX[0] == foodX && snakeY[0] == foodY) { snakeLength++; generateFood(); } draw(); delay(300); } void moveSnake() { for (int i = snakeLength - 1; i > 0; i--) { snakeX[i] = snakeX[i - 1]; snakeY[i] = snakeY[i - 1]; } snakeX[0] += dirX; snakeY[0] += dirY; } bool checkCollision() { // 撞墙 if (snakeX[0] < 0 || snakeX[0] >= WIDTH || snakeY[0] < 0 || snakeY[0] >= HEIGHT) return true; // 撞自己 for (int i = 1; i < snakeLength; i++) { if (snakeX[0] == snakeX[i] && snakeY[0] == snakeY[i]) return true; } return false; } void draw() { mx.clear(); for (int i = 0; i < snakeLength; i++) { mx.setPoint(snakeY[i], snakeX[i], true); } mx.setPoint(foodY, foodX, true); } void generateFood() { while (true) { bool conflict = false; foodX = random(0, WIDTH); foodY = random(0, HEIGHT); for (int i = 0; i < snakeLength; i++) { if (snakeX[i] == foodX && snakeY[i] == foodY) { conflict = true; break; } } if (!conflict) break; } } void gameOver() { mx.clear(); for (int i = 0; i < 8; i++) { mx.setRow(0, i, 0b11111111); // 修正参数顺序 delay(100); } delay(1000); snakeLength = 3; dirX = 1; dirY = 0; for (int i = 0; i < snakeLength; i++) { snakeX[i] = 2 - i; snakeY[i] = 0; } generateFood(); } // 读取AD按键并设置方向 void readKey() { int keyVal = analogRead(KEY_PIN); delay(20); // 消抖延时 int keyVal2 = analogRead(KEY_PIN); if (keyVal == keyVal2) { if (keyVal < 50) { dirX = 0; dirY = -1; } // 上 else if (keyVal < 200) { dirX = 0; dirY = 1; } // 下 else if (keyVal < 400) { dirX = -1; dirY = 0; } // 左 else if (keyVal < 600) { dirX = 1; dirY = 0; } // 右 } } ``` 额外需要注意的逻辑点 1. 在 `readKey` 函数里,按键的阈值(如 `50`、`200`、`400`、`600`)可能会因硬件差异而有所不同,实际使用时需要根据具体情况进行调整。 2. 代码里使用了 `delay` 函数,这会阻塞程序的执行。若后续需要添加其他功能,建议采用非阻塞的延时方式,例如使用 `millis` 函数。 3. 在 `generateFood` 函数中,采用的是随机生成食物位置再检查冲突的方法。当蛇的长度接近屏幕大小时,这种方法可能会导致生成食物的时间变长,可考虑优化生成算法。 [2025-07-23 14:49:18 | AI写代码神器 | 1917点数解答]