Вторая жизнь старому стрелочному мультиметру

Бывает, что у радиолюбителей есть старый стрелочный мультиметр советских времен, лежит где-то далеко на полке. По прямому назначению его уже использовать не хочется, а выкинуть жалко. Так и лежит. В этой статье мы сделаем его модернизацию, а именно – добавим USB, для возможности анализа данных и построения графиков.

Вторая жизнь старому стрелочному мультиметру Мультиметр, Новая жизнь старых вещей, Схемотехника, Микроконтроллеры, Arduino, Stm32, Delphi, Программирование, Видео, Длиннопост
Вторая жизнь старому стрелочному мультиметру Мультиметр, Новая жизнь старых вещей, Схемотехника, Микроконтроллеры, Arduino, Stm32, Delphi, Программирование, Видео, Длиннопост

Из курса школьной физики вспоминаем принцип работы такого измерительного прибора – ток течет по обмотке, находящейся в магнитном поле, пытается покрутиться и отклоняет стрелку. Первым делом вскрываем мультиметр и смотрим на подключение стрелки.

Вторая жизнь старому стрелочному мультиметру Мультиметр, Новая жизнь старых вещей, Схемотехника, Микроконтроллеры, Arduino, Stm32, Delphi, Программирование, Видео, Длиннопост

Подаем ему на измерение напряжение с потенциометра, а другим мультиметром снимаем напряжение между каждым проводом от стрелки и общим. Данные заносим в табличку и строим график.

Вторая жизнь старому стрелочному мультиметру Мультиметр, Новая жизнь старых вещей, Схемотехника, Микроконтроллеры, Arduino, Stm32, Delphi, Программирование, Видео, Длиннопост

Выбираем провод с более резким наклоном прямой. В моем случае получилось что при максимальном отклонении стрелки напряжение равно 96,4 мВ. Для оцифровки микроконтроллером мало, но ничего страшного, это напряжение можно усилить операционным усилителем. Подойдет любой ОУ, я взял LM2904, просто потому что у меня такой был. Смотрим документ на микросхему – два ОУ в одном корпусе, максимальное выходное напряжение Vcc-1.5v. Запитывать будем от 3.3 вольт, значит надо подобрать коэффициенты усиления так, чтобы при зашкаливающей стрелке ОУ выдавал максимально возможное напряжение.

Вторая жизнь старому стрелочному мультиметру Мультиметр, Новая жизнь старых вещей, Схемотехника, Микроконтроллеры, Arduino, Stm32, Delphi, Программирование, Видео, Длиннопост

Готово. Первый каскад усиливает напряжение со стрелки мультиметра в 10 раз, второй каскад усиливает выход первого в зависимости от настройки потенциометра. Для тестов я собрал все на старом кусочке текстолита.

Вторая жизнь старому стрелочному мультиметру Мультиметр, Новая жизнь старых вещей, Схемотехника, Микроконтроллеры, Arduino, Stm32, Delphi, Программирование, Видео, Длиннопост

Проверяем напряжение на выходе усилителя при разных положениях стрелки. Нужно настроить так, чтобы когда стрелка зашкаливает, напряжение продолжало увеличиваться пока она не упрется в ограничитель хода. Теперь это напряжение надо оцифровать. Я взял китайскую платку с STM, купленную на Али.

Вторая жизнь старому стрелочному мультиметру Мультиметр, Новая жизнь старых вещей, Схемотехника, Микроконтроллеры, Arduino, Stm32, Delphi, Программирование, Видео, Длиннопост

На борту у нее микроконтроллер STM32F103C8T6. Есть АЦП и USB. Подходит. Для первоначальной настройки предлагаю воспользоваться STM32CubeMX. Включаем тактирование, настраиваем кварцевые резонаторы.

Вторая жизнь старому стрелочному мультиметру Мультиметр, Новая жизнь старых вещей, Схемотехника, Микроконтроллеры, Arduino, Stm32, Delphi, Программирование, Видео, Длиннопост

Включаем и настраиваем АЦП, не забываем про прерывание по готовности.

Вторая жизнь старому стрелочному мультиметру Мультиметр, Новая жизнь старых вещей, Схемотехника, Микроконтроллеры, Arduino, Stm32, Delphi, Программирование, Видео, Длиннопост

АЦП будет запускаться по событию таймера, настраиваем таймер.

Вторая жизнь старому стрелочному мультиметру Мультиметр, Новая жизнь старых вещей, Схемотехника, Микроконтроллеры, Arduino, Stm32, Delphi, Программирование, Видео, Длиннопост

Таймер тактируется частотой 48 МГц, с предделителем 24 и периодом 2000 получится, что он будет запускать АЦП каждую 1 мс. В принципе так часто нет смысла, но мы будем использовать усреднение значений, поэтому пусть будет. Включаем USB, выбираем Custom HID.

Вторая жизнь старому стрелочному мультиметру Мультиметр, Новая жизнь старых вещей, Схемотехника, Микроконтроллеры, Arduino, Stm32, Delphi, Программирование, Видео, Длиннопост

Генерируем проект и переходим к написанию кода. Я использовал System Workbench for STM32. Добавляем в «main.c» запуск таймера и АЦП, и несколько глобальных переменных.


/* USER CODE BEGIN PV */

//uint16_t adc_arr[ADC_MAX_CONVERSATIONS];

uint16_t adc_to_send;

uint32_t adc_sum;

uint8_t adc_counter;

uint8_t send_flag;

volatile uint16_t x;

/* USER CODE END PV */

/* USER CODE BEGIN 2 */

HAL_ADC_Start(&hadc1);

HAL_ADC_Start_IT(&hadc1);

HAL_TIM_Base_Start(&htim3);

/* USER CODE END 2 */


В прерывании прибавляем к переменной значение с АЦП и увеличиваем счетчик. Когда счетчик достигнет 200, усредняем значение и перекладываем в буфер для отправки по USB. Поднимем флаг, что пора отправлять.


/* USER CODE BEGIN 4 */

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc){

adc_sum+=HAL_ADC_GetValue(hadc);

adc_counter++;

if(adc_counter==ADC_MAX_CONVERSATIONS){

HAL_GPIO_TogglePin(LD_1_GPIO_Port,LD_1_Pin);

adc_to_send=adc_sum/ADC_MAX_CONVERSATIONS;

adc_counter=0;

adc_sum=0;

send_flag=1;

}

}

/* USER CODE END 4 */


В основном цикле все время проверяем флаг, если поднят опускаем и отправляем буфер. Получится что мы будем отправлять значения каждые 200 мс.


/* USER CODE BEGIN WHILE */

while (1)

{

// HAL_GPIO_TogglePin(LD_1_GPIO_Port,LD_1_Pin);

if(send_flag){

send_flag=0;

..USB_Send_report(adc_to_send);

}

/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */

}


Дескриптор USB устройства уже создался стм кубом, его трогать не будем, только проверим интервал опроса, должно быть не больше наших 200 мс.


/* 34 */

0x07, /* bLength: Endpoint Descriptor size */

USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: */

CUSTOM_HID_EPOUT_ADDR, /*bEndpointAddress: Endpoint Address (OUT)*/

0x03, /* bmAttributes: Interrupt endpoint */

CUSTOM_HID_EPOUT_SIZE, /* wMaxPacketSize: 2 Bytes max */

0x00,

0x20, /* bInterval: Polling Interval (20 ms) */

/* 41 */


Далее составим «HID Report» дескриптор в программке HID Descriptor Tool.

Вторая жизнь старому стрелочному мультиметру Мультиметр, Новая жизнь старых вещей, Схемотехника, Микроконтроллеры, Arduino, Stm32, Delphi, Программирование, Видео, Длиннопост

Тут мы говорим, что наше устройство сообщает температуру в комнате (Usage). Report Size=8 и Report Count=4 означают, что 32 бита посылается от устройства к компьютеру (Input) и столько же от компьютера к устройству (Output). Нам из этого всего понадобится только 2 байта, остальное на будущее. Сохраняем как заголовочный файл, и копируем в наш код (куб там оставил место в файле usbd_custom_hid_if.c). Так же надо проверить соответствие размеров репорт дескриптора 35 байт и размер буфера под отправку (тут должно быть 5 байт, потому что мы еще указали Report ID – это еще 1 байт в самом начале). Прошьем и проверим, что устройство правильно определилось в системе.

Вторая жизнь старому стрелочному мультиметру Мультиметр, Новая жизнь старых вещей, Схемотехника, Микроконтроллеры, Arduino, Stm32, Delphi, Программирование, Видео, Длиннопост

Раскомментируем функцию отправки в файле «usbd_custom_hid_if.c» и заполняем, указав первым байтом Report ID, дальше наше значение АЦП.


/* USER CODE BEGIN 7 */

/**

* @brief Send the report to the Host

* @Param report: The report to be sent

* @Param len: The report length

* @retval USBD_OK if all operations are OK else USBD_FAIL

*/

static uint8_t USBD_CUSTOM_HID_SendReport_FS(uint8_t *report, uint16_t len)

{

return USBD_CUSTOM_HID_SendReport(&hUsbDeviceFS, report, len);

}

uint8_t USB_Send_report(uint16_t data){

Rep_buffer[0]=0x01;//report id

Rep_buffer[1]=data>>8;

Rep_buffer[2]=data;

Rep_buffer[3]=0xFF;

Rep_buffer[4]=0xFF;

return USBD_CUSTOM_HID_SendReport_FS(Rep_buffer,5);

}

/* USER CODE END 7 */


Проверяем в какой-нибудь утилитке что пакеты действительно идут.

Вторая жизнь старому стрелочному мультиметру Мультиметр, Новая жизнь старых вещей, Схемотехника, Микроконтроллеры, Arduino, Stm32, Delphi, Программирование, Видео, Длиннопост

Осталось написать программку под Windows, которая бы все это обрабатывала. Берем любимую среду программирования и библиотеку для работы с HID устройствами. Я взял старенькую Delphi 7 и библиотеку компонентов JEDI VCL. Из нее нужны «TJvHidDeviceController» и «TJvHidDevice». Добавляем обработчик «OnEnumerate» у девайс контроллера, в него по очереди прилетают все HID устройства при вызове энумерации. Остается отфильтровать наше устройство по VID и PID, затем связать с компонентом «TJvHidDevice».


function TUSBMeter.HidControllerEnumerate(HidDev: TJvHidDevice; const Idx: Integer): Boolean;

begin

if (IntToHex(HidDev.Attributes.VendorID,4)=VID)and

(IntToHex(HidDev.Attributes.ProductID,4)=PID) then

begin

if (HidDev.Caps.OutputReportByteLength=OUT_REPORT_COUNT_AMPERAGE) then

HidController.CheckOutByIndex(HidAmperage,Idx);

usb_ready:=true;

end;

Result := True;

end;


Данные будут приходить в обработчик «OnDeviceData». В нем вычисляем из посылки значение АЦП и выводим куда-нибудь для проверки.


procedure TUSBMeter.HidControllerDeviceData(HidDev: TJvHidDevice; ReportID: Byte; const Data: Pointer; Size: Word);


var

buf:^byte;

begin

if (IntToHex(HidDev.Attributes.VendorID,4)<>VID)or((IntToHex(HidDev.Attributes.ProductID,4)<>PID)) then exit;

buf:=Data; // rep

adc_abs:=buf^;

adc_abs:= adc_abs shl 8;

inc(buf);

adc_abs:=adc_abs+(buf^);

inc(buf);

callback;

end;


Теперь надо сделать пересчет, добавим на форму RadioGroup и настроим как на переключателе мультиметра. Я не стал добавлять шкалу сопротивлений, не нужна.

Вторая жизнь старому стрелочному мультиметру Мультиметр, Новая жизнь старых вещей, Схемотехника, Микроконтроллеры, Arduino, Stm32, Delphi, Программирование, Видео, Длиннопост

Заведем так же масштабирующий массив для пересчета и массив с единицами измерений.


const

scale_arr: array[1..18] of real = (600,300,150,60,30,15,6,3,0.75,1500,300,60,15,3,0.6,0.12,0.000012,1);

scale_arr_symb: array[1..18] of string[2] = ('V','V','V','V','V','V','V','V','V','mA','mA','mA','mA','mA','mA','mA','uA','');


Для пересчета еще понадобятся два граничных значения acd_min и adc_max. Подключаем потенциометр к мультиметру, выставляем стрелку на 0 и смотрим, что присылается в программу. Если тоже 0 – хорошо, если нет – не беда, подкорректируем. Потом выставляем стрелку на максимум и так же смотрим. Важно чтобы когда стрелка «зашкаливала» значение продолжало увеличиваться, так будет запас. Если этого нет, надо подкрутить потенциометр ОУ. У меня получилось 0 и 2365. Пересчитываем и выводим уже на основное табло.


procedure TMainForm.HID_Callback;

var

s:string;

buf:string;

rec_s:string;

begin

s:=floattostr(((meter.ADC-adc_min)/(adc_max-adc_min))*scale_arr[RadioGroup1.ItemIndex+1]);

buf:=copy(s,1,5);

buf[pos(',',buf)]:='.';

Label2.Caption:=buf;

end;

Вторая жизнь старому стрелочному мультиметру Мультиметр, Новая жизнь старых вещей, Схемотехника, Микроконтроллеры, Arduino, Stm32, Delphi, Программирование, Видео, Длиннопост
Вторая жизнь старому стрелочному мультиметру Мультиметр, Новая жизнь старых вещей, Схемотехника, Микроконтроллеры, Arduino, Stm32, Delphi, Программирование, Видео, Длиннопост
Вторая жизнь старому стрелочному мультиметру Мультиметр, Новая жизнь старых вещей, Схемотехника, Микроконтроллеры, Arduino, Stm32, Delphi, Программирование, Видео, Длиннопост

Большая часть готова, теперь надо прикрутить запись в файл, страницу настроек с сохранением и красивый GUI. Формат файла я взял CSV, так как из него будет легко строить графики в Экселе.

Вторая жизнь старому стрелочному мультиметру Мультиметр, Новая жизнь старых вещей, Схемотехника, Микроконтроллеры, Arduino, Stm32, Delphi, Программирование, Видео, Длиннопост
Вторая жизнь старому стрелочному мультиметру Мультиметр, Новая жизнь старых вещей, Схемотехника, Микроконтроллеры, Arduino, Stm32, Delphi, Программирование, Видео, Длиннопост
Вторая жизнь старому стрелочному мультиметру Мультиметр, Новая жизнь старых вещей, Схемотехника, Микроконтроллеры, Arduino, Stm32, Delphi, Программирование, Видео, Длиннопост
Вторая жизнь старому стрелочному мультиметру Мультиметр, Новая жизнь старых вещей, Схемотехника, Микроконтроллеры, Arduino, Stm32, Delphi, Программирование, Видео, Длиннопост
Вторая жизнь старому стрелочному мультиметру Мультиметр, Новая жизнь старых вещей, Схемотехника, Микроконтроллеры, Arduino, Stm32, Delphi, Программирование, Видео, Длиннопост

Все, готово. Осталось собрать все в корпус мультиметра, свободного места там полно. Прорезать отверстие под USB шнурок и убрать обратно на самую дальнюю полку до тех пор, пока не понадобится снять долгий график разряда аккумулятора или график потребления тока каким-нибудь устройством.


Надеюсь, кому-нибудь будет полезно.

6
Автор поста оценил этот комментарий
Это круто
раскрыть ветку (1)
4
Автор поста оценил этот комментарий

Спасибо

6
Автор поста оценил этот комментарий

Точной схемы подключения я в посте не увидел. Но вангую, что один из щупов мультиметра у тебя получился соединенным с USB землей. Которая в свою очередь соединена с корпусом компьютера. А теперь подумай, что произойдет если ты решишь этим мультиметров ткнуться в розетку? С некоторой долей везения ты попадаешь этим соединенным с землей щупом в фазу и у тебя весь корпус оказывается под напряжение. Ты касаешься корпуса компьютера и получаешь целительных заряд электричества.

раскрыть ветку (1)
2
Автор поста оценил этот комментарий

Да, так и есть. Общий мультиметра соединен с общим usb и соответственно корпусом ПК. Но работать модифицированным прибором с переменкой, тем более сетью 220 я не буду. Теперь надо учитывать что общий соединен с землей, даже если щуп не подключен никуда. Какие варианты развязки можете предложить кстати?

показать ответы
Автор поста оценил этот комментарий

Погромирование сам изучал?

раскрыть ветку (1)
Автор поста оценил этот комментарий

Да

4
Автор поста оценил этот комментарий

Я описал только один из вариантов. Отсутствие гальванической развязки может в разных местах аукнуться. Предположим ты работаешь с устройством которое питается от USB порта того же компьютера. Ты касаешься земляным щупом земли и получаешь земляную петлю которая тут же начинает давать помехи. А потом ты решаешь измерить падение напряжения на резисторе. Ты цепляешься щупами к выходу этого резистора и бонусом получаешь что выход этого резистора через мультиметр содится на землю. Если этот транзистор и так сидел на земле ничего страшного. А если он например ведет на базу транзистора, то подключение мультиметра, который в теории ни как не должен влиять на схему, внезапно начинает оказывать. Причем вплоть до коротного замыкания.


И как бы да, можно сказать "сеть я менять не буду", устройства питающиеся от того же USB я мерять не буду, и еще много разных вещей которые "я делать не буду". Но имхо это заряженное ружье на стене. Сегодня ты вроде бы этого не планировал, а завтра потребовалось а об этом подвохе ты уже забыл.


В промышленных мультиметрах делают самым недежным образом. Ставят две пары светод + фотодиод и через них пробрасывают USART. Можно чуть проще поступить и поставить оптроны. Можно как вариант ADUM4160.

раскрыть ветку (1)
Автор поста оценил этот комментарий

"Теперь надо учитывать что общий соединен с землей, даже если щуп не подключен никуда."
Ну а вообще, если развязка станет необходима, можно подключить вход усилителя к одному выходу обмотки стрелки, землю  к другому, так входы мультиметра не будут контактировать, а ОУ будет усиливать падение напряжения на обмотке стрелки. Поставить DC-DC источник B0505S для развязки питания и через пару оптронов организовать USART с микрухой FTDI, а она уже будет подключаться к компу и имитировать COM-порт. Потом дописать в программу поддержку COM-порта, это даже легче чем HID. Вроде все, развязано.

показать ответы
4
Автор поста оценил этот комментарий

и опять USB без гальваноразвязки.... комп не жалко?

раскрыть ветку (1)
Автор поста оценил этот комментарий

Для чего развязка? Объясните, пожалуйста.

показать ответы