我是超超我最棒 发表于 2025-1-11 14:42

【Follow me第二季第4期】任务汇总

本帖最后由 我是超超我最棒 于 2025-1-13 15:42 编辑

<p>任务物料清单如下:</p>

<p>一根Micro USB 线</p>

<p>一块Arduino Nano RP2040 Connect开发板</p>

<p>一根自制跳线</p>

<p>&nbsp;</p>

<p>&nbsp;</p>

<p>本次活动的心得体会如下:</p>

<p>&nbsp;</p>

<p>从技术学习角度看,一方面深入了解了传感器与外设交互的细节。像代码中对 IMU(惯性测量单元)的操作,不仅熟悉了其初始化流程,还掌握如何获取加速度计和陀螺仪的采样率数据,以及实时读取运动数据,这为开发涉及运动监测、姿态感知类项目,如可穿戴设备、智能运动器材等奠定基础。对于 PDM 麦克风的运用同样如此,知晓了从配置数据接收回调,到依据采样规则处理音频样本的全过程,在音频相关开发,像是简易录音设备、环境声音监测有了技术支撑。</p>

<p>编程思维上有很大提升,整个代码结构严谨,遵循 Arduino 典型的 setup () 与 loop () 框架。在 setup () 里有条不紊地完成初始化工作,确保后续程序稳定运行,这教会我们前期准备工作的全面性和重要性。loop () 函数内,通过巧妙的条件判断来处理不同传感器数据就绪情况,以及对音频样本阈值判断控制 LED,体现了事件驱动编程思维,让程序高效响应外部变化,而非盲目执行指令。</p>

<p>调试过程更是积累宝贵经验,遇到 IMU 初始化失败、PDM 启动异常等问题时,学会借助串口输出信息排查。比如 IMU 初始化不成功时在串口打印错误提示并阻塞程序,方便定位硬件连接、驱动配置错误;处理音频样本时,通过串口输出观察样本数据,辅助判断数据处理逻辑正误,明白了调试工具在开发中的 &ldquo;眼睛&rdquo; 作用,让看不见的代码流程和数据流转可视化。</p>

<p>项目整合视野得到拓展,这段代码融合多种功能,集传感器数据采集、音频处理、LED 控制于一体。意识到在实际物联网项目中,往往需要整合不同模块,各模块协同运作才能实现复杂系统功能,单一技术难以满足需求,为未来设计综合性更强的嵌入式项目积累信心与思路。</p>

<p>总之,编写此代码如同经历一场知识与技能的小型探险,从技术细节到宏观项目构建,全方位提升了 Arduino 开发能力。</p>

<p>&nbsp;</p>

<p><br />
任务一:搭建环境并Blink三色LED,以及踩坑</p>

<p><br />
虽然踩了坑,回想起来还是很有收获的</p>

<p>cd68124d8bc65f19e3a7b03252f474d2</p>

<p>&nbsp;</p>

<p><a href="https://content.arduino.cc/assets/Blink.ino.elf.uf2" target="_blank">https://content.arduino.cc/assets/Blink.ino.elf.uf2</a></p>

<p>最后还是用最简单的方法让板子闪了起来。</p>

<p>&nbsp;</p>

<p>&nbsp;</p>

<p>任务二:学习IMU基础知识,调试IMU传感器,串口打印数据</p>

<p>&nbsp;</p>

<p>有了上面的经验Arduino不是驾轻就熟的事。别忘了安装Arduino_LSM6DSOX的库</p>

<pre>
<code>#include &lt;Arduino_LSM6DSOX.h&gt;

float Ax, Ay, Az;
float Gx, Gy, Gz;

void setup() {
Serial.begin(9600);

while(!Serial);

if (!IMU.begin()) {
    Serial.println("初始化 IMU 失败!");
    while (1);
}

Serial.print("加速度计采样率 = ");
Serial.print(IMU.accelerationSampleRate());
Serial.println("Hz");
Serial.println();

Serial.print("陀螺仪采样率 = ");
Serial.print(IMU.gyroscopeSampleRate());
Serial.println("Hz");
Serial.println();

}

void loop() {

if (IMU.accelerationAvailable()) {
    IMU.readAcceleration(Ax, Ay, Az);

    Serial.println("加速度计数据: ");
    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("陀螺仪数据: ");
    Serial.print(Gx);
    Serial.print('\t');
    Serial.print(Gy);
    Serial.print('\t');
    Serial.println(Gz);
    Serial.println();
}

delay(500);

}
</code></pre>

<p>&nbsp;</p>

<p>软件流程图如下:</p>

<h3>开始</h3>

<p>&nbsp;</p>

<p>|-- 初始化串口通信,设置波特率为 9600<br />
|-- 等待串口准备就绪<br />
|-- 尝试初始化 IMU(惯性测量单元)<br />
|-- 判断 IMU 初始化是否成功<br />
|-- 若失败,串口输出 &ldquo;初始化 IMU 失败!&rdquo; 并进入死循环<br />
|-- 若成功,执行以下操作:<br />
|---- 串口输出加速度计采样率信息<br />
|---- 串口输出陀螺仪采样率信息</p>

<h3>进入循环(loop)</h3>

<p>&nbsp;</p>

<p>|-- 判断加速度计数据是否可用<br />
|-- 若可用<br />
|---- 读取加速度计数据(Ax、Ay、Az)<br />
|---- 串口输出 &ldquo;加速度计数据:&rdquo; 以及 Ax、Ay、Az 的值<br />
|-- 判断陀螺仪数据是否可用<br />
|-- 若可用<br />
|---- 读取陀螺仪数据(Gx、Gy、Gz)<br />
|---- 串口输出 &ldquo;陀螺仪数据: &rdquo; 以及 Gx、Gy、Gz 的值<br />
|-- 程序延迟 500 毫秒<br />
|-- 循环回到开头,重复上述判断与操作</p>

<p>&nbsp;</p>

<p>&nbsp;</p>

<p>任务三:学习PDM麦克风技术知识,调试PDM麦克风,通过串打印</p>

<p>麦克风这还是很特别的</p>

<p>&nbsp;</p>

<p>Arduino代码如下,别忘了安装WIFININA的库</p>

<pre>
<code>#include &lt;WiFiNINA.h&gt;
#include &lt;PDM.h&gt;

bool LED_SWITCH = false;

// 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;

// Number of audio samples read
volatile int samplesRead;

void setup() {
Serial.begin(9600);
pinMode(LEDB, OUTPUT);
while (!Serial);
// Configure the data receive callback
PDM.onReceive(onPDMdata);

// Optionally set the gain
// Defaults to 20 on the BLE Sense and -10 on the Portenta Vision Shields
// PDM.setGain(30);

// Initialize PDM with:
// - one channel (mono mode)
// - a 16 kHz sample rate for the Arduino Nano 33 BLE Sense
// - a 32 kHz or 64 kHz sample rate for the Arduino Portenta Vision Shields
if (!PDM.begin(channels, frequency)) {
    Serial.println("启动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 &lt; samplesRead; i++) {
      if (channels == 2) {
      Serial.print("左:");
      Serial.print(sampleBuffer);
      Serial.print(" 右:");
      i++;
      }
      Serial.println(sampleBuffer);

      if (sampleBuffer &gt; 10000 || sampleBuffer &lt;= -10000) {
      LED_SWITCH = !LED_SWITCH;
      if (LED_SWITCH) {
          Serial.println();
          digitalWrite(LEDB, HIGH);
          Serial.println("开启!");
          Serial.println();
          delay(1000);
      }
      else {
          Serial.println();
          digitalWrite(LEDB, LOW);
          Serial.println("关闭!");
          Serial.println();
          delay(1000);
      }
      }
    }

    // Clear the read count
    samplesRead = 0;
}
}

/**
   Callback function to process the data from the PDM microphone.
   NOTE: This callback is executed as part of an ISR.
   Therefore using `Serial` to print messages inside this function isn't supported.
* */
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;
}
</code></pre>

<p>&nbsp;</p>

<p>任务三的软件流程如下:</p>

<p>&nbsp;</p>

<h3><b>开始</b></h3>

<p>&nbsp;</p>

<p>|-- 初始化串口通信,设置波特率为 9600<br />
|-- 将引脚(对应 LED)设置为输出模式<br />
|-- 等待串口准备就绪<br />
|-- 配置 PDM(脉冲密度调制)数据接收回调函数(关联onPDMdata函数)<br />
|-- (可选操作,此处代码中注释掉了)设置 PDM 增益<br />
|-- 初始化 PDM,传入通道数和频率参数<br />
|-- 判断 PDM 初始化是否成功<br />
|-- 若失败,串口输出 &ldquo;启动 PDM 失败!&rdquo; 并进入死循环</p>

<h3><b>进入循环(loop)</b></h3>

<p>&nbsp;</p>

<p>|-- 判断是否有音频样本被读取(即samplesRead是否大于 0)<br />
|-- 若有样本被读取:<br />
|---- 遍历已读取的样本(循环变量&nbsp;i&nbsp;从 0 到samplesRead - 1)<br />
|------ 判断通道数是否为 2<br />
|-------- 若是,输出 &ldquo;左:&rdquo; 及对应样本值,再输出 &ldquo;右:&rdquo; 及下一个样本值,并让&nbsp;i&nbsp;自增 1<br />
|------ 输出当前样本值(单通道情况或双通道中的一个通道情况)<br />
|------ 判断样本值是否大于 10000 或者小于等于 -10000<br />
|-------- 若是,切换&nbsp;LED_SWITCH&nbsp;的状态<br />
|-------- 根据&nbsp;LED_SWITCH&nbsp;状态:<br />
|---------- 若为&nbsp;true(开启):<br />
|------------ 向串口输出开启提示信息<br />
|------------ 将 LED 引脚置为高电平(点亮 LED)<br />
|------------ 程序延迟 1000 毫秒<br />
|---------- 若为&nbsp;false(关闭):<br />
|------------ 向串口输出关闭提示信息<br />
|------------ 将 LED 引脚置为低电平(熄灭 LED)<br />
|------------ 程序延迟 1000 毫秒<br />
|---- 将samplesRead置为 0(清除已读样本计数)<br />
|-- 循环回到开头,重复上述判断与样本处理操作</p>

<h3><b>回调函数&nbsp;</b><b>onPDMdata</b><b>(由 PDM 数据接收触发执行)</b></h3>

<p>&nbsp;</p>

<p>|-- 查询可用字节数(通过PDM.available获取)<br />
|-- 将数据读取到样本缓冲区(sampleBuffer)<br />
|-- 根据 16 位、每个样本 2 字节的规则,计算已读取的样本数量</p>

<p>&nbsp;</p>

<p>&nbsp;</p>

<p>&nbsp;</p>

<p>&nbsp;</p>

<p><strong>总结视频如下</strong></p>

<p>&nbsp;</p>

<p><iframe allowfullscreen="true" frameborder="0" height="450" src="https://training.eeworld.com.cn/shareOpenCourseAPI?isauto=true&amp;lessonid=42243" style="background:#eee;margin-bottom:10px;" width="700"></iframe><br />
&nbsp;</p>

<p>&nbsp;</p>

<div></div>
页: [1]
查看完整版本: 【Follow me第二季第4期】任务汇总