34浏览
查看: 34|回复: 0

[入门] Firework!BOOM!(基于DFR1188简单的烟花生成)

[复制链接]
本帖最后由 uQ1GA4qGEMEQ 于 2025-5-23 22:54 编辑

——很幸运能够参与本次DFR1188(基于RP2350)开发板的测试
先从一些小东西上手吧!
一、环境配置
首先本帖项目是使用Arduino完成的,安装arduino的步骤就先不赘述了,重点说一下arduino的配置过程。

1.添加json
在文件→首选项→附加开发板管理器网址中,添加该链接
  1. https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
复制代码
Firework!BOOM!(基于DFR1188简单的烟花生成)图1
Firework!BOOM!(基于DFR1188简单的烟花生成)图2
2.下载开发板管理包
接着在开发板管理器(旧版的arduino在顶层的“工具”中)中搜索rp2350并下载(受限于网络问题,可以尝试使用镜像站或离线包安装)
Firework!BOOM!(基于DFR1188简单的烟花生成)图3
开发板选择“[backcolor=rgba(0, 92, 95, 0.1)]Generic RP2350”
Firework!BOOM!(基于DFR1188简单的烟花生成)图4
连接USB线即可开始使用了!
二、Firework!BOOM!
这是一个简单的烟花效果生成的简单程序,使用i2c连接oled屏幕播放
1.材料与接线
本项目仅使用到一个oled(128x64)屏幕和一个无源蜂鸣器(用于模仿烟花声音)
接线如下
Firework!BOOM!(基于DFR1188简单的烟花生成)图5
记得把蜂鸣器的+连接到支持pwm的引脚上,RP2350全GPIO皆支持pwm,所以我就随意了
注意!!!这里的oled和蜂鸣器都使用了开发板的板载供电,这是没问题的,但是如果有电机等大功率设备或各种感性、容性负载直接使用开发板供电极易引起开发板损坏!!!需要另接供电,与开发板共地即可。
2.程序设计
设计思路:
(1)生成一个烟花本体向上运动;
(2)记录本体的运动轨迹,在其后方添加拖尾特效;
(3)上升至屏幕中央后**
(4)**产生随机方向粒子效果,每个粒子的初始位置和速度方向使用随机数+极坐标初始化;
(5)为粒子添加重力加速度模仿重力效果;
(6)增加升空和**的音效
效果展示:
https://mc.dfrobot.com.cn/forum.php?mod=attachment&aid=MTk0OTUzfDg0NmFiODgyYWU2NDQ1OTA1OWQ0ZDZiODdkZGU0MmI4fDE3NDgxODY5ODY%3D&request=yes&_f=.mp4
废话不多说,先把代码端上来:
  1. #include <Adafruit_GFX.h>
  2. #include <Adafruit_SSD1306.h>
  3. #define SCREEN_WIDTH 128
  4. #define SCREEN_HEIGHT 64
  5. #define OLED_RESET     -1
  6. Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
  7. #define PARTICLE_COUNT 30
  8. #define BUZZER_PIN 1 //蜂鸣器引脚
  9. #define TRAIL_LENGTH 8  //烟花的拖尾长度
  10. int trailX[TRAIL_LENGTH];
  11. int trailY[TRAIL_LENGTH];
  12. struct Particle {
  13.   float x, y;
  14.   float vx, vy;
  15.   bool active;
  16. };
  17. Particle particles[PARTICLE_COUNT];
  18. bool exploded = false;
  19. unsigned long lastLaunch = 0;
  20. //升空音效
  21. void playLaunchSound() {
  22.   for (int freq = 400; freq <= 1000; freq += 20) {
  23.     tone(BUZZER_PIN, freq);
  24.     delay(5);
  25.   }
  26.   noTone(BUZZER_PIN);
  27. }
  28. //**音效
  29. void playExplosionSound() {
  30.   tone(BUZZER_PIN, 2000, 80); delay(90);
  31.   tone(BUZZER_PIN, 1200, 60); delay(70);
  32.   tone(BUZZER_PIN, 600, 50); delay(60);
  33.   noTone(BUZZER_PIN);
  34. }
  35. void launchFirework() {
  36.   exploded = false;
  37.   for (int i = 0; i < PARTICLE_COUNT; i++) {
  38.     particles[i].x = SCREEN_WIDTH / 2;
  39.     particles[i].y = SCREEN_HEIGHT;
  40.     particles[i].vx = 0;
  41.     particles[i].vy = -3.5;
  42.     particles[i].active = true;
  43.   }
  44.   //初始化拖尾
  45.   for (int i = 0; i < TRAIL_LENGTH; i++) {
  46.     trailX[i] = SCREEN_WIDTH / 2;
  47.     trailY[i] = SCREEN_HEIGHT;
  48.   }
  49.   playLaunchSound();
  50. }
  51. //随机数生成**效果(极坐标)
  52. void explodeFirework() {
  53.   exploded = true;
  54.   for (int i = 0; i < PARTICLE_COUNT; i++) {
  55.     float angle = (2 * PI / PARTICLE_COUNT) * i;
  56.     float speed = random(10, 25) / 10.0;
  57.     particles[i].vx = cos(angle) * speed;
  58.     particles[i].vy = sin(angle) * speed;
  59.   }
  60.   playExplosionSound();
  61. }
  62. void setup() {
  63.   Serial.begin(115200);
  64.   display.clearDisplay();
  65.   display.display();
  66.   launchFirework();
  67. }
  68. void updateParticles() {
  69.   for (int i = 0; i < PARTICLE_COUNT; i++) {
  70.     if (!particles[i].active) continue;
  71.     particles[i].x += particles[i].vx;
  72.     particles[i].y += particles[i].vy;
  73.     particles[i].vy += 0.1;
  74.     // 出界了就消失
  75.     if (particles[i].x < 0 || particles[i].x > SCREEN_WIDTH ||
  76.         particles[i].y < 0 || particles[i].y > SCREEN_HEIGHT) {
  77.       particles[i].active = false;
  78.     }
  79.   }
  80. }
  81. bool allParticlesInactive() {
  82.   for (int i = 0; i < PARTICLE_COUNT; i++) {
  83.     if (particles[i].active) return false;
  84.   }
  85.   return true;
  86. }
  87. void drawParticles() {
  88.   if (!exploded) {
  89.     //拖尾缓冲
  90.     for (int i = TRAIL_LENGTH - 1; i > 0; i--) {
  91.       trailX[i] = trailX[i - 1];
  92.       trailY[i] = trailY[i - 1];
  93.     }
  94.     trailX[0] = (int)particles[0].x;
  95.     trailY[0] = (int)particles[0].y;
  96.     //拖尾绘制
  97.     for (int i = 0; i < TRAIL_LENGTH; i++) {
  98.       display.drawPixel(trailX[i], trailY[i], SSD1306_WHITE);
  99.       if (i % 2 == 0 && i < TRAIL_LENGTH - 1) {
  100.         display.drawPixel(trailX[i] + 1, trailY[i], SSD1306_WHITE);
  101.       }
  102.     }
  103.     //画一个小球(烟花本体)
  104.     display.fillCircle((int)particles[0].x, (int)particles[0].y, 2, SSD1306_WHITE);
  105.   } else {
  106.     //**
  107.     for (int i = 0; i < PARTICLE_COUNT; i++) {
  108.       if (particles[i].active) {
  109.         display.drawPixel((int)particles[i].x, (int)particles[i].y, SSD1306_WHITE);
  110.       }
  111.     }
  112.   }
  113. }
  114. void loop() {
  115.   display.clearDisplay();
  116.   if (!exploded && particles[0].y < random(20, 40)) {
  117.     explodeFirework();
  118.   }
  119.   updateParticles();
  120.   drawParticles();
  121.   display.display();
  122.   delay(30);
  123.   if (allParticlesInactive() && millis() - lastLaunch > 1000) {
  124.     lastLaunch = millis();
  125.     launchFirework();
  126.   }
  127. }
复制代码

代码注解:
(1)两个音效函数使用pwm的频率变化控制无源蜂鸣器来模拟烟花升空和**的音效,所以不能有源蜂鸣器,不然就变成了pwm控制声音大小不能控制频率了
(2)launchFirework()对烟花效果进行初始化,explodeFirework()则是**粒子效果初始化,updateParticles()对粒子的位置信息进行实时更新。
总结:本项目涉及i2c外设配置、物理模拟与声音生成,使用比较低的硬件成本(只使用了rp2350开发板的3%flash和2%的ROM)完成了一次“赛博烟花”,给大家提供一个电子摆件的简单思路

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4 备案 沪公网安备31011502402448

© 2013-2025 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail