一、硬件介绍
1、产品特点
Beetle RP2350【RP2350A_QFN60】是一款基于RP2350微控制器的高性能迷你开发板,双核双架构设计(Arm Cortex-M33或Hazard3 RISC-V内核);
采用Raspberry Pi RP2350高性能微控制器,支持Arm Cortex-M33或Hazard3 RISC-V内核选择;
主频高达150MHz,配备520KB RAM和2MB Flash,可高效处理大量数据,满足高性能计算需求;

2、功能引脚示意图 / 原理图
板载LED灯
IO25引脚控制
用户按键
使用QSPI_SS引脚控制该按钮

主要原理图


3、外部硬件
1、摇杆模块
该模块为一个双向的10K电阻器,随着摇杆方向变化,阻值也会随着变化,从而改变输出的值;
本模块可用 5V / 3.3V 供电,初始状态下X,Y读出电压为供电电压的1/2左右( 1.65V / 2.5V );
当随着X、Y方向移动,读出电压值减小(0V) / 增大(VCC); 其中X、Y方向输出的数据为模拟量,而Z轴输出的为数字量 (0 / 1);

模块引脚介绍:

2、8*8 LED模块【WS2812B】
WS2812B是一个集控制电路与发光电路于一体的智能外控LED光源其外型与一个5050LED灯珠相同, 每个元件即为一个像素点。
像素点内部包含了智能数字接口数据锁存信号整形放大驱动电路, 还包含有高精度的内部振荡器和可编程定电流控制部分, 有效保证了像素点光的颜色高度一致。
数据协议采用单线归零码的通讯方式, 像素点在上电复位以后, DIN端接受从控制器传输过来的数据。
首先送过来的24bit数据被第一个像素点提取后, 送到像素点内部的数据锁存器, 剩余的数据经过内部整形处理电路整形放大后通过DO端口开始转发输出给下一个级联的像素点, 每经过一个像素点的传输, 信号减少24bit。


主要特点:
● IC控制电路与LED点光源共用一个电源。
● 控制电路与RGB芯片集成在一个5050封装的元器件中, 构成一个完整的外控像素点。
● 内置信号整形电路, 任何一个像素点收到信号后经过波形整形再输出, 保证线路波形畸变不会累加。
● 内置上电复位和掉电复位电路。
● 每个像素点的三基色颜色可实现256级亮度显示, 完成16777216种颜色的全真色彩显示。
● 端口扫描频率2KHz/s。
● 串行级联接口, 能通过一根信号线完成数据的接收与解码。
● 任意两点传输距离在不超过5米时无需增加任何电路。
● 当刷新速率30帧/秒时, 级联数不小于1024点。
● 数据发送速度可达800Kbps。
3、喇叭模块【GSPK2307P-8R1W】



二、硬件连接
模块与开发板引脚之间的连接方式如下:

实物效果搭建如下:


三、功能实现
【摇杆控制LED贪吃蛇游戏】
实现效果:通过摇杆模块控制8*8 LED模块实现贪吃蛇游戏;
通过控制摇杆上、下、左、右分别控制LED移动方向;
按下中间按钮时,实现LED清屏复位(既游戏重启);
游玩过程中,游戏运行速度会随着蛇身长度逐渐加速; 当蛇碰到墙壁或自身时,喇叭模块发生声音,提示游戏结束(此时需按下按钮,重新开启);
开发板通过ADC功能获取摇杆模块数据;
通过PWM功能控制喇叭模块、LED模块;
四、相关代码
主要相关代码
#include <FastLED.h>
#define Sound_Pin D18
#define VRx A0
#define VRy A1
#define SW D19
#define X_POS 498
#define Y_POS 505
#define LED_PIN D8
#define LED_COLS 8 // 列
#define LED_ROWS 8 // 行
#define NUM_LEDS (LED_COLS * LED_ROWS) // 8*8
#define LED_TYPE WS2812B
#define COLOR_ORDER GRB
#define UP 0
#define DOWN 1
#define LEFT 2
#define RIGHT 3
CRGB HeadColor(255,0,0); //蛇头颜色
CRGB BodyColor(0,0,255); //蛇身颜色
CRGB FoodColor(0,255,0); //食物颜色
CRGB leds[NUM_LEDS];
unsigned long lastUpdate = 0;
int gameSpeed = 500; // 游戏运行初始速度 ms
static byte lastDir = UP; //默认方向向上
bool buttonPressed = false;
unsigned long lastTime = 0;
const int Delay = 50;
bool collisionsState = false;
// 蛇结构体
struct {
int x, y; // 蛇头坐标
int tail[65][2]; // 蛇身坐标数组 (x,y)
int length = 3; // 初始长度
int dir = 0; // 运动方向(0上,1下,2左,3右)
} snake;
// 食物结构体
struct {
int x, y;
bool eaten = true; //食物状态
} food;
//移动蛇身体
void moveSnake() {
for(int i=snake.length-1; i>0; i--){
snake.tail[i][0] = snake.tail[i-1][0]; //x
snake.tail[i][1] = snake.tail[i-1][1]; //y
}
//更新蛇头位置
snake.tail[0][0] = snake.x;
snake.tail[0][1] = snake.y;
// 移动蛇头
switch(snake.dir){
case UP: snake.y++; break; // 上
case DOWN: snake.y--; break; // 下
case LEFT: snake.x++; break; // 左
case RIGHT: snake.x--; break; // 右
}
}
//生成食物
void spawnFood() {
if(food.eaten){
bool valid = false;
while(!valid){
//生成食物位置
valid = true;
food.x = random(LED_COLS);
food.y = random(LED_ROWS);
// 检查是否与蛇重叠
if(food.x == snake.x && food.y == snake.y) valid = false;
for(int i=0; i<snake.length; i++){
if(food.x == snake.tail[i][0] && food.y == snake.tail[i][1]){
valid = false;
break;
}
}
}
food.eaten = false;
}
}
//蛇碰撞检测
void checkCollisions() {
// 吃食物检测
if(snake.x == food.x && snake.y == food.y){
snake.length++;
food.eaten = true;
gameSpeed = max(100, gameSpeed-50); // 游戏加速
spawnFood();
}
// 撞墙检测
if(snake.x<0 || snake.x>=LED_COLS || snake.y<0 || snake.y>=LED_ROWS){
playSound();
collisionsState = true;
}
// 撞自身检测
for(int i=0; i<snake.length; i++){
if(snake.x == snake.tail[i][0] && snake.y == snake.tail[i][1]){
playSound();
}
}
}
//刷新显示
void updateDisplay() {
if(!collisionsState){ //发生碰撞 暂停显示
FastLED.clear();
// 绘制食物
leds[food.y * LED_COLS + food.x] = FoodColor;
// 绘制蛇头
leds[snake.y * LED_COLS + snake.x] = HeadColor;
// 绘制蛇身
for(int i=0; i<snake.length; i++){
int index = snake.tail[i][1] * LED_COLS + snake.tail[i][0];
leds[index] = BodyColor;
}
FastLED.show();
}
}
//重新开始
void resetGame(){
collisionsState = false;
gameSpeed = 500;
snake.x = LED_COLS/2;
snake.y = LED_ROWS/2;
snake.length = 3;
updateDisplay();
}
//摇杆按下
void buttonSet() {
int buttonState = digitalRead(SW);
if (buttonState == LOW && !buttonPressed && (millis() - lastTime) > Delay) {
buttonPressed = true;
lastTime = millis();
resetGame();
}else if (buttonState == HIGH && buttonPressed) {
buttonPressed = false;
lastTime = millis();
}
}
//摇杆XY数据读取
void controllerRead() {
byte newDir = lastDir;
int xVal = analogRead(VRx) - X_POS;
int yVal = analogRead(VRy) - Y_POS;
//方向保持上一次
if(abs(xVal)< 400 && abs(yVal)<400)
{
xVal = 0;
yVal = 0;
snake.dir = lastDir;
}else{
// 计算角度方向
float angle = atan2(yVal, xVal) * 180/PI;
if (angle >= -45 && angle < 45) {
newDir = LEFT; // 左
} else if (angle >= 45 && angle < 135) {
newDir = UP; // 上
} else if (angle >= 135 || angle < -135) {
newDir = RIGHT; // 右
} else if (angle >= -135 && angle < -45) {
newDir = DOWN; // 下
}
}
// 防止直接反向180°移动
if (!(snake.dir == RIGHT && newDir == LEFT) &&
!(snake.dir == LEFT && newDir == RIGHT) &&
!(snake.dir == UP && newDir == DOWN) &&
!(snake.dir == DOWN && newDir == UP)) {
snake.dir = newDir; //更新方向
lastDir = newDir;
}
}
//喇叭播放声音
void playSound(){
tone(Sound_Pin, 3000, 1000); //3Khz 1s
}
void setup() {
//串口初始化
Serial.begin(115200);
while (!Serial);
//摇杆初始化
pinMode(VRx, INPUT);
pinMode(VRy, INPUT);
pinMode(SW, INPUT_PULLUP);
// 初始化snake LED
FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS);
FastLED.setBrightness(15);
snake.x = LED_COLS/2;
snake.y = LED_ROWS/2;
for(int i=0; i<snake.length; i++){
snake.tail[i][0] = snake.x - i;
snake.tail[i][1] = snake.y;
}
randomSeed(millis()); // 食物随机数种子
}
void loop() {
//控制游戏速度
if(millis() - lastUpdate > gameSpeed){
lastUpdate = millis();
//摇杆数据读取
controllerRead();
//摇杆按下
buttonSet();
//移动蛇位置
moveSnake();
//检测碰撞
checkCollisions();
//更新显示
updateDisplay();
}
}五、实现效果
通过控制摇杆上、下、左、右分别控制LED移动方向;按下按钮时,实现LED清屏复位(既游戏重启);
游玩过程中,游戏运行速度会随着蛇身长度逐渐加速;
当蛇碰到墙壁或自身时,喇叭模块发生声音,提示游戏结束(此时需按下按钮,重新开启);


我要赚赏金
