
1、介绍
电子指南针罗盘模块是基于磁传感与姿态解算技术的高精度感知组件,核心功能为精准输出航向角(精度士0.5°~士2)与设备姿态数据,广泛适配消费电子、智能穿戴、无人机、车载设备等场景。模块集成高灵敏度传感器与抗干扰校准算法,支持I2C/SPI等主流通信协议,具备宽电压适配、高低温稳定工作(-40°C~85°C)及低功耗特性,可快速与各类智能设备集成,为其提供可靠的方向定位与姿态反馈能力,是实现设备“空间感知”的核心组件。
2、原理图

3、模块参数
引脚名称 | 描述 |
|---|---|
G | GND(电源输入负极) |
V | VCC(电源输入正极) |
SDA | 数据引脚 |
SCL | 时钟引脚 |
供电电压: 3.3V-5V
连接方式:PH2.0 4P端子线
安装方式:乐高搭建
4、电路板尺寸

5、添加Arduino库文件
不会使用库文件的参考这里:参考链接
库文件下载:点击下载
米思齐库文件下载步骤(使用代码前前下载米思齐库文件):
不会安装库文件的请点击这里:参考链接
6、添加MicroPython环境库文件
米思齐库文件下载步骤(使用代码前前下载米思齐库文件):
不会安装库文件的请点击这里:参考链接
7、Arduino IDE示例程序
示例程序(UNO开发板):点击下载
#include <QMC5883LCompassSoft.h>
#include <SoftwareWire.h>
SoftwareWire softWire6_5(6, 5);
QMC5883LCompassSoft compass(&softWire6_5);
void setup(){
compass.init();
Serial.begin(9600);
}
void loop(){
compass.read();Serial.println(String("方位角:") + String(compass.getAzimuth()));
delay(100);
}示例程序(ESP32开发板——python代码不适用Arduino环境):
import time
import math
from machine import I2C, Pin
import sys
QMC5883L_ADDR = 0x0D
QMC5883L_REG_OUT_X_L = 0x00
QMC5883L_REG_CTRL1 = 0x09
QMC5883L_REG_CTRL2 = 0x0A
QMC5883L_REG_FBR = 0x0B
QMC5883L_MODE_CONTINUOUS = 0b00000001
QMC5883L_ODR_200HZ = 0b00001100
QMC5883L_RNG_8G = 0b00010000
QMC5883L_OSR_512 = 0b00000000
_BEARINGS = (
(' ', ' ', 'N'), ('N', 'N', 'E'), (' ', 'N', 'E'), ('E', 'N', 'E'),
(' ', ' ', 'E'), ('E', 'S', 'E'), (' ', 'S', 'E'), ('S', 'S', 'E'),
(' ', ' ', 'S'), ('S', 'S', 'W'), (' ', 'S', 'W'), ('W', 'S', 'W'),
(' ', ' ', 'W'), ('W', 'N', 'W'), (' ', 'N', 'W'), ('N', 'N', 'W'),
)
def _to_signed_16bit(val):
if val > 32767:
return val - 65536
return val
class QMC5883LCompassSoft:
def __init__(self, i2c: I2C):
self._i2c = i2c
self._ADDR = QMC5883L_ADDR
self._smooth_use = False
self._smooth_steps = 5
self._smooth_advanced = False
self._vRaw = [0, 0, 0]
self._vHistory = [[0, 0, 0] for _ in range(10)]
self._vScan = 0
self._vTotals = [0.0, 0.0, 0.0]
self._vSmooth = [0, 0, 0]
self._calibration_use = False
self._vCalibration = [[0, 0], [0, 0], [0, 0]]
self._vCalibrated = [0, 0, 0]
def _write_reg(self, reg, val):
try:
self._i2c.writeto(self._ADDR, bytes([reg, val]))
except Exception as e:
print(f"I2C Write Error to {reg}: {e}")
def _read_raw(self):
try:
data = self._i2c.readfrom_mem(self._ADDR, QMC5883L_REG_OUT_X_L, 6)
x_raw_unsigned = int.from_bytes(data[0:2], 'little', False)
y_raw_unsigned = int.from_bytes(data[2:4], 'little', False)
z_raw_unsigned = int.from_bytes(data[4:6], 'little', False)
self._vRaw[0] = _to_signed_16bit(x_raw_unsigned)
self._vRaw[1] = _to_signed_16bit(y_raw_unsigned)
self._vRaw[2] = _to_signed_16bit(z_raw_unsigned)
return True
except Exception as e:
return False
def init(self):
self._write_reg(QMC5883L_REG_FBR, 0x01)
self.setMode(QMC5883L_MODE_CONTINUOUS, QMC5883L_ODR_200HZ, QMC5883L_RNG_8G, QMC5883L_OSR_512)
def setMode(self, mode, odr, rng, osr):
"""Set the chip mode, ODR, RNG, and OSR."""
control_val = mode | odr | rng | osr
self._write_reg(QMC5883L_REG_CTRL1, control_val)
def setSmoothing(self, steps: int, adv: bool):
"""Set smoothing parameters (steps 1-10)."""
self._smooth_use = True
self._smooth_steps = min(max(1, steps), 10)
self._smooth_advanced = adv
def setCalibration(self, x_min, x_max, y_min, y_max, z_min, z_max):
"""Set calibration values (Hard and Soft Iron Compensation)."""
self._calibration_use = True
self._vCalibration[0] = [x_min, x_max]
self._vCalibration[1] = [y_min, y_max]
self._vCalibration[2] = [z_min, z_max]
def _applyCalibration(self):
"""Applies hard-iron offset and soft-iron scaling."""
x_min, x_max = self._vCalibration[0]
y_min, y_max = self._vCalibration[1]
z_min, z_max = self._vCalibration[2]
x_offset = (x_min + x_max) / 2
y_offset = (y_min + y_max) / 2
z_offset = (z_min + z_max) / 2
x_avg_delta = (x_max - x_min) / 2
y_avg_delta = (y_max - y_min) / 2
z_avg_delta = (z_max - z_min) / 2
x_avg_delta = x_avg_delta if x_avg_delta != 0 else 1.0
y_avg_delta = y_avg_delta if y_avg_delta != 0 else 1.0
z_avg_delta = z_avg_delta if z_avg_delta != 0 else 1.0
avg_delta = (x_avg_delta + y_avg_delta + z_avg_delta) / 3
x_scale = avg_delta / x_avg_delta
y_scale = avg_delta / y_avg_delta
z_scale = avg_delta / z_avg_delta
self._vCalibrated[0] = int((self._vRaw[0] - x_offset) * x_scale)
self._vCalibrated[1] = int((self._vRaw[1] - y_offset) * y_scale)
self._vCalibrated[2] = int((self._vRaw[2] - z_offset) * z_scale)
def _smoothing(self):
"""Rolling average and optional min/max removal."""
if self._vScan >= self._smooth_steps:
self._vScan = 0
current_data = self._vCalibrated if self._calibration_use else self._vRaw
for i in range(3):
old_val = self._vHistory[self._vScan][i]
new_val = current_data[i]
self._vTotals[i] -= old_val # Safe even if old_val is 0 initially
self._vHistory[self._vScan][i] = new_val
self._vTotals[i] += new_val
current_window = [self._vHistory[j][i] for j in range(self._smooth_steps)]
if self._smooth_advanced:
max_val = max(current_window)
min_val = min(current_window)
divisor = self._smooth_steps - 2
if divisor > 0:
self._vSmooth[i] = int((sum(current_window) - max_val - min_val) / divisor)
else: # steps <= 2
self._vSmooth[i] = int(sum(current_window) / self._smooth_steps)
else:
self._vSmooth[i] = int(self._vTotals[i] / self._smooth_steps)
self._vScan += 1
def read(self):
"""Reads the sensor and applies calibration/smoothing."""
if self._read_raw():
if self._calibration_use:
self._applyCalibration()
if self._smooth_use:
self._smoothing()
return True
return False
def _get_axis_value(self, i):
"""Get the final value (smoothed, calibrated, or raw)."""
if self._smooth_use:
return self._vSmooth[i]
if self._calibration_use:
return self._vCalibrated[i]
return self._vRaw[i]
def getX(self):
return self._get_axis_value(0)
def getY(self):
return self._get_axis_value(1)
def getZ(self):
return self._get_axis_value(2)
def getAzimuth(self):
x = self.getX()
y = self.getY()
if x == 0 and y == 0:
return 0
a = math.atan2(y, x) * 180.0 / math.pi
return int(360 + a) if a < 0 else int(a)
def getBearing(self, azimuth: int):
return int(round(azimuth / 22.5)) % 16
def getDirection(self, azimuth: int):
d = self.getBearing(azimuth)
return _BEARINGS[d]
i2c = I2C(1, scl=Pin(22), sda=Pin(21), freq=400000)
compass = QMC5883LCompassSoft(i2c)
compass.init()
compass.setSmoothing(5, False)
import machine
import time
while True:
compass.read()
value = compass.getAzimuth()
print(value)
time.sleep(1)
8、米思齐 Mixly 示例程序(图形化语言)
示例程序(UNO开发板):点击下载

示例程序(ESP32开发板):点击下载

9、测试环境搭建
Arduino UNO 测试环境搭建
准备配件:
UNO-R3 开发板 *1
UNO-R3 EXP 扩展板 *1
USB type-c 数据线 *1
HS-S75-L 电子罗盘模块*1
PH2.0 4P双头端子线 *1
电路接线图:

ESP32 Python 测试环境搭建
10、视频教程
Arduino UNO视频教程:
ESP32 Python视频教程:
11、测试结论
Arduino UNO测试结论:



上传代码后根据串口打印的数值来判断方向。