网站开发一般做几个适配,wordpress实现分享,如何建设好营销网站,潍坊昌乐县城乡建设局网站✔零知IDE 是一个真正属于国人自己的开源软件平台#xff0c;在开发效率上超越了Arduino平台并且更加容易上手#xff0c;大大降低了开发难度。零知开源在软件方面提供了完整的学习教程和丰富示例代码#xff0c;让不懂程序的工程师也能非常轻而易举的搭建电路来创作产品在开发效率上超越了Arduino平台并且更加容易上手大大降低了开发难度。零知开源在软件方面提供了完整的学习教程和丰富示例代码让不懂程序的工程师也能非常轻而易举的搭建电路来创作产品测试产品。快来动手试试吧 ✔访问零知实验室获取更多实战项目和教程资源吧 www.lingzhilab.com 目录
一、硬件系统设计
1.1 硬件清单 1.2 接线方案
1.3 硬件连接图
1.4 接线实物图
二、软件系统设计
2.1 头文件与引脚定义
2.2 对象初始化与全局变量
2.3 核心函数详解
2.4 完整代码
三、操作结果展示
3.1 操作流程
3.2 显示屏界面分布
3.3 视频演示
四、ADXL362的SPI接口技术
4.1 SPI通信方式
4.2 SPI数据传输和接收机制
4.3 加速度数据格式和解析
五、常见问题解答 (FAQ)
Q1: 为什么我的串口打印是乱码
Q2: 小球控制不灵敏或反向
Q3: 小球穿墙bug如何处理 1项目概述 本项目是一个有趣的嵌入式体感交互游戏。核心功能是通过一个三维加速度传感器ADXL362来检测开发板的倾斜姿态从而控制屏幕上的小球在迷宫内移动躲避墙壁最终抵达随机生成的目标点。项目综合了传感器数据采集、数据处理、图形显示、碰撞检测等多个嵌入式开发的关键知识点 2项目亮点 通过倾斜ADXL362传感器进行体感交互操作游戏 实时绘制迷宫、小球和目标点视觉效果清晰 系统启动时自动校准加速度计消除静态误差 采用局部刷新策略避免整屏刷新带来的闪烁
3项目难点及解决方案 问题1描述简单的中心点检测会导致小球“嵌”入墙壁。 解决方案 采用多点检测法同时检测小球的上、下、左、右四个边缘点以及四个角点确保任何部位触墙都能被准确识别。 问题2描述传感器原始数据存在噪声和偏移导致小球无故移动。 解决方案 软件死区 设置一个阈值 (deadZone)忽略微小的加速度值。 开机校准 在 setup() 阶段读取多次数据求平均值将后续读数减去此平均值以消除零偏。 一、硬件系统设计
1.1 硬件清单
组件数量说明零知标准板1主控制器基于STM32F103RBT6。ST7789 TFT屏11.3英寸240x240分辨率SPI接口。ADXL362加速度计1超低功耗SPI/I2C接口本项目使用SPI。杜邦线若干用于连接各模块。Micro USB线1为开发板供电和程序下载。 1.2 接线方案
请严格按照代码中的引脚定义进行连接
1ADXL362 传感器接线
ADXL362引脚零知标准板引脚功能VCC3.3V电源GNDGND地CS10片选SPIMOSI11 (硬件SPI)SPI主出从入MISO12 (硬件SPI)SPI主入从出SCLK13 (硬件SPI)SPI时钟
2ST7789显示屏接线
ST7789引脚零知标准板引脚功能VCC3.3V 或 5V*电源 (*视屏幕型号而定)GNDGND地CS6片选软件SPIDC2数据/命令控制RST4复位MOSI8软件SPI数据线SCK7软件SPI时钟线BL3.3V背光可选 PS代码中TFT屏使用了软件SPI引脚7 8而ADXL362使用了硬件SPI引脚10111213 1.3 硬件连接图 1.4 接线实物图 二、软件系统设计
2.1 头文件与引脚定义 BALL_RADIUS 决定了小球的大小和碰撞检测范围。 MAZE_CELL_SIZE 决定了迷宫的精细度。增大它会使迷宫更简单小球移动空间更大。 MAZE_WIDTH MAZE_HEIGHT 由屏幕分辨率和单元格大小自动计算得出。 #include SPI.h
#include Wire.h // 本项目未使用I2C可移除
#include Adafruit_GFX.h
#include Adafruit_ST7789.h
#include ADXL362.h// ST7789 显示屏引脚定义 (使用软件SPI)
#define TFT_CS 6
#define TFT_RST 4
#define TFT_DC 2
#define TFT_MOSI 8
#define TFT_SCLK 7// 定义显示屏参数
#define SCREEN_WIDTH 240
#define SCREEN_HEIGHT 240// 颜色定义 (ST77XX_ 是Adafruit库预定义的颜色)
#define BACKGROUND ST77XX_BLACK
#define TEXT_COLOR ST77XX_WHITE
#define WALL_COLOR ST77XX_BLUE
#define BALL_COLOR ST77XX_RED
#define TARGET_COLOR ST77XX_GREEN
#define PATH_COLOR ST77XX_WHITE // 路径颜色通常为背景色或浅色// 游戏参数
#define BALL_RADIUS 8 // 小球像素半径
#define MAZE_CELL_SIZE 20 // 每个迷宫单元格的像素大小
#define MAZE_WIDTH (SCREEN_WIDTH / MAZE_CELL_SIZE) // 迷宫宽度单元格数
#define MAZE_HEIGHT (SCREEN_HEIGHT / MAZE_CELL_SIZE) // 迷宫高度单元格数 2.2 对象初始化与全局变量 maze数组 这是一个二维数组完全定义了迷宫的布局。修改这个数组就可以创造全新的关卡。1代表墙0代表可通行的路径。 Adafruit_ST7789 tft Adafruit_ST7789(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);
ADXL362 xl;// 小球和目标的初始位置位于迷宫左上角和右下角路径的中央
int ballX MAZE_CELL_SIZE MAZE_CELL_SIZE / 2;
int ballY MAZE_CELL_SIZE MAZE_CELL_SIZE / 2;
int targetX (MAZE_WIDTH - 2) * MAZE_CELL_SIZE MAZE_CELL_SIZE / 2;
int targetY (MAZE_HEIGHT - 2) * MAZE_CELL_SIZE MAZE_CELL_SIZE / 2;// 迷宫地图 (0路径, 1墙)
byte maze[MAZE_HEIGHT][MAZE_WIDTH] { ... }; // 此处省略数组内容// 加速度校准值
int16_t calibX 0;
int16_t calibY 0;
int16_t calibZ 0; 2.3 核心函数详解
1calibrateAccelerometer() - 传感器校准
void calibrateAccelerometer() {Serial.println(Calibrating accelerometer...);// 读取多次样本并取平均值long sumX 0, sumY 0, sumZ 0;int samples 20;for (int i 0; i samples; i) {xl.readXYZTData(accelX, accelY, accelZ, temp);sumX accelX;sumY accelY;sumZ accelZ;delay(10);}calibX sumX / samples;calibY sumY / samples;calibZ sumZ / samples;
} 2clearBall() - 优化的小球清除 避免了重绘整个屏幕或整个单元格极大减少了刷新时间消除了画面闪烁精确地恢复小球所占区域的原始迷宫图案。 void clearBall(int x, int y) {// 只清除小球区域不重新绘制整个迷宫// 创建一个临时缓冲区来存储小球区域的背景uint16_t bgBuffer[(BALL_RADIUS*22) * (BALL_RADIUS*22)];// 确定要清除的区域int clearX1 max(0, x - BALL_RADIUS - 1);int clearY1 max(0, y - BALL_RADIUS - 1);int clearX2 min(SCREEN_WIDTH - 1, x BALL_RADIUS 1);int clearY2 min(SCREEN_HEIGHT - 1, y BALL_RADIUS 1);int width clearX2 - clearX1 1;int height clearY2 - clearY1 1;// 绘制正确的背景for (int py clearY1; py clearY2; py) {for (int px clearX1; px clearX2; px) {// 计算像素到小球中心的距离int dx px - x;int dy py - y;int distance dx*dx dy*dy;// 如果在小球半径范围内则绘制正确的背景if (distance (BALL_RADIUS1)*(BALL_RADIUS1)) {// 获取像素所在的迷宫单元格int cellX px / MAZE_CELL_SIZE;int cellY py / MAZE_CELL_SIZE;// 根据单元格类型选择颜色uint16_t color (maze[cellY][cellX] 1) ? WALL_COLOR : PATH_COLOR;// 绘制像素tft.drawPixel(px, py, color);}}}
} 3updateBallPosition() - 控制逻辑 deadZone 死区范围。绝对值小于50的加速度读数将被视为噪声并忽略防止小球轻微抖动。 void updateBallPosition() {const int deadZone 50; // 死区阈值过滤微小抖动xl.readXYZTData(accelX, accelY, accelZ, temp); // 读取数据accelX - calibX; // 应用校准accelY - calibY;int moveX 0;int moveY 0;// 映射加速度值到移动速度if (abs(accelX) deadZone) {moveX map(accelX, -200, 200, -5, 5); // 映射范围可调整}if (abs(accelY) deadZone) {moveY map(accelY, -200, 200, -5, 5);}ballX constrain(ballX moveX, BALL_RADIUS, SCREEN_WIDTH - BALL_RADIUS);ballY constrain(ballY - moveY, BALL_RADIUS, SCREEN_HEIGHT - BALL_RADIUS); // 注意Y轴是减
} 4checkCollision() 与 checkPointCollision() - 碰撞检测 综合检查四边中点和四个角点共8个点是否进入墙壁单元格。这种多点检测法比只检查中心点要准确得多能有效防止卡墙和穿墙的Bug bool checkCollision() {// 检查小球边缘的四个中点int top ballY - BALL_RADIUS;int cellYTop top / MAZE_CELL_SIZE;if (maze[cellYTop][ballX/MAZE_CELL_SIZE] 1) return true;// ... 检查bottom, left, right ...// 检查四个角点if (checkPointCollision(ballX - BALL_RADIUS, ballY - BALL_RADIUS)) return true; // 左上角// ... 检查其他三个角 ...return false;
}bool checkPointCollision(int x, int y) {int cellX x / MAZE_CELL_SIZE;int cellY y / MAZE_CELL_SIZE;// 检查是否撞墙return (maze[cellY][cellX] 1);
} 2.4 完整代码
#include SPI.h
#include Wire.h
#include Adafruit_GFX.h
#include Adafruit_ST7789.h
#include ADXL362.h// ST7789 显示屏引脚定义
#define TFT_CS 6 // 设置软件SPI的片选引脚
#define TFT_RST 4 // 显示屏复位引脚
#define TFT_DC 2 // 显示屏数据/控制命令引脚
#define TFT_MOSI 8 // 软件SPI的MOSI引脚
#define TFT_SCLK 7 // 软件SPI的SCK引脚Adafruit_ST7789 tft Adafruit_ST7789(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);// 定义显示屏参数
#define SCREEN_WIDTH 240
#define SCREEN_HEIGHT 240// 颜色定义
#define BACKGROUND ST77XX_BLACK
#define TEXT_COLOR ST77XX_WHITE
#define WALL_COLOR ST77XX_BLUE
#define BALL_COLOR ST77XX_RED
#define TARGET_COLOR ST77XX_GREEN
#define PATH_COLOR ST77XX_WHITE// ADXL362对象
ADXL362 xl;// 游戏参数
#define BALL_RADIUS 8
#define MAZE_CELL_SIZE 20
#define MAZE_WIDTH (SCREEN_WIDTH / MAZE_CELL_SIZE)
#define MAZE_HEIGHT (SCREEN_HEIGHT / MAZE_CELL_SIZE)// 小球位置
int ballX MAZE_CELL_SIZE MAZE_CELL_SIZE / 2;
int ballY MAZE_CELL_SIZE MAZE_CELL_SIZE / 2;// 目标位置
int targetX (MAZE_WIDTH - 2) * MAZE_CELL_SIZE MAZE_CELL_SIZE / 2;
int targetY (MAZE_HEIGHT - 2) * MAZE_CELL_SIZE MAZE_CELL_SIZE / 2;// 加速度数据
int16_t accelX, accelY, accelZ, temp;// 迷宫地图 (0路径, 1墙)
byte maze[MAZE_HEIGHT][MAZE_WIDTH] {{1,1,1,1,1,1,1,1,1,1,1,1},{1,0,0,0,1,0,0,0,0,0,0,1},{1,0,1,0,1,0,1,1,1,1,0,1},{1,0,1,0,0,0,0,0,0,1,0,1},{1,0,1,1,1,1,1,1,0,1,0,1},{1,0,0,0,0,0,0,1,0,1,0,1},{1,0,1,1,1,1,0,1,0,1,0,1},{1,0,1,0,0,1,0,1,0,0,0,1},{1,0,1,0,1,1,0,1,1,1,0,1},{1,0,1,0,0,0,0,0,0,1,0,1},{1,0,0,0,1,1,1,1,0,0,0,1},{1,1,1,1,1,1,1,1,1,1,1,1}
};// 游戏状态
bool gameActive true;
int score 0;// 加速度校准值
int16_t calibX 0;
int16_t calibY 0;
int16_t calibZ 0;// 计时器变量
unsigned long lastDebugUpdate 0;
const unsigned long DEBUG_UPDATE_INTERVAL 10; // 每500ms更新一次调试信息void setup() {Serial.begin(9600);// 初始化显示屏tft.init(SCREEN_WIDTH, SCREEN_HEIGHT);tft.setRotation(1);tft.fillScreen(BACKGROUND);tft.setTextColor(TEXT_COLOR);tft.setTextSize(1);// 显示初始化信息tft.setCursor(50, 100);tft.print(Initializing...);// 初始化加速度计xl.begin(10); // CS引脚连接D10xl.beginMeasure(); // 进入测量模式// 校准加速度计 - 读取初始值作为偏移calibrateAccelerometer();// 绘制迷宫drawMaze();// 绘制目标drawTarget();// 绘制初始小球drawBall();// 显示游戏信息displayGameInfo();delay(1000);
}void loop() {if (!gameActive) {delay(100);return;}// 读取加速度数据xl.readXYZTData(accelX, accelY, accelZ, temp);// 应用校准accelX - calibX;accelY - calibY;accelZ - calibZ;// 保存旧位置int oldBallX ballX;int oldBallY ballY;// 根据加速度更新小球位置updateBallPosition();// 检查碰撞if (checkCollision()) {// 如果碰撞恢复旧位置ballX oldBallX;ballY oldBallY;} else {// 清除旧位置的小球clearBall(oldBallX, oldBallY);// 绘制新位置的小球drawBall();}// 检查是否到达目标if (checkTargetReached()) {score;displayGameInfo();// 生成新目标generateNewTarget();drawTarget();// 短暂暂停delay(500);}// 控制调试信息刷新率unsigned long currentTime millis();if (currentTime - lastDebugUpdate DEBUG_UPDATE_INTERVAL) {displayDebugInfo();lastDebugUpdate currentTime;}// 控制游戏速度delay(50);
}// 校准加速度计
void calibrateAccelerometer() {Serial.println(Calibrating accelerometer...);// 读取多次样本并取平均值long sumX 0, sumY 0, sumZ 0;int samples 20;for (int i 0; i samples; i) {xl.readXYZTData(accelX, accelY, accelZ, temp);sumX accelX;sumY accelY;sumZ accelZ;delay(10);}calibX sumX / samples;calibY sumY / samples;calibZ sumZ / samples;Serial.print(Calibration values - X: );Serial.print(calibX);Serial.print( Y: );Serial.print(calibY);Serial.print( Z: );Serial.println(calibZ);
}// 绘制迷宫
void drawMaze() {for (int y 0; y MAZE_HEIGHT; y) {for (int x 0; x MAZE_WIDTH; x) {if (maze[y][x] 1) {tft.fillRect(x * MAZE_CELL_SIZE, y * MAZE_CELL_SIZE, MAZE_CELL_SIZE, MAZE_CELL_SIZE, WALL_COLOR);} else {tft.fillRect(x * MAZE_CELL_SIZE, y * MAZE_CELL_SIZE, MAZE_CELL_SIZE, MAZE_CELL_SIZE, PATH_COLOR);}}}
}// 绘制小球
void drawBall() {tft.fillCircle(ballX, ballY, BALL_RADIUS, BALL_COLOR);// 绘制小球轮廓tft.drawCircle(ballX, ballY, BALL_RADIUS, BACKGROUND);
}// 清除小球
void clearBall(int x, int y) {// 只清除小球区域不重新绘制整个迷宫// 创建一个临时缓冲区来存储小球区域的背景uint16_t bgBuffer[(BALL_RADIUS*22) * (BALL_RADIUS*22)];// 确定要清除的区域int clearX1 max(0, x - BALL_RADIUS - 1);int clearY1 max(0, y - BALL_RADIUS - 1);int clearX2 min(SCREEN_WIDTH - 1, x BALL_RADIUS 1);int clearY2 min(SCREEN_HEIGHT - 1, y BALL_RADIUS 1);int width clearX2 - clearX1 1;int height clearY2 - clearY1 1;// 绘制正确的背景for (int py clearY1; py clearY2; py) {for (int px clearX1; px clearX2; px) {// 计算像素到小球中心的距离int dx px - x;int dy py - y;int distance dx*dx dy*dy;// 如果在小球半径范围内则绘制正确的背景if (distance (BALL_RADIUS1)*(BALL_RADIUS1)) {// 获取像素所在的迷宫单元格int cellX px / MAZE_CELL_SIZE;int cellY py / MAZE_CELL_SIZE;// 根据单元格类型选择颜色uint16_t color (maze[cellY][cellX] 1) ? WALL_COLOR : PATH_COLOR;// 绘制像素tft.drawPixel(px, py, color);}}}
}// 绘制目标
void drawTarget() {tft.fillCircle(targetX, targetY, BALL_RADIUS, TARGET_COLOR);// 绘制目标轮廓tft.drawCircle(targetX, targetY, BALL_RADIUS, BACKGROUND);
}// 更新小球位置
void updateBallPosition() {// 应用死区过滤微小移动const int deadZone 50;// 映射加速度到移动速度int moveX 0;int moveY 0;// 根据您的传感器数据调整映射范围if (abs(accelX) deadZone) {moveX map(accelX, -200, 200, -5, 5);}if (abs(accelY) deadZone) {moveY map(accelY, -200, 200, -5, 5);}// 更新位置ballX constrain(ballX moveX, BALL_RADIUS, SCREEN_WIDTH - BALL_RADIUS);ballY constrain(ballY - moveY, BALL_RADIUS, SCREEN_HEIGHT - BALL_RADIUS); // 注意Y轴方向// 调试输出Serial.print(Accel - X: );Serial.print(accelX);Serial.print( Y: );Serial.print(accelY);Serial.print( Move - X: );Serial.print(moveX);Serial.print( Y: );Serial.print(moveY);Serial.print( Ball - X: );Serial.print(ballX);Serial.print( Y: );Serial.println(ballY);
}// 检查碰撞 - 使用小球边缘进行检测
bool checkCollision() {// 检查小球边缘的四个点int top ballY - BALL_RADIUS;int bottom ballY BALL_RADIUS;int left ballX - BALL_RADIUS;int right ballX BALL_RADIUS;// 检查上边缘int cellXTop ballX / MAZE_CELL_SIZE;int cellYTop top / MAZE_CELL_SIZE;if (cellYTop 0 cellYTop MAZE_HEIGHT cellXTop 0 cellXTop MAZE_WIDTH maze[cellYTop][cellXTop] 1) {return true;}// 检查下边缘int cellXBottom ballX / MAZE_CELL_SIZE;int cellYBottom bottom / MAZE_CELL_SIZE;if (cellYBottom 0 cellYBottom MAZE_HEIGHT cellXBottom 0 cellXBottom MAZE_WIDTH maze[cellYBottom][cellXBottom] 1) {return true;}// 检查左边缘int cellXLeft left / MAZE_CELL_SIZE;int cellYLeft ballY / MAZE_CELL_SIZE;if (cellYLeft 0 cellYLeft MAZE_HEIGHT cellXLeft 0 cellXLeft MAZE_WIDTH maze[cellYLeft][cellXLeft] 1) {return true;}// 检查右边缘int cellXRight right / MAZE_CELL_SIZE;int cellYRight ballY / MAZE_CELL_SIZE;if (cellYRight 0 cellYRight MAZE_HEIGHT cellXRight 0 cellXRight MAZE_WIDTH maze[cellYRight][cellXRight] 1) {return true;}// 检查四个角点if (checkPointCollision(left, top) || checkPointCollision(right, top) ||checkPointCollision(left, bottom) || checkPointCollision(right, bottom)) {return true;}return false;
}// 检查单个点是否碰撞
bool checkPointCollision(int x, int y) {int cellX x / MAZE_CELL_SIZE;int cellY y / MAZE_CELL_SIZE;// 检查是否超出边界if (cellX 0 || cellX MAZE_WIDTH || cellY 0 || cellY MAZE_HEIGHT) {return true;}// 检查是否撞墙if (maze[cellY][cellX] 1) {return true;}return false;
}// 检查是否到达目标
bool checkTargetReached() {// 计算小球和目标之间的距离int dx ballX - targetX;int dy ballY - targetY;int distance dx*dx dy*dy;// 如果距离小于两者半径之和则认为到达目标return distance (BALL_RADIUS * 2);
}// 生成新目标
void generateNewTarget() {int newX, newY;bool validPosition false;int attempts 0;// 尝试找到有效位置while (!validPosition attempts 50) {newX random(1, MAZE_WIDTH - 1) * MAZE_CELL_SIZE MAZE_CELL_SIZE / 2;newY random(1, MAZE_HEIGHT - 1) * MAZE_CELL_SIZE MAZE_CELL_SIZE / 2;// 检查是否在墙上int cellX newX / MAZE_CELL_SIZE;int cellY newY / MAZE_CELL_SIZE;if (maze[cellY][cellX] 0) {validPosition true;}attempts;}// 清除旧目标clearBall(targetX, targetY);// 设置新目标targetX newX;targetY newY;
}// 显示游戏信息
void displayGameInfo() {// 在屏幕顶部显示分数tft.fillRect(0, 0, SCREEN_WIDTH, 20, BACKGROUND);tft.setCursor(10, 5);tft.setTextColor(TEXT_COLOR);tft.setTextSize(2);tft.print(Score: );tft.print(score);
}// 显示调试信息
void displayDebugInfo() {// 在屏幕底部显示加速度数据tft.fillRect(0, SCREEN_HEIGHT - 20, SCREEN_WIDTH, 20, BACKGROUND);tft.setCursor(10, SCREEN_HEIGHT - 15);tft.setTextColor(TEXT_COLOR);tft.setTextSize(1);tft.print(X:);tft.print(accelX);tft.print( Y:);tft.print(accelY);tft.print( Z:);tft.print(accelZ);
}三、操作结果展示
3.1 操作流程 按照接线图连接硬件。用零知IDE打开并上传代码至零知标准板。将开发板平放在桌面上系统自动进行加速度计校准。游戏开始后倾斜传感器。向前倾斜小球向下移动向左倾斜小球向左移动以此类推。倾斜角度越大小球移动速度越快。 3.2 显示屏界面分布 顶部区域约20像素高 显示当前得分Score。 主体区域 显示迷宫、红色小球和绿色目标点。 底部区域约20像素高 调试信息区实时滚动显示原始的加速度值X, Y, Z。 3.3 视频演示
ADXL362三轴加速度计的体感迷宫游戏设计实际游戏运行效果包括倾斜控制、碰撞、得分 四、ADXL362的SPI接口技术
4.1 SPI通信方式 ADXL362支持SPI和I2C两种通信协议。本项目采用SPI协议因其速度更快时序更稳 4.2 SPI数据传输和接收机制 在传输数据前通过设置GPIO引脚的电平来激活CS信号开始通信。 通过SPI的数据寄存器发送数据到SPI总线上。 发送数据的同时通过读取SPI的数据寄存器来接收数据。 4.3 加速度数据格式和解析 加速度数据以数字值的形式存储在特定的寄存器中每个轴的数据通常由两个连续的寄存器组成一个用于高字节一个用于低字节。代码中使用 xl.readXYZTData(...) 函数一次性读取X, Y, Z三轴的12位数字输出和温度值 XDATA_L包含8个最低有效位LSBs XDATA_H包含4个最高有效位MSBs 五、常见问题解答 (FAQ)
Q1: 为什么我的串口打印是乱码
A请排查 确保零知IDE的串口监视器的波特率设置为9600与代码中的 Serial.begin(9600) 一致。 Q2: 小球控制不灵敏或反向
A请根据以下提示操作 调整 updateBallPosition() 函数中的 map 函数的参数例如将 map(accelY, -200, 200, -5, 5) 改为 map(accelY, -200, 200, 5, -5) 可以反转Y轴方向。 增大 deadZone 值可以减少抖动增大 map 的输出范围如-8~8可以增加灵敏度。 Q3: 小球穿墙bug如何处理
A可能的原因 小球移动速度map输出的值设置过快单帧移动距离超过了墙壁的厚度。尝试减小 map 的输出范围如改为-2~2让小球每帧移动慢一些。 项目资源 零知IDE零知实验室官网下载 ADXL362加速度计库ADXL362-master ADXL362数据手册ADXL362 (Rev.G) 通过实践我们掌握了如何驱动SPI显示屏、读取和处理加速度传感器数据、设计高效的图形刷新算法以及实现复杂的游戏碰撞逻辑