Товары из Китая

Victor VC921 в домашней автоматизированной лаборатории


  • Цена: 8.24 евро
  • Сегодня будет суперзапоздавший обзор тестера, уже много лет валявшегося в дальнем углу абсолютно без дела. Предпримем попытку расширить нашу автоматизированную домашнюю лабораторию и подключим дешевый тестер к системе на базе Labview.

    Телега сильно забежала впереди лошади — у меня был запланирован обзор одного прибора и половина статьи, касающейся установки и использования Labview вполне легально, уже написана, а прибор еще где-то идет, и на разработку виртуальных инструментов для этого прибора и дописывания обзора понадобится еще неделя-другая после получения. Последовательность оказалось перепутана. Пояснения, если кому они нужны, будут в моем следующем обзоре.

    Для начала — хорошие обзоры на этот тестер здесь уже есть, первый и второй, повторяться не буду. Это не все — я насчитал здесь 4 обзора на этот тестер.

    Если есть много денег и большая нужда, конечно, самый простой вариант поставить на полочку штуки 2-3 старых добрых мультиметра 6.5 Hewlett-Packard HP 34401A, который вроде как Agilent сейчас кличут, парочку источников-измерителей Keithley 24xx с последними циферками по вашему вкусу, несколько программируемых источников питания — все это соединить IEEE-488 (Hewlett-Packard Interface Bus в девичестве).

    Victor VC921 в домашней автоматизированной лаборатории

    Всего этого добра не нашлось, зато нашелся Victor VC921, который я купил лет 6 тому назад за 8.24 евро на Али.

    Victor VC921 в домашней автоматизированной лаборатории

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

    Victor VC921 в домашней автоматизированной лаборатории

    С тех пор клиент уехал, гипс сняли и даже магазин больше не существует.

    Если пойдете по этой кривой дорожке — имейте в виду, что этот тестер в большинстве случаев уже не торт — внешне выглядит так же, но нутро другое.

    Вид снизу:

    Victor VC921 в домашней автоматизированной лаборатории

    и сверху:

    Victor VC921 в домашней автоматизированной лаборатории

    На правильном тестере должна быть надпись True RMS. Но написать можно что угодно, более надежный критерий — если открыть отсек с батарейками, на печатной плате должно быть видно 2 контактных площадки для кнопок.

    Victor VC921 в домашней автоматизированной лаборатории

    Хотел бы еще один для системы такой найти — но дешево уже нет. И еще бы в довесок пару тестеров с измерением тока и температуры — у Victor VC921 таких возможностей нет, из полезного для меня — только напряжение и сопротивление. Может, у кого есть на примете подходящие недорогие варианты? — но похоже, что Victor брать смысла уже нет, за такую цену, как у него сейчас, лучше уже что-то с измерением тока найти.

    Фотографировал тестер на окне — а тут кошка Рыжик отдыхает, на вид очень счастливая кошка. Обойти и не сфотографировать ее было просто невозможно.

    Victor VC921 в домашней автоматизированной лаборатории

    Тем более так беззаботна она бывает очень редко — кошка очень тяжело болеет, ветеринары ее больше трех лет назад приговорили. Несколько раз в году у нее какой-то приступ кошачьей неврологии случается — при этом она не может глотать несколько дней подряд, хотя кушать очень хочет. Если не заталкивать кусочки мяса прямо в горло — умрет от голода. На этот раз уже больше двух недель все это длится и никак кошке лучше не становится.

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

    Совпадение или мистика? Не знаю.

    Ладно, вернемся к предмету обзора. Тестер сделан на базе широко известной в узких кругах DTM0660, у которой конфигурация и калибровки хранятся в 24C02. Нужно изменить один битик, чтобы включить последовательный протокол и заодно выключить автовыключение — для работы в составе автоматизированной системы это нам даром не надь. Идея была позаимствована отсюда.

    Victor VC921 в домашней автоматизированной лаборатории

    Victor VC921 в домашней автоматизированной лаборатории

    Чтобы не извращаться с выпаиванием EEPROM, самый простой вариант — закоротить кварц резистором на несколько десятков ом, процессор успокоится и мешать делать вам свое дело не будет. Теперь одеваем прищепку на 24C02 и меняем наши битики. Не используйте чужую прошивку — калибровка, если она делалась, вещь индивидуальная и будет сбита.

    Victor VC921 в домашней автоматизированной лаборатории

    Оригинальное содержимое EEPROM:

    Victor VC921 в домашней автоматизированной лаборатории

    и модифицированное:

    Victor VC921 в домашней автоматизированной лаборатории

    После этого на 20 ноге после долгого нажатия клавиши REL появится какая-то информация.

    Victor VC921 в домашней автоматизированной лаборатории

    По наивности считал, что это будет удобоваримая посылка, которую будет легко использовать. Зря радовался — с логическим анализатором удалось определить, что это обычный последовательной интерфейс, скорость обмена 2400 бод, в пакете 15 байт и пакет посылается 10 раз в секунду.

    Victor VC921 в домашней автоматизированной лаборатории

    Пришлось рыться в интернете — но все-таки нашел, и это похоже на бред — вместо того, чтобы отправить измеренную величину, DTM0660 отправляет состояние сегментов дисплея.

    Victor VC921 в домашней автоматизированной лаборатории

    Пришлось вытаскивать Ардуину и писать декодер наоборот — изображение 7-сегментного дисплея превращать в измеряемую величину.

    Victor VC921 в домашней автоматизированной лаборатории

    Дабы мозги понапрасну не напрягать, нашел готовый алгоритм распознавания цифр с семисегментника:

    Victor VC921 в домашней автоматизированной лаборатории

    Код ниже — но это только, чтобы понять как все работает. Старался писать как можно проще, ничего не оптимизируя, чтобы алгоритм был максимально понятен.

    Дополнительная информация
    
    
    #include <Arduino.h>
    #include <SoftwareSerial.h>
    uint8_t DiplayNums[4];
    uint32_t DisplayFlags;
    // 0 - AC
    // 1 - DC
    // 2 - AUTO
    // 3 - RS232
    // 4 - minus
    // 5 - DP1
    // 6 - DP2
    // 7 - DP3
    // 8 - u
    // 9 - n
    // 10 - k
    // 11 - diode
    // 12 - m
    // 13 - %
    // 14 - M
    // 15 - beep
    // 16 - F
    // 17 - Ohm
    // 18 - Rel
    // 19 - HOLD
    // 20 - A
    // 21 - V
    // 22 - Hz
    // 23 - Low Batt
    // 24 - Far
    // 25 - Cel
    // 26 - user1
    // 27 - user2
    // 28 - AutoOff
    // 29 - Min
    // 30 - min-max
    // 31 - max
    SoftwareSerial mySerial(2, 3); // RX, TX
    void ClearDisp(void)
    {
    for (uint8_t i=0; i<4; i++) DiplayNums[i]=0;
    DisplayFlags = 0;
    }
    void Decode(uint8_t Number)
    {
    uint8_t i = Number>>4;
    if (i>0xf) return;
    Number &= 0xF;
    uint32_t lNumber = Number;
    switch (i)
    {
    case 1:
    DisplayFlags = Number;
    break;
    case 2:
    if (Number&1) DisplayFlags |= 1<<4; // minus
    if (Number&2) DiplayNums[0] |= 1<<4; // 1E
    if (Number&4) DiplayNums[0] |= 1<<5; // 1F
    if (Number&8) DiplayNums[0] |= 1<<0; // 1A
    break;
    case 3:
    if (Number&1) DiplayNums[0] |= 1<<3; // 1D
    if (Number&2) DiplayNums[0] |= 1<<2; // 1C
    if (Number&4) DiplayNums[0] |= 1<<6; // 1G
    if (Number&8) DiplayNums[0] |= 1<<1; // 1B
    break;
    case 4:
    if (Number&1) DisplayFlags |= 1<<5; // DP1
    if (Number&2) DiplayNums[1] |= 1<<4; // 2E
    if (Number&4) DiplayNums[1] |= 1<<5; // 2F
    if (Number&8) DiplayNums[1] |= 1<<0; // 2A
    break;
    case 5:
    if (Number&1) DiplayNums[1] |= 1<<3; // 2D
    if (Number&2) DiplayNums[1] |= 1<<2; // 2C
    if (Number&4) DiplayNums[1] |= 1<<6; // 2G
    if (Number&8) DiplayNums[1] |= 1<<1; // 2B
    break;
    case 6:
    if (Number&1) DisplayFlags |= 1<<6; // DP2
    if (Number&2) DiplayNums[2] |= 1<<4; // 3E
    if (Number&4) DiplayNums[2] |= 1<<5; // 3F
    if (Number&8) DiplayNums[2] |= 1<<0; // 3A
    break;
    case 7:
    if (Number&1) DiplayNums[2] |= 1<<3; // 3D
    if (Number&2) DiplayNums[2] |= 1<<2; // 3C
    if (Number&4) DiplayNums[2] |= 1<<6; // 3G
    if (Number&8) DiplayNums[2] |= 1<<1; // 3B
    break;
    case 8:
    if (Number&1) DisplayFlags |= 1<<7; // DP3
    if (Number&2) DiplayNums[3] |= 1<<4; // 4E
    if (Number&4) DiplayNums[3] |= 1<<5; // 4F
    if (Number&8) DiplayNums[3] |= 1<<0; // 4A
    break;
    case 9:
    if (Number&1) DiplayNums[3] |= 1<<3; // 4D
    if (Number&2) DiplayNums[3] |= 1<<2; // 4C
    if (Number&4) DiplayNums[3] |= 1<<6; // 4G
    if (Number&8) DiplayNums[3] |= 1<<1; // 4B
    break;
    case 0xa:
    DisplayFlags |= lNumber<<8;
    break;
    case 0xb:
    DisplayFlags |= lNumber<<12;
    break;
    case 0xc:
    DisplayFlags |= lNumber<<16;
    break;
    case 0xd:
    DisplayFlags |= lNumber<<20;
    break;
    case 0xe:
    DisplayFlags |= lNumber<<24;
    break;
    case 0xf:
    DisplayFlags |= lNumber<<28;
    break;
    default:
    break;
    }
    }
    uint16_t SegmentDecoder(void)
    {
    uint16_t Result =0;
    for(uint8_t i=0; i<4; i++)
    {
    uint8_t Number =0 ;
    Result *= 10;
    switch (DiplayNums[i])
    {
    case 0x3F:
    Number = 0;
    break;
    case 0x06:
    Number = 1;
    break;
    case 0x5B:
    Number = 2;
    break;
    case 0x4F:
    Number = 3;
    break;
    case 0x66:
    Number = 4;
    break;
    case 0x6D:
    Number = 5;
    break;
    case 0x7D:
    Number = 6;
    break;
    case 0x07:
    Number = 7;
    break;
    case 0x7F:
    Number = 8;
    break;
    case 0x6F:
    Number = 9;
    break;
    default:
    break;
    }
    Result += Number;
    }
    return Result;
    }
    float DecodeFloat(uint16_t iValue)
    {
    float fValue = iValue;
    // 4 - minus
    // 5 - DP1
    // 6 - DP2
    // 7 - DP3
    if (DisplayFlags & (1<<5)) fValue /= 1000;
    else if (DisplayFlags & (1<<6)) fValue /= 100;
    else if (DisplayFlags & (1<<7)) fValue /= 10;
    if (DisplayFlags & (1<<4)) fValue = -fValue;
    return fValue;
    }
    void build_mode(char *String)
    {
    char * Pointer;
    Pointer = String;
    for(uint8_t i=4; i<20; i++) *(Pointer++) = '';
    Pointer = String;
    *(Pointer++)= ' ';
    // 23 - Low Batt

    // 8 - u
    // 9 - n
    // 10 - k
    // 12 - m
    // 14 - M
    if (DisplayFlags & (1<<8)) *(Pointer++)= 'u';
    else if (DisplayFlags & (1<<9)) *(Pointer++)= 'n';
    else if (DisplayFlags & (1<<10)) *(Pointer++)= 'k';
    else if (DisplayFlags & (1<<12)) *(Pointer++)= 'm';
    else if (DisplayFlags & (1<<14)) *(Pointer++)= 'M';
    // 16 - F
    // 17 - Ohm
    // 20 - A
    // 21 - V
    // 22 - Hz
    if (DisplayFlags & (1L<<16)) *(Pointer++)= 'F';
    else if (DisplayFlags & (1L<<17)) *(Pointer++)= 'W';
    else if (DisplayFlags & (1L<<20)) *(Pointer++)= 'A';
    else if (DisplayFlags & (1L<<21)) *(Pointer++)= 'V';
    else if (DisplayFlags & (1L<<22))
    {
    *(Pointer++)= 'H';
    *(Pointer++)= 'z';
    }

    // 0 - AC
    // 1 - DC
    if (DisplayFlags & (1<<0))
    {
    strcpy(Pointer, " AC");
    Pointer +=3;
    }
    else
    if (DisplayFlags & (1<<1))
    {
    strcpy(Pointer, " DC");
    Pointer +=3;
    }
    // 2 - AUTO
    if (DisplayFlags & (1<<2))
    {
    strcpy(Pointer, " AUTO");
    Pointer +=5;
    }
    // 23 - Low Batt
    if (DisplayFlags & (1L<<23))
    {
    strcpy(Pointer, " BATT");
    Pointer +=5;
    }
    }
    void setup()
    {
    Serial.begin(115200);
    Serial.println(F("Serial Hub"));
    mySerial.begin(2400);
    ClearDisp();
    }
    void loop()
    {
    char mode_str[20];
    if (mySerial.available())
    {
    uint8_t Number;
    Number = mySerial.read();
    Decode(Number);
    if ((Number>>4)==0x0F)
    {
    uint16_t Digits;
    Serial.write(':');
    Digits = SegmentDecoder();
    float fValue;
    fValue = DecodeFloat(Digits);
    Serial.print(fValue,3);
    build_mode(mode_str);
    Serial.print((const char*)mode_str);
    Serial.println();
    ClearDisp();
    }
    }
    }

    В реальной лаборатории хотелось бы подключить хотя бы 4 тестера, а к каждому подключать свой USB — в программном потом замучаешься разбираться, какой USB к какому тестеру относится. В IEEE-488 все проще — у каждого устройства свой адрес и при перезагрузке компьютера ничего не перемешается. Поэтому желательно бы на одну Ардуино повесить несколько тестеров, ну и программируемый релейный коммутатор до кучи. У простейшей ATMega328 всего один UART, но есть библиотека, которая может использовать любые выводы для программного UART. Все бы хорошо, но одновременно принимать посылку может только один — а несколько приборов будут слать информацию одновременно. Поэтому для теста одного тестера я использую эту библиотеку, реально надо все переписывать. И нет смысла слать информацию в компьютер 10 раз в секунду — тестер делает 3 измерения в секунду.

    Проверив работоспособность идеи в целом, неплохо было бы сделать гальваническую развязку. Чтобы сделать оптоприемник, отпилим крышечку МП42А.

    Victor VC921 в домашней автоматизированной лаборатории

    Серьезно — инфракрасного светодиода и фототранзистора не нашлось, пришлось разобрать оптический концевик.

    Victor VC921 в домашней автоматизированной лаборатории

    Светодиод припаиваем и заливаем ножки эпоксидкой, чтобы не оторвался. В боку корпуса мультиметра проделываем дырку и печатаем держалку для фототранзистора. Безобразно, но для эксперимента сойдет.

    Victor VC921 в домашней автоматизированной лаборатории

    Теперь переходим к нашей LabView — много лет назад это была очень дорогая система, но сейчас появилась вполне себе бесплатная community версия, которая работает на основных операционных системах. Как я написал в начале — статья еще в ручке :), но она будет.

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

    Экспертом по LabView я никогда не был, но использовал ее иногда между делом по нужде, которая возникала пару раз в году.

    Вот эта, картинка, которую вы видите ниже — это и есть исходный код программы. Больше нет ничего.

    Victor VC921 в домашней автоматизированной лаборатории

    А это — получившийся пользовательский интерфейс.

    Victor VC921 в домашней автоматизированной лаборатории

    Все это довольно просто и предназначено для того, чтобы человек, не будучи программистом, мог сделать очень многое. Очень богатая математика, обработка сигналов, пакет для управления роботами, техническое зрение — ну очень много всего. И чтобы пользоваться — в первом приближении нужно просто накидать иконок. Но здесь задача суперпростая — просто ввести данные с прибора и отобразить их на виртуальном осциллографе. Я это делал, чтобы посмотреть, как часто обновляются данные — просто крутил ручку регулировки напряжения на блоке питания. Оказалось, данные у Victor VC921 обновляются меньше 5 раз в секунду — собственно, в описании было сказано, что обновление 3 раза в секунду, но кто же эти описания читает?

    На этом пожалуй и все, надеюсь, что обзор кого-то заинтересовал — речь не о Victor VC921, конечно, а о LabView. Ну и если кто присоветует недорогие тестеры — буду благодарен, один тестер в автоматизированной тестовой системе — это ни о чем. Когда я работал, у меня были подключены десятки приборов, которые пахали круглосуточно, а я только успевал отчеты снимать и итоги документировать.


СМОТРИ ТАКЖЕ

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *