ESP32 - шаговый двигатель, єнкодер и чтение аналогового порта
- Войдите на сайт для отправки комментариев
Втр, 27/11/2018 - 01:57
Доброго времени суток!
пітаюсь разобраться с модуем ESP32, а именно с многозадачностью... Идея такова, есть:
-два шаговых двигателя (ШД),
-энкодер
-экранчик
-аналоговый вход
надо чтобы:
на экранчике обновлялись показания с аналогового входа, причем даже при команде ШД вращаться на заданное количество шагов, данные на экране должны продолжать обновляться и энкодер должен продолжать работать....
в планах еще прикрутить вебсервер и.. телеграмбота...
сейчас пособирал по нету кучу кусков кода - как-то оно работает, но многое по коду не понятно и команда на вращение двигателей рубит чтение аналогового входа и реакцию на энкодер...
буду благодарен за любые подсказки...
#include "AiEsp32RotaryEncoder.h" #include "Arduino.h" #include <Wire.h> #include <LiquidCrystal_I2C.h> LiquidCrystal_I2C lcd(0x3F, 16, 2); /* connecting Rotary encoder CLK (A pin) - to any microcontroler intput pin with interrupt -> in this example pin 32 DT (B pin) - to any microcontroler intput pin with interrupt -> in this example pin 21 SW (button pin) - to any microcontroler intput pin -> in this example pin 25 VCC - to microcontroler VCC (then set ROTARY_ENCODER_VCC_PIN -1) or in this example pin 25 GND - to microcontroler GND */ #define ROTARY_ENCODER_A_PIN 26 #define ROTARY_ENCODER_B_PIN 27 #define ROTARY_ENCODER_BUTTON_PIN 25 #define ROTARY_ENCODER_VCC_PIN -1 /*put -1 of Rotary encoder Vcc is connected directly to 3,3V; else you can use declared output pin for powering rotary encoder */ #define analog_PIN 35 int val = 0; // variable to store the value read int val_old = 0; AiEsp32RotaryEncoder rotaryEncoder = AiEsp32RotaryEncoder(ROTARY_ENCODER_A_PIN, ROTARY_ENCODER_B_PIN, ROTARY_ENCODER_BUTTON_PIN, ROTARY_ENCODER_VCC_PIN); int test_limits = 5; int _encoderValue = 0; TaskHandle_t get_analog_val; const int led1 = 2; void get_analog_val_fn( void * pvParameters ){ // Serial.print("Task1 running on core "); // Serial.println(xPortGetCoreID()); for(;;){ val = analogRead(analog_PIN); // read the input pin digitalWrite(led1, HIGH); delay(1000); digitalWrite(led1, LOW); delay(1000); } } #include "freertos/event_groups.h" #include "freertos/queue.h" #if CONFIG_FREERTOS_UNICORE #define ARDUINO_RUNNING_CORE 0 #else #define ARDUINO_RUNNING_CORE 1 #endif // DRV8825 GPIO Pins #define M1_STEP 15 #define M1_DIR 4 #define M1_EN 23 #define M2_STEP 19 #define M2_DIR 18 #define M2_EN 5 struct mot_send { // струкура, для хренения количества шагов и задержка мс int steps; uint32_t delayms; }; // Handles for Multitasking const int MOT1_BIT = BIT0; const int MOT2_BIT = BIT1; xQueueHandle mot1_queue; xQueueHandle mot2_queue; EventGroupHandle_t mot_eventgroup; void setup() { Serial.begin(115200); Serial.println("Hello"); pinMode(ROTARY_ENCODER_A_PIN, INPUT_PULLUP); pinMode(ROTARY_ENCODER_B_PIN, INPUT_PULLUP); pinMode(ROTARY_ENCODER_BUTTON_PIN, INPUT_PULLUP); pinMode(led1, OUTPUT); xTaskCreatePinnedToCore( get_analog_val_fn, /* Task function. */ "Task1", /* name of task. */ 10000, /* Stack size of task */ NULL, /* parameter of the task */ 1, /* priority of the task */ &get_analog_val, /* Task handle to keep track of created task */ 1); /* pin task to core 0 */ delay(500); pinMode(M1_DIR, OUTPUT); pinMode(M1_STEP, OUTPUT); pinMode(M1_EN, OUTPUT); digitalWrite(M1_DIR, LOW); digitalWrite(M1_STEP, LOW); digitalWrite(M1_EN, LOW); pinMode(M2_DIR, OUTPUT); pinMode(M2_STEP, OUTPUT); pinMode(M2_EN, OUTPUT); digitalWrite(M2_DIR, LOW); digitalWrite(M2_STEP, LOW); digitalWrite(M2_EN, LOW); // Multitasking setup mot1_queue = xQueueCreate(10, sizeof(mot_send)); // что это? mot2_queue = xQueueCreate(10, sizeof(mot_send)); mot_eventgroup = xEventGroupCreate(); xTaskCreatePinnedToCore(mot_task_step, /* Указатель на функцию, которая реализует задачу. */ "mot_task_step1", /* Текстовое имя задачи. Этот параметр нужен только для упрощения отладки. */ 4096, /* Глубина стека */ (void *)1, /* ?? Мы не используем параметр задачи. */ // что это? 1, /* Задача будет запущена с приоритетом 1. */ NULL, /* Мы не будем использовать хендл задачи. */ ARDUINO_RUNNING_CORE); xTaskCreatePinnedToCore(mot_task_step, "mot_task_step2", 4096, (void *)2, 1, NULL, ARDUINO_RUNNING_CORE); //we must initialize rorary encoder rotaryEncoder.begin(); rotaryEncoder.setup([]{rotaryEncoder.readEncoder_ISR();}); //optionally we can set boundaries and if values should cycle or not rotaryEncoder.setBoundaries(0, 20, true); //minValue, maxValue, cycle values (when max go to min and vice versa) Wire.begin (21, 22); // sda= GPIO_21 /scl= GPIO_22 // pinMode(SDA,INPUT_PULLUP); // pinMode(SCL,INPUT_PULLUP); lcd.init(); // initialize the lcd // Print a message to the LCD. lcd.backlight(); lcd.setCursor(0,0); lcd.print("Hello world"); lcd.setCursor(0,1); lcd.print("ESP32 I2C LCD"); } void loop() { //in loop call your custom function which will process rotary encoder values rotary_loop(); if (val_old != val) { val_old = val; Serial.print("analog = "); Serial.println(val); lcd.setCursor(0,0); lcd.print("analog = "); lcd.setCursor(5,0); lcd.print(val); } if (Serial.available()) { char c = Serial.read(); if (c == 'm') { dubmot_step(-1000, 1, -1000, 1); } else if (c == 'l') { dubmot_step(1000, 2, 1000, 1); } else if (c == 'h') { dubmot_step(1000, 1, 0, 1); } else if (c == 'c') { dubmot_step(0, 1, 1000, 1); } } //delay(50); //if (millis()>20000) rotaryEncoder.enable (); // для чего это? } void rotary_loop() { //first lets handle rotary encoder button click if (rotaryEncoder.currentButtonState() == BUT_RELEASED) { //we can process it here or call separate function like: rotary_onButtonClick(); } //lets see if anything changed int16_t encoderDelta = rotaryEncoder.encoderChanged(); //optionally we can ignore whenever there is no change if (encoderDelta == 0) return; //for some cases we only want to know if value is increased or decreased (typically for menu items) if (encoderDelta>0) Serial.print("+"); if (encoderDelta<0) Serial.print("-"); //for other cases we want to know what is current value. Additionally often we only want if something changed //example: when using rotary encoder to set termostat temperature, or sound volume etc //if value is changed compared to our last read if (encoderDelta!=0) { //now we need current value int16_t encoderValue = rotaryEncoder.readEncoder(); _encoderValue = encoderValue; //process new value. Here is simple output. Serial.print("Value: "); Serial.println(encoderValue); lcd.setCursor(14,0); lcd.print(" "); lcd.setCursor(14,0); lcd.print(encoderValue); } } void rotary_onButtonClick() { //rotaryEncoder.reset(); //rotaryEncoder.disable(); // rotaryEncoder.setBoundaries(-test_limits, test_limits, false); // test_limits *= 1; // lcd.setCursor(0,0); // lcd.print("analog = "); lcd.setCursor(0,1); lcd.print("encoderVal = "); lcd.print(" "); lcd.setCursor(0,1); lcd.print("encoderVal = "); lcd.print(_encoderValue); lcd.setCursor(14,0); lcd.print(" "); } /* typedef enum { BUT_DOWN = 0, BUT_PUSHED = 1, BUT_UP = 2, BUT_RELEASED = 3, BUT_DISABLED = 99, //this state is after you call rotaryEncoder.disable(); } ButtonState; */ /**@brief Function for handling one Steppermotor with multitasking. * Runs forever waiting for orders in the queue and after finishing * set the eventgroup bit for the motor. * * @param[in] pvParameters motor number. */ void mot_task_step(void *pvParameters) { int m_step,m_dir,m_en; int mot = (int)pvParameters; int steps; uint32_t delayms; xQueueHandle mot_queue; // что это? struct mot_send oMotSendPara; if (mot==2) { mot_queue=mot2_queue; m_step=M2_STEP; m_dir=M2_DIR; m_en=M2_EN; } else { mot_queue=mot1_queue; // xQueueHandle mot1_queue; m_step=M1_STEP; m_dir=M1_DIR; m_en=M1_EN; } while (1) { if(xQueueReceive(mot_queue,&oMotSendPara,60000/portTICK_RATE_MS)==pdTRUE) { // max wait 60s // что это все такое? steps = oMotSendPara.steps; delayms = oMotSendPara.delayms; Serial.print("task motor "); Serial.print(mot); digitalWrite(m_en, LOW); if (steps > 0) { Serial.print(" CCW Steps "); digitalWrite(m_dir, HIGH); } else { Serial.print(" CW Steps "); digitalWrite(m_dir, LOW); } steps = abs(steps); Serial.print(steps); Serial.print(" Speed "); Serial.println(delayms); Serial.print("task motor "); Serial.print(mot); Serial.println(" start"); for (int pos=0;pos<steps;pos++) { digitalWrite(m_step, HIGH); vTaskDelay(delayms/portTICK_RATE_MS); // delay x 1ms // что это такое? digitalWrite(m_step, LOW); vTaskDelay(delayms/portTICK_RATE_MS); // delay x 1ms } Serial.print("task motor "); Serial.print(mot); Serial.println(" stop"); if (mot==2) { Serial.println("mot_task_step xEventGroupSetBits 2"); xEventGroupSetBits(mot_eventgroup, MOT2_BIT); // что это за MOT2_BIT? } else { Serial.println("mot_task_step xEventGroupSetBits 1"); xEventGroupSetBits(mot_eventgroup, MOT1_BIT); } } if (uxQueueMessagesWaiting(mot_queue)==0) { // no message? take a break vTaskDelay(100 / portTICK_RATE_MS); // delay 100ms // что это, зачем делим на 1?? } } Serial.println("mot_task_step ends"); } int dubmot_step(int steps1, uint32_t delayms1,int steps2, uint32_t delayms2) { EventBits_t bits; struct mot_send oMotSendPara1,oMotSendPara2; oMotSendPara1.steps=steps1; oMotSendPara1.delayms=delayms1; oMotSendPara2.steps=steps2; oMotSendPara2.delayms=delayms2; // inter task information exchange Serial.println("dubmot_step xQueueSendToBack 1 "); if(xQueueSendToBack(mot1_queue,&oMotSendPara1,1000/portTICK_RATE_MS)!=pdTRUE) { // что это такое?((( Serial.println("dubmot_step error stop 1"); return 1; } Serial.println("dubmot_step xQueueSendToBack 2 "); if(xQueueSendToBack(mot2_queue,&oMotSendPara2,1000/portTICK_RATE_MS)!=pdTRUE) { Serial.println("dubmot_step error stop 2"); return 1; // что это возвращается и для чего? } // sync while (1) { bits=xEventGroupWaitBits(mot_eventgroup, MOT1_BIT|MOT2_BIT,pdTRUE, pdTRUE, 60000 / portTICK_RATE_MS); // max wait 60s // что это, откуда 60 секунд?? if(bits==(MOT1_BIT|MOT2_BIT)) { // xWaitForAllBits == pdTRUE, so we wait for MOT1_BIT and MOT2_BIT so all other is timeout Serial.println("dubmot_step sync 1+2"); break; } else { if (uxQueueMessagesWaiting(mot1_queue)==0 && uxQueueMessagesWaiting(mot2_queue)==0 ) { // no message? take a break // что это за сравнение?? break; } Serial.println("dubmot_step wait sync"); } } return 0; // что это возвращается и для чего? }