272|0

5

帖子

2

TA的资源

一粒金砂(中级)

楼主
 

【Follow me第二季第1期】任务提交贴 [复制链接]

  本帖最后由 Alohaq 于 2024-11-4 13:04 编辑
一、前言
Follow me第二季第1期的用的主板为Adafruit Circuit Playground Express,其为一块一体化设计板,具有处理器、传感器、LED、USB等,非常适合用于电子产品和编程,能够让创意充分发挥。这期共有四个任务,分别为入门任务,基础任务,进阶任务和创意任务,创意任务选择了其中之一——《章鱼哥》,所有任务均已完成,视频链接为:https://training.eeworld.com.cn/video/40998
本人这期任务所用器件如下:
  1. Adafruit Circuit Playground Express,为本期任务主板,任务必购硬件;  
  2. Round Display for Xiao(Seeed Studio),在我看来,没有显示的主板是不完整的,加上本期任务主板为圆形主板,遂配备圆形显示器,其驱动芯片为GC9A01,任务选购硬件;  
  3. 自制转接板,用于将任务主板与圆形显示器组合,自制PCB打印;    
  4. SG90S,180°舵机,为创意任务《章鱼哥》配备,并配备机械手模拟触角,个人自备;  
  5. 鲸鱼不倒翁一只,为进阶任务配备,个人自备;  
  6. 机械手一个,模拟章鱼哥的触角,为创意任务《章鱼哥》配备,个人自备。
本人这期任务所用环境为:VScode+PlatformIO,软件开发框架为Arduino,主要依赖的驱动库为Adafruit Circuit Playground、GFX Library for Arduino,其中Adafruit Circuit Playground为官方Arduino驱动库,可以控制Adafruit Circuit Playground Express上的所有外设;GFX Library for Arduino是一个 Arduino 图形库,支持具有各种数据总线接口的各种显示器,本次用于驱动Round Display for Xiao显示板。
二、任务实现详情
2.1 入门任务
任务介绍:开发环境搭建,板载LED点亮(个人增加显示屏点亮)。
涉及器件:Adafruit Circuit Playground Express;Round Display for Xiao(Seeed Studio)。
涉及库:Adafruit Circuit Playground、GFX Library for Arduino。
具体内容:
开发环境采用VSCode+PlatformIO,其中PlatformIO为VSCode的插件,VSCode的安装不再赘述,安装完成后在扩展中搜索PaltformIO进行安装,随后新建项目,以本项目为例:Board选择Adafruit Circuit Playground Express,Framework选择Arduino,Name我命名为01_Primer_Led,可以个人选择保存路径,详情可见图2-1,随后创建即可,开发环境初步搭建完成。
图2-1 首次创建项目
接着我们再添加官方为准备的驱动库Adafruit Circuit Playground,在VSCode的标签页中选择PIO Home,然后点击侧边工具栏中的Libraries,搜索Adafruit Circuit Playground,找到后选择打开,并在进入后选择添加至工程,详情如图2-2所示。
图2-2 添加官方驱动库
添加完官方驱动库后,在源文件中包含头文件<Adafruit_CircuitPlayground.h>即可,随后进行编译,此时会发现编译不通过,如图2-3所示,有errors产出:#error TinyUsB is not selected, please select it in "Tools->Menu->USB Stack“,同时也能看出是源文件Adafruit_TinyUSB_API.cpp的29行报出。
图2-3 errors
追根溯源,打开Adafruit_TinyUSB_API.cpp,找到29行,如图2-4所示,可发现是在没有USE_TINYUSB宏定义的情况下,又宏定义了ARDUINO_ARCH_SAMD(Board选择Adafruit Circuit Playground Express时会定义该宏定义)的时候,会报出上述错误。我们可以在预编译中增加USE_TINYUSB来解决报错,也可以选择忽略Tiny USB的驱动库,两者均可在platformio.ini中实现,分别为build_flags = -D USE TINYUSB和lib_ignore = Adafruit TinyUSB Library,具体如图2-4所示,具体使用哪一个,取决于您是否需要TinyUSB,二者选其一即可,可用‘;‘进行注释。随后便可正常编译烧录。
图2-4 platformio.ini添加内容
由于该任务本人还需驱动圆形显示器,需要额外添加库,我选择的驱动库为GFX Library for Arduino,操作步骤同库Adafruit Circuit Playground,详情如图2-2所示。
图2-3 添加显示驱动库
驱动库添加完成后,在需要使用的源文件中加上头文件<Arduino_GFX_Library.h>,然后选择合适的驱动函数即可,具体见代码:
#include <Adafruit_CircuitPlayground.h>
#include <Arduino_GFX_Library.h>

// #define GFX_BL DF_GFX_BL // default backlight pin, you may replace DF_GFX_BL to actual backlight pin

Arduino_DataBus *bus = new Arduino_SWSPI(3 /* DC */, 2 /*CS*/, 10 /* SCK*/, 9 /* MOSI*/, 6 /*MISO*/); //CS A5(2) SCK A3(10) MOSI A2(9) MISO A1(6) DC A4(3)
Arduino_GFX *gfx  = new Arduino_GC9A01(bus, DF_GFX_RST, 0 /* rotation */, true /* IPS */);

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin 13 as an output.
  pinMode(LED_BUILTIN, OUTPUT);

  gfx -> begin();
  gfx->fillScreen(BLACK);
  gfx->setTextSize(3);
  gfx->setTextColor(RED);
  gfx->setCursor(15, 90);
  gfx->println("Hello World!");
  gfx->println("Follow me 2-1");
  delay(1000); // 5 seconds
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);              // wait for a second
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);              // wait for a second
}

 

效果图:
图2-4 LED闪烁
图2-5 显示屏显示内容
2.2 基础任务一
任务介绍:控制板载炫彩LED,跑马灯点亮和颜色变换。
涉及库:Adafruit Circuit Playground。
具体内容:代码先是跑马灯,RGB逐一点亮,这个很好实现,for函数即可;随后是颜色变化,这里用上SIN函数加上时间,对r、g、b分别加上相位差赋值,进而实现炫彩呼吸渐变,详情见代码,代码如下:
#include <Adafruit_CircuitPlayground.h>

#include <math.h>

// do NOT include the standard NeoPixel library

void setup() {
  // initialize the Circuit Playground as usual
  // this will initialize the onboard NeoPixels as well
  CircuitPlayground.begin();

  delay(100);

  // 跑马灯
  for (uint8_t i=0; i<10; i++) {
    CircuitPlayground.setPixelColor(i, 255, 255, 255);
    delay(200);
  }
}

void loop() {
  static int time = 0;  // 用于控制颜色渐变的时间变量
  CircuitPlayground.clearPixels();
  // 呼吸灯
  for(int i=0; i<10; i++) {
    float angle = (float)(i + time) / 5.0 * M_PI;
    
    // 使用 sin 函数计算 RGB 颜色值
    uint8_t r = (uint8_t)((sin(angle) + 1) * 127.5);
    uint8_t g = (uint8_t)((sin(angle + 2.0 * M_PI / 3.0) + 1) * 127.5);
    uint8_t b = (uint8_t)((sin(angle + 4.0 * M_PI / 3.0) + 1) * 127.5);
    
    CircuitPlayground.setPixelColor(i, r, g, b); // 设置第 i 个 LED 的颜色
  }
  
  delay(50);     // 延迟,用于控制动画的速度
  time++;        // 递增时间变量,以生成渐变效果
}

 

效果图:
图2-6 炫彩RGB
2.3 基础任务二
任务介绍:监测环境温度和光线,通过板载LED展示舒适程度。
涉及库:Adafruit Circuit Playground。
具体内容:主要利用光传感器,毕竟温度的升降较难控制且周期很长,简易利用读数,对应上0~1,该部分用于红光显示,1剩下部分分给蓝光,进而展示舒适度,这里红光表示环境很不舒适,反之越蓝越舒适。详情见代码,代码如下:
#include <Adafruit_CircuitPlayground.h>

void setup() {
  CircuitPlayground.begin();

  // Serial.begin(9600);

  // while (!Serial); // Wait until serial console is opened

  // Serial.println("Ready to detection environment");
}

float temp_range = 42-30;
float r, b = 0;
void loop() {
  // Serial.print("Light sensor: ");
  // Serial.println(CircuitPlayground.lightSensor());
  // Serial.print("Temperature: ");
  // Serial.println(CircuitPlayground.temperature());
  r = (CircuitPlayground.temperature() - 30) / temp_range;
  // Serial.println(r);
  r += (300 - CircuitPlayground.lightSensor() ) / 300.0;
  // Serial.println(r);
  if (r > 1) r = 1;
  b = 1 - r;
  CircuitPlayground.clearPixels();
  for (int i = 0; i < 10; i++) {
    CircuitPlayground.setPixelColor(i, 255*r, 0, 255*b);
  }

  delay(500);
}

 

效果图:
图2-7 黑暗环境下,红灯表明不舒适
2.4 基础任务三
任务介绍:接近检测——设定安全距离并通过板载LED展示,检测到入侵时,发起声音报警。
涉及器件:Adafruit Circuit Playground Express;Round Display for Xiao(Seeed Studio)。
涉及库:Adafruit Circuit Playground、GFX Library for Arduino。
具体内容:
图2-8 RX对应引脚
利用红外的TX发出38KHz的信号,模拟超声波测距,然后直接读取RX处的ADC值,码值越大,说明接收的信号越强,即物体越接近,注意不能通过RX接收处的解码芯片,否则无法完成,遂涉及引脚的寄存器操作,对应工程图如图2-8所示,同时距离会在显示屏上显示,越近数字越小,当数字为1时,发出“danger”声报警,同时rgb颜色随距离越近,由绿变红,详情见代码,代码如下:
#include <Adafruit_CircuitPlayground.h>
#include <Arduino_GFX_Library.h>

// #define GFX_BL DF_GFX_BL // default backlight pin, you may replace DF_GFX_BL to actual backlight pin

Arduino_DataBus *bus = new Arduino_SWSPI(3 /* DC */, 2 /*CS*/, 10 /* SCK*/, 9 /* MOSI*/, 6 /*MISO*/); //CS A5(2) SCK A3(10) MOSI A2(9) MISO A1(6) DC A4(3)
Arduino_GFX *gfx  = new Arduino_GC9A01(bus, DF_GFX_RST, 0 /* rotation */, true /* IPS */);

void setup() {
  CircuitPlayground.begin();
  // PA4做ADC输入
  PORT->Group[PORTA].DIRCLR.reg = (1 << 4); // Set pin A4 as input
  PORT->Group[PORTA].PINCFG[4].bit.PMUXEN = 1; // Enable peripheral multiplexer on pin A4
  PORT->Group[PORTA].PMUX[4 >> 1].reg |= PORT_PMUX_PMUXE_B; // Set pin A4 to peripheral function B (ADC)

// 配置 ADC
  ADC->CTRLA.bit.ENABLE = 0;  // 先禁用 ADC 以进行配置
  ADC->INPUTCTRL.bit.MUXPOS = ADC_INPUTCTRL_MUXPOS_PIN4;  // 选择 PA4 作为 ADC 输入通道
  ADC->CTRLB.reg = ADC_CTRLB_PRESCALER_DIV64 | ADC_CTRLB_RESSEL_12BIT;  // 设置预分频器和分辨率
  ADC->SAMPCTRL.reg = 0x3F;  // 设置采样时间
  ADC->CTRLA.bit.ENABLE = 1;  // 启用 ADC

  // PORT->Group[PORTA].DIRSET.reg = (1 << 17);  // 将 PA17 配置为输出
  // PORT->Group[PORTA].OUTSET.reg = (1 << 17);  // 将 PA17 设置为高电平

  pinMode(CPLAY_IR_EMITTER, OUTPUT);
  pinMode(CPLAY_BUZZER, OUTPUT);
  // pinMode(CPLAY_SPEAKER_SHUTDOWN, OUTPUT);
  // digitalWrite(CPLAY_SPEAKER_SHUTDOWN, HIGH);


  gfx -> begin();
  gfx->fillScreen(BLACK);
  gfx->setTextSize(4);
  gfx->setTextColor(RED);
  

  // Serial.begin(9600);

  // while (!Serial); // Wait until serial console is opened

  // Serial.println("Ready to receive IR signals");
}
const uint8_t spDANGER[]        PROGMEM = {0x2D,0xBF,0x21,0x92,0x59,0xB4,0x9F,0xA2,0x87,0x10,0x8E,0xDC,0x72,0xAB,0x5B,0x9D,0x62,0xA6,0x42,0x9E,0x9C,0xB8,0xB3,0x95,0x0D,0xAF,0x14,0x15,0xA5,0x47,0xDE,0x1D,0x7A,0x78,0x3A,0x49,0x65,0x55,0xD0,0x5E,0xAE,0x3A,0xB5,0x53,0x93,0x88,0x65,0xE2,0x00,0xEC,0x9A,0xEA,0x80,0x65,0x82,0xC7,0xD8,0x63,0x0A,0x9A,0x65,0x5D,0x53,0xC9,0x49,0x5C,0xE1,0x7D,0x2F,0x73,0x2F,0x47,0x59,0xC2,0xDE,0x9A,0x27,0x5F,0xF1,0x8B,0xDF,0xFF,0x03};
void loop() {
  // CircuitPlayground.irSend.send(7, 0x5555, 16);
  // delay(1);
  
  for (int i = 0; i < 200; i++) {  // 38kHz PWM信号
    digitalWrite(CPLAY_IR_EMITTER, HIGH);
    delayMicroseconds(13);
    digitalWrite(CPLAY_IR_EMITTER, LOW);
    delayMicroseconds(13);
  }
  // digitalWrite(CPLAY_BUZZER, LOW);
  
  //Continue looping until you get a complete signal received
  // 开始转换
  ADC->SWTRIG.bit.START = 1;  // 启动 ADC 转换

  // 等待转换完成
  while (ADC->INTFLAG.bit.RESRDY == 0);
  // digitalWrite(CPLAY_IR_EMITTER, LOW);
  // 读取结果
  uint16_t result = ADC->RESULT.reg;
  uint8_t dis = (result - 2300) / 60;
  // if (result > 1500)
  // Serial.println(result);
  gfx->setCursor(110, 110);
  gfx->fillScreen(BLACK);
  gfx->println(7-dis);
  if (dis >= 6) {
    CircuitPlayground.speaker.say(spDANGER);
    CircuitPlayground.speaker.end();
  }
  for (int i = 0; i < 10; i++) {
    CircuitPlayground.setPixelColor(i, 255 * dis / 7.0, 255 * (7 - dis) / 7.0, 0);
  }

  delay(300);
  // delay(100);
}

 

效果图:
 
图2-9 物体距离过近,红光警示
2.5进阶任务
任务介绍:制作不倒翁——展示不倒翁运动过程中的不同灯光效果。
涉及库:Adafruit Circuit Playground。
具体内容:首先利用LIS3DH得到X、Y、Z,其中LIS3DH设置加速度为±2g,采样为50Hz,故需对其处理(乘上4),处理完后,进而算出横滚角和俯仰角,计算如下:
pitch = (short)(atan2((float)(0-Y), Z) * 180 / 3.14159);
roll = (short)(atan2((float)(X), Z) * 180 / 3.14159);
 
再通过俯仰角和横滚角计算出对应方位及深度,利用方向角索引至对应RGB,再利用深度,决定点亮几个RGB,达到RGB随不倒翁运动而变化的效果。详情见代码,代码如下:
#include <Adafruit_CircuitPlayground.h>

void setup() {
  CircuitPlayground.begin();
  CircuitPlayground.lis.setDataRate(LIS3DH_DATARATE_50_HZ);
  CircuitPlayground.lis.setRange(LIS3DH_RANGE_2_G);

  // Serial.begin(9600);
  // while (!Serial); // Wait until serial console is opened
  // Serial.println("Ready to read LIS3DH");
}

float X, Y, Z;
short pitch ,roll;
void loop() {
  CircuitPlayground.lis.read();
  X = (float)CircuitPlayground.lis.x*4/65536*1000; // 还可以试试看motionX
  Y = (float)CircuitPlayground.lis.y*4/65536*1000;
  Z = (float)CircuitPlayground.lis.z*4/65536*1000;

  pitch  = (short)(atan2((float)(0-Y), Z) * 180 / 3.14159);     //转换为度数
  roll  = (short)(atan2((float)(X), Z) * 180 / 3.14159);        //转换为度数

float direction = atan2(roll, pitch);  // 计算方向角
int ledIndex;
// Serial.println(direction); // direction范围是[-PI, PI]
if (direction >= 0) {
    ledIndex = round((direction / PI) * 6);  // 映射到LED索引
}
else {
    ledIndex = 11 + round((direction / PI) * 6);  // 映射到LED索引
}
// int ledIndex = round((direction / PI) * 6) % 12;  // 映射到LED索引
// Serial.println(ledIndex);

float tiltMagnitude = sqrt(pitch * pitch + roll * roll);  // 计算倾斜幅度
int ledCount = round((tiltMagnitude / 90.0) * 6) * 2;  // 映射点亮数量
static int time = 0;  // 用于控制颜色渐变的时间变量
CircuitPlayground.clearPixels();
// float angle = (float)(time) / 10 * 2.0 * M_PI;
float angle = (float)(time) / 5.0 * M_PI;
// 使用 sin 函数计算 RGB 颜色值
uint8_t r = (uint8_t)((sin(angle) + 1) * 127.5);
uint8_t g = (uint8_t)((sin(angle + 2.0 * M_PI / 3.0) + 1) * 127.5);
uint8_t b = (uint8_t)((sin(angle + 4.0 * M_PI / 3.0) + 1) * 127.5);
for (int i = -ledCount/2; i < ledCount/2; i++) {
    int indexToLight = ledIndex + i;
    // CircuitPlayground.setPixelColor(indexToLight, 0, 64, 64);
    CircuitPlayground.setPixelColor(indexToLight, r, g, b);
}
// Serial.println(ledIndex);
time++;        // 递增时间变量,以生成渐变效果
delay(100);
}

 

效果图:
图2-10 不倒翁倾斜,rgb随倾斜方向亮灯
2.6 创意任务
任务介绍:章鱼哥——章鱼哥的触角根据环境声音的大小,章鱼哥的触角可舒展或者收缩。
涉及库:Adafruit Circuit Playground。
具体内容:章鱼哥听到环境噪音(利用板载的麦克风噪音检测实现),认为敌人来临,遂伸张触角游泳离开,即环境音变大则伸张触角,环境正常则收缩触角。代码如下:
#include <Adafruit_CircuitPlayground.h>
#include <Servo.h>

Servo myservo;  // create Servo object to control a servo

void setup() {
  CircuitPlayground.begin();
  myservo.attach(A5);  // attaches the servo on pin 9 to the Servo object
  // Serial.begin(9600);
  // myservo.writeMicroseconds(1450);  // 舵机顺时针旋转 
}

void loop() {
  // for (int pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
  //   // in steps of 1 degree
  //   myservo.write(pos);              // tell servo to go to position in variable 'pos'
  //   delay(15);                       // waits 15ms for the servo to reach the position
  // }
  // CircuitPlayground.soundSensor();
  // Serial.println(CircuitPlayground.soundSensor());
  // Serial.println( CircuitPlayground.mic.soundPressureLevel(500) );
    // myservo.writeMicroseconds(1300);  // 舵机顺时针旋转 收缩
    // delay(1000);
    // myservo.writeMicroseconds(1600);// 舵机逆时针旋转 伸张
    // myservo.writeMicroseconds(2000);// 舵机逆时针旋转 
    // delay(2000);
  if ( CircuitPlayground.mic.soundPressureLevel(300) > 75)// 有噪声则伸张
  {
    myservo.writeMicroseconds(1800);// 舵机逆时针旋转 伸张
  }
  else
  {
    myservo.writeMicroseconds(1200);  // 舵机顺时针旋转 收缩
  }
}

 

效果图:
图2-11 章鱼听到噪音,准备伸张触角
三、活动心得
收获满满!动手能力进一步得到加强,思路进一步得以展开!祝越办越好!

 

点赞 关注
 
 

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

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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

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

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

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