本帖最后由 915992026 于 2025-3-16 20:40 编辑
前几天开箱和环境搭建测试完成,想想这块开发板搭配AI物联网蓝牙话筒内存卡等等结合在一起能实现很多功能,接下来结合例程做一个简单实用的小工具,制作过程很简单,看例程拿来主义搭配在一起,像是搭积木一样多个项目堆在一起就是一个实用工具。使用起来非常方便,对新手友好还实用
超市入口拍照门铃
功能:1、进门提示音“恭喜发财”或者“您已进入监控区域”,
2、有人进门就拍照(基于移动侦测功能,本来想人脸拍照来着,想想万一头戴丝袜的进去就没法识别了呢)
3、照片按当前时间存储
4、可查看监控视角用来调整拍摄角度(就是rtsp串流数据,电脑、手机也能播放,软件都是VLC)
优点:1、按照片存储比存储视频节省内存空间
2、按时间为名称查找方便,不用来回翻找视频
3、后期程序提升功能空间很大,比如利用话筒蓝牙等功能实现对开发板门铃的参数设置,连接物联网实现监控报警等等
用料- BW21-CBV-Kit x 1
- MicroSD 卡
- 3.5 毫米 TRS/TRRS 分线器 x 1(例如,Adafruit 2791 / Sparkfun 11570)
- 小音响、喇叭
实现流程使用读卡器将 SD 卡连接到计算机,然后将 自己想用的MP3门铃提示音 文件复制到 SD 卡中。在#define FILENAME "Audio_test"处,填写存储在 MicroSD 卡上的 MP3 文件名。插上内存卡到开发板。代码内改成自己当前的时间
完整代码:
- #include <Arduino.h>
- #include "WiFi.h"
- #include "VideoStream.h"
- #include "StreamIO.h"
- #include "RTSP.h"
- #include "MotionDetection.h"
- #include "VideoStreamOverlay.h"
- #include "AmebaFatFS.h"
- #include "Base64.h"
- #include <stdio.h>
- #include <time.h>
- #include "rtc.h"
- // 用户配置
- #define CHANNEL 0 // 视频通道用于流媒体和快照
- #define CHANNELMD 3 // 仅通道3支持RGB格式低分辨率运动检测
- /* Change these values to set the current initial date */
- #define YEAR 2020
- #define MONTH 1
- #define DAY 1
- /* Change these values to set the current initial time */
- #define HOUR 13
- #define MIN 14
- #define SEC 15
- #define FILENAME "Audio_test"
- AmebaFatFS fs;
- long long seconds = 0;
- struct tm *timeinfo;
- char ssid[] = "jifanG"; // 你的WiFi名称
- char pass[] = "88888888"; // 你的WiFi密码
- // 添加全局变量声明
- uint32_t img_addr = 0; // 声明图像地址变量
- uint32_t img_len = 0; // 声明图像长度变量
- // 创建对象
- VideoSetting config(VIDEO_D1, CAM_FPS, VIDEO_H264_JPEG, 1); // 高分辨率视频流配置
- VideoSetting configMD(VIDEO_VGA, 10, VIDEO_RGB, 0); // 低分辨率RGB视频流配置(用于运动检测)
- RTSP rtsp;
- StreamIO videoStreamer(1, 1);
- StreamIO videoStreamerMD(1, 1);
- MotionDetection MD;
- WiFiSSLClient wifiClient;
- // 全局变量
- char buf[512];
- char *p;
- bool flag_motion = false;
- // 运动检测结果处理回调函数
- void mdPostProcess(std::vector<MotionDetectionResult> md_results)
- {
- OSD.createBitmap(CHANNEL);
- if (MD.getResultCount() > 0) {
- for (uint16_t i = 0; i < MD.getResultCount(); i++) {
- MotionDetectionResult result = md_results[i];
- int xmin = (int)(result.xMin() * config.width());
- int xmax = (int)(result.xMax() * config.width());
- int ymin = (int)(result.yMin() * config.height());
- int ymax = (int)(result.yMax() * config.height());
- OSD.drawRect(CHANNEL, xmin, ymin, xmax, ymax, 3, COLOR_GREEN);
- }
- flag_motion = true;
- } else {
- flag_motion = false;
- }
- OSD.update(CHANNEL);
- delay(100);
- }
- void setup()
- {
- Serial.begin(115200);
- // WiFi连接
- while (WiFi.status() != WL_CONNECTED) {
- Serial.print("正在连接WiFi:");
- Serial.println(ssid);
- WiFi.begin(ssid, pass);
- delay(2000);
- }
- WiFiCon(); // 连接成功指示灯闪烁
- // 配置摄像头视频通道
- Camera.configVideoChannel(CHANNEL, config);
- Camera.configVideoChannel(CHANNELMD, configMD);
- Camera.videoInit();
- // 配置RTSP流媒体
- rtsp.configVideo(config);
- rtsp.begin();
- // 配置运动检测模块
- MD.configVideo(configMD);
- MD.setResultCallback(mdPostProcess);
- MD.begin();
- // 配置视频流管道(高分辨率通道→RTSP服务器)
- videoStreamer.registerInput(Camera.getStream(CHANNEL));
- videoStreamer.registerOutput(rtsp);
- if (videoStreamer.begin() != 0) {
- Serial.println("视频流管道启动失败");
- }
- // 启动视频通道
- Camera.channelBegin(CHANNEL);
- Serial.println("RTSP流媒体已启动");
- // 配置视频流管道(低分辨率通道→运动检测模块)
- videoStreamerMD.registerInput(Camera.getStream(CHANNELMD));
- videoStreamerMD.setStackSize();
- videoStreamerMD.registerOutput(MD);
- if (videoStreamerMD.begin() != 0) {
- Serial.println("视频流管道启动失败");
- }
- // 启动低分辨率通道
- Camera.channelBegin(CHANNELMD);
- Serial.println("===============================");
- Serial.println("运动检测系统已启动");
- Serial.println("===============================");
- delay(2000);
- rtc.Init();
- long long epochTime = rtc.SetEpoch(YEAR, MONTH, DAY, HOUR, MIN, SEC);
- rtc.Write(epochTime);
- }
- void loop()
- {
- if (flag_motion) {
- Serial.println("检测到运动!");
- //语音播放
- fs.begin();
- File file1 = fs.open(String(fs.getRootPath()) + String(FILENAME) + String(".mp3"));
- file1.close();
-
- // SD卡初始化
- if (!fs.begin()) {
- StreamEnd(); // 停止所有模块
- pinMode(LED_B, OUTPUT);
- digitalWrite(LED_B, HIGH); // 错误指示灯常亮
- Serial.println("===============================");
- Serial.println("[错误] SD卡挂载失败!");
- Serial.println("===============================");
- while (1); // 停止运行
- }
- // 获取当前时间并生成文件名
- long long current_seconds = rtc.Read();
- struct tm *current_timeinfo = localtime(¤t_seconds);
- char filename[25]; // 增大缓冲区确保安全
- int ret = snprintf(filename, sizeof(filename), "%04d%02d%02d_%02d%02d%02d.jpg",
- current_timeinfo->tm_year + 1900,
- current_timeinfo->tm_mon + 1,
- current_timeinfo->tm_mday,
- current_timeinfo->tm_hour,
- current_timeinfo->tm_min,
- current_timeinfo->tm_sec);
- // 安全检查(同时处理返回值错误和缓冲区溢出)
- if (ret < 0) {
- Serial.println("文件名格式错误!");
- return;
- }
- if (static_cast<unsigned int>(ret) >= sizeof(filename)) {
- Serial.println("文件名生成错误,缓冲区过小!");
- return;
- }
- String filepath = String(fs.getRootPath()) + String(filename);
- // 创建并打开文件
- File file = fs.open(filepath);
- if (!file) {
- Serial.println("===============================");
- Serial.println("[错误] 无法创建文件!");
- Serial.println("===============================");
- fs.end();
- return;
- }
- // 拍摄新照片
- CamFlash(); // 拍照指示灯闪烁
- Camera.getImage(CHANNEL, &img_addr, &img_len);
- file.write((uint8_t *)img_addr, img_len);
- file.close();
- Serial.println("===============================");
- Serial.print("[信息] 已保存照片:");
- Serial.println(filename);
- Serial.println("===============================");
- flag_motion = false; // 重置运动标志
- } else {
- Serial.print("."); // 无运动时显示进度
- }
- seconds = rtc.Read();
- printEpochTime();
- printBasicString();
- printStringTime();
- Serial.println("----------------------------------------------------------------------");
- rtc.Wait(1);
- }
- // LED闪烁函数(连接成功提示)
- void WiFiCon()
- {
- pinMode(LED_B, OUTPUT);
- for (int i = 0; i < 2; i++) {
- digitalWrite(LED_B, HIGH);
- delay(300);
- digitalWrite(LED_B, LOW);
- delay(300);
- }
- }
- // 拍照指示灯闪烁函数
- void CamFlash()
- {
- pinMode(LED_G, OUTPUT);
- for (int i = 0; i < 5; i++) {
- digitalWrite(LED_G, HIGH);
- delay(100);
- digitalWrite(LED_G, LOW);
- delay(100);
- }
- }
- // 停止所有模块函数
- void StreamEnd()
- {
- videoStreamer.pause();
- videoStreamerMD.pause();
- rtsp.end();
- Camera.channelEnd();
- MD.end();
- Camera.videoDeinit();
- delay(1000);
- }
- void printEpochTime(void)
- {
- Serial.print("Epoch Time(in s) since January, 1, 1970:");
- Serial.print(seconds);
- Serial.print("s");
- }
- void printBasicString(void)
- {
- Serial.println();
- Serial.print("Time as a basic string: ");
- Serial.print(ctime(&seconds));
- }
- void printStringTime(void)
- {
- timeinfo = localtime(&seconds);
- Serial.print("Time as a custom formatted string: ");
- Serial.print(timeinfo->tm_year + 1900);
- Serial.print("-");
- Serial.print(timeinfo->tm_mon + 1);
- Serial.print("-");
- Serial.print(timeinfo->tm_mday);
- Serial.print(" ");
- Serial.print(timeinfo->tm_hour);
- Serial.print(":");
- Serial.print(timeinfo->tm_min);
- Serial.print(":");
- Serial.println(timeinfo->tm_sec);
- }
复制代码
实测移动侦测人活动10米以内,挂在墙上完全够用。
参考例程:MotionDetectGoogleLineNotify、Simple_RTC、SDCardPlayMP3
|