Не работает программа

Shamanestr
Offline
Зарегистрирован: 17.03.2014

Задача проста:
По нажатию на кнопку старт, плавно запускаеться двиг. Делает 15 об. Колличество оборотов отслеживаеться д. Холла. Плавно останавливаеться. Потом задерживаеться. И возвращаеться обратно (пл. пуск, 15 об., плавн. остановка) Время задержки, регулируеться двумя кнопками (+ и -). И выводиться на 1602 экран, через айтуси.
Но почему то, он не работает.
Каждый из компонентов, был проверен в отдельности.

#include <Wire.h> // библиотека для ай2си
#include <EEPROM.h> // библиотека ЕРОПАМ
#include "LiquidCrystal_I2C.h"

LiquidCrystal_I2C lcd(0x27,16,2); // адрес шины

#define button_start 2 // пин кнопка - пуск
#define button_UP 7 // пин кнопка потенциометр +
#define button_DOWN 8 // пин кнопка потенциометр -
#define holla 3 // пин датчика холла
#define DC_UP 5 // пин движка +
#define DC_DOWN 6 // пин движка -

byte potenc = 30; // начальное значение потенциометра
byte i, y = 0, k = 0; // промежуточные переменные
long timer = potenc; // время для обратного отсчета (на всякий случай)))
byte adres0 = 0; // адрес еропама для сохранения значений
byte a=0; // регистр

void setup()
{
Serial.begin(9600); // порт
lcd.init(); // экран
potenc = EEPROM.read(adres0); // загрузка значений из еропам
lcd.clear(); // очистка экрана
lcd.setCursor(0,0); // установка курсора
lcd.print("Hello!"); // принт
}

void loop()
{
potenciometr(); // вызов метода потенциометр
if(digitalRead(button_start)==1 && a==0) // нажатие кнопки - старт
{
a=1; // сдвиг регистра вперед
k=0; // обнуление счетчика вращения вала
UP(); // вызов метода запуска двигателя вперед (15 оборотов)
delay(potenc*100); // задержка в милисекундлах (заданное время * 100 мс)
k=0; // обнуление счетчика
DOWN(); // вызов метода запуска двигателя назад (15 оборотов)
a=0; // сдвиг назад
}
}

void potenciometr() // потенциометр
{
if(digitalRead(button_UP)==1) // нажатие кнопки +
{ 
lcd.clear();
potenc+=1; // увеличение значения на 1
lcd.setCursor(0,0);
lcd.print("Hold = ");
lcd.setCursor(12,0);
lcd.print(potenc);
EEPROM.write(adres0,potenc); // запись значения в еропам
}
else if(digitalRead(button_DOWN)==1)//нажатие кнопки -
{
lcd.clear();
potenc-=1; // уменьш знач на 1
lcd.setCursor(0,0);
lcd.print("Hold = ");
lcd.setCursor(12,0);
lcd.print(potenc);
EEPROM.write(adres0,potenc); // запись в еропам
}
}
void oborot() // метод замера кол-ва оборотов вала
{
y = digitalRead(holla); // читаем датчик холла и при каждом у==1 прибавляем единицу к переменной "к"
if(y==1)
{
k++;
}
}
void UP() // метод движения движка вперед
{ 
oborot(); // замеряем кол-во оборотов
for(i=0;i<=255;i+=5) //медленный запуск
{
analogWrite(DC_UP,i);
analogWrite(DC_DOWN,0);
delay(60);
}
analogWrite(DC_UP,255);
analogWrite(DC_DOWN,0);
if(k>=15) // 15 оборотов прошло
{
for(i=255;i>=0;i-=5) // медленная остановка
{
analogWrite(DC_UP,i);
analogWrite(DC_DOWN,0);
delay(60);
}
analogWrite(DC_UP,0);
analogWrite(DC_DOWN,0);
}
}
void DOWN() // метод возврата движка, аналогичен методу вперед
{
oborot();
for(i=0;i<=255;i+=5)
{
analogWrite(DC_UP,0);
analogWrite(DC_DOWN,i);
delay(60);
}
analogWrite(DC_UP,0);
analogWrite(DC_DOWN,255);
if(k>=34)
{
for(i=255;i>=0;i-=5)
{
analogWrite(DC_UP,0);
analogWrite(DC_DOWN,i);
delay(60);
}
analogWrite(DC_UP,0);
analogWrite(DC_DOWN,0);
}
}

 

sergey323
Offline
Зарегистрирован: 21.08.2016

Как минимум нужно ввести антидребезг. Т.е. это вам "кажется" что вы нажали 1 раз. МК опрашивает порты с большой скоростью, поэтому ему "кажется" что вы отпускаете и нажимаете кнопку  много раз. И на еепроме скажется не хорошо, она рассчитана на определенное кол-во циклов записи.

ВН
Offline
Зарегистрирован: 25.02.2016

А где в скетче настройка режимов работы пинов, сетап там совершенно пустой?

Shamanestr
Offline
Зарегистрирован: 17.03.2014

1 программа, даже не выводит принт. Так что антидребезг тут не причём.
2 еерпом, расчитан на 100 000 циклов.
3 Ок. Сейчас допишу режим работы.
4 Спасибо, отписавшимся.
UPDT:
Ну немножичко ожило.
1 я забыл дописать подсветку экрана. Дописал.
2 Сейчас пишет "Hold = 218". И при каждом обращении, влюсует 1. (219,220,221...)

Shamanestr
Offline
Зарегистрирован: 17.03.2014

Вот, исправил:
 

#include <Wire.h>                    // библиотека для ай2си
#include <EEPROM.h>                  // библиотека ЕРОПАМ
#include "LiquidCrystal_I2C.h"
 
LiquidCrystal_I2C lcd(0x27,16,2); // адресс шины

#define button_start 2             // пин кнопка - пуск
#define button_UP 7                // пин кнопка потенциометр +
#define button_DOWN 8              // пин кнопка потенциометр -
#define holla 3                    // пин датчика холла
#define DC_UP 5                    // пин движка +
#define DC_DOWN 6                  // пин движка -

byte potenc = 30;                  // начальное значение потенциометра
byte i, y = 0, k = 0;              // промежуточные переменные
long timer = potenc;               // время для обратного отсчета (на всякий случай)))
byte adres0 = 0;                   // адрес еропама для сохранения значений
byte a=0;                          // регистр

void setup()
{
  {                                // устанавливает режим работы - выходов
  pinMode(button_start, INPUT);
  pinMode(button_UP, INPUT);
  pinMode(button_DOWN, INPUT);
  pinMode(holla, INPUT);
  pinMode(DC_UP, OUTPUT);
  pinMode(DC_DOWN, OUTPUT);
  }
{
  lcd.backlight();
}

  Serial.begin(9600);              // порт
  lcd.init();                      // экран
  potenc = EEPROM.read(adres0);    // загрузка значений из еропам
  lcd.clear();                     // очистка экрана
  lcd.setCursor(0,0);              // установка курсора
  lcd.print("MSG1");   // принт
}

void loop()
{
  potenciometr();                  // вызов метода потенциометр
  if(digitalRead(button_start)==1 && a==0) // нажатие кнопки - старт
  {
    a=1;                           // сдвиг регистра вперед
    k=0;                           // обнуление счетчика вращения вала
    UP();                          // вызов метода запуска двигателя вперед (15 оборотов)
    delay(potenc*100);             // задержка в милисекундлах (заданное время * 100 мс)
    k=0;                           // обнуление счетчика
    DOWN();                        // вызов метода запуска двигателя назад (15 оборотов)
    a=0;                           // сдвиг назад
  }
}

void potenciometr()          // потенциометр
{
  if(digitalRead(button_UP)==1)  // нажатие кнопки +
  {    
    lcd.clear();
    potenc+=1;                   // увеличение значения на 1
    lcd.setCursor(0,0);
    lcd.print("Hold = ");
    lcd.setCursor(12,0);
    lcd.print(potenc);
    Serial.println(potenc);
    EEPROM.write(adres0,potenc); // запись значения в еропам
  }
  else if(digitalRead(button_DOWN)==1)//нажатие кнопки -
  {
    lcd.clear();
    potenc-=1;                        // уменьш знач на 1
    lcd.setCursor(0,0);
    lcd.print("Hold = ");
    lcd.setCursor(12,0);
    lcd.print(potenc);
    Serial.println(potenc);
    
    
    
    EEPROM.write(adres0,potenc);   // запись в еропам
  }
}
void oborot()                  // метод замера кол-ва оборотов вала
{
  y = digitalRead(holla);     // читаем датчик холла и при каждом у==1 прибавляем единицу к переменной "к"
  if(y==1)
  {
    k++;
  }
}
void UP()              // метод движения движка вперед
{  
  oborot();            // замеряем кол-во оборотов
  for(i=0;i<=255;i+=5) //медленный запуск
  {
    analogWrite(DC_UP,i);
    analogWrite(DC_DOWN,0);
    delay(60);
  }
  analogWrite(DC_UP,255);
  analogWrite(DC_DOWN,0);
  if(k>=15)           // 15 оборотов прошло
  {
    for(i=255;i>=0;i-=5)  // медленная остановка
  {
    analogWrite(DC_UP,i);
    analogWrite(DC_DOWN,0);
    delay(60);
  }
  analogWrite(DC_UP,0);
  analogWrite(DC_DOWN,0);
  }
}
void DOWN()    // метод возврата движка, аналогичен методу вперед
{
  oborot();
  for(i=0;i<=255;i+=5)
  {
    analogWrite(DC_UP,0);
    analogWrite(DC_DOWN,i);
    delay(60);
  }
  analogWrite(DC_UP,0);
  analogWrite(DC_DOWN,255);
  if(k>=34)
  {
    for(i=255;i>=0;i-=5)
  {
    analogWrite(DC_UP,0);
    analogWrite(DC_DOWN,i);
    delay(60);
  }
  analogWrite(DC_UP,0);
  analogWrite(DC_DOWN,0);
  }
}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Вот вам функция из вашего кода

void oborot()                  // метод замера кол-ва оборотов вала
{
  y = digitalRead(holla);     // читаем датчик холла и при каждом у==1 прибавляем единицу к переменной "к"
  if(y==1)
  {
    k++;
  }
}

Что она делает? В произвольный момент времени считывает датчик и тупо суммирует. К подсчету оборотов это имеет далекое отношение. Представьте вахтер считает зашедших . В произвольный момент открывает глаза и дверь открыта. Есть зашедший. Но то что есть ситуация, что дверь еще открыта просто вахтер очень быстро моргал глазами и посчитал одного вошедшего за двоих, или тупо проспал кучу входящих, вахтера не волнует.

Shamanestr
Offline
Зарегистрирован: 17.03.2014

Так он начинает считать, после начала движения. Или я ошибаюсь?

{ 
oborot(); // замеряем кол-во оборотов
for(i=0;i<=255;i+=5) //медленный запуск
{

Многоуважаемые и достопочтенные программеры, не бросайте тапками. Я нуб. Но готов учиться.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

вот у вас датчик холла .  к примеру о это включено.

digitalRead(holla) идет постоянно. что будет?

0 0 0 0 и.т.д  или 1 1 1 1 и.т.д  колесо стоит в первом случает магнит напротив датчика, а в другом далеко.

А если 0 0 0 00 0 0 1 1 0 0  то колесо вращается.  а если 0 0 0 1  0 0 0 1 0 0 0 очень быстро вращается. И что бы определить 0 или 1 надо команду digitalRead(holla) делать рерулярно и сравнивать с 0 или 1

ПС: Я не готов вас учить, так как мой стиль , это кошмар для других программистов.

ВН
Offline
Зарегистрирован: 25.02.2016

Shamanestr, для подсчета оборотов лучше использовать прерывание http://arduino.ru/Reference/AttachInterrupt

настройте его работу по фронту или спаду импульса от датчика и  будет считаться только один оборот за оборот. 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Цитата из прерываний.http://arduino.ru/Reference/AttachInterrupt

Внутри функции обработки прерывания не работает delay(), значения возвращаемые millis() не изменяются. Возможна потеря данный передаваемых по последовательному соединению (Serial data) в момент выполнения функциии обработки прерывания. Переменные, изменяемые в функции, должным быть объявлены как volatile.

Особенно счетчик оборотов должен быть volatile.

sergey323
Offline
Зарегистрирован: 21.08.2016

По прерываниям, маленькое дополнение: имеет смысл там изменять переменную ( скажем присваивать 1 глобальную ест-но), а в основном цикле постоянно проверять ее и что то делать. Потом не забыть ее обратно  в 0.

Т.е. что то вроде такого получится:

volatile char i_start = 0; // каждое прерывание таймера установит в > 1.
..
..
void loop() {
  if (i_start > 0) {
   if (i_start == 1)
{ indikator_time(1); // время работы
// тут офигительно ресурсоемкий код, что нить считаем и т.п.
..
..
}
..
..
i_start =0; // не забываем обнулять
}
...
}
 // наше прерывание, код должен быть как можно быстрее выполняться
ISR (WDT_vect) {
  static char m = 0;
  m++;
  if (m > 4) m = 1;
  i_start = m;
}

 

Shamanestr
Offline
Зарегистрирован: 17.03.2014

вот это ответище. Буду изучать.
А то остальные посылают на прерывания, а там чорт ногу сломит. Я две недели назад не знал чем мега от уно отличаеться, а они мне про какие то дебри. Мне бы слепить, что бы оно заработало. А тогда появиться мотивация учиться дальше.
Спасибо!

sergey323
Offline
Зарегистрирован: 21.08.2016

Shamanestr - Я начинал изучать контроллеры с 0, без ардуино. Даже собрал на рассыпухе устройство с контроллером и читал..читал.. потом писал - оно до сих пор работает. А ардуино снижает "порог входа", с ней намного проще, но и многие вещи (те же прерывания) "не доходят". ибо зачем их копать, когда и так "все работает" (на чужом примере переделанном под себя). Только если хочешь сделать что то в "реальном времени" работающее - начинаешь догадываться, что ардуинковские проги не совсем то и без понимания внутреннего устройства не обойтись. У вас как раз такой случай. Прогу за вас никто не напишет. Ну.. за деньги только.

Mr.Privet
Mr.Privet аватар
Offline
Зарегистрирован: 17.11.2015

прерываний бояться не надо, там нет ничего сложного, это просто кусок программы который выполняется при подаче или снятии напряжения на пинах, которые эти самые прерывания поддерживают. Еще нужно понимать что если мы в этом куске делаем что то быстро то он будет не заметен на скорости выполнения программы в общем. Вот нам на пример в вашем случае выполняется программа, приходит 1 на пин прерывания, идем в спец программу, прибавляем плюсиком единичку, возвращяемся в основную программу и делаем дальше что надо до следующего прихода единички на пин прерывания. Мне понять прерывания помогло как раз работа с энкодером. в общем не так страшен черт...

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Во-во. Прерывания проще для понимания новичков. А вот если фоном организовывать 2 вычислительный процесс, для опроса датчика вращения, то у новичков становятся "анимешные глаза".

TovBender
Offline
Зарегистрирован: 12.04.2015

Кто нибудь подскажите, почему работает только половина Скетча. сделал доступ к РФИД , всё работает карты считываются, замок срабатывает. добавил код чтобы открыть с радио брелка,. в месте они не работают а по отдельности в полне даже быстро. вот если за ремить с 37 по 56 строки , то часть кода работает.                    а в месте не хотят. и Ардвинка на код не ругается. подскажите как заставить их работать, чтоб и карта доступа работала и радио брелок.

TovBender
Offline
Зарегистрирован: 12.04.2015

q

Shamanestr
Offline
Зарегистрирован: 17.03.2014

Вот это поворот!