Доброго времени суток!
Уже более полугода владею дешёвым китайским электронным штангелем 150мм, в инструкции к которому написана фраза «digital interface». Возможность вывода на компьютер заинтересовала сразу, но созрел я на этот подвиг только сейчас.
Изначально мотивацией являлось просто любопытство, «чтоб было!» и «вдруг кто спросит, а у меня есть!», позже (уже по факту «получилось!») нашлось и реальное применение в проекте с самодельным ЧПУ-станочком.
Главный герой, не смотря на свою дешевизну (около 8$), тем не менее, является очень точным прибором:

Принцип работы: емкостной датчик.
Всё связано с перемещением малой пластины (головка штангеля) вдоль большой (шкала штангеля), при этом незаряженная часть большой пластины заряжается и вроде как заряд протекающий через образованный этими пластинами конденсатор пропорционален перемещению малой пластины. Как-то так.
Начальные поиски информации о цифровом интерфейсе показали что многие его видели, кое-кто даже в курсе, но никто не знает как им пользоваться.
Углубленный поиск по не русскоязычным ресурсам дал более продуктивные результаты. Как казалось по началу — всё достаточно просто и понятно, разжёвано осциллографами, снято на ютубе и т.д., однако конечного и рабочего «сходу» варианта не нашлось.
Так что, основной проблемой стал поиск информации.
Второй проблемой стало изготовление вилки к этому разъёму (который, в общем-то и не разъём совсем, а просто голые дорожки на плате). Контакты упорно не желали держаться. В конце-концов догадался воткнуть в кусочек стёрки лапки от LPT-порта. Штука получилась ненадёжной, но для теста вполне годной. На будущее решил в обязательном порядке подпаяться напрямую к плате и вывести свой разъём (штыревой CD-IN от материнки).
Наткнувшись на статью на instructables.com решился повторить этот подвиг.
Для начала приведу нагло стыренные оттуда картинки с расположением контактов на циркуле и принципиальную схему подключения (не вижу смысла перерисовывать самому, а выдавать за своё — вообще непростительно):
Пины:

Схема:

Для согласования напряжений я использовал резистор 200Ом к��к и было рекомендовано. Конденсатора на 10мкФ не нашлось и я поставил 100мкФ выпаянный с мёртвой материнки.
Справившись с пайкой, приступил к написанию скетча. К слову сказать, в отсутствие макетной платы вышел из положения, собрав схему на «кроватке» от IDE-порта, с той же материнки.
Скетч, приведённый в вышеуказанной статье заработал без вопросов, но удовлетворения не принёс.
Китайский скетч из комментариев, работать «сходу» — отказался, но производил гораздо более серьёзное впечатление, вследствие чего, подвергся серьёзному «допиливанию».
Вот что из этого получилось (или готовый скетч для Arduino UNO, версия IDE 0022):
Удовлетворившись результатом, решил сделать финальное фото, и немного «босяцкой» рекламы для эффекта:

В описании протокола содержится ещё пара интересных плюшек, поэтому есть стимул для задела «на будущее»
[Ссылки]
Уже более полугода владею дешёвым китайским электронным штангелем 150мм, в инструкции к которому написана фраза «digital interface». Возможность вывода на компьютер заинтересовала сразу, но созрел я на этот подвиг только сейчас.
Изначально мотивацией являлось просто любопытство, «чтоб было!» и «вдруг кто спросит, а у меня есть!», позже (уже по факту «получилось!») нашлось и реальное применение в проекте с самодельным ЧПУ-станочком.
Вводная
Главный герой, не смотря на свою дешевизну (около 8$), тем не менее, является очень точным прибором:

Принцип работы: емкостной датчик.
Всё связано с перемещением малой пластины (головка штангеля) вдоль большой (шкала штангеля), при этом незаряженная часть большой пластины заряжается и вроде как заряд протекающий через образованный этими пластинами конденсатор пропорционален перемещению малой пластины. Как-то так.
Поиск
Начальные поиски информации о цифровом интерфейсе показали что многие его видели, кое-кто даже в курсе, но никто не знает как им пользоваться.
Углубленный поиск по не русскоязычным ресурсам дал более продуктивные результаты. Как казалось по началу — всё достаточно просто и понятно, разжёвано осциллографами, снято на ютубе и т.д., однако конечного и рабочего «сходу» варианта не нашлось.
Так что, основной проблемой стал поиск информации.
Второй проблемой стало изготовление вилки к этому разъёму (который, в общем-то и не разъём совсем, а просто голые дорожки на плате). Контакты упорно не желали держаться. В конце-концов догадался воткнуть в кусочек стёрки лапки от LPT-порта. Штука получилась ненадёжной, но для теста вполне годной. На будущее решил в обязательном порядке подпаяться напрямую к плате и вывести свой разъём (штыревой CD-IN от материнки).
Решение
Наткнувшись на статью на instructables.com решился повторить этот подвиг.
Для начала приведу нагло стыренные оттуда картинки с расположением контактов на циркуле и принципиальную схему подключения (не вижу смысла перерисовывать самому, а выдавать за своё — вообще непростительно):
Пины:

Схема:

Для согласования напряжений я использовал резистор 200Ом к��к и было рекомендовано. Конденсатора на 10мкФ не нашлось и я поставил 100мкФ выпаянный с мёртвой материнки.
Результат
Справившись с пайкой, приступил к написанию скетча. К слову сказать, в отсутствие макетной платы вышел из положения, собрав схему на «кроватке» от IDE-порта, с той же материнки.
Скетч, приведённый в вышеуказанной статье заработал без вопросов, но удовлетворения не принёс.
Китайский скетч из комментариев, работать «сходу» — отказался, но производил гораздо более серьёзное впечатление, вследствие чего, подвергся серьёзному «допиливанию».
Вот что из этого получилось (или готовый скетч для Arduino UNO, версия IDE 0022):
//CyberKot (он же... я же! Shadow) //Скетч Arduino, выводящий данные с циркуля в COM-порт //Версия для хабра int dataIn = 11; //шина данных, можно менять int clockIn = 2; //шина clock, не трогать, так надо (читайте про attachInterrupt) int isin = 0; //д=1 мм=0 int isfs = 0; //минус int index; //счётчик битов unsigned long xData, oData; //новые показания и старые (потом будет понятно зачем) int ledPin = 13; //мигалка на 13й вход (встроенная, чтоб понятно было, что ничего не повисло) int ledState = LOW; //статус мигалки long previousMillis = 0; //когда последний раз мигали long interval = 500; // интервал мигания long previousGetMillis = 0; long Timeout = 8; //таймаут чтения битов в мс float stringOne; //временные переменные для вывода char charBuf[5]; char charBuf2[8]; void setup(){ digitalWrite (dataIn, 1); digitalWrite (clockIn, 1); pinMode (dataIn, INPUT); //привязываем шину данных на dataIn pinMode (clockIn, INPUT); //и clock на 2й вход attachInterrupt(0,getBit,RISING); //и аттачим clock также на 2й вход Serial.begin(9600); delay(500); index = 0; xData = 0; oData = 999; } void loop(){ if ((index !=0) && (millis() - previousGetMillis > Timeout) ) { //обнуление по превышению таймаута index = 0; xData = 0; }; if (index >23) { //если слово считано полностью if (oData !=xData) { /* Этот вариант более изящен, по моему мнению, но съедает лишний килобайт if (isin==1){ //дюймы Serial.print("inch: "); stringOne =xData*5/10000.00000; stringOne *=pow(-1,isfs); Serial.println(floatToString(charBuf2,stringOne,5,5)); }else { //мм Serial.print("mm: "); stringOne =xData/100.00; stringOne *=pow(-1,isfs); Serial.println(floatToString(charBuf,stringOne,2,5)); }; */ if (isin==1){ //дюймы if (isfs==1){ //минус Serial.print("inch: -"); }else { Serial.print("inch: "); } stringOne =xData*5/10000.00000; Serial.println(floatToString(charBuf2,stringOne,5,5)); }else { //мм if (isfs==1){ //минус Serial.print("mm: -"); }else { Serial.print("mm: "); } stringOne =xData/100.00; Serial.println(floatToString(charBuf,stringOne,2,5)); }; }; oData =xData; index=0; xData=0; }; if (millis() - previousMillis > interval) { //мигалка previousMillis = millis(); if (ledState == LOW) ledState = HIGH; else ledState = LOW; digitalWrite(ledPin, ledState); } } void getBit(){ //чтение битов и флаги previousGetMillis=millis(); if(index < 20){ if(digitalRead(dataIn)==1){ xData|= 1<<index; } } else { if (index==20) //минус isfs=digitalRead(dataIn); if (index==23) //дюймы isin=digitalRead(dataIn); }; index++; } //функция для безгеморойного конверта переменной типа float в строку char * floatToString(char * outstr, double val, byte precision, byte widthp){ //буфер под результат, число, точность (после запятой), минимальная длина char temp[16]; byte i; //обсчёт округления double roundingFactor = 0.5; unsigned long mult = 1; for (i = 0; i < precision; i++) { roundingFactor /= 10.0; mult *= 10; } temp[0]='\0'; outstr[0]='\0'; if(val < 0.0){ strcpy(outstr,"-\0"); val = -val; } val += roundingFactor; strcat(outstr, itoa(int(val),temp,10)); // ц��лая часть if( precision > 0) { strcat(outstr, ".\0"); // дробная unsigned long frac; unsigned long mult = 1; byte padding = precision -1; while(precision--) mult *=10; if(val >= 0) frac = (val - int(val)) * mult; else frac = (int(val)- val ) * mult; unsigned long frac1 = frac; while(frac1 /= 10) padding--; while(padding--) strcat(outstr,"0\0"); strcat(outstr,itoa(frac,temp,10)); } // пробелы (для форматирования) if ((widthp != 0)&&(widthp >= strlen(outstr))){ byte J=0; J = widthp - strlen(outstr); for (i=0; i< J; i++) { temp[i] = ' '; } temp[i++] = '\0'; strcat(temp,outstr); strcpy(outstr,temp); } return outstr; }
Итог
Удовлетворившись результатом, решил сделать финальное фото, и немного «босяцкой» рекламы для эффекта:

Послесловие
В описании протокола содержится ещё пара интересных плюшек, поэтому есть стимул для задела «на будущее»
- быстрый режим (50Гц, против 3Гц в умолчальном режиме)
- обработка «абсолютного» положения
- программные кнопки «Zero» и «Mode»
[Ссылки]
