ura308

Отрицательный Отсчет-Реверсивный Счетчик На Энкодере

13 сообщений в этой теме

ura308    0

Подскажите как реализовать? реверсивный счетчик, энкодер крутит в сторону вычитания до нуля и счетчик останавливается-как сделать чтоб неостанавливалось дальше считало от нуля 1,2,3,...реверсивно

void fnBtEnc(void)

{

static uchar cButt;

static uchar cEnc;

//------------------

cButt=fnReadButt();

if(cButt)

{

lCnt=0;

fnCalc(lCnt);

}

//------------------

cEnc=Encoder_Exe();

if(cEnc != NULL_ENC)

{

switch(cEnc)

{

case PLUS_ENC:

lCnt+=1; // энкодер вправо

break;

case MINUS_ENC:

if(lCnt)lCnt-=1; //энкодер влево

break;

}

fnCalc(lCnt);

}

}

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Alex    546
и счетчик останавливается
В коде этого нет. Не понятно, из-за чего это у Вас происходит.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
ura308    0

Только начал осваивать "Си" для AVR

Архив с проектом в конце сообщения ( WinAvr 2010,симуляция Proteus 7.на семисегментниках )

Проект с радиокота http://radiokot.ru/f...hp?f=61&t=84965

Вариант с Lcd16х2 не рассматриваю - некомфортно,нечитабельно с расстояния! только на сегментных индикаторах!

Поставил дома на станок в качестве линейки,А он считает реверсивно только в одном направлении - если при резе дошел до "0" то при резе в другом направлении относительно "0" счет не происходит. Толку от него ровным счетом ноль!

У заводского на другой оси все в порядке! у него энкодер имеет выходы A ,B и Z-изменение направления.

У меня стоит обычный оптический 200 импульсов энкодер A и B выходы.

Нужно чтобы при изменении направления вращения энкодера относительно "0" (допустим после первого импульса ) -инверсировался опрос энкодера так, что бы счетчик считал как и считал ранее а минус высвечивался в зависимости он направления счета относительно "0"

Вывод на индикацию через 74HC595 чтобы освободить ножки для вывода "индикации - (Минус)"

Неплохо бы было и делитель добавить чтоб убрать погрешность (количество импульсов на 1мм)

Довести проект "до ума" Таких проектов в интернете просто нет!

Я думаю он многим будет полезен!

сам код опроса энкодера

:


//! Файл	 : button_enc.h
//!**************************************************
#include "button_enc.h"
#include "hard_config.h"
//----------------------------- Константы: -----------------------------------
enum { State0, StateA, StateB, StateAB }; //состояния энкодера
//----------------------------- Переменные: ----------------------------------
static char EncPrev;	 //предыдущее состояние энкодера
static char EncPrevPrev; //пред-предыдущее состояние энкодера
//----------------------- Инициализация энкодера: ----------------------------
void Encoder_Init(void)
{
EncPrev = State0;	 //инициализация предыдущего состояния
EncPrevPrev = State0; //инициализация пред-предыдущего состояния
PORTA=0xFF;
}
//------------------------- Обработка энкодера: ------------------------------
REZ_ENC Encoder_Exe(void)
{
char EncCur = 0;

char cRezEnc=NULL_ENC;

if(!Pin_ENC_F1) {EncCur = StateA;} //опрос фазы 1 энкодера
if(!Pin_ENC_F2) {EncCur |= StateB;} //опрос фазы 2 энкодера
if(EncCur != EncPrev)			 //если состояние изменилось,
{
if(EncPrev == StateAB &&	 //если предыдущее состояние StateAB
 EncCur != EncPrevPrev )	 //и текущее и пред-предыдущее не равны,
{
 if(EncCur == StateB) {cRezEnc= MINUS_ENC;}
 else{ cRezEnc=PLUS_ENC;}
}
//----------------------------------------------------------------------------------------------------------------
вот когда это дописал считает реверсивно!только в другом направлении вращения Но неправильно( начал пропускать импульсы)
а реверсивно в этом направлении вообще почти не считает ( на 200 импульсах в сек) а на 24 считает кое как
( в другом направлении когда считает импульсы не пропускает)
как автоматизировать процесс переключения между ними? в зависимости от направления вращения если на табло "0" или сброс в ноль
с какой переменной брать результат счетчика - или этот ноль?
что подправить чтоб импульсы не пропускал?
------------------------------------------------------------------------------------------------------------------//
else
if(EncPrev == StateAB && //если предыдущее состояние StateAB
EncCur != EncPrevPrev ) //и текущее и пред-предыдущее не равны,
{
if(EncCur == StateB) {cRezEnc=PLUS_ENC;}
else{ cRezEnc= MINUS_ENC;}
}
//---------------------------------------------------------------------------------------------------------------------
EncPrevPrev = EncPrev;		 //сохранение пред-предыдущего состояния
EncPrev = EncCur;			 //сохранение предыдущего состояния
}
return cRezEnc;
}

главная функция;

//!**************************************************
//! Файл	 : main.c
//! Авторское право (с) :
//! Разработка	 : urry <urry1@rambler.ru>
//! Дата создания	 :
//! Описание
//!
//!**************************************************
#include "hard_config.h"
// определяем массив вывода и флаги
volatile sFlags_ strFlags;
volatile uchar cCalculate[DIGIT];
static unsigned long lCnt;
// определение используемых функций --------------
static void fnInit(void);
void fnBtEnc(void);
void fnLtoA(unsigned long tmp);
void fnCalc(unsigned long l);
//------------------------------------------------
//=========================================
int __attribute__((naked)) main (void)
//=========================================
{
fnInit();
for(;
{
if(strFlags.bTick)
{
strFlags.bTick=false;
fnBtEnc();
if(BITTST0(PINA,1))// пропадание напряжения !
{
fnEepSave(lCnt); // записываемся
off:
asm("wdr");
goto off;// до сброса питания ничего не делаем
}
} //end strFlags.bTick
asm("wdr");
}// end for
}// end main
//=========================================
//-----------------------------------------
static void fnInit(void)
{
DDRD=0;
DDRD|=(1<<R_1)|(1<<R_2)|(1<<R_3)|(1<<R_4)|(1<<R_5);
PORTD=0xFF;
DDRB=0xFF;
// Timer/Counter 0 initialization
TCCR0A=0x00;
TCCR0B=0x00;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;
// Timer/Counter 1 initialization
TCCR1A=0x00;
TCCR1B=0x01;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
// External Interrupt(s) initialization
GIMSK=0x00;
MCUCR=0x00;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x80;
// Universal Serial Interface initialization
USICR=0x00;
// Analog Comparator initialization
ACSR=0x80;
asm("wdr");
wdt_enable(WDTO_1S);
lCnt=fnEepRead();
fnCalc(lCnt);
strFlags.bReady=1;
Encoder_Init();
//--------------------------------
sei();
}
//------------------------------------
void fnBtEnc(void)
{
static uchar cButt;
static uchar cEnc;
//------------------
cButt=fnReadButt();
if(cButt)
{
lCnt=0;
fnCalc(lCnt);
}
//------------------
cEnc=Encoder_Exe();
if(cEnc != NULL_ENC)
{
switch(cEnc)
{
case PLUS_ENC:
lCnt+=5;
break;
case MINUS_ENC:
if(lCnt)lCnt-=5;
break;
}
fnCalc(lCnt);
}
}
//------------------------------------
void fnLtoA(unsigned long tmp)
{
const unsigned long step[DIGIT]={10000,1000,100,10,1};
uchar i,atemp;
unsigned long val,temp;
char flag=0;
val=tmp;
for (i=0; i<DIGIT; i++)
{
if(i==3){flag =1;}
temp=step[i];
atemp=0;
while(val >= temp)
{
atemp++;
val-=temp;
}
if((flag) || (atemp))
{
 cCalculate[i]=atemp;
 flag=1;
}
else{cCalculate[i]=10;}
}
}
//------------------------------------
void fnCalc(unsigned long l)
{
if(l >= 99999){l=0;}
fnLtoA(l);
strFlags.bReady=1;
}
//------------------------------------

kot_impuls_metr_05.rar

Изменено пользователем ura308

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Alex    546

case MINUS_ENC:
if(lCnt)lCnt-=5;

А для чего тут проверка lCnt на нулевой значение ?

Оно Вам и вредит.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Starichok    1 210

надуманная проблема.

в какой-то точке есть "0" энкодера.

крутим вправо - счетчик увеличивается - получаем положительное число.

крутим влево - счетчик уменьшается. при переходе через ноль после декремента получаем число 0xFFFF. это уже ОТРИЦАТЕЛЬНОЕ  число и равно -1.

ну, и так далее, получаем отрицательные числа.

превращаем их в положительные с флагом "минус", и при выводе на индикатор сначала выводим этот минус, потом выводим само положительное число.

при выводе положительной координаты флаг "минус", естественно, остается сброшенным, и выводится просто положительное число.

для двухбайтового числа имеем максимальное положительное число 32767 и минимальное отрицательное -32768.

думаю, такого диапазона координаты должно хватить.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
ruhi    35
В 27.02.2016 в 13:28, ura308 сказал:

if(EncPrev == StateAB && //если предыдущее состояние StateAB

EncCur != EncPrevPrev ) 

{

...

}

else

if(EncPrev == StateAB && //если предыдущее состояние StateAB

EncCur != EncPrevPrev ) //и текущее и пред-предыдущее не равны,

Это что за чудо??? Типа:

Если условие не выполнилось

(EncPrev == StateAB && EncCur != EncPrevPrev ) 

, проверим еще раз ничего не меняя, вдруг оно со второго раза выполнится???? Рассчитываете на глюк процессора???

Что вы добавили???

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Zhuk72    12

Этой теме скоро 2 года будет. Автор давно либо плюнул на МК, либо решил вопрос.

  • Лайк 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Darth_Vader    62

Очень сложное решение простой проблемы.

Ловим, допустим, передний фронт на INTO (один вывод энкодера) и считываем состояние второго вывода энкодера.

Если там 1 - в одну сторону крутится, 0 - гарантированно в другую.

//функция обработчик внешнего прерывания INT0
ISR( INT0_vect )
{
	cw = 0;
	ccw = 0;
	if (PIND & (1 << PIND1))
	{
		cw = 1;
	}
	else
	{
		ccw = 1;
	}
}

int main(void)
{
  while(1)
		if(cw+ccw > 0)
		{
    		//////////////
			cw = 0;
			ccw = 0;
		}
  }
}

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Zhuk72    12
В 28.12.2017 в 21:57, Darth_Vader сказал:

Ловим, допустим, передний фронт на INTO (один вывод энкодера) и считываем состояние второго вывода энкодера.

Если там 1 - в одну сторону крутится, 0 - гарантированно в другую.

А если энкодер разболтан, его случайно коснулись и он дернул ИНТ0? Засчитаете вращение? Это самый неправильный алгоритм.

По таймеру нужно считывать состояние обеих выводов и в случае изменения сравнивать с правильной последовательностью состояний (01001011 или 10000111). Могу выложить подпрограмму опроса, если интересно. Очень небольшая и работает очень стабильно. На выводах энкодера кроме подтяжек ничего фильтрующего не требует.

Изменено пользователем Zhuk72

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Darth_Vader    62
2 часа назад, Zhuk72 сказал:

энкодер разболтан

Неисправные детали нужно менять.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Zhuk72    12

А может лучше правильные алгоритмы выбирать?

Энкодеры разбалтываются достаточно быстро, даже фирменные.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
mazzi    25

Хорошие энкодеры работают годами и дребезг граничного положения как правило можно скомпенсировать как программно так и аппаратно.

Но если энкодер дешёвый, то при неправильно настроенной оптике могут происходить чудеса.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте аккаунт или войдите в него для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать аккаунт

Зарегистрируйтесь для получения аккаунта. Это просто!

Зарегистрировать аккаунт

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас