Если ваш вопрос не влез ни в одну из вышеперечисленных тем, вам сюда.
Ответить

Простое управление коллекторным двигателем с помощью МК

Ср мар 14, 2018 20:07:30

Всем категорическое здравствуйте!

Есть проект, для которого необходимо простейшее управление коллекторным моторчиком 12V с энкодером на микроконтроллере:
- нажатие кнопки "Вперед" - вращение на полных оборотах, по часовой стрелке, на протяжении 30 сек. И пока поступают импульсы с энкодера;
- нажатие кнопки "Назад" - вращение на полных оборотах против часовой стрелки, на протяжении 30 сек. И пока поступают импульсы с энкодера;
- если в течении 2 сек. энкодер выдал меньше 50 импульсов (т. е. мотор провернул рычаг до упора) - стоп.
Вот и все. Программированием МК я не занимался, язык Си или Ассемблер - не знаю. Строить это на ардуино принципиально не хочу.
Решил, что с такой "мега сложной" задачей справлюсь с помощью гугля и своих скромных познаний в элетротехнике, но что то пошло не так...
Я разобрался как посчитать импульсы с энкодера таймером ТС1 на МК ATMega8 и остановить двигатель по заданному числу импульсов: сконфигурировал ТС1 на внешний источник тактирования, установил прерывание по совпадению, снимаю импульсы с входа Т1 счетчика, сравниваю с регистром ОСR1A (5000 импульсов) и при совпадении останавливаю двигатель подав лог. "0" на выход OC1A счетчика, который в свою очередь управляет драйвером L298.
Но вот как сделать, что бы мотор останавливать при падении импульсов до заданного числа да еще на протяжении заданного времени никак понять не могу. Подскажите кому не лень как в принципе можно решить эту "мега задачу"?
Всем откликнувшимся - категорическое Спасибо!

Re: Простое управление коллекторным двигателем с помощью МК

Ср мар 14, 2018 20:19:23

Другим таймером считайте время и если в течении заданного времени нет ни одного импульса, то останавливайте мотор.

Re: Простое управление коллекторным двигателем с помощью МК

Ср мар 14, 2018 20:34:44

Другим таймером считайте время и если в течении заданного времени нет ни одного импульса, то останавливайте мотор.

Можно пример конструкции на Си? Как посчитать отрезок времени другим таймером я понимаю, но как указать МК сравнивать каждые 2 сек. количество импульсов с заданным и если оно меньше 50 импульсов НА ПРОТЯЖЕНИИ ДВУХ СЕКУНД - останавливать мотор - не пойму....

Re: Простое управление коллекторным двигателем с помощью МК

Ср мар 14, 2018 20:46:28

по прерыванию таймера (скажем 4 раза в секунду) сравниваешь состояние твоего счетного таймера с ячейкой массива на 8 элементов если разница меньше 50 - выключаешь мотор, если больше - записываешь состояние в ячейку и переключаешся на следующую ячейку массива, к этой ячейке он вернётся какраз через 2 сек (только первые 8 замеров всегда считай набравшими 50, это надо чтобы первые 2 секунды выдержать, пока счетчик наполнится).
так ходя по кругу счетчик точнее отмерит эти 2 секунды, можно, конечно не заморачиваться и заглядывать в счетчик раз в 2 секунды, но тогда работа мотора в заклиненном состоянии может дойти почти до 4сек (если заклинит в начале цикла измерения, но, уже набрав 50 отсчетов)

Добавлено after 1 minute 33 seconds:
чтобы считать импульсы можно один из таймеров настроить в режим счетчика внешних импульсов или используя внешнее прерывание инкрементировать переменную-счетчик программно

Re: Простое управление коллекторным двигателем с помощью МК

Ср мар 14, 2018 20:47:56

Запоминайте текущее число импульсов в переменной, ждите 2 секунды и сравнивайте текущее число импульсов с тем что ранее было сохранено в переменной. Если значения одинаковы, то новых импульсов не было.

Re: Простое управление коллекторным двигателем с помощью МК

Ср мар 14, 2018 21:14:27

Запоминайте текущее число импульсов в переменной, ждите 2 секунды и сравнивайте текущее число импульсов с тем что ранее было сохранено в переменной. Если значения одинаковы, то новых импульсов не было.

ВО! Спасибо, суть понял! Только мне нужно сравнивать с тем значением что было 2 сек. назад: если оно увеличилось меньше чем на 50 импульсов - стоп, если больше чем на 50 импульсов - продолжать работу 30 сек. или 5000 импульсов. ибо мотор с редуктором и в заклиненном состоянии как нибудь да шевелиться будет, выдавая енкодеру эти самые несколько импульсов. Но это уже простая математика.
Пошел искать синтаксис для реализации на Си. Нужно еще разобраться с delay. Я так понимаю он полностью останавливает программу на время задержки. Как правильно "ждать" эти 2 сек. нужно еще разобраться... Так же еще не уяснил как задать время работы 30 сек.
Спасибо за помощь!

Re: Простое управление коллекторным двигателем с помощью МК

Ср мар 14, 2018 21:23:04

есть такая штука - прерывания, а просто ждать - не вариант

Re: Простое управление коллекторным двигателем с помощью МК

Ср мар 14, 2018 22:11:47

Может лучше не количество импульсов оценивать, а время между ними? 50 импульсов за 2 секунды - это 40 миллисекунд между передними (или задними) фронтами импульсов. Как время между очередными 2 импульсами превысило 80 миллисекунд - стоп.

Re: Простое управление коллекторным двигателем с помощью МК

Чт мар 15, 2018 08:20:28

Пару релюшек и концевички (можно геркон или мелкосхемку магниточуствительную).
Ежли алгоритм "туда-сюда до упора" вполне достаточно.
8)

Re: Простое управление коллекторным двигателем с помощью МК

Чт мар 15, 2018 08:43:13

...5000 импульсов...

Что это за число?

Re: Простое управление коллекторным двигателем с помощью МК

Ср мар 21, 2018 17:39:17

Блин, что я делаю не так?
int b;
int a;
unsigned char takt = 0;
ISR (TIMER2_OVF_vect)
{
a=TCNT1;
takt++;
if (takt>=31) {b=TCNT1;
if (a==b) {/*TCCR1A &= ~(1 << FOC1A)*/PORTD = (1 << PD4);}}
}
int main(void)
{
TIMSK |= (1<< TOIE2);
TCCR2 |= (1<< CS22)|(1<< CS20);
TCCR1A = 0b01011000;
TCCR1B = 0b00000111;
TIMSK = (1 << OCIE1A);
sei();
while(1) {

}
return 0;
}

Re: Простое управление коллекторным двигателем с помощью МК

Пн мар 26, 2018 22:27:27

Первое, что вы делаете не так -- это обращаетесь в обработчике прерывания к переменным, которые к таким обращениям не предрасположены. Я имею ввиду, что переменные не имеют в объявлении модификатора volatile.

Re: Простое управление коллекторным двигателем с помощью МК

Ср мар 28, 2018 14:37:29

В общем сделал я вот так:
ISR (TIMER2_OVF_vect)
{
a=TCNT0;
takt++;
if (takt==40) {b=TCNT0;}
if (takt==45) {if (b==a){PORTD &= ~(1 << PD6)&&~(1 << PD7);} takt=0;}
}


Теперь при заклинивании мотора (рычаг доходит до крайнего положения) идет команда СТОП.
Но в проекте мотор с редуктором и при заклинивании его ротор будет делать незначительные движения за счет люфта шестерней редуктора, зазоров соединений с рычага и т. п..
То есть енкодер всегда будет выдавать некое (небольшое) значение даже при заклиненном моторе.
Не могу придумать как осуществлять команду СТОП, если количество импульсов на Т0, за промежуток времени (2 сек), не превышает к примеру там 20, 50, 100 (в зависимости от енкодера и частоты вращения мотора).
Уже пробовал a-b<20 и т. п. ничего не выходит...
Подскажите плз как реализовать.

Re: Простое управление коллекторным двигателем с помощью МК

Ср мар 28, 2018 18:05:07

вот у тебя Т1 ведёт счёт времени
настрой Т0 на отсчет временнЫх интервалов (получи прерывание с определённой частотой)
в прерывании:
Код:
static unsigned int LastMeas;
if ((TCNT1-LastMeas)<50) {Остановка мотора};
LastMeas=TCNT1;

Re: Простое управление коллекторным двигателем с помощью МК

Ср мар 28, 2018 18:49:15

вот у тебя Т1 ведёт счёт времени
настрой Т0 на отсчет временнЫх интервалов (получи прерывание с определённой частотой)
в прерывании:
Код:
static unsigned int LastMeas;
if ((TCNT1-LastMeas)<50) {Остановка мотора};
LastMeas=TCNT1;

Так я так и делаю, только у меня T0 считает импульсы энкодера, а Т2 ведет отсчет времени.
Полный код:

#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <util/delay.h>

volatile int b;
volatile int a;
volatile int takt = 0;
////////////////////////////////////////////////ПРЕРЫВАНИЯ ПО ТАЙМЕРУ №2/////////////////////////////////////////////
ISR (TIMER2_OVF_vect)
{
a=TCNT0;
takt++;
if (takt==40) {b=TCNT0;}
if (takt==45) {if (b==a){PORTD &= ~(1 << PD6)&&~(1 << PD7);} takt=0;}
}

int main(void)
{

//////////////////////////////////КОНФИГУРАЦИЯ ПОРТОВ/////////////////////////////////////////////////////////////

////////Порт В
DDRB = 0b00000110; //порты PB1 и PB2 установлены как выход.
////////Порт С
DDRC = 0x00; //все порты C установлены как входы.
PORTC = 0xFF; //подтягивающие резисторы на входы порта С.
////////Порт D
DDRD = 0b11000000;//порт PD6, PD7 установлены как выход.


//////////////////////////////////ТАЙМЕРЫ////////////////////////////////////////////////////////////////////////

////////Таймер №0 (захват импульсов с экодера)
TCCR0 |= (1 << CS02)|(1 << CS01)|(1 << CS00);//Внешний источник тактирования по растущему фронту на T0.
////////Таймер №2 (счет задержки)
TIMSK |= (1<< TOIE2);//установка прерывания по переполнению
TCCR2 |= (1<< CS22)|(1<< CS20)|(1<< CS21);//предделитель тактов на 1024.
sei();

while(1)
{
//////////////////////////////////КНОПКИ////////////////////////////////////////////////////////////////////////
////////Кнопки управления двигателем
//SW1
if ((PINC&(1 << PC0))==0)
{PORTD = (1 << PD6);}

//SW2
if ((PINC&(1 << PC1))==0)
{
PORTD = (1 << PD7);
}

}
return 0;
}

Вот только если дописать строчку (красным)
ISR (TIMER2_OVF_vect)
{
a=TCNT0;
takt++;
if (takt==40) {b=TCNT0;}
if (takt==45) {if (b==a){PORTD &= ~(1 << PD6)&&~(1 << PD7);}}

if (takt==50) {if (a-b<20) {PORTD &= ~(1 << PD6)&&~(1 << PD7);} takt=0;}}
}
То происходит произвольная, через периоды, остановка мотора...

Re: Простое управление коллекторным двигателем с помощью МК

Ср мар 28, 2018 19:35:19

1) если у тебя на заклиненном моторе может набраться 50 импульсов, то при работе мотора размеров таймера т0 не хватит - он на второй круг пойдёт с описанными тобой последствиями: либо используй Т1 либо сокращай время замера (так, чтобы при остановленном моторе импульса 3 - 4 было за время замера)
2) както странно ты засекаешь импульсы - 40 прерываний ждёшь, потом в течении 10 - замеряешь (точка отсчета засекается на 40 такте, а сравнение на 50м).

Re: Простое управление коллекторным двигателем с помощью МК

Ср мар 28, 2018 20:12:20

1) если у тебя на заклиненном моторе может набраться 50 импульсов, то при работе мотора размеров таймера т0 не хватит - он на второй круг пойдёт с описанными тобой последствиями: либо используй Т1 либо сокращай время замера (так, чтобы при остановленном моторе импульса 3 - 4 было за время замера)
2) както странно ты засекаешь импульсы - 40 прерываний ждёшь, потом в течении 10 - замеряешь (точка отсчета засекается на 40 такте, а сравнение на 50м).


1. Точно так же ведет себя, если поставить и 10 импульсов и 5... Все зависит от частоты вращения мотора и скорости переполнения Т0. Я так понимаю, что здесь нужно математически высчитывать, или, скорее всего использовать другой подход.
2. Если проводить сравнение на 40 такте, то там же происходит запись значения из TCNT0 в переменную b и в этот же момент , будет происходить прерывание, так как на 40 такте значения а и b будут равны.

Re: Простое управление коллекторным двигателем с помощью МК

Чт мар 29, 2018 03:54:48

1) нет, не так, почему бездействует 40 тактов? почему не записываешь в переменную a сразу после сравнения? примерно так
Код:
ISR (TIMER2_OVF_vect){
takt++;
if (5<=takt) //длительность замера
  {
  b=TCNT0;
  if (4>(b-a)) PORTD &= ~(1 << PD6)&&~(1 << PD7); //количество импульсов
  a=TCNT0;
  takt=0;
  };
}

2) Т0 умеет считать только до 255, а Т1 и 65000 выдержит (есть разница? :) ) так что если есть возможность перейти на Т1 - это лучше сделать
3) померь частоту на энкодере работающего мотора чтобы знать, с какими скоростями имеем дело.
4) ты точно знаешь что все переменные у тебя понимаются как беззнаковые? а то при копировании при разных типах можно получить ерунду (и потом махать ею :) ) если используешь Т0, то сделай переменные а и b типа char.

Re: Простое управление коллекторным двигателем с помощью МК

Чт мар 29, 2018 10:28:59

1) нет, не так, почему бездействует 40 тактов? почему не записываешь в переменную a сразу после сравнения? примерно так
Код:
ISR (TIMER2_OVF_vect){
takt++;
if (5<=takt) //длительность замера
  {
  b=TCNT0;
  if (4>(b-a)) PORTD &= ~(1 << PD6)&&~(1 << PD7); //количество импульсов
  a=TCNT0;
  takt=0;
  };
}

2) Т0 умеет считать только до 255, а Т1 и 65000 выдержит (есть разница? :) ) так что если есть возможность перейти на Т1 - это лучше сделать
3) померь частоту на энкодере работающего мотора чтобы знать, с какими скоростями имеем дело.
4) ты точно знаешь что все переменные у тебя понимаются как беззнаковые? а то при копировании при разных типах можно получить ерунду (и потом махать ею :) ) если используешь Т0, то сделай переменные а и b типа char.


1. Они не бездействуют, это время задержки (1-2 сек) которую нужно выждать, перед отключением мотора. Алгоритм: сразу передаем значение TCNT0 переменной a; ждем 40 тактов (1-2 сек) - передаем значение TCNT0 переменной b (делаем это каждые 40 тактов); ждем еще 5 тактов и сравниваем переменные a и b - если равны - СТОП. Так вот если не ждать эти 5 доп. тактов, то при сравнении а будет всегда равняться b. Пять доп тактов это время сравнения, 40 тактов это время задержки между сравнениями. Твой пример не работает по этой причине.
2. Знаю про 8 битные и 16 битные таймеры. Но, если честно, не вижу разницы какой применять касательно данного примера. В проекте еще предусмотрен цикличный таймер c , LSD с меню, Bluetooth и ИК управление. Поэтому 16 битный таймер еще будет нужен. Правда можно взять другой МК.
3. Мотор будет примерно такой: https://ru.aliexpress.com/item/Best-Pri ... 2747006160
Выдавить из китайцев точную инфу по нему пока что сложно, на данном этапе мне это и не нужно. Я хочу изначально разобраться с принципом, что бы наработанный результат можно было применить потом к любому мотору с незначительными правками. В среднем, скорость вращения ротора мотора будет где то 2500 - 3500 об\мин. За оборот энкодер выдает порядка 20-50 импульсов.
4. Ок.
Решения пока не нашел...

Re: Простое управление коллекторным двигателем с помощью МК

Чт мар 29, 2018 11:42:31

тогда хотябы так:
Код:
ISR (TIMER2_OVF_vect)
{
takt++;
if (takt==40) {b=TCNT0;}
if (takt==50)
  {
  a=TCNT0;
  if (a-b<20) {PORTD &= ~(1 << PD6)&&~(1 << PD7);}
  b=a;
  takt=40;
  }
}

ждет 40 тактов, берёт первую пробу, ещё через 10 берет вторую и сравнивает, следующее сравнение будет через 10 тактов
при запуске двигателя не забудь скинуть takt=0; чтобы обеспечить твои обязательные 2 секунды работы двигателя.

Добавлено after 7 minutes 11 seconds:
по приблизительным подсчетам при тактовой 8 МГц при рабочих оборотах переполнение Т0 может произойти уже на 3х тактах (а при меньшей тактовой частоте и раньше), поэтому вместо (takt==50) надо писать (takt==42)
Ответить