Jump to content
ura308

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

Recommended Posts

Подскажите как реализовать? реверсивный счетчик, энкодер крутит в сторону вычитания до нуля и счетчик останавливается-как сделать чтоб неостанавливалось дальше считало от нуля 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);

}

}

Share this post


Link to post
Share on other sites
и счетчик останавливается
В коде этого нет. Не понятно, из-за чего это у Вас происходит.

Share this post


Link to post
Share on other sites

Приглашаем на вебинар «Новинки и уникальные решения Molex. На что обратить внимание и почему»

15 апреля приглашаем на вебинар, который будет интересен разработчикам и инженерам-схемотехникам, интересующимся тенденциями рынка, новыми перспективными решениями для соединений «провод-провод», «провод-плата», «плата-плата». Для инженеров КИПиА и IT будут освещены уникальные решения Molex для «удлинения» интерфейсов HDMI, DisplayPort и USB даже в условиях сильного зашумления, а также семейство бесконтактных датчиков Contrinex. Помимо этого, будет уделено внимание дальнейшему развитию направления антенн, где Molex имеет ряд интересных и уникальных решений.

Подробнее

Только начал осваивать "Си" для 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

Edited by ura308

Share this post


Link to post
Share on other sites

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

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

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

Share this post


Link to post
Share on other sites
                     

Выбираем преобразователь для портативных устройств

Портативные устройства могут различаться по типам элементов питания, а также по разным функциям. В статье на примере 3-х устройств демонстрируется, как многоканальные SIMO-преобразователи помогают эффективно реализовывать потенциал системы питания и первичного элемента, а также гибко подстраиваться под требуемый функционал.

Читать статью

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

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

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

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

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

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

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

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

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


Мудрость приходит вместе с импотенцией...

Share this post


Link to post
Share on other sites
В 27.02.2016 в 13:28, ura308 сказал:

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

EncCur != EncPrevPrev ) 

{

...

}

else

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

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

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

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

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

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

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


Можно сделать все! Но чем больше можно, тем больше нельзя!

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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

Ловим, допустим, передний фронт на 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;
		}
  }
}

 

Share this post


Link to post
Share on other sites
В 28.12.2017 в 21:57, Darth_Vader сказал:

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

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

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

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

Edited by Zhuk72

Share this post


Link to post
Share on other sites

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

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

Share this post


Link to post
Share on other sites

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

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


Пока ты жив, надежда есть.

Share this post


Link to post
Share on other sites

Всем привет! Не отвечал по теме так как были утеряны файлы проекта.

Возможно кому то и пригодится в своих проектах 

Код был частично изменен и доработан;

1: Переход через ноль. но без индикации "минус" ( не заморачивался с отриц. показаниями).

2:  Была увеличена скорость обработки (энкодер на 400 импульсов).

      Скорость измерения около 1м в секунду-без пропусков шагов.

      С индикацией 1или 2 знака после запятой.

3: Вот само решение переход через "0" .Основные изменения в коде;

   //------------------
    cEnc=Encoder_Exe();
    if(cEnc != NULL_ENC)
    {
        switch(cEnc)    // считаем от нуля в обе сторны реверсивно
        {
        case PLUS_ENC:
            if(lCnt == 0 && (signed long)(lCnt + incStep) < 0)
                incStep *= -1; 
            lCnt+=incStep;   
            break;
        case MINUS_ENC:
            if(lCnt == 0 && (signed long)(lCnt - incStep) < 0)
                incStep *= -1; //на 1имп число на табло 10 десятки мм на табло
            lCnt-=incStep;   
            break;
            
        }
        
        fnCalc(lCnt);
    }
}        
//-----------------------------------

Даташит.rar Прошивка.rar схема.rar Счетчик исходник WinAVR-2010.rar

Edited by Falconist

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

×
×
  • Create New...