571|5

57

帖子

5

TA的资源

一粒金砂(高级)

楼主
 

【Follow me第二季第1期】基础任务1-3与进阶任务 [复制链接]

  本帖最后由 MioChan 于 2024-7-31 00:09 编辑

基础任务一(必做):控制板载炫彩LED,跑马灯点亮和颜色变换

 

这个用Adafruit_NeoPixel.h这个库就能实现,还加入了一些额外的功能,左边的按钮可以切换亮度,右边的按钮可以切换灯效,一共设置了五种灯效,分别是三种常亮,追逐,彩虹。除此之外,按下按钮蜂鸣器也会依次发出do, re, mi, fa, sol, la, si的音调,通过调节占空比我们还能控制蜂鸣器音量。

 

 

 

 

 

 

#include <Adafruit_NeoPixel.h>

#define PIN 8

// 定义按钮引脚
#define BUTTON_BRIGHTNESS 4 // 调节亮度
#define BUTTON_EFFECT 5     // 切换效果

// 定义音调
const int tones[] = {262, 294, 330, 349, 392, 440, 494}; // do, re, mi, fa, sol, la, si
int toneIndex = 0; // 当前音调
int volume = 30; // 音量

Adafruit_NeoPixel strip = Adafruit_NeoPixel(10, PIN, NEO_GRB + NEO_KHZ400);

int currentEffect = 0;
int brightness = 50;
int lastButtonBrightnessState = LOW;
int lastButtonEffectState = LOW;

void setup() {
  pinMode(BUTTON_BRIGHTNESS, INPUT); // 设置按钮
  pinMode(BUTTON_EFFECT, INPUT);
  pinMode(A0, OUTPUT); // 设置扬声器

  strip.begin();
  strip.setBrightness(brightness);
  strip.show(); 
  Serial.begin(9600);
}

void loop() {
  // 检查按钮状态
  checkButtons();

  // 执行当前效果
  switch (currentEffect) {
    case 0:
      colorWipe(strip.Color(255, 0, 0), 50); 
      break;
    case 1:
      colorWipe(strip.Color(0, 255, 0), 50); 
      break;
    case 2:
      colorWipe(strip.Color(0, 0, 255), 50);
      break;
    case 3:
      theaterChase(strip.Color(127, 127, 127), 50); 
      break;
    case 4:
      rainbowCycle(20); 
      break;
  }
}

bool checkButtons() {
  bool buttonPressed = false;
  
  // 检查D4按钮是否被按下以更改亮度
  int buttonBrightnessState = digitalRead(BUTTON_BRIGHTNESS);
  if (buttonBrightnessState == HIGH && lastButtonBrightnessState == LOW) {
    brightness = (brightness + 30) % 128; // 增加亮度
    strip.setBrightness(brightness);
    strip.show();
    playTone(); // 播放音调
    buttonPressed = true;
    delay(200); 
  }
  lastButtonBrightnessState = buttonBrightnessState;

  // 检查D5按钮是否被按下以更改效果
  int buttonEffectState = digitalRead(BUTTON_EFFECT);
  if (buttonEffectState == HIGH && lastButtonEffectState == LOW) {
    currentEffect = (currentEffect + 1) % 5; // 效果循环
    playTone(); // 播放音调
    buttonPressed = true;
    delay(200); 
  }
  lastButtonEffectState = buttonEffectState;

  return buttonPressed;
}

// 用一种颜色逐个填充像素点
void colorWipe(uint32_t c, uint8_t wait) {
  for (uint16_t i = 0; i < strip.numPixels(); i++) {
    strip.setPixelColor(i, c);
    strip.show();
    delay(wait);
    if (checkButtons()) return; // 如果按钮被按下,则中断循环
  }
}

// 使彩虹色均匀分布
void rainbowCycle(uint8_t wait) {
  uint16_t i, j;

  for (j = 0; j < 256 * 5; j++) { 
    for (i = 0; i < strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
    }
    strip.show();
    delay(wait);
    if (checkButtons()) return; // 如果按钮被按下,则中断循环
  }
}

// 剧院风格的爬行灯
void theaterChase(uint32_t c, uint8_t wait) {
  for (int j = 0; j < 10; j++) { 
    for (int q = 0; q < 3; q++) {
      for (uint16_t i = 0; i < strip.numPixels(); i = i + 3) {
        strip.setPixelColor(i + q, c); // 每三个像素点亮一个
      }
      strip.show();
      delay(wait);
      if (checkButtons()) return; // 如果按钮被按下,则中断循环

      for (uint16_t i = 0; i < strip.numPixels(); i = i + 3) {
        strip.setPixelColor(i + q, 0); 
      }
    }
  }
}


uint32_t Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if (WheelPos < 85) {
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if (WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}

// 播放音调
void playTone() {
  int frequency = tones[toneIndex];
  int period = 1000000L / frequency; 
  int pulse = (period * volume) / 256; 
  for (long i = 0; i < 200L * frequency / 1000L; i++) {
    digitalWrite(A0, HIGH);
    delayMicroseconds(pulse);
    digitalWrite(A0, LOW);
    delayMicroseconds(period - pulse);
  }
  toneIndex = (toneIndex + 1) % 7; // 循环切换音调
}

 


基础任务二(必做):监测环境温度和光线,通过板载LED展示舒适程度

这里直接用到了#include <Adafruit_CircuitPlayground.h>这个库,传感器已经封装好了,直接获取数值就行。这里对灯珠做了一个划分,左边五颗用来显示温度,亮三颗处于绿色表示在人体舒服的20-24度,红色表示过热,蓝色表示过冷(因为MCU多少会发热,这个温度传感器放的太靠近了导致测得不准,我对比了一下温度计会比我环境高个五度所以代码里简单粗暴减了5)。右边五颗白色灯珠对应当前环境亮度,板子上所有led也会跟着亮度进行变化(环境亮度比较低的时候,LED也会变暗)

 

目前环境灯光温度都很适宜

 

 

把台灯关了右边亮度就剩一格了

 

 

压了一个冰盒到开发版上,可以看见温度显示为蓝色

 

#include <Adafruit_CircuitPlayground.h>

int prevTempLedCount = -1; // 初始化
int prevBrightnessLedCount = -1; // 初始化

void setup() {
  CircuitPlayground.begin();
}

void loop() {
  displayTemperature();
  displayBrightness();
  delay(1000); // 每秒更新
}

void displayTemperature() {
  float temperature = CircuitPlayground.temperature() - 6;
  int ledCount = 3; // 20-24度时亮三颗
  uint32_t color = CircuitPlayground.colorWheel(85); // 绿色
  
  if (temperature < 20) {
    ledCount = max(0, 3 - (20 - temperature) / 5);
    color = CircuitPlayground.colorWheel(170); // 蓝色
  } else if (temperature > 24) {
    ledCount = min(5, 3 + (temperature - 24) / 5);
    color = CircuitPlayground.colorWheel(0); // 红色
  }
  
  // 如果LED数量没有变化,则不更新
  if (ledCount != prevTempLedCount) {
    for (int i = 0; i < 5; i++) {
      if (i < ledCount) {
        CircuitPlayground.setPixelColor(4 - i, color);
      } else {
        CircuitPlayground.setPixelColor(4 - i, 0); // 关闭LED
      }
    }
    prevTempLedCount = ledCount; // 更新上一次的LED数量
  }
}

void displayBrightness() {
  int brightness = CircuitPlayground.lightSensor();
  int ledCount = min(5, brightness / 50); // 亮度每增加50 LED增加一颗
  uint8_t overallBrightness = map(brightness, 0, 500, 0, 100); 
  
  // 如果LED数量没有变化,则不更新
  if (ledCount != prevBrightnessLedCount) {
    CircuitPlayground.setBrightness(overallBrightness); //调整所有灯珠亮度
    for (int i = 0; i < 5; i++) {
      if (i < ledCount) {
        CircuitPlayground.setPixelColor(5 + i, 255, 255, 255); // 白色
      } else {
        CircuitPlayground.setPixelColor(5 + i, 0); // 关闭LED
      }
    }
    prevBrightnessLedCount = ledCount; // 更新上一次的LED数量
  }
}

 

 


基础任务三(必做):接近检测——设定安全距离并通过板载LED展示,检测到入侵时,发起声音报警

前面已经用过光照传感器了,这里发现红外还没玩,所以这里我用红外传感器来做,通过IR LED发射38KHZ的IR脉冲,再读取接收器测得的模拟值,当模拟值增大即有物体靠近。没有物体接近时灯珠全灭或显示一个,随着物体接近灯珠会亮的越来越多,最后全亮蜂鸣器报警。

下面是文档中的IR介绍:

 

 

没有物体靠近时

 

 

用手靠近时,灯珠全亮以及蜂鸣器报警

 

#include <Adafruit_CircuitPlayground.h>


#define SAFE_DISTANCE 450 // 定义安全距离


const int alertTone = 1000; // 警报音调

const int irTransmitterPin = 25; //引脚定义
const int irReceiverPin = A10; 

void setup() {
  CircuitPlayground.begin();
  Serial.begin(9600); // 
  pinMode(irReceiverPin, INPUT); // 红外传感器输入
   pinMode(irTransmitterPin, OUTPUT);// 红外led输出

  
  delay(100); 
  
}


void loop() {
   sendIRPulse();
  int distance = analogRead(irReceiverPin); // 读取红外传感器的值
  displayDistance(distance);
  checkForIntrusion(distance);
  delay(300); 
}

void displayDistance(int distance) {
  int ledCount = map(distance, 290, SAFE_DISTANCE, 1, 10); // 将距离值映射到0-10的LED数量

 
  Serial.print("Distance: ");
  Serial.print(distance);
  Serial.print(", LED Count: ");
  Serial.println(ledCount);

  for (int i = 0; i < 10; i++) {
    if (i < ledCount) {
      CircuitPlayground.setPixelColor(i, 0, 255, 0); 
    } else {
      CircuitPlayground.setPixelColor(i, 0); 
    }
  }
 
}

void checkForIntrusion(int distance) {
  if (distance > SAFE_DISTANCE) {
    Serial.println("Intrusion detected!");
    playAlertTone();
  }
}
void sendIRPulse() {
  for (int i = 0; i < 32; i++) {
    digitalWrite(irTransmitterPin, HIGH);
    delayMicroseconds(13); 
    digitalWrite(irTransmitterPin, LOW);
    delayMicroseconds(13);
  }
}
void playAlertTone() {
  CircuitPlayground.playTone(alertTone, 500); // 播放警报音500ms
}

 


进阶任务(必做):制作不倒翁——展示不倒翁运动过程中的不同灯光效果

这个任务本质上就是用板载陀螺仪检测板子的姿态,然后给出对应的灯光效果。我实现的是根据板子的倾斜方向亮起对应的灯,当板子水平时所有灯全亮。唯一有点麻烦的是,要搞清楚不同x y z值对应的真实方向,为了方便处理我直接计算了x y两个方向对于x y水平面的夹角。

angleX = atan2(x, z) * 180 / PI; angleY = atan2(y, z) * 180 / PI;

 

水平时所有灯都亮,并为绿色(这里是对着桌面俯拍)

 

 

朝不同方向倾斜的效果,可以看见都能很好的识别,灯珠的颜色是根据灯珠编号定义的 CircuitPlayground.colorWheel(LED Number),这样刚好构成了一个色环

 

 

 

直接把板子垂直也能正确识别

 

拆了个家里的不倒翁,把开发版安在了底座上

 

下面是代码

#include <Adafruit_CircuitPlayground.h>
#include <math.h>

void setup() {
  CircuitPlayground.begin();
  Serial.begin(115200); 
}

void loop() {
  float x = CircuitPlayground.motionX();
  float y = CircuitPlayground.motionY();
  float z = CircuitPlayground.motionZ();

  // 计算与水平面夹角
  float angleX = atan2(x, z) * 180 / PI;
  float angleY = atan2(y, z) * 180 / PI;
 
  int ledToLight = -1;

//映射到彩色灯珠
  if(angleX>11){
    if(angleY<-11)  ledToLight = 1;
    if(angleY<11  && angleY>-11) ledToLight = 2;
     if(angleY>11)  ledToLight =3;
  }

 if(angleX>-11&& angleX<11){
 
     if(angleY>11)  
     {
     ledToLight =4;
      // CircuitPlayground.setPixelColor(5, CircuitPlayground.colorWheel(85)); 
     }

      if(angleY<-11)  
     {
       ledToLight = 0; // X: 0, Y: -9, Z: 0
   //   CircuitPlayground.setPixelColor(9, CircuitPlayground.colorWheel(85));  
     }
  }

 if(angleX<-11){
   if(angleY<-11)  ledToLight = 8;
    if(angleY<11  && angleY>-11) ledToLight = 7;
     if(angleY>11)  ledToLight =6;
 }



 uint8_t color= map( ledToLight, 0, 9, 0, 255);
 

  if (ledToLight == -1) {
    for (int i = 0; i < 10; i++) {
      CircuitPlayground.setPixelColor(i, CircuitPlayground.colorWheel(85)); //水平时都点亮
    }
  } else {
    for (int i = 0; i < 10; i++) {
      if (i == ledToLight || (ledToLight == 4 && i == 5) || (ledToLight == 0 && i == 9)) {
        CircuitPlayground.setPixelColor(i, CircuitPlayground.colorWheel(color));//点亮对应位置的
      } else {
        CircuitPlayground.setPixelColor(i, 0); 
      }
    }
  }

 

  Serial.print("X: ");
  Serial.print(x);
  Serial.print(" - Y: ");
  Serial.print(y);
  Serial.print(" - Z: ");
  Serial.print(z);
  Serial.print(" - angleX: ");
  Serial.print(angleX);
  Serial.print(" - angleY: ");
  Serial.print(angleY);
  Serial.print(" - LED To Light: ");
  Serial.println(ledToLight);

  delay(100); 
}

 

到这里基本任务就做完了,开始折腾创意任务啦,三个打算尽量都做做看,视频到时候会放到汇总贴里

最新回复

嗯嗯,我再搞搞看   详情 回复 发表于 2024-7-29 13:27
点赞 关注
 
 

回复
举报

281

帖子

7

TA的资源

一粒金砂(高级)

沙发
 
int distance = analogRead(A6); // 读取红外传感器的值

红外传感器应该是A10吧?

点评

是的,没仔细看文档还以为板子上RX就是对应IR接收器上面的RX,A6 A7是串口的,已经修改了,之前那个相当于是靠检测电容实现的接近检测😂  详情 回复 发表于 2024-7-29 08:45
 
 
 

回复

57

帖子

5

TA的资源

一粒金砂(高级)

板凳
 
sipower 发表于 2024-7-29 00:41 int distance = analogRead(A6); // 读取红外传感器的值 红外传感器应该是A10吧?

是的,没仔细看文档还以为板子上RX就是对应IR接收器上面的RX,A6 A7是串口的,已经修改了,之前那个相当于是靠检测电容实现的接近检测,感谢纠正😂

点评

你这个板A10检测效果如何,我这个板,A10用ADC采集的数不对,我用的是CircuitPython做的  详情 回复 发表于 2024-7-29 09:57
 
 
 

回复

281

帖子

7

TA的资源

一粒金砂(高级)

4
 
MioChan 发表于 2024-7-29 08:45 是的,没仔细看文档还以为板子上RX就是对应IR接收器上面的RX,A6 A7是串口的,已经修改了,之前那个相 ...

你这个板A10检测效果如何,我这个板,A10用ADC采集的数不对,我用的是CircuitPython做的

点评

挺灵敏的,没有东西阻挡时读出来285,有物体阻挡的话最大能到670左右,他这个IR接收器只能接受脉冲信号,官方文档里有说是38KHZ,arduino可以这么实现 void sendIRPulse() {   for (int i = 0; i < 3  详情 回复 发表于 2024-7-29 11:23
 
 
 

回复

57

帖子

5

TA的资源

一粒金砂(高级)

5
 
sipower 发表于 2024-7-29 09:57 你这个板A10检测效果如何,我这个板,A10用ADC采集的数不对,我用的是CircuitPython做的

挺灵敏的,没有东西阻挡时读出来285,有物体阻挡的话最大能到670左右,他这个IR接收器只能接受脉冲信号,官方文档里有说是38KHZ,arduino可以这么实现

void sendIRPulse() {

  for (int i = 0; i < 32; i++) { 

    digitalWrite(irTransmitterPin, HIGH);

    delayMicroseconds(13); 

    digitalWrite(irTransmitterPin, LOW);

    delayMicroseconds(13); 

  }

 

点评

嗯嗯,我再搞搞看  详情 回复 发表于 2024-7-29 13:27
 
 
 

回复

281

帖子

7

TA的资源

一粒金砂(高级)

6
 
MioChan 发表于 2024-7-29 11:23 挺灵敏的,没有东西阻挡时读出来285,有物体阻挡的话最大能到670左右,他这个IR接收器只能接受脉冲信号, ...

嗯嗯,我再搞搞看

 
 
 

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

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
推荐帖子
dsp论文系列

现在越来越火爆的,比起单片机来,功能是强大不少,看看现在都研究些什么?不过主要是关注电机控制这一块,其他的了解不是很多, ...

快快乐乐跟我学开关电源设计

转自ourdev,非常好的学习指导,推荐给大家。 “我想DIY开关电源,要具备哪些理论知识、实践技能和工程素质啊?&rdquo ...

自制廉价的GPS外接天线

有网友试过,效果确实不错:宿舍窗台上(11楼)不到20秒,显示了时间,再过几秒,就显示了经纬度,没调,就收到4颗心!! 材 ...

一张图让你明白共模电压 (VCM) 与输出电压 (VOUT)的关系

工程师们几十年来一直在努力理解神秘的共模电压 (VCM) 与输出电压 (VOUT) 比较图。尽管 VCM 与 VOUT 形状经常会因器件及设置配置 ...

CAN IAP实例

此内容由EEWORLD论坛网友雪山飞狐11原创,如需转载或用于商业用途需征得作者同意并注明出处 CAN IAP botloader,在我 ...

C6000系列DSP的GPIO框图

首先看一下GPIO的框图: 474214 通过查看GPIO框图,我们可以得出许多信息: DIR寄存器控制GPIO管脚是输入还是输出,其 ...

[EETALk]作为一名蓝牙工程师,需要掌握哪些知识?

作为一个蓝牙工程师,一般的工作职能是什么呢??? 又需要掌握哪些知识呢??? 坛子里有蓝牙工程师吗? 又或者从事蓝 ...

【STM32U599J-DK】添加自定义驱动文件夹

本帖最后由 lugl4313820 于 2023-12-11 09:45 编辑 【前言】 在touchgfx4.22在生成的工程中,用stm32CubeIde编译下载到开 ...

雷达信号处理和数据处理技术

本书可以帮助雷达工程技术人员和雷达使用人员掌握有关雷达信号处理和数据处理技术,解决有关应用问题;同时还可以作为高等学校电 ...

百问MQTT协议分析 - 报文分析①

## 16.3 报文分析 ### 16.3.1 CONNECT-连接服务端 ​ 客户端到服务端的网络连接建立(完成三次握手)后,客户端发 ...

关闭
站长推荐上一条 1/9 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表