使用 Arduino Nano 33 BLE Sense 实现音频数据传输
组件与物料
| Arduino Nano 33 BLE Sense | × | 1 |
项目简介
在 Chirp 总部,我们对 Arduino 发布搭载多项新功能的新款开发板感到无比兴奋。这些功能包括丰富的传感器、强大的处理器,以及最重要的——板载麦克风!Arduino 团队慷慨地寄送了一块 Nano 33 Sense 预发布版板卡,它完美兼容 Chirp SDK,让创客社区能够利用声音发送和接收数据。
Chirp 为 Arduino 开发板引入了一种全新的传输机制——声波数据传输,极大地拓展了硬件的连接选项。声波数据传输的主要优势包括:
- 设备无关性:数据可从移动应用、网页甚至普通音频文件发送
- 一对多广播:听觉范围内的所有设备均可在单次传输中接收数据
- 零配置:无需配对、密码或任何初始设置
本教程将演示如何使用 Chirp SDK 发送 RGB 值,以改变板载 LED 的颜色。得益于多年的算法研究,Chirp 即使在嘈杂环境下也能稳健解码。如果你仍有疑虑,不妨亲自试一试——上手比以往更简单。
快速开始
若尚未注册,请前往 developers.chirp.io 创建账号。注册后即可获取应用的 Key、Secret 以及音频配置。
接收数据
Nano 33 Sense 内置麦克风,接收数据仅需安装 Chirp SDK。打开库管理器(Tools > Manage Libraries),搜索“Chirp SDK”并安装 v3.3.0 或更高版本。
随后打开示例代码:File > Examples > ChirpSDK > Nano33SenseReceive。将 16khz-mono-embedded 协议的凭据(从 developers.chirp.io 获取)复制到 credentials.h 文件中。
示例代码默认将接收到的数据打印到串口监视器。我们只需修改 onReceivedCallback 函数,即可让板载 LED 随数据变色。
硬件引脚定义
#define R_LED_PIN 22
#define G_LED_PIN 23
#define B_LED_PIN 24
void setup() {
pinMode(R_LED_PIN, OUTPUT);
pinMode(G_LED_PIN, OUTPUT);
pinMode(B_LED_PIN, OUTPUT);
}
回调函数处理 RGB 数据
void onReceivedCallback(void *chirp, uint8_t *payload, size_t length, uint8_t channel) {
if (length > 0) {
// 高数值对应低亮度,故用 UINT8_MAX 减去载荷值
analogWrite(R_LED_PIN, UINT8_MAX - payload[0]);
analogWrite(G_LED_PIN, UINT8_MAX - payload[1]);
analogWrite(B_LED_PIN, UINT8_MAX - payload[2]);
} else {
Serial.println("Decode failed");
}
}
上传代码后,播放教程提供的音频文件,即可观察 LED 依次变为红、绿、蓝三色。
后续展望
当前版本仅支持可听频段的 16khz-mono-embedded 协议。未来几个月将推出近超声波频段的不可听版本,可将数据嵌入音乐、视频等现有音频中触发动作,而不干扰人耳聆听。我们还将发布更多结合 Arduino 的声波数据传输教程。欢迎在 Twitter @chirp 或邮件 contact@chirp.io 分享你的创意项目。
完整代码
/**--------------------------------------------------------------------
Arduino Nano 33 Sense 接收数据示例代码
@file Nano33SenseReceive.ino
@brief 在 https://developers.chirp.io 创建开发者账号,
将 "16khz-mono-embedded" 协议的 key、secret、config 填入下方宏定义。
本示例监听 RGB 值并改变板载 LED 颜色。
Circuit: - Arduino Nano 33 BLE board
Copyright © 2011-2019, Asio Ltd. All rights reserved.
-------------------------------------------------------------------*/
#include <PDM.h>
#include "chirp_connect.h"
#define CHIRP_APP_KEY "YOUR_APP_KEY"
#define CHIRP_APP_SECRET "YOUR_APP_SECRET"
#define CHIRP_APP_CONFIG "YOUR_APP_CONFIG"
#define SAMPLE_RATE 16000
#define BUFFER_SIZE 256
#define R_LED_PIN 22
#define G_LED_PIN 23
#define B_LED_PIN 24
// 全局变量
static chirp_connect_t *chirp = NULL;
short sampleBuffer[BUFFER_SIZE];
volatile int samplesRead;
// 函数声明
void setupChirp(void);
void chirpErrorHandler(chirp_connect_error_code_t code);
void onPDMdata(void);
void setup() {
Serial.begin(115200);
// while (!Serial);
pinMode(R_LED_PIN, OUTPUT);
pinMode(G_LED_PIN, OUTPUT);
pinMode(B_LED_PIN, OUTPUT);
setupChirp();
PDM.onReceive(onPDMdata);
PDM.setGain(30);
if (!PDM.begin(1, SAMPLE_RATE)) {
Serial.println("Failed to start PDM!");
while (1);
}
analogWrite(R_LED_PIN, UINT8_MAX);
analogWrite(G_LED_PIN, UINT8_MAX);
analogWrite(B_LED_PIN, UINT8_MAX);
}
void loop() {
if (samplesRead) {
chirp_connect_error_code_t err = chirp_connect_process_shorts_input(chirp, sampleBuffer, samplesRead);
chirpErrorHandler(err);
samplesRead = 0;
}
}
void onPDMdata() {
int bytesAvailable = PDM.available();
PDM.read(sampleBuffer, bytesAvailable);
samplesRead = bytesAvailable / sizeof(short);
}
// Chirp 回调函数
void onReceivingCallback(void *chirp, uint8_t *payload, size_t length, uint8_t channel) {
Serial.println("Receiving data...");
analogWrite(R_LED_PIN, UINT8_MAX);
analogWrite(G_LED_PIN, UINT8_MAX);
analogWrite(B_LED_PIN, UINT8_MAX);
}
void onReceivedCallback(void *chirp, uint8_t *payload, size_t length, uint8_t channel) {
if (length) {
analogWrite(R_LED_PIN, UINT8_MAX - payload[0]);
analogWrite(G_LED_PIN, UINT8_MAX - payload[1]);
analogWrite(B_LED_PIN, UINT8_MAX - payload[2]);
} else {
analogWrite(R_LED_PIN, 0);
analogWrite(G_LED_PIN, UINT8_MAX);
analogWrite(B_LED_PIN, UINT8_MAX);
delay(500);
analogWrite(R_LED_PIN, UINT8_MAX);
delay(500);
analogWrite(R_LED_PIN, 0);
Serial.println("Decode failed");
}
}
void chirpErrorHandler(chirp_connect_error_code_t code) {
if (code != CHIRP_CONNECT_OK) {
const char *error_string = chirp_connect_error_code_to_string(code);
Serial.println(error_string);
exit(42);
}
}
void setupChirp(void) {
chirp = new_chirp_connect(CHIRP_APP_KEY, CHIRP_APP_SECRET);
if (chirp == NULL) {
Serial.println("Chirp initialisation failed.");
return;
}
chirp_connect_error_code_t err = chirp_connect_set_config(chirp, CHIRP_APP_CONFIG);
chirpErrorHandler(err);
char *info = chirp_connect_get_info(chirp);
Serial.println(info);
chirp_connect_free(info);
chirp_connect_callback_set_t callback_set = {
.on_state_changed = NULL,
.on_sending = NULL,
.on_sent = NULL,
.on_receiving = onReceivingCallback,
.on_received = onReceivedCallback
};
err = chirp_connect_set_callbacks(chirp, callback_set);
chirpErrorHandler(err);
err = chirp_connect_set_input_sample_rate(chirp, SAMPLE_RATE);
chirpErrorHandler(err);
err = chirp_connect_set_frequency_correction(chirp, 1.0096);
chirpErrorHandler(err);
err = chirp_connect_start(chirp);
chirpErrorHandler(err);
Serial.println("Chirp SDK initialised.");
Serial.flush();
}
制造工艺
- 实时数据洞察重塑数字化制造团队:从数据饱和到关键参数聚焦
- 黑胶唱片LP制作的艺术与工艺
- 树莓派传感器数据融合实战:GPS 与 MPU‑9150 IMU 的 I²C 与 UART 接入
- 高阶HMI驱动工厂能效跃升:测量、监控、优化全链路
- 8大常见数据泄露类型实战剖析:真实案例、影响深度与防御启示
- 前沿工业4.0技术:十大实际创新与应用场景解析
- OT与IT无缝融合:现代工业软件连接智能传感器至企业系统
- 可靠性互联网中的数据驾驭:高效管理策略
- 边缘时代的物联网:增长、数据、安全与合作伙伴策略
- 提升工业 4.0:利用边缘分析实现更智能、更快速的制造
- 利用实时城市数据驱动智慧城市创新
- C++ char 类型完全指南:声明、ASCII 码、输入输出与字符串转换