Передача данных от штангенциркуля
через USB и WiFi (часть вторая)
Успешно победив новый штангенциркуль, я решил добить и старый.
Очевидные проблемы с 1,5 В питания и нестандартным разъемом
казались легко преодолимыми. Внешне мой штангенциркуль не
отличался от описанного в известной
статье. Однако подключение осциллографа показало, что
приятная внешность не всегда содержит аналогичное содержание.
Протокол здесь сильно напоминал описанный в статье Chinese
Scale Protocol. И основная неприятность была не в
расшифровке, а в тактовой частоте, которая была на
порядок больше, чем в модели, которую я победил. Не я первый, и
решение было известно: вместо опроса тактового сигнала
использовать прерывания. Однако моя попытка реализовать эту идею
на Arduino Nano не увенчалась успехом. Почти треть тактов я не
замечал. Наверное, можно было улучшить программу, ведь были статьи
где писалось о положительном результате. Но я пошел путем
улучшения железа. Поскольку в конечном случае предполагалось
использовать ESP-32, то я перешел на нее сразу.
Эксперименты показали, что с желтым светодиодом с падением
напряжения в 1,9 В устройство работает стабильнее. Это превышение
напряжения, возможно, отрицательно сказалось на работе устройства
и потреблении им энергии, но пока не сгорело, а питание
штангенциркуля мы все равно теперь получаем не от батарейки, а
извне. Сопротивление 220 Ом, конденсатор 10 мкФ.
В результате, программа, позволяющая стабильно передавать данные
в компьютер через USB, выглядит так:
int dataIn = 18; int cn = 0; int out = 0; long longout=0; float finalout; float finalout2; #define ZERO_PIN 19 hw_timer_t * timer = NULL; volatile SemaphoreHandle_t timerSemaphore; portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
void ARDUINO_ISR_ATTR onTimer(){ // Give a semaphore that we can check in the loop xSemaphoreGiveFromISR(timerSemaphore, NULL); // It is safe to use digitalRead/Write here if you want to toggle an output } void IRAM_ATTR isr() { cn=cn+1; out = digitalRead(dataIn)+digitalRead(dataIn)+digitalRead(dataIn); if (out > 1){ longout=longout|0b01000000000000000000000000000000; longout=longout>>1; } else{ longout=longout>>1; } timerRestart(timer); timerAlarmEnable(timer); } void setup() { pinMode(dataIn, INPUT); Serial.begin(115200); Serial.println("START"); attachInterrupt(digitalPinToInterrupt(ZERO_PIN), isr, FALLING); // Create semaphore to inform us when the timer has fired timerSemaphore = xSemaphoreCreateBinary();
// Use 1st timer of 4 (counted from zero). // Set 80 divider for prescaler (see ESP32 Technical Reference Manual for more // info). timer = timerBegin(0, 80, true);
// Attach onTimer function to our timer. timerAttachInterrupt(timer, &onTimer, true);
// Set alarm to call onTimer function every second (value in microseconds). // Repeat the alarm (third parameter) timerAlarmWrite(timer, 200000, true);
// Start an alarm timerAlarmEnable(timer); }
void loop() { // If Timer has fired if (xSemaphoreTake(timerSemaphore, 0) == pdTRUE){
Serial.print(cn); Serial.println(" cn"); cn=0; longout=longout>>8; if (longout & 0b00000000000010000000000000000000){ longout=longout & 0b11111111111101111111111111111111; //longout=~longout ; } finalout=-(float(longout))/100; finalout2=finalout*0.9922; if(finalout<-15000){ finalout = 15728.63 +finalout; finalout2=finalout*0.9922; } Serial.print("data:"); Serial.println(finalout2); longout=0;
}
}
Не мудрствуя, я попытался воспользоваться уже имеющейся
программой расшифровки и, как не странно, она заработала, но
отсчет шел в обратную сторону и набегала небольшая ошибка. Добавил
сдвиг на 15728,63 и умножил на 0,9922, и показания на дисплее
штангенциркуля и передаваемые в компьютер совпали с точностью до
двух сотых. Вероятно, расшифровку сигналае можно осуществить
более красивым способом, но работает - не трогай.
Дальше больше, берем ESP-32 и создаем веб-сервер для
передачи данных через wi-fi. Пишем окончательный
вариант программы, который позволяет при запуске точки доступа
записать в eprom данные локальной сети wi-fi. Дополняем интерфейс
программы возможностью замораживать сигнал и показывать изменения
относительно него.
int dataIn = 18; int cn = 0; int out = 0; long longout=0; float finalout; float finalout2; #define ZERO_PIN 19 hw_timer_t * timer = NULL; volatile SemaphoreHandle_t timerSemaphore; portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
int i=0; float hold1; //int tempc = 110; #include <GyverPortal.h> GyverPortal ui; #include <EEPROM.h> struct LoginPass { char ssid[20]; char pass[20]; }; LoginPass lp; TaskHandle_t Task1; TaskHandle_t Task2; void ARDUINO_ISR_ATTR onTimer(){ // Give a semaphore that we can check in the loop xSemaphoreGiveFromISR(timerSemaphore, NULL); // It is safe to use digitalRead/Write here if you want to toggle an output } void IRAM_ATTR isr() { cn=cn+1; out = digitalRead(dataIn)+digitalRead(dataIn)+digitalRead(dataIn); if (out > 1){ longout=longout|0b01000000000000000000000000000000; longout=longout>>1; } else{ longout=longout>>1; } timerRestart(timer); timerAlarmEnable(timer); } // конструктор страницы void build() { GP.BUILD_BEGIN(); GP.THEME(GP_DARK); GP.PAGE_TITLE("CALIPER"); GP.UPDATE("lb,lbb,lbbb");
GP.LABEL("NAN", "lb",GP_GREEN,44,0);GP.BREAK(); GP.BUTTON_MINI("btn2", "DATA HOLD"); GP.LABEL("NAN", "lbb",GP_RED,44,0);GP.BREAK(); GP.LABEL("NAN", "lbbb",GP_GREEN,44,0);GP.BREAK(); GP.FORM_BEGIN("/login"); GP.TEXT("lg", "Login", lp.ssid); GP.BREAK(); GP.TEXT("ps", "Password", lp.pass); GP.SUBMIT("Submit"); GP.FORM_END(); GP.BUILD_END(); }
void setup() { // Pin Set Up pinMode(dataIn, INPUT); Serial.begin(115200); Serial.println("START"); attachInterrupt(digitalPinToInterrupt(ZERO_PIN), isr, FALLING); // Create semaphore to inform us when the timer has fired timerSemaphore = xSemaphoreCreateBinary();
// Use 1st timer of 4 (counted from zero). // Set 80 divider for prescaler (see ESP32 Technical Reference Manual for more // info). timer = timerBegin(0, 80, true);
// Attach onTimer function to our timer. timerAttachInterrupt(timer, &onTimer, true);
// Set alarm to call onTimer function every second (value in microseconds). // Repeat the alarm (third parameter) timerAlarmWrite(timer, 200000, true);
// Start an alarm timerAlarmEnable(timer); EEPROM.begin(100); EEPROM.get(0, lp); Serial.println(lp.ssid); Serial.println(lp.pass); if (touchRead(15)<35) startap2(); else startup(); // подключаем конструктор и запускаем ui.attachBuild(build); ui.attach(action); ui.start(); // Создаем задачу с кодом из функции Task1code(), // с приоритетом 1 и выполняемую на ядре 0: xTaskCreatePinnedToCore( Task1code, /* Функция задачи */ "Task1", /* Название задачи */ 10000, /* Размер стека задачи */ NULL, /* Параметр задачи */ 1, /* Приоритет задачи */ &Task1, /* Идентификатор задачи, чтобы ее можно было отслеживать */ 0); /* Ядро для выполнения задачи (0) */ delay(500);
// Создаем задачу с кодом из функции Task2code(), // с приоритетом 2 и выполняемую на ядре 1: xTaskCreatePinnedToCore( Task2code, /* Функция задачи */ "Task2", /* Название задачи */ 10000, /* Размер стека задачи */ NULL, /* Параметр задачи */ 2, /* Приоритет задачи */ &Task2, /* Идентификатор задачи, чтобы ее можно было отслеживать */ 1); /* Ядро для выполнения задачи (1) */ delay(500); } void startap2() { Serial.println("Portal start"); // запускаем точку доступа WiFi.mode(WIFI_AP); WiFi.softAP("CALIPER"); //Serial.println(WiFi.localIP()); Serial.println(WiFi.softAPIP()); } void startup() { WiFi.mode(WIFI_STA); WiFi.begin(lp.ssid, lp.pass); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(WiFi.localIP()); } void action() { if (ui.form("/login")) { // кнопка нажата ui.copyStr("lg", lp.ssid); // копируем себе ui.copyStr("ps", lp.pass); EEPROM.put(0, lp); // сохраняем EEPROM.commit(); // записываем // WiFi.softAPdisconnect(); // отключаем AP } if (ui.click("btn2")) { hold1= finalout2; } if (ui.update()) { if (ui.update("lb")) ui.answer(String(finalout2)); if (ui.update("lbb")) ui.answer(String(hold1)); if (ui.update("lbbb")) ui.answer(String(finalout2-hold1)); } } // Функция Task2code: void Task2code( void * pvParameters ){ Serial.print("Task2 running on core "); // "Задача Task2 выполняется на ядре " Serial.println(xPortGetCoreID()); for(;;){ // If Timer has fired if (xSemaphoreTake(timerSemaphore, 0) == pdTRUE){
Serial.print(cn); Serial.println(" cn"); cn=0; longout=longout>>8; if (longout & 0b00000000000010000000000000000000){ longout=longout & 0b11111111111101111111111111111111; //longout=~longout ; } finalout=-(float(longout))/100; finalout2=finalout*0.9922; if(finalout<-15000){ finalout = 15728.63 +finalout; finalout2=finalout*0.9922; } Serial.print("data:"); Serial.println(finalout2); longout=0;
} } } // Функция Task1code: void Task1code( void * pvParameters ){ Serial.print("Task1 running on core "); // "Задача Task1 выполняется на ядре " Serial.println(xPortGetCoreID());
for(;;){ ui.tick(); } } void loop() { }
В заключение, приведу 3D модель корпуса для получившегося
устройства.
19.11.2024
Установите проигрыватель Flash
|
Облако тегов:
...
|