Разберемся, почему использование GPIO 12 и/или 2 в ESP32 может привести к неработосопособности модуля и как совмещать 3 и 5 вольтовую логику
Добрый день!
С некоторых пор мы предпочитаем использовать контроллеры ESP32 обычным AVR контроллерам вроде ATMega328 (arduino nano/uno). Причина тому в функциональности ESP32 при схожей стоимости.
Гикие возможности программирования прерываний и высокая скорость работы (240МГц против 16 МГц, 32 разряда против 8 разрядов) дает просто огромный выигрыш в производительности: (240/16)*(32/8) = 60 раз, грубый подсчет говорит о том, что ESP32 производительнее ATMega328 в 60 раз, но это весьма грубо. Без учета других особенностей, например, энергопотребление, которое может быть значительно выше при работе с беспроводными интерфейсам.
ESP32 поделка китайских мастеров и как все восточное несет некоторую таинственность, недосказаннность, неопределенность.
Мы расскажем о подводных камнях, с которыми столкнулись и о которых нужно сообщить, дабы Конструктора не начали сходить с ума от непредсказуемого поведения ESP32, как при попытках прошивки, так и при работе.
Потребовалось нам для стола большого 3d-принтера, имеющего два ходовых винта и пару шаговых подъемных моторов сконструировать систему выравнивания положения. Дело в том, что использование пары несвязанных жестко ходовых винтов на подъем стола обязательно приведет к ппоявлению отклонений в положении осей, так как после отключения драйверов оси можно свободно вращать отдельно, а это приводит к вероятному наклону поверхности стола относительно печатного сопла (в сторону одной из подъемных осей), а при больших смещениях к даже заклиниванию стола.
Стандартные платы 3d принтеров имеют только один выход (набор выходных сигналов) для управления осью Z, что позволяет поднимать и опускать ось, но не дают возможности управлять подъемными моторами отдельно. Обычно пару моторов включают так, что их драйвера управляются параллельно (сигналы STEP, DIR, ENABLE приходят на оба драйвера с одних контактов управления), китайские умельцы "научились" управлять парой моторов от одного драйвера, подключая обмотки моторов последовательно, в этом случае пара моторов как-бы становится одним, деля мощность между собой, но отдельное управляемое перемещение осей в этих случаях также не осуществляется, а вот неуправляемый скос/разбаланс осей вполне вероятен.
Но кто может нам помешать самостоятельно сделать систему выравнивания осей. Главное, чтобы основная плата управления не имела препятствий в управлении перемещением стола при печати, а вот если в свободное от печати время мы будем иметь возможность автоматически проверить и выровнять стол, это хорошо и удобно.
В качество драйверов для шаговых моторов были использованы драйверы средней мощности HY-DIV268N-5А
А для управление через ESP32 был использован конвертер уровней, хотя управление можно было осуществить проще, используя возможности использования GPIO ESP32 в режиме с открытым коллектором. Но режим "с отрытым коллектором" может быть небезопасен для контроллера, ведь подача ничем неограниченного даже небольшого напряжения в этом режиме вполне может сжечь ESP32.
Двунаправленные конвертеры уровней очень удобная вещь, но если входы находяться в неопределенном состоянии, то как поведет себя данная пара BX-AX предсказать трудно. В наше случае, при подключении конверторов уровней на GPIO по схеме изображенной ниже, модуль перестал загружаться, веренее ушел в постоянную перезгрузку, указывая на ошибку памяти через UART.
Причина оказалась в том, что на GPIO12, после подачи напряжения питания схемы, выставлялся высокий уровень сигнала от конвертера уровней, что приводило к уходу ESP32 в бесконечный ребут.
Решение проблемы состоит в неиспользовании данного GPIO или контролю, за тем, чтобы при включении и до загрузки ESP32, на данном GPIO (GPIO12 GPIO2) был/эмулировался разрыв - отсутствие подключения к GND или питанию. Для этого мы подтянем к GND контакты 0E конвертеров, отвечающие за их включение и будем отдельно управлять включением конвертеров тогда, кода нам это поребуется в программе. Мы подключили управление к GPIO33, теперь следует не забыть в программе перевести GPIO33 в состояние OUTPUT и до использования конвертора уровней подать на GPIO33 высокий уровень сигнала digitalWrite(33,HIGH);
Программа тестирования функциональности созданной схемы приведена ниже.
Мы имеем три кнопки S1,S2,S3, которые подтянуты через различные по номиналу резисторы (R1 R2 R3) к земле. С другой стороны замыкающего контакта кнопки подтянуты к питанию через резистор R4. Сигнал снимается между резисторами и, за счет того что при змыкании определенной кнопки потенциал на GPIO32 будет отличаться, мы считывая его (analogRead(BUTTON_GPIO);) получаем информацию о том, какая кнопка нажата.
Аналогично, но в цифровом виде, мы снимаем информацию с оптических концевых датчиков fc-03, они подключены к GPIO19 и GPIO15.
Работоспособность схемы проверяется сигналом светодиода WS2812, для которого компания Adafruit предлагает библиотеку Adafruit_NeoPixel.h. Нажимая на разные кнопки или перекрывая световой поток в оптодатчике мы даем команду светодиоду светить определеным-разным светом.
Тестирование схемы прошло успешно, теперь нужно написать программу управления шаговыми моторами и получения внешних команд.
Тестовая программа опробована в Arduino IDE
-
#include < Adafruit_NeoPixel.h >
-
-
#define LED_PIN 17
-
-
// How many NeoPixels are attached to the Arduino?
-
#define LED_COUNT 1
-
-
// NeoPixel brightness, 0 (min) to 255 (max)
-
#define BRIGHTNESS 50
-
-
#define BUTTON_GPIO 32
-
#define white_GPIO_BUTTON 1860
-
#define blue_GPIO_BUTTON 208
-
#define red_GPIO_BUTTON 1120
-
#define dX 40
-
-
#define SENSOR_1_GPIO 15
-
#define SENSOR_2_GPIO 19
-
-
#define STEP_1_GPIO 25
-
#define DIR_1_GPIO 26
-
#define EN_1_GPIO 27
-
-
#define STEP_2_GPIO 14
-
#define DIR_2_GPIO 12
-
#define EN_2_GPIO 13
-
-
-
#define EN_CONVERTOR_GPIO 33
-
-
-
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRBW + NEO_KHZ800);
-
// Argument 1 = Number of pixels in NeoPixel strip
-
// Argument 2 = Arduino pin number (most are valid)
-
// Argument 3 = Pixel type flags, add together as needed:
-
// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
-
// NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
-
// NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products)
-
// NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
-
// NEO_RGBW Pixels are wired for RGBW bitstream (NeoPixel RGBW products)
-
-
void setup() {
-
-
pinMode(EN_CONVERTOR_GPIO, OUTPUT); //
-
digitalWrite(EN_CONVERTOR_GPIO, LOW); //Выключаем конверторы уровней.
-
strip.begin(); // INITIALIZE NeoPixel strip object (REQUIRED)
-
strip.show(); // Turn OFF all pixels ASAP
-
strip.setBrightness(50); // Set BRIGHTNESS to about 1/5 (max = 255)
-
pinMode(BUTTON_GPIO, INPUT); //button
-
pinMode(SENSOR_1_GPIO, INPUT); //sens 1
-
pinMode(SENSOR_2_GPIO, INPUT); //sens 1
-
-
pinMode(STEP_1_GPIO, OUTPUT);
-
pinMode(DIR_1_GPIO, OUTPUT);
-
pinMode(EN_1_GPIO, OUTPUT);
-
-
pinMode(STEP_2_GPIO, OUTPUT);
-
pinMode(DIR_2_GPIO, OUTPUT);
-
pinMode(EN_2_GPIO, OUTPUT);
-
-
digitalWrite(STEP_1_GPIO, LOW);
-
digitalWrite(DIR_1_GPIO, LOW);
-
digitalWrite(EN_1_GPIO, LOW);
-
-
digitalWrite(STEP_2_GPIO, LOW);
-
digitalWrite(DIR_2_GPIO, LOW);
-
digitalWrite(EN_2_GPIO, LOW);
-
-
Serial.begin(115200);
-
digitalWrite(EN_CONVERTOR_GPIO, HIGH); //Включаем конверторы уровней.
-
}
-
-
void loop() {
-
int X = analogRead(BUTTON_GPIO);
-
-
if (((white_GPIO_BUTTON - dX) < X) && ((white_GPIO_BUTTON + dX) > X))
-
{
-
strip.setPixelColor(0, strip.Color(155, 155, 155));
-
strip.show();
-
}
-
else if (((blue_GPIO_BUTTON - dX) < X) && ((blue_GPIO_BUTTON + dX) > X))
-
{
-
strip.setPixelColor(0, strip.Color(0, 0, 255));
-
strip.show();
-
}
-
else if (((red_GPIO_BUTTON - dX) < X) && ((red_GPIO_BUTTON + dX) > X))
-
{
-
strip.setPixelColor(0, strip.Color(255, 0, 0));
-
strip.show();
-
}
-
else if (digitalRead(SENSOR_1_GPIO) == 1)
-
{
-
strip.setPixelColor(0, strip.Color(155, 155, 0));
-
strip.show();
-
}
-
else if (digitalRead(SENSOR_2_GPIO) == 1)
-
{
-
strip.setPixelColor(0, strip.Color(155, 0, 155));
-
strip.show();
-
}
-
else
-
{
-
strip.setPixelColor(0, strip.Color(0, 0, 0));
-
strip.show();
-
}
-
-
-
-
Serial.println(X);
-
delay(30);
-
return;
-
}
ОСТАВИТЬ КОММЕНТАРИЙ
Форма авторизации
ВОЙТИ С ПОМОЩЬЮ:
ИЛИ Авторизация на сайте: