README.md

RF Power Meter V5.0 — открытая прошивка и приложение управления

Проект для китайского USB RF-измерителя мощности RF_POWER_METER V5.0 (100 кГц - 10 ГГц, -60…0 дБм, детектор AD8317 на STM32F401CC): установка открытой прошивки со SCPI-интерфейсом взамен заводской и написанное с нуля приложение на Python3 + PyQt5 для управления прибором.

Состав репозитория

  • usb_powermeter_firmware/ — форк прошивки iamaiy/usb_powermeter_firmware (Arduino/STM32duino) с доработками: рабочая калибровка и три исправленных бага (подробности ниже). Собственный README форка описывает происхождение и железо.
  • app/ — приложение управления измерителем (PyQt5, интерфейс на русском).
  • NOTES.md — свободные заметки о ходе работы: что делали, что нашли, какие решения почему приняли.

Что изменено в прошивке относительно апстрима

  1. Калибровка заработала. В апстриме CALibration:FREQuency был пустой заглушкой. Добавлена одноточечная калибровка смещения (offset) для дБм/мВт, действует только на сессию (не пишется во флеш, сбрасывается при перезагрузке):

    • CALibration:FREQuency <Гц> / ? — информационная метка частоты калибровочной точки (на саму формулу не влияет).
    • CALibration:POWer <дБм> — подать на вход известную опорную мощность и по текущему свежему отсчёту вычислить смещение; отвечает вычисленным смещением в дБ.
    • CALibration:OFFSet? — текущее применяемое смещение (дБ).
    • CALibration:CLEar — сбросить калибровку.
    • CALibration:STATe? — активна ли калибровка (0/1).
    • Смещение прибавляется только к дБм/мВт; RAW и Volt остаются «сырыми».
  2. Баг напряжения/температуры MCU (SYStem:VOLTage?, было отмечено как “buggy” в апстриме). В setup() строка analogReadResolution(12); была закомментирована. STM32duino по умолчанию отдаёт analogRead() в 10-битной шкале (0-1023), а формула пересчёта опорного напряжения жёстко делит на 4096 (12 бит) — отсюда 4-кратное завышение (реальные 3.3В читались как ~13В). На основной канал детектора (PA1) это не влияло — он настраивается отдельно, явно на 12 бит. Раскомментировано.

  3. TRIGger:SINGLE не останавливал измерение. Команда только выставляла флаг continuous=0, но аппаратный таймер АЦП продолжал свободно тикать — то есть «одиночный» режим ничем не отличался от непрерывного. Теперь TRIGger:SINGLE реально останавливает таймер, а TRIGger:IMMediate запускает его ровно на один (пост-усреднённый) отсчёт и снова останавливает.

  4. DATA:UNIT теперь принимает и имя единицы, и число. В апстриме документация обещала строки (RAW/dBm/mW/Volt), а код по факту понимал только числовой индекс units_t (0-3) — строка молча парсилась как 0 (.toInt() на нечисловой строке). Теперь работает оба варианта.

Сборка и прошивка

Инструменты: arduino-cli (Arduino IDE 2.2.1) и библиотека Vrekrer_scpi_parser.

ACLI=arduino-ide_2.2.1_Linux_64bit/resources/app/lib/backend/resources/arduino-cli
CFG=.arduinoIDE/arduino-cli.yaml
FQBN="STMicroelectronics:stm32:GenF4:pnum=BLACKPILL_F401CC,xserial=generic,usb=CDCgen,xusb=FS,upload_method=swdMethod"

cd usb_powermeter_firmware
$ACLI --config-file $CFG compile --fqbn "$FQBN" --export-binaries .

Прошивка вручную через dfu-util (без проприетарного STM32CubeProgrammer, который используется в инструкции апстрима):

  1. Замкнуть BOOT0 на MCU (на этой плате штатной кнопки/перемычки нет — нужен проводок с 5В на BOOT0-пин, см. README форка прошивки, раздел Bootloader) и подать питание/сбросить — прибор должен определиться как 0483:df11 в lsusb.
  2. dfu-util -l — убедиться, что alt=0 это @Internal Flash /0x08000000/....
  3. Прошить:

    dfu-util -a 0 -s 0x08000000:leave -D build/STMicroelectronics.stm32.GenF4/usb_powermeter_firmware.ino.bin
    
  4. Отсоединить перемычку BOOT0 и переподключить USB — иначе плата снова уйдёт в DFU вместо загрузки прошивки.

Приложение (app/)

Зависимости: PyQt5, pyserial, pyqtgraph (см. app/requirements.txt).

cd app
python3 main.py

Возможности:

  • Подключение по последовательному порту (авто-поиск портов, USB CDC ACM).
  • Идентификация и служебные данные (*IDN?, температура, опорное напряжение, автообновление).
  • Настройка АЦП: интервал/частота дискретизации, число сэмплов пост-усреднения (NAVG).
  • Управление запуском измерения: непрерывно / одиночно / принудительный пуск / стоп.
  • Единицы измерения RAW/дБм/мВт/В, разовое считывание и потоковая передача (DATA:PUSH).
  • Быстрое переключение RAW/дБм и кнопка «Непрерывный сбор и график» (включает continuous + push в один клик).
  • Панель калибровки (см. выше).
  • Живой график (pyqtgraph) с фильтрацией сигнала на стороне приложения — три алгоритма на выбор:
    • Скользящее среднее — простое сглаживание шума, задержка растёт с размером окна.
    • Экспоненциальное (EMA) — быстрее реагирует при том же уровне сглаживания, параметр — коэффициент α.
    • Медианный фильтр — давит одиночные выбросы/помехи, не размывая реальные перепады сигнала.
  • Консоль SCPI для ручной отправки произвольных команд и просмотра сырого потока.

Справочник команд SCPI

*IDN?                            - идентификация прибора
SYStem:TEMPerature?              - температура MCU
SYStem:VOLTage?                  - опорное напряжение MCU (после фикса; было "buggy")
ACQuire:INTerval [мкс] / ?       - интервал дискретизации АЦП
ACQuire:FREQuency [Гц] / ?       - частота дискретизации АЦП (жёстко ограничена 50000 Гц прошивкой;
                                    это НЕ частота измеряемого ВЧ-сигнала, а скорость опроса детектора)
ACQuire:NAVG [N] / ?             - число сэмплов пост-усреднения
CALibration:FREQuency [Гц] / ?   - метка частоты калибровочной точки (информационная)
CALibration:POWer <дБм>          - калибровка по опорной мощности; отвечает вычисленным смещением
CALibration:OFFSet?              - текущее смещение (дБ)
CALibration:CLEar                - сбросить калибровку
CALibration:STATe?               - активна ли калибровка (0/1)
TRIGger:CONTinuous [0|1] / ?     - непрерывный запуск
TRIGger:SINGLE / ?               - одиночный режим (арм)
TRIGger:IMMediate                - пуск (в одиночном режиме — ровно один отсчёт)
TRIGger:STOP                     - стоп
DATA:UNIT [RAW|dBm|mW|Volt|0-3] / ? - единицы (принимает имя и число)
DATA:FETCH?                      - разовое считывание ("P: <знач> T: <мкс>" либо "NREADY: n/N")
DATA:PUSH <0|1>                  - потоковая передача отсчётов по мере готовности

Известные особенности

  • Калибровка не сохраняется между перезагрузками устройства (сознательное решение — проще и без риска износа флеш-памяти).
  • После TRIGger:IMMediate первый отсчёт иногда приходит не мгновенно (до ~0.3 с) — особенность родного ADC-драйвера производителя (my_analog.cpp), не трогали.
  • Абсолютная точность дБм/мВт зависит от констант slope/intercept в AD8317_format(), подобранных автором прошивки без калибровки под конкретный экземпляр платы и частоту — используйте CALibration:POWer для компенсации смещения на нужной частоте.
Описание
Проект для китайского USB RF-измерителя мощности RF_POWER_METER V5.0 (100 кГц - 10 ГГц, -60...0 дБм
Конвейеры
0 успешных
0 с ошибкой
Разработчики