Python自动化测试EC20模块:AT指令全流程实战指南

在物联网设备开发中,EC20系列模块因其稳定的4G通信能力成为众多项目的首选。但每次手动通过串口工具发送AT指令测试模块功能,不仅效率低下,还容易遗漏关键测试场景。本文将带你用Python构建一套完整的自动化测试方案,覆盖从基础查询到网络状态模拟的全流程。

1. 环境搭建与基础连接

工欲善其事,必先利其器。开始前需要准备:

  • EC20模块(带SIM卡)
  • USB转TTL串口模块
  • Python 3.8+环境

首先安装核心依赖库:

pip install pyserial==3.5 pandas==1.3.3

创建基础连接类时,建议采用上下文管理器模式确保资源释放:

import serial
from contextlib import contextmanager

class EC20Tester:
    def __init__(self, port, baudrate=115200, timeout=1):
        self.port = port
        self.baudrate = baudrate
        self.timeout = timeout
        
    @contextmanager
    def connect(self):
        try:
            ser = serial.Serial(
                port=self.port,
                baudrate=self.baudrate,
                timeout=self.timeout
            )
            yield ser
        finally:
            if 'ser' in locals():
                ser.close()

注意:不同操作系统下串口名称格式不同,Windows通常为COM3,Linux则为/dev/ttyUSB0

2. 核心AT指令测试框架

构建可复用的指令发送函数需要考虑以下关键点:

  • 指令终止符处理(\r\n)
  • 响应超时机制
  • 结果编码转换
def send_at_command(ser, command, wait_time=1):
    """发送AT指令并获取响应"""
    try:
        ser.write(f"{command}\r\n".encode())
        time.sleep(wait_time)
        response = ser.read_all().decode('utf-8', errors='ignore')
        return {
            'command': command,
            'response': response.strip(),
            'status': 'success'
        }
    except Exception as e:
        return {
            'command': command,
            'error': str(e),
            'status': 'failed'
        }

常用查询指令对照表:

指令 功能 典型响应
AT+CSQ 信号强度 +CSQ: 24,99
AT+CGSN IMEI查询 864475045612345
AT+QCCID SIM卡ID 8986061910000123456
AT+CREG? 网络注册 +CREG: 0,1

3. 关键参数配置实战

模块初始化时需要配置的几个重要参数:

  1. 错误报告等级设置
def set_error_reporting(ser, level=2):
    """配置详细错误报告"""
    return send_at_command(ser, f"AT+CMEE={level}")
  1. 串口流控制配置
def set_flow_control(ser, cts_rts=0):
    """禁用硬件流控制"""
    return send_at_command(ser, f"AT+IFC={cts_rts},{cts_rts}")
  1. DTR信号处理
def set_dtr_handling(ser, mode=0):
    """忽略DTR状态变化"""
    return send_at_command(ser, f"AT&D{mode}")

测试时发现的一个典型问题:某些EC20模块需要先发送ATE0关闭回显,否则响应会包含重复的指令内容。建议在初始化序列中加入:

send_at_command(ser, "ATE0")  # 关闭指令回显

4. 网络状态模拟与异常处理

模拟网络环境变化是测试的重要环节,主要涉及:

  • 强制模块重新注册网络
def trigger_reregistration(ser):
    results = []
    results.append(send_at_command(ser, "AT+COPS=2"))  # 手动注销
    results.append(send_at_command(ser, "AT+COPS=0"))  # 自动注册
    return results
  • 信号强度模拟(需模块支持)
def set_signal_simulation(ser, rssi=20):
    return send_at_command(ser, f'AT+QTESTSET="RSSI",{rssi}')

常见异常及处理方法:

  1. 响应超时
def safe_send_command(ser, command, retries=3):
    for i in range(retries):
        result = send_at_command(ser, command)
        if result['status'] == 'success':
            return result
        time.sleep(2)
    raise TimeoutError(f"Command {command} failed after {retries} retries")
  1. 乱码响应处理
def clean_response(text):
    # 移除不可打印字符
    return ''.join(char for char in text if char.isprintable() or char in '\r\n')

5. 测试报告生成与分析

将测试结果结构化存储便于后续分析:

import pandas as pd

def generate_report(test_results, filename):
    df = pd.DataFrame(test_results)
    df['timestamp'] = pd.Timestamp.now()
    
    # 关键指标提取
    df['passed'] = df['response'].apply(
        lambda x: 'OK' in x if isinstance(x, str) else False
    )
    
    df.to_excel(filename, index=False)
    return df

报告分析时可关注以下指标:

  • 指令平均响应时间
  • 失败指令分类统计
  • 网络注册延迟分布

6. 持续集成集成方案

将测试脚本集成到CI/CD流程中:

# Jenkins Pipeline示例
def test_ec20_module():
    tester = EC20Tester("/dev/ttyUSB0")
    with tester.connect() as ser:
        basic_tests = [
            "AT", "AT+CSQ", "AT+CGSN",
            "AT+QCCID", "AT+CREG?"
        ]
        results = [send_at_command(ser, cmd) for cmd in basic_tests]
        
        if all(r['status'] == 'success' for r in results):
            generate_report(results, "ec20_test_report.xlsx")
            return True
    return False

对于生产线环境,可以扩展以下功能:

  • 模块序列号自动记录
  • 测试结果与工单系统对接
  • 不良品自动分类标记

实战技巧与经验分享

  1. 波特率自适应技巧 某些模块可能需要先以默认波特率连接后才能设置高速波特率:
def adjust_baudrate(ser, target_baudrate):
    send_at_command(ser, f"AT+IPR={target_baudrate}")
    ser.baudrate = target_baudrate
    send_at_command(ser, "AT&W")  # 保存设置
  1. SIM卡状态检测
def check_sim_status(ser):
    result = send_at_command(ser, "AT+CPIN?")
    if "READY" not in result['response']:
        raise ValueError("SIM卡未就绪: " + result['response'])
  1. 温度监控集成
def get_module_temp(ser):
    result = send_at_command(ser, "AT+QTEMP")
    # 响应示例: "+QTEMP: 35"
    return float(result['response'].split(':')[1].strip())

在实际项目中,建议将常用指令封装为高阶API。例如创建一个NetworkManager类,封装所有网络相关操作,这样业务代码只需关注逻辑而非AT指令细节。

更多推荐