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; // что это возвращается и для чего?
}