- 2025-01-14
-
回复了主题帖:
以拆会友!看看2.3寸“大”电视和32寸的大彩电内里乾坤
00后表示头回看见过这种小型电视,跟着楼主开眼界
- 2025-01-12
-
发表了主题帖:
【Follow me第二季第4期】任务提交
本帖最后由 坛/我=佬 于 2025-1-13 14:18 编辑
一、视频介绍
二、任务实现详情
必做任务一:搭建环境并开启第一步Blink三色LED / 串口打印Hello DigiKey & EEWorld!
物料清单:Arduino Nano RP2040 Connect
设计思路:
Arduino Nano RP2040 Connect板载一颗共阳RGB LED,但是没有直接连接到RP2040的IO上,而是连接到Nina W102 Wi-Fi/Bluetooth模组的IO上。
由原理图可知,当Nina W102的IO输出高电平时,LED熄灭;输出低电平时,LED点亮。对应代码为digitalWrite(LEDR, LOW)熄灭LED,digitalWrite(LEDR, HIGH)点亮LED。
所以本质上是RP2040通过SPI控制W102模组的IO,使其输出高低电平,进一步控制RGB LED亮灭。但是Arduino通过WiFiNINA library简化了这个步骤,使用pinMode、digitalWrite等函数就可以控制,具体的实现流程被封装到WiFiNINA库里面。因此,要控制板载的RGB LED,首先需要安装WiFiNINA库并调用。
RP2040片上具有USB1.1控制器和PHY,支持Host和Device模式。Arduino官方基于此硬件设计了bootloader,使该USB接口具有下载代码和串口调试的功能。
软件流程图
代码实现
#include <SPI.h>
#include <WiFiNINA.h>
void setup() {
Serial.begin(115200); // initialize serial communication
delay(500);
while(!Serial); //等待串口初始化完毕
// {
// Serial.println("Serial init failed!");
// while(1);
// }
Serial.println("Programme Starting!");
Serial.println("Hello DigiKey & EEWorld!"); //打印信息
pinMode(LEDR, OUTPUT); //初始化RGB引脚
pinMode(LEDG, OUTPUT);
pinMode(LEDB, OUTPUT);
digitalWrite(LEDR, LOW); //设置RGB引脚默认状态为低,对应熄灭状态
digitalWrite(LEDG, LOW);
digitalWrite(LEDB, LOW);
}
void loop() {
digitalWrite(LEDR, HIGH); //显示红色
digitalWrite(LEDG, LOW);
digitalWrite(LEDB, LOW);
delay(500);
digitalWrite(LEDR, LOW); //显示绿色
digitalWrite(LEDG, HIGH);
digitalWrite(LEDB, LOW);
delay(500);
digitalWrite(LEDR, LOW); //显示蓝色
digitalWrite(LEDG, LOW);
digitalWrite(LEDB, HIGH);
delay(500);
}
功能展示
必做任务二:学习IMU基础知识,调试IMU传感器,通过串口打印六轴原始数据
物料清单:Arduino Nano RP2040 Connect
设计思路:
Arduino Nano RP2040 Connect板载一颗六轴IMU(LSM6DSOXTR),内置3轴加速度计和3轴陀螺仪,通过3轴加速度计可以获得物体的运动方向,通过3轴陀螺仪可以获得物体的旋转角度。LSM6DSOXTR的具体参数如下
LSM6DSOXTR通过IIC与LSM6DSOXTR进行通信,并且由于RP2040配置为IIC模式时,IO口为开漏输出,需要通过硬件对SCL和SDA两根信号线进行上拉操作。
要通过IIC对LSM6DSOXTR进行操作,首先需要安装对应的Arduino_LSM6DSOX library,里面包含Arduino官方封装过的API函数,可以快速上手获取IMU的加速度和陀螺仪原始数据。
软件流程图
代码实现
#include <Arduino_LSM6DSOX.h>
float Ax, Ay, Az;
float Gx, Gy, Gz;
void setup() {
Serial.begin(115200);
while(!Serial); //防止程序run直到串口打开
if (!IMU.begin()) {
Serial.println("Failed to initialize IMU!");
while (1);
}
Serial.print("Accelerometer sample rate = ");
Serial.print(IMU.accelerationSampleRate());
Serial.println("Hz");
Serial.println();
Serial.print("Gyroscope sample rate = ");
Serial.print(IMU.gyroscopeSampleRate());
Serial.println("Hz");
Serial.println();
}
void loop() {
if (IMU.accelerationAvailable()) {
IMU.readAcceleration(Ax, Ay, Az);
Serial.println("Accelerometer data: ");
Serial.print(Ax);
Serial.print('\t');
Serial.print(Ay);
Serial.print('\t');
Serial.println(Az);
Serial.println();
}
if (IMU.gyroscopeAvailable()) {
IMU.readGyroscope(Gx, Gy, Gz);
Serial.println("Gyroscope data: ");
Serial.print(Gx);
Serial.print('\t');
Serial.print(Gy);
Serial.print('\t');
Serial.println(Gz);
Serial.println();
}
delay(500);
}
功能展示
必做任务三:学习PDM麦克风技术知识,调试PDM麦克风,通过串口打印收音数据和音频波形
物料清单:Arduino Nano RP2040 Connect
设计思路:
Arduino Nano RP2040 Connect板载一颗全向MEMS麦克风(MP34DT06JTR),可以用来感知外界环境的声音变化,并将其记录并量化为数值。MP34DT06JTR的具体参数如下
MP34DT06JTR通过PDM接口与RP2040连接。操作MEMS麦克风也需要额外的PDM library,但是与任务一和任务二不同的是,在安装Arduino Nano RP2040 Connect板的时候,内部就已经带了PDM library,不需要额外搜索安装,直接用就可以。
软件流程图
代码实现
#include <PDM.h>
// default number of output channels
static const char channels = 1;
// default PCM output frequency
static const int frequency = 20000;
// Buffer to read samples into, each sample is 16-bits
short sampleBuffer[512];
// Number of audio samples read
volatile int samplesRead;
void setup() {
Serial.begin(115200);
while (!Serial);
// Configure the data receive callback
PDM.onReceive(onPDMdata);
if (!PDM.begin(channels, frequency)) {
Serial.println("Failed to start PDM!");
while (1);
}
}
void loop() {
// Wait for samples to be read
if (samplesRead) {
// Print samples to the serial monitor or plotter
for (int i = 0; i < samplesRead; i++) {
if (channels == 2) {
Serial.print("L:");
Serial.print(sampleBuffer[i]);
Serial.print(" R:");
i++;
}
Serial.println(sampleBuffer[i]);
}
// Clear the read count
samplesRead = 0;
}
}
void onPDMdata() {
// Query the number of available bytes
int bytesAvailable = PDM.available();
// Read into the sample buffer
PDM.read(sampleBuffer, bytesAvailable);
// 16-bit, 2 bytes per sample
samplesRead = bytesAvailable / 2;
}
功能展示
扩展任务:雷达感应氛围灯
物料清单:Arduino Nano RP2040 Connect、6x10 RGB MATRIX、24GHz mmWave
来自seeed的XIAO RGB灯板,上面一共有6x10个RGB灯珠
来自seeed的24GHz mmWave雷达传感器,可以用来检测附近是否有人存在
设计思路:
当人离开电脑长时间不使用时,电脑会进入休眠状态节省电量。同理,当人离开桌面时,氛围灯关闭;重新回来时,氛围灯开启。一方面可以带来绚丽多彩的氛围特效,另一方面还可以节省电量。
24GHz mmWave通过串口与RP2040通信,RP2040接收到串口数据后,对数据进行解析,从而获取到传感器识别到的当前状态。在使用前需要安装mmwave_for_xiao library。模块参数如下
6x10 RGB MATRIX通过级联方式可以控制60个RGB,同时还可以通过板与板之间级联,方便扩展,采用WS2812灯珠。使用前需要安装Adafruit_NeoPixel library可以方便控制指定颜色和指定灯珠。特性如下
软件流程图
代码实现
#include <mmwave_for_xiao.h>
#include <Adafruit_NeoPixel.h>
// Which pin on the Arduino is connected to the NeoPixels?
#define PIN 25 // On Trinket or Gemma, suggest changing this to 1
// How many NeoPixels are attached to the Arduino?
#define NUMPIXELS 60 // Popular NeoPixel ring size
// Creates a global Serial object for printing debugging information
#define ShowSerial Serial
// Initialising the radar configuration
// Seeed_HSP24 xiao_config(COMSerial, ShowSerial);
Seeed_HSP24 xiao_config(Serial1);
Seeed_HSP24::RadarStatus radarStatus;
// When setting up the NeoPixel library, we tell it how many pixels,
// and which pin to use to send signals. Note that for older NeoPixel
// strips you might need to change the third parameter -- see the
// strandtest example for more information on possible values.
Adafruit_NeoPixel strip(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
#define DELAYVAL 500 // Time (in milliseconds) to pause between pixels
void setup() {
ShowSerial.begin(115200);
Serial1.begin(115200);
while(!ShowSerial);
delay(500);
strip.begin(); // INITIALIZE NeoPixel strip object (REQUIRED)
strip.setBrightness(64);
ShowSerial.println("Programme Starting!");
xiao_config.disableEngineeringModel(); //关闭工程上报模式,此时为基本上报模式
// xiao_config.enableEngineeringModel(); //开启工程上报模式
}
void loop() {
int retryCount = 0;
const int MAX_RETRIES = 10; // Maximum number of retries to prevent infinite loops
//Get radar status
do {
radarStatus = xiao_config.getStatus();
retryCount++;
} while (radarStatus.targetStatus == Seeed_HSP24::TargetStatus::ErrorFrame && retryCount < MAX_RETRIES);
//Parses radar status and prints results from debug serial port
if (radarStatus.targetStatus != Seeed_HSP24::TargetStatus::ErrorFrame) {
ShowSerial.print("Status: " + String(targetStatusToString(radarStatus.targetStatus)) + " ---- ");
ShowSerial.println("Distance: " + String(radarStatus.distance) + " Mode: " + String(radarStatus.radarMode));
if (radarStatus.radarMode == 1) { //如果工程上报模式开启,为1
ShowSerial.print("Move:");
for (int i = 0; i < 9; i++) {
ShowSerial.print(" " + String(radarStatus.radarMovePower.moveGate[i]) + ",");
}
ShowSerial.println("");
ShowSerial.print("Static:");
for (int i = 0; i < 9; i++) {
ShowSerial.print(" " + String(radarStatus.radarStaticPower.staticGate[i]) + ",");
}
ShowSerial.println("");
ShowSerial.println("Photosensitive: " + String(radarStatus.photosensitive));
}
}
delay(100);
}
// Parsing the acquired radar status
const char* targetStatusToString(Seeed_HSP24::TargetStatus status) {
switch (status) {
case Seeed_HSP24::TargetStatus::NoTarget:
{
// if(radarStatus.noTargrtduration > 1000)
// {
// }
return "NoTarget";
}
case Seeed_HSP24::TargetStatus::MovingTarget:
{
colorWipe(strip.Color(255, 0, 0), 50); // Red
colorWipe(strip.Color( 0, 255, 0), 50); // Green
colorWipe(strip.Color( 0, 0, 255), 50); // Blue
// theaterChase(strip.Color(127, 127, 127), 50); // White
// theaterChase(strip.Color(127, 0, 0), 50); // Red
// theaterChase(strip.Color( 0, 0, 127), 50); // Blue
return "MovingTarget";
}
case Seeed_HSP24::TargetStatus::StaticTarget:
{
rainbow(10);
return "StaticTarget";
}
case Seeed_HSP24::TargetStatus::BothTargets:
{
theaterChaseRainbow(200);
return "BothTargets";
}
default:
return "Unknown";
}
}
// Fill strip pixels one after another with a color. Strip is NOT cleared
// first; anything there will be covered pixel by pixel. Pass in color
// (as a single 'packed' 32-bit value, which you can get by calling
// strip.Color(red, green, blue) as shown in the loop() function above),
// and a delay time (in milliseconds) between pixels.
void colorWipe(uint32_t color, int wait) {
for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...
strip.setPixelColor(i, color); // Set pixel's color (in RAM)
strip.show(); // Update strip to match
delay(wait); // Pause for a moment
}
}
// Theater-marquee-style chasing lights. Pass in a color (32-bit value,
// a la strip.Color(r,g,b) as mentioned above), and a delay time (in ms)
// between frames.
void theaterChase(uint32_t color, int wait) {
for(int a=0; a<10; a++) { // Repeat 10 times...
for(int b=0; b<3; b++) { // 'b' counts from 0 to 2...
strip.clear(); // Set all pixels in RAM to 0 (off)
// 'c' counts up from 'b' to end of strip in steps of 3...
for(int c=b; c<strip.numPixels(); c += 3) {
strip.setPixelColor(c, color); // Set pixel 'c' to value 'color'
}
strip.show(); // Update strip with new contents
delay(wait); // Pause for a moment
}
}
}
// Rainbow cycle along whole strip. Pass delay time (in ms) between frames.
void rainbow(int wait) {
// Hue of first pixel runs 3 complete loops through the color wheel.
// Color wheel has a range of 65536 but it's OK if we roll over, so
// just count from 0 to 3*65536. Adding 256 to firstPixelHue each time
// means we'll make 3*65536/256 = 768 passes through this outer loop:
for(long firstPixelHue = 0; firstPixelHue < 3*65536; firstPixelHue += 256) {
for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...
// Offset pixel hue by an amount to make one full revolution of the
// color wheel (range of 65536) along the length of the strip
// (strip.numPixels() steps):
int pixelHue = firstPixelHue + (i * 65536L / strip.numPixels());
// strip.ColorHSV() can take 1 or 3 arguments: a hue (0 to 65535) or
// optionally add saturation and value (brightness) (each 0 to 255).
// Here we're using just the single-argument hue variant. The result
// is passed through strip.gamma32() to provide 'truer' colors
// before assigning to each pixel:
strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue)));
}
strip.show(); // Update strip with new contents
delay(wait); // Pause for a moment
}
}
// Rainbow-enhanced theater marquee. Pass delay time (in ms) between frames.
void theaterChaseRainbow(int wait) {
int firstPixelHue = 0; // First pixel starts at red (hue 0)
for(int a=0; a<30; a++) { // Repeat 30 times...
for(int b=0; b<3; b++) { // 'b' counts from 0 to 2...
strip.clear(); // Set all pixels in RAM to 0 (off)
// 'c' counts up from 'b' to end of strip in increments of 3...
for(int c=b; c<strip.numPixels(); c += 3) {
// hue of pixel 'c' is offset by an amount to make one full
// revolution of the color wheel (range 65536) along the length
// of the strip (strip.numPixels() steps):
int hue = firstPixelHue + c * 65536L / strip.numPixels();
uint32_t color = strip.gamma32(strip.ColorHSV(hue)); // hue -> RGB
strip.setPixelColor(c, color); // Set pixel 'c' to value 'color'
}
strip.show(); // Update strip with new contents
delay(wait); // Pause for a moment
firstPixelHue += 65536 / 90; // One cycle of color wheel over 90 frames
}
}
}
功能展示
心得体会:
这是我第一次参加得捷follow me的活动,整体上来说收获很多,而且提供的板子非常适合大家快速上手,希望明年还会有类似活动,积极参加!
三、可编译下载的代码
完成任务源码下载地址https://download.eeworld.com.cn/detail/%E5%9D%9B/%E6%88%91=%E4%BD%AC/635603
-
加入了学习《【Follow me第二季第4期】任务提交》,观看 【Follow me第二季第4期】任务提交
-
上传了资料:
【Follow me第二季第4期】任务提交