我来提供几个可直接运行的真实代码片段,用于调试拨号网络:
1. 基础AT命令交互片段
# dial_basic.py - 基础拨号调试
import serial
import time
import sys
def test_basic_at_commands(port='COM3', baudrate=115200):
"""基本AT命令测试 - 立即运行"""
try:
# 1. 打开串口
ser = serial.Serial(
port=port,
baudrate=baudrate,
bytesize=8,
parity='N',
stopbits=1,
timeout=2,
rtscts=True # 硬件流控
)
print(f"✓ 已连接 {port} @ {baudrate}bps")
# 2. 清空缓冲区
ser.reset_input_buffer()
ser.reset_output_buffer()
time.sleep(0.5)
# 3. 测试基本命令
commands = [
'AT', # 测试连接
'ATE1', # 打开回显
'ATV1', # 详细响应模式
'AT+CGMI', # 制造商
'AT+CGMM', # 型号
'AT+CGMR', # 版本
'AT+CGSN', # IMEI
'AT+CSQ', # 信号强度
'AT+COPS?', # 运营商
'AT+CREG?', # 网络注册
]
for cmd in commands:
print(f"\n[发送] {cmd}")
ser.write((cmd + '\r\n').encode())
# 读取响应
time.sleep(1)
if ser.in_waiting:
response = ser.read(ser.in_waiting).decode('ascii', errors='ignore')
print(f"[响应] {response.strip()}")
time.sleep(0.5)
ser.close()
except Exception as e:
print(f"✗ 错误: {e}")
sys.exit(1)
# 立即运行
if __name__ == "__main__":
# Windows: COM1-COM10, Linux: /dev/ttyUSB0, /dev/ttyACM0
test_basic_at_commands('COM3', 115200)
2. 真实拨号连接片段
# dial_connection.py - 真实拨号连接
import serial
import time
import re
def dial_and_connect(port='COM3', phone_number='*99#'):
"""执行实际拨号连接"""
def send_and_wait(ser, command, wait_for=None, timeout=5):
"""发送命令并等待特定响应"""
print(f">>> {command}")
ser.write((command + '\r\n').encode())
start_time = time.time()
buffer = ""
while time.time() - start_time < timeout:
if ser.in_waiting:
chunk = ser.read(ser.in_waiting).decode('ascii', errors='ignore')
buffer += chunk
print(f"<<< {chunk}", end='')
if wait_for and wait_for in buffer:
return buffer
time.sleep(0.1)
return buffer
try:
# 初始化串口
ser = serial.Serial(port, 115200, timeout=2, rtscts=True)
time.sleep(2)
print("="*50)
print("开始拨号调试流程...")
print("="*50)
# 阶段1: 初始化Modem
print("\n[阶段1] Modem初始化")
send_and_wait(ser, 'ATZ') # 重置
send_and_wait(ser, 'ATE0') # 关闭回显
send_and_wait(ser, 'AT+CFUN=1') # 全功能模式
# 阶段2: 检查网络状态
print("\n[阶段2] 网络状态检查")
send_and_wait(ser, 'AT+CPIN?') # SIM卡状态
send_and_wait(ser, 'AT+CSQ') # 信号强度
send_and_wait(ser, 'AT+CREG?') # 网络注册
send_and_wait(ser, 'AT+CGREG?') # GPRS注册
# 阶段3: 配置PDP上下文 (GPRS/3G/4G)
print("\n[阶段3] 配置数据连接")
send_and_wait(ser, 'AT+CGDCONT=1,"IP","cmnet"') # 设置APN
send_and_wait(ser, 'AT+CGACT=1,1') # 激活PDP
# 阶段4: 实际拨号
print(f"\n[阶段4] 拨号连接: {phone_number}")
response = send_and_wait(ser, f'ATD{phone_number}', 'CONNECT', 30)
# 阶段5: 分析连接结果
if 'CONNECT' in response:
print("\n✅ 拨号连接成功!")
print(f"连接速率: {re.findall(r'CONNECT (\d+)', response)} bps")
# 获取IP地址
send_and_wait(ser, 'AT+CGPADDR=1')
# 进入数据模式(这里可以开始发送PPP帧或TCP数据)
print("\n进入数据模式...")
print("按 Ctrl+C 中断连接")
try:
# 保持连接,监听数据
while True:
if ser.in_waiting:
data = ser.read(ser.in_waiting)
try:
print(data.decode('ascii', errors='ignore'), end='')
except:
print(data.hex(), end=' ')
time.sleep(0.1)
except KeyboardInterrupt:
print("\n用户中断连接")
elif 'NO CARRIER' in response:
print("\n❌ 无载波信号")
elif 'BUSY' in response:
print("\n❌ 线路忙")
elif 'ERROR' in response:
print("\n❌ AT命令错误")
else:
print("\n⚠️ 未知响应")
print(f"完整响应:\n{response}")
# 挂断
print("\n[清理] 挂断连接")
send_and_wait(ser, 'ATH')
ser.close()
except KeyboardInterrupt:
print("\n用户终止程序")
except Exception as e:
print(f"错误: {e}")
sys.exit(1)
if __name__ == "__main__":
# 根据不同运营商修改号码和APN
# 中国移动: *99***1# 或 *99#, APN: cmnet
# 中国联通: *99#, APN: 3gnet
# 中国电信: #777, APN: ctnet
dial_and_connect('COM3', '*99#')
3. PPP拨号调试片段
# ppp_dialer.py - PPP协议拨号调试
import serial
import time
import struct
import binascii
class PPPDebugger:
"""PPP协议调试器"""
def __init__(self, port='COM3'):
self.ser = serial.Serial(port, 115200, timeout=0.1)
self.ppp_state = 'INIT'
def send_ppp_frame(self, protocol, data):
"""发送PPP帧"""
# PPP帧格式: Flag(0x7E) + Address(0xFF) + Control(0x03) + Protocol + Info + FCS + Flag(0x7E)
frame = struct.pack('!BBH', 0xFF, 0x03, protocol) + data
# 计算FCS(简单版本)
fcs = self.calc_fcs(frame)
frame += struct.pack('!H', fcs)
# 字符填充和添加标志位
frame = self.escape_frame(frame)
frame = b'\x7E' + frame + b'\x7E'
self.ser.write(frame)
print(f"发送PPP帧: 协议=0x{protocol:04X}, 长度={len(data)}")
def escape_frame(self, data):
"""PPP字符填充"""
escaped = b''
for byte in data:
if byte == 0x7E:
escaped += b'\x7D\x5E'
elif byte == 0x7D:
escaped += b'\x7D\x5D'
else:
escaped += bytes([byte])
return escaped
def calc_fcs(self, data):
"""计算PPP帧校验序列(简化版)"""
fcs = 0xFFFF
for byte in data:
fcs ^= byte
for _ in range(8):
if fcs & 0x0001:
fcs = (fcs >> 1) ^ 0x8408
else:
fcs >>= 1
return fcs ^ 0xFFFF
def lcp_negotiation(self):
"""LCP协商过程"""
print("开始LCP协商...")
# 发送LCP配置请求
lcp_config = struct.pack('!BBHI', 0x01, 0x01, 0x00, 0x01) # 类型,ID,长度,魔术数
self.send_ppp_frame(0xC021, lcp_config)
# 监听响应
start_time = time.time()
while time.time() - start_time < 10:
if self.ser.in_waiting:
frame = self.ser.read(self.ser.in_waiting)
if b'\x7E' in frame:
print(f"收到PPP帧: {binascii.hexlify(frame).decode()}")
# 解析PPP帧
if frame[0] == 0x7E and frame[-1] == 0x7E:
# 简单的帧解析
print("有效的PPP帧")
break
time.sleep(0.1)
def debug_ppp_session(self):
"""调试PPP会话"""
print("PPP调试模式启动...")
# 1. 发送AT命令建立连接
self.ser.write(b'ATDT*99#\r\n')
time.sleep(3)
# 2. 进入PPP协商
self.lcp_negotiation()
# 3. 监听PPP数据
print("\n监听PPP数据流...")
try:
while True:
if self.ser.in_waiting:
data = self.ser.read(self.ser.in_waiting)
if data:
# 显示为hex和ascii
hex_str = binascii.hexlify(data).decode()
ascii_str = ''.join([chr(c) if 32 <= c < 127 else '.' for c in data])
print(f"HEX: {hex_str[:64]}...")
print(f"ASCII: {ascii_str[:32]}...")
print("-" * 50)
time.sleep(0.5)
except KeyboardInterrupt:
print("结束PPP调试")
if __name__ == "__main__":
debugger = PPPDebugger('COM3')
debugger.debug_ppp_session()
4. 信号质量监控片段
# signal_monitor.py - 实时信号监控
import serial
import time
import re
from collections import deque
import matplotlib.pyplot as plt
import numpy as np
def monitor_signal_quality(port='COM3', duration=300):
"""实时监控信号质量"""
ser = serial.Serial(port, 115200, timeout=1)
signal_history = deque(maxlen=100)
time_history = deque(maxlen=100)
print("开始信号质量监控...")
print("按 Ctrl+C 停止\n")
start_time = time.time()
update_count = 0
try:
# 初始化Modem
ser.write(b'ATE0\r\n')
time.sleep(1)
ser.reset_input_buffer()
while time.time() - start_time < duration:
# 发送CSQ命令
ser.write(b'AT+CSQ\r\n')
time.sleep(1)
# 读取响应
if ser.in_waiting:
response = ser.read(ser.in_waiting).decode('ascii', errors='ignore')
# 解析信号强度
match = re.search(r'CSQ:\s*(\d+),', response)
if match:
rssi = int(match.group(1))
if rssi != 99: # 99表示无效
# 转换为dBm (近似)
if rssi == 0:
dbm = -113
elif 1 <= rssi <= 31:
dbm = -113 + (rssi * 2)
else:
dbm = -51
current_time = time.time() - start_time
signal_history.append(dbm)
time_history.append(current_time)
update_count += 1
# 显示当前信号
bars = '█' * min(rssi, 20)
print(f"[{current_time:6.1f}s] RSSI: {rssi:2d} | {bars:20s} | {dbm:4d} dBm")
# 每10次更新显示统计
if update_count % 10 == 0:
if signal_history:
avg = np.mean(list(signal_history))
std = np.std(list(signal_history))
print(f"统计: 平均={avg:.1f}dBm, 波动={std:.1f}dBm")
print("-" * 50)
time.sleep(2) # 每2秒采样一次
except KeyboardInterrupt:
print("\n监控停止")
finally:
ser.close()
# 绘制信号图
if signal_history:
plt.figure(figsize=(10, 6))
plt.plot(time_history, signal_history, 'b-', linewidth=2)
plt.xlabel('时间 (秒)')
plt.ylabel('信号强度 (dBm)')
plt.title('信号强度历史')
plt.grid(True, alpha=0.3)
plt.savefig('signal_quality.png')
plt.show()
if __name__ == "__main__":
monitor_signal_quality('COM3', duration=60) # 监控60秒
5. 快速测试脚本
# quick_dial_test.py - 一键拨号测试
import serial
import sys
def quick_test():
"""快速测试拨号连接"""
port = input("请输入串口 (默认 COM3): ") or "COM3"
number = input("请输入拨号号码 (默认 *99#): ") or "*99#"
print(f"\n测试配置:")
print(f" 串口: {port}")
print(f" 号码: {number}")
print(f" 波特率: 115200")
print("-" * 40)
try:
ser = serial.Serial(port, 115200, timeout=2)
print("✓ 串口打开成功")
# 发送测试命令
test_cmds = [
'AT',
'AT+CSQ',
'AT+COPS?',
f'ATD{number}',
]
for cmd in test_cmds:
print(f"\n>>> {cmd}")
ser.write((cmd + '\r\n').encode())
# 等待并显示响应
import time
time.sleep(2)
if ser.in_waiting:
response = ser.read(ser.in_waiting).decode('ascii', errors='ignore')
print(f"<<< {response.strip()}")
# 检查是否连接成功
if 'CONNECT' in response:
print("\n✅ 连接成功!")
print("可以开始PPP协商或数据传输")
# 保持连接5秒
time.sleep(5)
# 挂断
ser.write(b'ATH\r\n')
print("连接已挂断")
break
ser.close()
except Exception as e:
print(f"✗ 错误: {e}")
return 1
return 0
if __name__ == "__main__":
sys.exit(quick_test())
使用说明 安装依赖: bash 复制 下载 pip install pyserial matplotlib numpy 确定串口号: Windows:设备管理器查看端口 Linux:ls /dev/tty* 查看设备 运行测试: bash 复制 下载 # 基础AT命令测试 python dial_basic.py # 拨号连接测试 python dial_connection.py # 信号监控 python signal_monitor.py 常见问题解决: 如果提示"Access Denied",可能是串口被其他程序占用 如果无响应,尝试不同的波特率(9600, 19200, 38400, 57600, 115200) GSM/3G/4G Modem需要SIM卡且已开通数据业务 这些代码片段可以直接运行,帮助你真实地调试拨号网络连接!