Re: Узел отбора на перистальтическом насосе
Заказал нормальный еще.
А что с этой не так? Работает ведь.
Форум самогонщиков, винокуров, виноделов, пивоваров, бондарей и очень хороших людей |
с 181 по 200 из 1 059
Заказал нормальный еще.
А что с этой не так? Работает ведь.
Работает ведь.
Как оказалось хреновенько. Т.е не хватает мощи. Когда навешиваешь на него сам насос, он начинает пропускать обороты
А я спалил все.. коротнул с подстроечника на какой-то контакт. Сгорел и драйвер и ардуина. Заказал новое, драйвер такой же. А какой надо-то? Закажу еще один.
А я спалил все.
О, брат как!
Вот номерок 1609523735 нужен DRV8825
Danil, да ебтить... Как так-то?
Как так-то?
Крутил подстречник и случайно коротнул на соседний контакт
спалил все
Danil, ардуина с драйвером связана всего лишь одним портом, может ты порт спалил? Неужели всю ардуину?
Четланин, на ардуине лампочки горят, а дисплей погас. Да хрен с ней, новая скоро приедет.
скоро приедет.
У тебя персональный канал с Китая?!
У меня если там выставить 0,65в нихрена не работает.
Возможно это А4988. У него надо в 1,6 раза больше напряжение выставлять, чем на DRV8825. Хотя, как пишут, бывают варианты. Но скорее всего, именно в 1,6 раза. Вот, - у одного продавца:
Аркадий, месяц... разве это долго?
в 1,6 раза больше напряжение выставлять,
Не, эт ваще хрень какая-то. На нем если 0,6 выставляешь он не работает, так куда больше то.
месяц... разве это долго?
а разве это быстро?!
Коллеги, просветите по поводу пина EN на драйвере. Я так понял, что драйвер включается при соединении его с массой. А с управляющего пина ардуины тмаса что мы получим? Там же вроде либо +5В, либо ничего...
Извиняюсь за дилетантские вопросы.
Там же вроде либо +5В, либо ничего...
Та либо высокий уровень, равный 5В, либо низкий, эквивалентный замыканию на gnd.
Danil, "ничего" быть не должно. Либо 0 (масса, как ты назвал), либо единица (+5 В).
Если GND контроллеров соединены, то на ЕN будет 0, если на внешнем (тмас?) контроллере 0 и единица (+5В) - в любом другом случае (он "подтянут" на +5 В).
Ну да... пока писал уже ответили...
UPD Не... ошибся, на 0 он подтянут...
Димон, Kusnezov Oleg, дошло Спасибо!
очередь за тобой.
Вот очередь и подошла.
kvic скетчи писать не умеет, не дай бог свой код выложит... Аж страшно...
Попытался написать. Что-то получилось.
Подождём...твою скетч.
Скетч....
Из функциональности.
1. Отбор с заданной скоростью (мл/час)
2. Автостоп по задаваемому объему.
3. Калибровка с записью в EEPROM.
4. Может отображать общий объем отбора, скорость отбора, шаг отбора, остаток до автостопа.
5. Нелинейные регулировки скорости отбора и шага дозатора. При малых скоростях/объемах шаг мелкий, при средних средний при больших большой.
За основу принят аппарат Четланина:
Узел отбора на перистальтическом насосе
по схеме из:
Узел отбора на перистальтическом насосе
с некоторыми доработками:
Добавлено подключение кнопки энкодера и сигнал "стоп" с TMAS заведён непосредственно в контроллер отбора.
Ввод сигнала схематичен.
Можно как есть, можно напрямую уровнем, можно через оптрон, например.
Активный уровень - низкий, вызывает немедленный стоп.
Алгоритм работы изображён на нижеприведённой каринке:
Скетч написан исходя из имеющихся подключений оригинального варианта.
Но это вариабельно, подключать устройства /энкодер, дисплей, вход от TMAS/ можно практически к любым ногам ардуины,
библиотеки позволяют некоторую вольность,
надо только отредактировать это в скетче.
---
Все строки, относящиеся к Serial можно безболезненно удалить.
---
Вот и сам скетч:
#include <EEPROM.h> // Стандартная библиотека
#include "GyverEncoder.h" // Библиотеки с сайта
#include "GyverTM1637.h" // https://alexgyver.ru/lessons/arduino-libraries/
#include "directTimers.h" // https://codeload.github.com/AlexGyver/GyverLibs/zip/master
//------------------------------------------------------------------------------------------
//**********************************************************************************************************
#define STEP8 // Закомментировать, если используется шаг/4, раскомментировать, если используется шаг/8 *
//**********************************************************************************************************
//--------------------------- Настройка железа ---------------------------------------------
// Подключение энкодера
#define SW1 A2 // Сигнал энкодера 1 // Если кручение влево/вправо перепутано,
#define SW2 A3 // Сигнал энкодера 2 // можно поменять местами
#define KEY A4 // Кнопка энкодера
Encoder enc1(SW1, SW2, KEY, TYPE2);
// Подключение TM1637
#define CLK 9 // Тактовые импульсы TM1637
#define DIO 10 // Данные для TM1637
GyverTM1637 disp(CLK, DIO);
// Подключение DRV8825
#define STEP 2 // Тактовые импульсы на драйвер ШД
// Внешнее управление
#define TMAS 5 // Сюда подключаем управление от TMAS, низкий уровень вызовет паузу
#define LED 13 // Встроенный светодиод
//--------------------------------------------------------------------------------------
// Наименования режимов работы
//----------------------------------------------
#define RUNNING 0 //
#define PAUSED 1 //
#define PAUSED_BY_EXT 2 //
#define PAUSED_BY_VOL 3 //
#define SELECT_VOL 4 //
#define TUNING 10 //
#define TUNING_PAUSE 11 //
//----------------------------------------------
// Константы
//----------------------------------------------
#define maximumRate 2500 // Максимальная скорость отбора мл/час
#define rateStep 10 // Мелкий шаг регулировки отбора
#define rateMidStep 50 // Средний шаг регулировки отбора
#define rateBigStep 100 // Крупный шаг регулировки отбора
#define volStep 10 // Шаг регулировки дозатора
#define volMidStep 50 // Средний шаг регулировки дозатора
#define volBigStep 500 // Крупный шаг регулировки дозатора
#define maxDrinkVol 5000 // Максимальный объем, выдаваемый дозатором
#define defaultDrink 0 // Объем дозатора по умолчанию. 0 - без ограничения.
#define defaultStepsFor100ml 400000 // Количество шагов потребное для отбора 100 мл по умолчанию при шаге/4
#define minStepsFor100ml 150000 // Минимально возможное число шагов для отбора 100 мл при шаге/4
#ifdef STEP8
#define defaultStepsFor100ml 800000 // Количество шагов потребное для отбора 100 мл по умолчанию при шаге/8
#define minStepsFor100ml 550000 // Минимально возможное число шагов для отбора 100 мл при шаге/8
#endif
//----------------------------------------------
// Переменные
//----------------------------------------------
unsigned long stepsFor100ml; // Количество шагов потребное для отбора 100 мл
unsigned int stepsForOneMl; // Количество шагов потребное для отбора 1 мл
unsigned long stepsCount = 0; // Счетчик количества шагов
unsigned long drinkBackCounter = 0; // Обратный счётчик шагов дозатора
unsigned long temp = 0; // Временная переменная для разнообразных нужд
unsigned int timer1EndValue = 65535; // Значение при котором происходит прерывание от таймера 1 (11739)
byte thousandth = 0; //
byte tenth = 0; //
byte backCounter0 = 0; //
byte backCounter1 = 0; //
byte counterA = 0; //
byte currentMode = RUNNING; // Текущий режим работы
int rate = 0; // Скорость отбора мл/час 0 - maximumRate
int totalVolume = 0; // Общий объем отбора мл
int drinkVolume = 0; // Шаг рОзлива
bool newSecond = false;
bool newTenth = false;
bool stepEnabled = false;
bool tmasStop = false;
bool drinkStop = false;
bool infoEnable = false;
bool bc0flag = false;
bool bc1flag = false;
//--------------------------------------------------------------------------------------
void setup()
{
Serial.begin(115200);
// Настройка входов и выходов
pinMode(STEP, OUTPUT);
pinMode(CLK, OUTPUT);
pinMode(DIO, OUTPUT);
pinMode(LED, OUTPUT);
pinMode(SW1, INPUT_PULLUP);
pinMode(SW2, INPUT_PULLUP);
pinMode(KEY, INPUT_PULLUP);
pinMode(TMAS, INPUT_PULLUP);
digitalWrite(STEP, 1);
// Настройка таймера 1, он задаёт частоту шагания двигателя
TIMER1_setClock(PRESCALER_64); // Частота тактирования таймера 1: 16/64 = 0.25 МГц при шаге/4
#ifdef STEP8
TIMER1_setClock(PRESCALER_8); // Частота тактирования таймера 1: 16/8 = 2 МГц при шаге/8
#endif
TIMER1_setMode(CTC_MODE); // Режим работы таймера - сравнение со значением, прерывание и рестарт
TIMER1_COMPA_setValue(timer1EndValue); // Значение для сравнения
TIMER1_attach_COMPA(); // Прерывание от таймера 1 по сравнению
// Настройка таймера 2, он отсчитывает временные интервалы для работы программы
TIMER2_setClock(PRESCALER_128); // Частота тактирования таймера 2: 16/128 = 0.125 МГц
TIMER2_setMode(CTC_MODE); // включаем сброс таймера по совпадению
TIMER2_COMPA_setValue(124); // настраиваем следование прерываний с частотой 1000 гц
TIMER2_attach_COMPA(); // прерывание с опросом энкодера
// Настройка дисплея и вывод привета.
disp.clear();
disp.brightness(1);
byte welcome_banner[] = { _empty, _empty,_dash, _dash, _r, _u, _n, _dash, _dash, _empty, _empty};
disp.runningString(welcome_banner, sizeof(welcome_banner), 200);
//byte troll[4] = {_r, _U, _n, _empty};
//disp.scrollByte(troll, 100);
disp.displayInt(0);
// Попытка прочитать установки из EEPROM
EEPROM.get(0, stepsFor100ml);
if ((stepsFor100ml < minStepsFor100ml) or (stepsFor100ml > minStepsFor100ml * 4)) // Если в EEPROM не установлено число шагов на 100 мл, то
{
stepsFor100ml = defaultStepsFor100ml; // Установим число шагов на 100 мл по умолчанию
}
stepsForOneMl = round((float)stepsFor100ml / 100);
calcOCR1A();
drinkVolume = defaultDrink;
drinkBackCounter = (uint32_t)drinkVolume * stepsForOneMl - 1;
//if (enc1.isHolded()) {
if (!digitalRead(KEY)) {
currentMode = TUNING;
byte troll[4] = {_t, _u, _n, _E};
disp.displayByte(troll);
backCounter0 = 0;
infoEnable = false;
enc1.isHolded();
}
else {
currentMode = RUNNING;
infoEnable = true;
}
Serial.println(drinkVolume); //
Serial.println(stepsFor100ml); //
Serial.println(stepsForOneMl); //
Serial.println(drinkBackCounter); //
Serial.println("Setup completed");
}
//--------------------------------------------------------------------------------------
//---------------------- Начало основного цикла ----------------------------------------
void loop()
{
if (newSecond) {
newSecond = false;
oneSecSub();
}
if (newTenth) {
newTenth = false;
oneTenthSub();
}
if (bc0flag) {
bc0flag = false;
infoEnable = true;
}
//---------------------------------------------------------------
switch (currentMode)
{
//-------------------------------------------------------------
// Режим калибровки насоса основной экран ---------------------
//-------------------------------------------------------------
case TUNING: // Настройка количества шагов на 100 мл.
{
infoEnable = false;
//--------------------
if (bc1flag)
{
bc1flag = false;
byte troll[4] = {_t, _u, _n, _E};
disp.displayByte(troll);
}
//--------------------
if (enc1.isRight()) // Поворот по часовой стрелке увеличивает частоту шагов
{
increaseRate();
stepEnabled = true;
disp.displayInt(rate);
backCounter1 = 20;
}
//--------------------
if (enc1.isLeft()) // Поворот против часовой стрелки уменьшает частоту шагов
{
decreaseRate();
if (rate != 0)
{
stepEnabled = true;
}
disp.displayInt(rate);
backCounter1 = 20;
}
//--------------------
if (enc1.isClick())
{
stepEnabled = false;
currentMode = TUNING_PAUSE;
byte troll[4] = {_t, _P, _A, _u};
disp.displayByte(troll);
}
//--------------------
if (enc1.isHolded())
{
Reset();
}
//--------------------
}
break;
//-------------------------------------------------------------
// Пауза в режиме калибровки насоса ---------------------------
//-------------------------------------------------------------
case TUNING_PAUSE:
{
//--------------------
if (bc1flag)
{
bc1flag = false;
counterA = 0;
byte troll[4] = {_t, _P, _A, _u};
disp.displayByte(troll);
}
//--------------------
if (enc1.isRight()) // Поворот по часовой стрелке увеличивает частоту шагов
{
increaseRate();
disp.displayInt(rate);
backCounter1 = 20;
}
//--------------------
if (enc1.isLeft()) // Поворот против часовой стрелки уменьшает частоту шагов
{
decreaseRate();
disp.displayInt(rate);
backCounter1 = 20;
}
//--------------------
if (enc1.isClick())
{
stepEnabled = true;
currentMode = TUNING;
byte troll[4] = {_t, _u, _n, _E};
disp.displayByte(troll);
}
//--------------------
if (enc1.isHolded())
{
stepsCount = 0;
totalVolume = 0;
byte welcome_banner[] = {_c, _o, _u, _n, _t, _E, _r, _S, _empty, _c, _l, _e, _a, _r, _e, _d};
disp.runningString(welcome_banner, sizeof(welcome_banner), 200);
bc1flag = true;
}
//--------------------
if (enc1.isRightH())
{
tryToSaveStepsFor100ml();
}
//--------------------
if (enc1.isLeftH())
{
tryToSaveStepsFor100ml();
}
//--------------------
}
break;
//-------------------------------------------------------------
// Основной режим. Идёт отбор. --------------------------------
//-------------------------------------------------------------
case RUNNING:
{
//--------------------
if (enc1.isClick()) // Клик на кнопку (режим RUNNING)
{
stepEnabled = false;
currentMode = PAUSED;
byte troll[4] = {_S, _t, _o, _P};
//disp.twistByte(troll, 20);
disp.displayByte(troll);
backCounter0 = 0;
infoEnable = false;
}
//--------------------
if (tmasStop) // Внешний сигнал, появление (режим RUNNING)
{
stepEnabled = false;
currentMode = PAUSED_BY_EXT;
byte troll[4] = {_o, _u, _t, _S};
//disp.twistByte(troll, 20);
disp.displayByte(troll);
backCounter0 = 0;
infoEnable = false;
}
//--------------------
if (drinkStop) // Налит запрошенный объем (режим RUNNING)
{
stepEnabled = false;
drinkStop = false;
currentMode = PAUSED_BY_VOL;
drinkBackCounter = (uint32_t)drinkVolume * stepsForOneMl - 1;
byte troll[4] = {_d, _o, _n, _E};
//disp.twistByte(troll, 20);
disp.displayByte(troll);
backCounter0 = 0;
infoEnable = false;
}
//--------------------
if (enc1.isRight()) // Вращение по часовой (режим RUNNING)
{
if (backCounter0 != 0)
{
increaseRate();
stepEnabled = true;
}
disp.displayInt(rate);
infoEnable = false;
backCounter0 = 20;
}
//--------------------
if (enc1.isLeft()) // Вращение против часовой (режим RUNNING)
{
if (backCounter0 != 0)
{
decreaseRate();
if (rate != 0)
{
stepEnabled = true;
}
}
disp.displayInt(rate);
infoEnable = false;
backCounter0 = 20;
}
//--------------------
if (enc1.isHolded()) // Удержание кнопки (режим RUNNING)
{
if ((rate == 0) and (stepsCount != 0))
{
stepsCount = 0;
totalVolume = 0;
drinkBackCounter = (uint32_t)drinkVolume * stepsForOneMl - 1;
byte welcome_banner[] = {_c, _o, _u, _n, _t, _E, _r, _S, _empty, _c, _l, _e, _a, _r, _e, _d};
disp.runningString(welcome_banner, sizeof(welcome_banner), 200);
}
else
{
if (infoEnable) {
if (drinkVolume == 0)
{
byte troll[4] = {_empty, _i, _n, _f};
disp.displayByte(troll);
}
else
{
disp.displayInt((drinkBackCounter + 1) / stepsForOneMl);
}
}
infoEnable = false;
backCounter0 = 20;
}
}
//--------------------
}
break;
//-------------------------------------------------------------
// Остановка по нажатию кнопки --------------------------------
//-------------------------------------------------------------
case PAUSED:
{
//--------------------
if (bc1flag)
{
bc1flag = false;
//stepEnabled = false;
byte troll[4] = {_S, _t, _o, _P};
disp.displayByte(troll);
infoEnable = false;
}
//--------------------
if (enc1.isClick())
{
resumeRun();
}
//--------------------
if (enc1.isRight())
{
if (backCounter1 != 0)
{
increaseRate();
}
disp.displayInt(rate);
infoEnable = false;
backCounter1 = 20;
}
//--------------------
if (enc1.isLeft())
{
if (backCounter1 != 0)
{
decreaseRate();
}
disp.displayInt(rate);
infoEnable = false;
backCounter1 = 20;
}
//--------------------
if (enc1.isHolded())
{
infoEnable = false;
currentMode = SELECT_VOL;
byte troll[4] = {_S, _t, _E, _P};
disp.displayByte(troll);
}
//--------------------
}
break;
//-------------------------------------------------------------
// Остановка по внешнему сигналу ------------------------------
//-------------------------------------------------------------
case PAUSED_BY_EXT:
{
if (!tmasStop)
{
resumeRun();
}
//--------------------
}
break;
//-------------------------------------------------------------
// Остановка по достижению заданного разового объема отбора ---
//-------------------------------------------------------------
case PAUSED_BY_VOL:
{
//--------------------
if (enc1.isHolded())
{
infoEnable = false;
currentMode = SELECT_VOL;
byte troll[4] = {_S, _t, _E, _P};
disp.displayByte(troll);
}
//--------------------
if (enc1.isClick())
{
resumeRun();
}
//--------------------
}
break;
//-------------------------------------------------------------
// Режим выбора разового объема -------------------------------
//-------------------------------------------------------------
case SELECT_VOL:
{
//--------------------
if (bc1flag)
{
bc1flag = false;
byte troll[4] = {_S, _t, _E, _P};
disp.displayByte(troll);
}
//--------------------
if (enc1.isHolded())
{
drinkBackCounter = (uint32_t)drinkVolume * stepsForOneMl - 1;
resumeRun();
}
//--------------------
if (enc1.isClick())
{
currentMode = PAUSED;
drinkBackCounter = (uint32_t)drinkVolume * stepsForOneMl - 1;
byte troll[4] = {_S, _t, _o, _P};
disp.displayByte(troll);
}
//--------------------
if (enc1.isRight())
{
if (backCounter1 != 0)
{
if (drinkVolume >= 1000) {
drinkVolume = drinkVolume + volBigStep;
} else {
if (drinkVolume >= 100) {
drinkVolume = drinkVolume + volMidStep;
} else {
drinkVolume = drinkVolume + volStep;
}
}
if (drinkVolume >= maxDrinkVol) drinkVolume = 5000;
}
disp.displayInt(drinkVolume);
backCounter1 = 20;
}
//--------------------
if (enc1.isLeft())
{
if (backCounter1 != 0)
{
if (drinkVolume >= (1000 + volBigStep)) {
drinkVolume = drinkVolume - volBigStep;
} else {
if (drinkVolume >= (100 + volMidStep)) {
drinkVolume = drinkVolume - volMidStep;
} else {
drinkVolume = drinkVolume - volStep;
}
}
if (drinkVolume <= 0) drinkVolume = 0;
}
disp.displayInt(drinkVolume);
backCounter1 = 20;
}
//--------------------
}
break;
//-------------------------------------------------------------
default:
//-------------------------------------------------
break;
}
//-------------------------------------------------
}
//---------------------- Конец основного цикла -----------------------------------------
//--------------------------------------------------------------------------------------
void resumeRun()
{
byte troll[4] = {_dash, _G, _o, _dash};
disp.displayByte(troll);
currentMode = RUNNING;
if (rate != 0)
{
stepEnabled = true;
}
backCounter0 = 5;
}
//--------------------------------------------------------------------------------------
// То, что выполняется каждую секунду --------------------------------------------------
void oneSecSub()
{
calcTotalVolume();
Serial.println(String(stepsCount) + " " + String(totalVolume) + " " + String(timer1EndValue));
if (infoEnable)
{
//noInterrupts();
disp.displayInt(totalVolume % 10000);
//interrupts();
}
}
//--------------------------------------------------------------------------------------
// То, что выполняется каждую десятую долю секунды -------------------------------------
void oneTenthSub()
{
tmasStop = !digitalRead(TMAS);
digitalWrite(13, tmasStop);
}
//--------------------------------------------------------------------------------------
// Прерывание таймера 2 (1000 раз в секунду) -------------------------------------------
ISR_T2_COMPA
{
enc1.tick();
thousandth++; // Счетчик миллисекунд
if (thousandth >= 100) // Началась новая десятая доля секунды
{ thousandth = 0; tenth++; newTenth = true; // Счетчик десятых долей секунды
if (backCounter0 != 0) {
backCounter0--;
if (backCounter0 == 0) {
bc0flag = true;
}
}
if (backCounter1 != 0) {
backCounter1--;
if (backCounter1 == 0) {
bc1flag = true;
}
}
if (tenth >= 10) {
tenth = 0; // Началась новая секунда
newSecond = true;
}
}
}
//--------------------------------------------------------------------------------------
// Прерывание по совпадению А в таймере 1 ----------------------------------------------
ISR_T1_COMPA
{
if ((stepEnabled) or (!(stepEnabled) and !(digitalRead(STEP).
// Если шаги разрешены или запрещены и уровень на тактовом выходе низкий, то:
{
digitalWrite(STEP, !digitalRead(STEP)); // Меняем уровень на шагательной ноге на противоположный
if (digitalRead(STEP)) // Если был переход 0->1,
{
stepsCount++; // то увеличиваем счетчик шагов
TIMER1_COMPA_setValue(timer1EndValue); // и перезагружаем значение сравнения счетчика.
if (drinkVolume != 0) // Если задан ненулевой объем наливайки
{
if (drinkBackCounter == 0) // и налито, сколько запрошено,
{
stepEnabled = false; // останавливаем отбор
drinkStop = true; // и устанавливаем флаг готовности дринка. (обрабатывается в основном цикле)
}
else
{
drinkBackCounter--; // Иначе уменьшаем дринковый счетчик.
}
}
}
}
}
//--------------------------------------------------------------------------------------
// Расчет числа, загружаемого в OCR1A в зависимости от нужной скорости отбора ----------
void calcOCR1A()
{
stepEnabled = false;
temp = round((float)450000000 / stepsForOneMl); // шаг/4
#ifdef STEP8
temp = round((float)3600000000 / stepsForOneMl); // шаг/8
#endif
// OCR1A = (Fcpu*3600)/(2*N*K*R)-1
temp = round((float)temp / rate); // Fcpu = 16000000 Гц, N - количество шагов на 1 мл,
temp = temp - 1; // K - делитель перед счетчиком Т1 (64), R - скорость отбора мл/час
if (temp >= 65535)
{
rate = 0;
disp.displayInt(rate);
}
else
{
noInterrupts(); // Обеспечиваем атомарность действия
timer1EndValue = temp; //
interrupts(); // Восстанавливаем прерывания
}
}
//--------------------------------------------------------------------------------------
// Пересчёт количества шагов в миллилитры ----------------------------------------------
void calcTotalVolume()
{
totalVolume = stepsCount / stepsForOneMl;
}
//--------------------------------------------------------------------------------------
// Увеличение скорости отбора ----------------------------------------------------------
void increaseRate()
{
if (rate >= 1000) {
rate = rate + rateBigStep;
} else {
if (rate >= 200) {
rate = rate + rateMidStep;
} else {
rate = rate + rateStep;
}
}
if (rate >= maximumRate) rate = maximumRate;
calcOCR1A();
}
//--------------------------------------------------------------------------------------
// Уменьшение скорости отбора ----------------------------------------------------------
void decreaseRate()
{
if (rate >= (1000 + rateBigStep)) {
rate = rate - rateBigStep;
} else {
if (rate >= (200 + rateMidStep)) {
rate = rate - rateMidStep;
} else {
rate = rate - rateStep;
}
}
if (rate <= 0) rate = 0;
calcOCR1A();
}
//--------------------------------------------------------------------------------------
void tryToSaveStepsFor100ml()
{
backCounter1 = 20;
counterA++;
if (counterA > 10)
{
if ((stepsCount > minStepsFor100ml) and (stepsCount < 4 * minStepsFor100ml))
{
EEPROM.put(0, stepsCount);
byte welcome_banner[] = {_C, _A, _L, _i, _b, _r, _A, _t, _i, _n, _G, _empty, _d, _o, _n, _E, _empty, _r, _e, _S, _t, _A, _r, _t, _i, _n, _G, _empty, _empty};
disp.runningString(welcome_banner, sizeof(welcome_banner), 200);
Reset();
}
}
}
//--------------------------------------------------------------------------------------
inline void Reset() {
asm("JMP 0");
}
Отдельно на гуглодиске:
https://drive.google.com/open?id=1F2CP0 … BD6CzoVWvZ
В архиве сам скетч и требуемые библиотеки.
Ссылки на библиотеки приведены в теле скетча.
Из общей кучи нужны библиотеки GyverEncoder , GyverTM1637 , directTimers .
Всё это испытано на макетке.
Вроде работает.
Желающие могут испытать всё это на своём оборудовании.
Как всегда, от всякой ответственности отказываюсь.
Всё на свой страх и риск с осознанием возможных последствий.
Так же всё отдаётся в свободное использование и модификацию.
----------
Конструктивная критика и предложения принимаются.
----------
Если что не понятно, пишите, постараюсь пояснить.
----------
09.11
Один косячок уже нашёл и исправил.
Не отрабатывала корректно ветка RUNNING->STOP->STEP->(изменить шаг)->STOP->RUNNING
Поправлено. Файл перезалил.
----------
27.11
Ниже по ссылке архив со всеми необходимыми библиотеками.
Версия со звуковым сопровождением. (см.ветку обсуждения)
https://drive.google.com/file/d/1ZHZ6Nh … 1XrW6x3gqy
Сегодня попробовал прошить ардуину. С IDE не шьется, что-то там в ардуине крутится и постоянно мигает красный диод, и выводит в сом-порт какое-то значение напряжения и еще что-то. Взял загрузочный файл ТМАСа, грузанул его, ардуина прогрузилась, первоначальное мигание закончилось.
Тогда сделал скетч чтобы помигать диодом на 13 ноге, скомпилировал в HEX и прогрузил X-loader'ом, все вроде нормально, мигает. Потом скомпилировал скетч Четланина, он судя по индикаторам и реакции X-loader'а тоже прогрузился.
Пне это все так понравилось, что я решил еще раз перезаписать скетч с мигающим диодом. И тут наступила засада. X-loader выдал сообщение Upload failed, и больше ни одного скетча загрузить на ардуину я не могу. И судя по диодам rx/tx никакого обмена не идет.
Сломался загрузчик? За новой ехать?
с 181 по 200 из 1 059