Перейти к содержанию

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


ura308

Рекомендуемые сообщения

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

}

}

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

Реклама: ООО ТД Промэлектроника, ИНН: 6659197470, Тел: 8 (800) 1000-321

20% скидка на весь каталог электронных компонентов в ТМ Электроникс!

Акция "Лето ближе - цены ниже", успей сделать выгодные покупки!

Плюс весь апрель действует скидка 10% по промокоду APREL24 + 15% кэшбэк и бесплатная доставка!

Перейти на страницу акции

Реклама: ООО ТМ ЭЛЕКТРОНИКС, ИНН: 7806548420, info@tmelectronics.ru, +7(812)4094849

Выбираем схему BMS для корректной работы литий-железофосфатных (LiFePO4) аккумуляторов

 Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ, также как и для других, очень важен контроль процесса заряда и разряда, а специализированных микросхем для этого вида аккумуляторов не так много. Инженеры КОМПЭЛ подготовили список имеющихся микросхем и возможных решений от разных производителей. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

Только начал осваивать "Си" для 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
Ссылка на комментарий
Поделиться на другие сайты

  • 1 год спустя...

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

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

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

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

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

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

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

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

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

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

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

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

В 27.02.2016 в 13:28, ura308 сказал:

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

EncCur != EncPrevPrev ) 

{

...

}

else

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

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

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

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

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

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

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

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

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

  • 2 недели спустя...

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

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

 

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

В 28.12.2017 в 21:57, Darth_Vader сказал:

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

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

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

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

Изменено пользователем Zhuk72
Ссылка на комментарий
Поделиться на другие сайты

  • 4 недели спустя...

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

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

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

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

  • 2 года спустя...

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

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

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

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

Изменено пользователем Falconist
Ссылка на комментарий
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.
Примечание: Ваш пост будет проверен модератором, прежде чем станет видимым.

Гость
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Ответить в этой теме...

×   Вставлено с форматированием.   Восстановить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

Загрузка...
  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
  • Сообщения

    • @Gomerchik а вы контролировали как меняется уровень сигнала на А1 ардуины?
    • Спасибо за совет. Автором данного проекта я не являюсь, мне нужно было воссоздать уличный датчик для метеостанции взамен пропавшего(( Из разного найденного в интернете этот проект работает с моей станцией Орегон (спасибо автору). В понедельник попробую последовать Вашему совету. Но все равно куча непоняток  как блин это работает)) Если дело в неправильной отправки команды, то как на это влияет подключение датчика температуры? Если совсем не подключать таймер, то передача идет один раз (как и прописано в программе), станция принимает и отображает, но минут через сколько-то естественно станция уже ни чего не показывает, но с таймером питание полностью не пропадает с ардуинки, но передача сигнала каким-то образом работает по таймеру.  В моем понимании данная команда подается один раз потому, что таймер должен отключать питание МК после передачи сигнала и каждые 43 сек снова подавать питание (так того требует станция).  Ардуино передает показания температуры отключается полностью и 43 секунды мк не работает.  Сейчас у меня питание пока сделано на подпитке от солнечной батареи, но пару пасмурных дней и аккумулятор съедается до отключения(
    • thickman Так и сделаю. Вытащу из бу БП.  Буду знать, как отличить. Благодарю. Заменил транзисторы на IRFB20N50K. Картина стала, совсем другой.  Похоже трудность не в драйвере, на момент подвозбуда, переходные процессы, в нем, завершены. Увеличил затворные резисторы до 50ом, стало немного лучше.  Не понятно, почему верхний ключ греется несколько сильнее. Возможно, стоит посмотреть ток в коллекторе.  Снабберные емкости временно удалил, изменений не произошло.  Замена ТГР на другой, на кольце MSTN-16A-TH, так же, результата не принесла.   irfb20n50k.pdf
    • А что нить из ассортимента активных щупов производства СССР..))
    • Типа такого: https://aliexpress.ru/item/2044864227.html?sku_id=58855020183
    • поняли неправильно. У ТЛ494 никакой защиты нет, усилители ошибки не защита, они не должны приводить к ложным импульсам. Причем тут "микруха" ?  надо нагружать ВСЁ. До сих пор вообще непонятно о каком ИИП идет речь и сколько у него каналов. Бесполезно схему рисовать? - Помогать так бесполезно. Картина кривая по самое "немогу" продолжаются картинки, снятые через ногу и без цены деления.
×
×
  • Создать...