Victor VC921 в домашней автоматизированной лаборатории
- Цена: 8.24 евро
- Лучшие в мире батарейки по 13 рублей
- «Верни мне мой 1996-й - часть 1»: программируем пейджер в 2021
- Планшет Lenovo 4/64 11" Android 10 (купон для заказов с РФ)
- Установка круиз-контроля в Peugeot 307 своими руками. Заводской, оригинальный.
- Кассеты (8 шт.) для Gillette Mach 3 из Китая
- SHARP AQUOS V Global Version за 109.99$
- Ремонт светодиодного дюралайта в домашних условиях
- Система сигнализации о наличии протечек Neptun СКПВ220В-DIN - ремонт и устройство.
- 9.00$ за 64ГБ Быстрые SSD флешки BlitzWolf BW-UP2
- Патрон звуковой резьбовой «Гром» для сигнала охотника
Сегодня будет суперзапоздавший обзор тестера, уже много лет валявшегося в дальнем углу абсолютно без дела. Предпримем попытку расширить нашу автоматизированную домашнюю лабораторию и подключим дешевый тестер к системе на базе Labview.
Телега сильно забежала впереди лошади — у меня был запланирован обзор одного прибора и половина статьи, касающейся установки и использования Labview вполне легально, уже написана, а прибор еще где-то идет, и на разработку виртуальных инструментов для этого прибора и дописывания обзора понадобится еще неделя-другая после получения. Последовательность оказалось перепутана. Пояснения, если кому они нужны, будут в моем следующем обзоре.
Для начала — хорошие обзоры на этот тестер здесь уже есть, первый и второй, повторяться не буду. Это не все — я насчитал здесь 4 обзора на этот тестер.
Если есть много денег и большая нужда, конечно, самый простой вариант поставить на полочку штуки 2-3 старых добрых мультиметра 6.5 Hewlett-Packard HP 34401A, который вроде как Agilent сейчас кличут, парочку источников-измерителей Keithley 24xx с последними циферками по вашему вкусу, несколько программируемых источников питания — все это соединить IEEE-488 (Hewlett-Packard Interface Bus в девичестве).
Всего этого добра не нашлось, зато нашелся Victor VC921, который я купил лет 6 тому назад за 8.24 евро на Али.
Друг такой купил — ему он очень понравился в качестве пищалки-звонилки. Глядя на его восторг, я тоже приобрел такой же — с тех пор и валялся в дальнем углу без использования.
С тех пор клиент уехал, гипс сняли и даже магазин больше не существует.
Если пойдете по этой кривой дорожке — имейте в виду, что этот тестер в большинстве случаев уже не торт — внешне выглядит так же, но нутро другое.
Вид снизу:
и сверху:
На правильном тестере должна быть надпись True RMS. Но написать можно что угодно, более надежный критерий — если открыть отсек с батарейками, на печатной плате должно быть видно 2 контактных площадки для кнопок.
Хотел бы еще один для системы такой найти — но дешево уже нет. И еще бы в довесок пару тестеров с измерением тока и температуры — у Victor VC921 таких возможностей нет, из полезного для меня — только напряжение и сопротивление. Может, у кого есть на примете подходящие недорогие варианты? — но похоже, что Victor брать смысла уже нет, за такую цену, как у него сейчас, лучше уже что-то с измерением тока найти.
Фотографировал тестер на окне — а тут кошка Рыжик отдыхает, на вид очень счастливая кошка. Обойти и не сфотографировать ее было просто невозможно.
Тем более так беззаботна она бывает очень редко — кошка очень тяжело болеет, ветеринары ее больше трех лет назад приговорили. Несколько раз в году у нее какой-то приступ кошачьей неврологии случается — при этом она не может глотать несколько дней подряд, хотя кушать очень хочет. Если не заталкивать кусочки мяса прямо в горло — умрет от голода. На этот раз уже больше двух недель все это длится и никак кошке лучше не становится.
Говорят, кошки могут лечить людей — но, похоже, за счет своего здоровья или жизни. Несколько лет назад я заболел и в итоге передвигался в инвалидной коляске. Потом вроде стало отпускать, и я даже стал обходиться без коляски — но в это время заболела кошка, врачи были уверены, что умрет. Но она выжила — и сейчас мы на пару с ней глотаем таблетки из одной бутылочки.
Совпадение или мистика? Не знаю.
Ладно, вернемся к предмету обзора. Тестер сделан на базе широко известной в узких кругах DTM0660, у которой конфигурация и калибровки хранятся в 24C02. Нужно изменить один битик, чтобы включить последовательный протокол и заодно выключить автовыключение — для работы в составе автоматизированной системы это нам даром не надь. Идея была позаимствована отсюда.
Чтобы не извращаться с выпаиванием EEPROM, самый простой вариант — закоротить кварц резистором на несколько десятков ом, процессор успокоится и мешать делать вам свое дело не будет. Теперь одеваем прищепку на 24C02 и меняем наши битики. Не используйте чужую прошивку — калибровка, если она делалась, вещь индивидуальная и будет сбита.
Оригинальное содержимое EEPROM:
и модифицированное:
После этого на 20 ноге после долгого нажатия клавиши REL появится какая-то информация.
По наивности считал, что это будет удобоваримая посылка, которую будет легко использовать. Зря радовался — с логическим анализатором удалось определить, что это обычный последовательной интерфейс, скорость обмена 2400 бод, в пакете 15 байт и пакет посылается 10 раз в секунду.
Пришлось рыться в интернете — но все-таки нашел, и это похоже на бред — вместо того, чтобы отправить измеренную величину, DTM0660 отправляет состояние сегментов дисплея.
Пришлось вытаскивать Ардуину и писать декодер наоборот — изображение 7-сегментного дисплея превращать в измеряемую величину.
Дабы мозги понапрасну не напрягать, нашел готовый алгоритм распознавания цифр с семисегментника:
Код ниже — но это только, чтобы понять как все работает. Старался писать как можно проще, ничего не оптимизируя, чтобы алгоритм был максимально понятен.
#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++) = '