You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用AT指令实现SIM800C与Arduino UNO通话录音至SD卡

SIM800C + Arduino Uno 通话录音到SD卡解决方案

核心AT指令说明

SIM800C的通话录音依赖文件系统指令+录音指令组合,以下是关键指令:

  • AT+FSINIT:初始化文件系统,确认SD卡是否被模块识别(返回OK则正常)
  • AT+FSCD="D:":切换存储目录到外部SD卡(模块内部存储为C:,SD卡对应D:)
  • AT+CREC=1,"[唯一文件名].AMR",0:通话中启动录音,参数说明:
    • 1:启动录音模式
    • 文件名:建议用时间戳命名避免覆盖,比如REC_202405201430.AMR
    • 0:录音格式为AMR(SIM800C仅支持该格式)
  • AT+CREC=2:停止当前录音
  • AT+FSLS:列出SD卡内的文件,验证录音是否保存

完整操作步骤

  1. 模块初始化:

    • 上电后发送AT+FSINIT确认SD卡挂载正常
    • 发送AT+FSCD="D:"切换到SD卡目录
    • 配置自动接听(如需要):ATS0=1(1声铃后自动接听)
  2. 通话录音流程:

    • 呼入/呼出通话接通后,发送AT+CREC=1,"[文件名].AMR",0启动录音
    • 通话过程中保持模块串口空闲,避免干扰录音
    • 通话结束前(或主动挂断前)发送AT+CREC=2停止录音
    • 可通过AT+FSLS确认文件已保存

修正后的Arduino示例代码

解决了你原代码中路径错误、录音指令参数问题,以及AMR文件直接读取到SD卡的逻辑:

#include <SoftwareSerial.h>
#include <SD.h>
#include <SPI.h>

const int chipSelect = 10;   // SD卡CS引脚
const int sim800Tx = 2;      // SIM800C TX接Arduino RX
const int sim800Rx = 3;      // SIM800C RX接Arduino TX
const int sim800Reset = 9;   // SIM800C复位引脚

SoftwareSerial sim800(sim800Rx, sim800Tx);
File sdFile;
String currentRecordFileName = ""; // 存储当前录音文件名

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

  pinMode(sim800Reset, OUTPUT);
  digitalWrite(sim800Reset, HIGH);

  // 初始化SD卡
  if (!SD.begin(chipSelect)) {
    Serial.println("SD卡初始化失败");
    return;
  }
  Serial.println("SD卡初始化完成");

  // 复位SIM800C
  resetSIM800();

  // 等待网络注册
  waitForNetwork();

  // 初始化SIM800C文件系统,切换到SD卡目录
  initSIM800FileSystem();

  // 设置1声铃后自动接听
  sim800.println("ATS0=1");
  delay(1000);
  readSIM800Response();
}

void loop() {
  if (sim800.available()) {
    String response = sim800.readString();
    Serial.println("模块返回:" + response);

    // 检测来电
    if (response.indexOf("RING") != -1) {
      Serial.println("检测到来电,等待自动接听...");
      delay(2000); // 等待自动接听完成
      startCallRecording();
    }

    // 检测通话结束
    if (response.indexOf("NO CARRIER") != -1 || response.indexOf("BUSY") != -1) {
      Serial.println("通话结束");
      stopCallRecording();
      saveRecordingToSD();
    }
  }
}

void resetSIM800() {
  digitalWrite(sim800Reset, LOW);
  delay(1000);
  digitalWrite(sim800Reset, HIGH);
  delay(3000); // 延长复位等待时间,确保模块重启完成
}

void waitForNetwork() {
  while (true) {
    sim800.println("AT+CREG?");
    delay(1000);
    if (sim800.find("+CREG: 0,1") || sim800.find("+CREG: 0,5")) {
      Serial.println("网络注册成功");
      readSIM800Response(); // 清空缓存
      break;
    } else {
      Serial.println("等待网络注册...");
      readSIM800Response();
    }
  }
}

void initSIM800FileSystem() {
  // 初始化文件系统
  sim800.println("AT+FSINIT");
  delay(1000);
  if (sim800.find("OK")) {
    Serial.println("文件系统初始化成功");
  } else {
    Serial.println("文件系统初始化失败,请检查SD卡连接");
  }
  readSIM800Response();

  // 切换到SD卡目录
  sim800.println("AT+FSCD=\"D:\"");
  delay(1000);
  if (sim800.find("OK")) {
    Serial.println("已切换到SD卡目录");
  } else {
    Serial.println("切换SD卡目录失败");
  }
  readSIM800Response();
}

void startCallRecording() {
  // 生成唯一文件名(用当前毫秒数简化命名)
  currentRecordFileName = "REC_" + String(millis()) + ".AMR";
  String cmd = "AT+CREC=1,\"" + currentRecordFileName + "\",0";
  
  sim800.println(cmd);
  delay(1000);
  if (sim800.find("OK")) {
    Serial.println("录音已启动,文件名:" + currentRecordFileName);
  } else {
    Serial.println("启动录音失败");
  }
  readSIM800Response();
}

void stopCallRecording() {
  sim800.println("AT+CREC=2");
  delay(1000);
  if (sim800.find("OK")) {
    Serial.println("录音已停止");
  } else {
    Serial.println("停止录音失败");
  }
  readSIM800Response();
}

void saveRecordingToSD() {
  if (currentRecordFileName.isEmpty()) {
    Serial.println("无有效录音文件名");
    return;
  }

  String readCmd = "AT+FSREAD=\"" + currentRecordFileName + "\",0";
  sim800.println(readCmd);
  delay(1000);

  // 打开SD卡文件准备写入
  sdFile = SD.open(currentRecordFileName, FILE_WRITE);
  if (!sdFile) {
    Serial.println("SD卡打开文件失败");
    readSIM800Response();
    return;
  }

  // 读取SIM800C返回的文件内容(跳过响应头,直接读取数据)
  bool skipHeader = true;
  while (sim800.available()) {
    char c = sim800.read();
    // 跳过AT指令响应的OK及换行符,只写入音频数据
    if (skipHeader) {
      if (c == 'O' && sim800.peek() == 'K') {
        sim800.read(); // 跳过K
        sim800.read(); // 跳过换行
        sim800.read(); // 跳过回车
        skipHeader = false;
      }
    } else {
      sdFile.write(c);
    }
  }

  sdFile.close();
  Serial.println("录音文件已保存到SD卡:" + currentRecordFileName);
  currentRecordFileName = ""; // 重置文件名
}

void readSIM800Response() {
  // 清空模块串口缓存
  while (sim800.available()) {
    sim800.read();
  }
}

关键注意事项

  • SIM800C仅支持AMR格式录音,无需在Arduino端转WAV(如需播放可在电脑端转换)
  • 必须确保SD卡为FAT32格式,且容量不超过32GB
  • 录音指令必须在通话接通后发送,否则会返回错误
  • 文件名必须唯一,避免覆盖已有录音文件

内容的提问来源于stack exchange,提问作者Swap

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 10:36:00