Телесистемы
 Разработка, производство и продажа радиоэлектронной аппаратуры
На главную   | Карта сайта | Пишите нам | В избранное
Требуется программист в Зеленограде
- обработка данных с датчиков; ColdFire; 40 тыс.
e-mail:jobsmp@pochta.ru

Телесистемы | Электроника | Конференция «Микроконтроллеры и их применение»

Энкодер-концепт. Если у кого есть возможность, проверьте на педикулез(+)

Отправлено Quasy 23 сентября 2008 г. 10:40



////////////////////////////////////////////////////////////////////
// Энкодер
#define ENCODER_PORT PORTA
#define ENCODER_DDR DDRA
#define ENCODER_PIN PINA
//////
#define MAXIMUM ( 10000 )
#define MINIMUM ( 0 )
///////////////
#define DIRECT_INC (0x01) /* код направления ++ */
#define INC_F1 (0x03) /* фаза инкремента 1 */
#define INC_F2 (0x01) /* фаза инкремента 2 */
#define INC_F3 (0x00) /* фаза инкремента 3 */
#define INC_F4 (0x02) /* фаза инкремента 4 */
#define FIFO_INC ( (INC_F1 << 6) | (INC_F2 << 4) | \
(INC_F3 << 2) | (INC_F4 << 0) )
#define FIFO_INC_2 ( (INC_F3 << 6) | (INC_F2 << 4) | \
(INC_F3 << 2) | (INC_F4 << 0) )
#define FIFO_INC_6 ( (INC_F1 << 4) | \
(INC_F2 << 2) | (INC_F3 << 0) )
///////////////
#define DIRECT_DEC (0x02) /* код направления -- */
#define DEC_F1 INC_F4 /* фаза декремента 1 */
#define DEC_F2 INC_F3 /* фаза декремента 2 */
#define DEC_F3 INC_F2 /* фаза декремента 3 */
#define DEC_F4 INC_F1 /* фаза декремента 4 */
#define FIFO_DEC ( (DEC_F1 << 6) | (DEC_F2 << 4) | \
(DEC_F3 << 2) | (DEC_F4 << 0) )
#define FIFO_DEC_2 ( (DEC_F3 << 6) | (DEC_F2 << 4) | \
(DEC_F3 << 2) | (DEC_F4 << 0) )
#define FIFO_DEC_6 ( (DEC_F1 << 4) | \
( DEC_F2 << 2) | (DEC_F3 << 0) )
//////
// Переменная Move - перемещение. Знаковая. Допускаются
// отрицательные величины.Иначе - "unsigned int Move"
signed int Move;
// FIFO_Enc - буфер FIFO для последних 4-х двухбитовых состояний фаз
unsigned char FIFO_Enc;
// Переменная old_state для подавления дребезга
unsigned char old_state;
// Переменная direct для флага направления INC или DEC.
unsigned char direct;
/////////////////////////////////////////////////
// Необязательно, но желательно inline
#pragma inline = forced
// Функция дает 0 если входные аргументы отличаются
// не более чем одним битом.
unsigned char Check_Mask( unsigned char a, unsigned char b )
{
a = (a ^ b);
return( a &= ((unsigned char)(a - 1)) );
}/*Check_Mask*/
/////////////////////////////////////////////////
// Функция Encoder() здесь выполнена как вызываемая
// программно функция. Возвращает unsigned char флаг об
// обнаружении перемещения.
// Для каждого нового состояния фаз Encoder() вызывается дважды,
// с задержкой, для подавления дребезга.
// Величина задержки выбирается с учетом конкретного
// датчика и с учетом необходимой скорости чердования фаз.
unsigned char Encoder( void )
{
// Phase 1 (pin A.1) ____/^^^^^^^^\________/^^^^^^^^\______
// Phase 0 (pin A.0) ________/^^^^^^^^\________/^^^^^^^^\__
//
// При ИНкременте история состояний: ...10 11 01 00 - пришло 10!
// При ДЕкременте история состояний: ...11 10 00 01 - пришло 11!
// Т.о., инкремент стробируется положительным фронтом Phase 1,
// а декремент - отрицательным. Получается гистерезис.
register unsigned char state;

// Каждый раз инициализовать порт энкодера (для параноиков).
// ENCODER_DDR &= 0xfc;
//////// ENCODER_PORT |= 0x02; // pull up
//////// _NOP();
//////// _NOP();

state = ENCODER_PIN;

state &= 0x03; // Убрать лишние биты слева

if( state != old_state ) // Подтверждение состояния.
{
// Изменение или дребезг? Разобраться при следующем проходе.
// А пока запомним это новое состояние - и на выход.
old_state = state;
}/*if*/
else
{
// Фазы стоят устойчиво.
if( state != (FIFO_Enc & 0x03) )
{
// Это новое устойчивое состояние фаз!
FIFO_Enc <<= 2; // Вталкивание справа нового состояния в FIFO_Enc
FIFO_Enc |= state; //FIFO_Enc-буфер FIFO для 4 последних состояний

// Какую "историю" из четырех последних фаз имеем?

//////////////////////////////////////////////////////
// Проверяю на инкремент. Проверка считается пройденной,
// если все 4 принятые фазы FIFO отличаются от образца не более
// чем одним битом. Причем образцов два: для нормального
// чередования фаз Ф1,Ф2,Ф3,Ф4!!!(Move++), и для "болтанки фаз"
// внутри FIFO. Второй образец нужен, чтобы не пропустить
// приращения Move для случая чередования фаз:
// Ф1,Ф2,Ф3,Ф2,Ф3,Ф4!!!(Move++). Эта "болтанка" есть нормальное
// состояние, но только тогда, когда ранее (по трем фазам) было
// выбрано правильное для этого случая направление DIRECT_INC.
// Норма: binary (11 01 00 10)
// Дрожание фаз: binary (00 01 00 10)
if( (!(Check_Mask(FIFO_Enc, FIFO_INC))) ||
( (!(Check_Mask(FIFO_Enc,FIFO_INC_2))) && (direct == DIRECT_INC) ) )
{
// Есть перемещение "+"
if( Move < MAXIMUM )
Move++;
else
Move = MAXIMUM; // Ограничение количества перемещений.

return (1); // Было перемещение!
}/*if +*/
//////////////////////////////////////////////////////

//////////////////////////////////////////////////////
// Проверяю на декремент.Проверка считается пройденной,
// если все 4 принятые фазы FIFO отличаются от образца не более
// чем одним битом. Причем образцов два: для нормального
// чередования фаз Ф1,Ф2,Ф3,Ф4!!!(Move--), и для "болтанки фаз"
// внутри FIFO. Второй образец нужен, чтобы не пропустить
// приращения Move для случая чередования фаз:
// Ф1,Ф2,Ф3,Ф2,Ф3,Ф4!!!(Move--). Эта "болтанка" есть нормальное
// состояние, но только тогда, когда ранее (по трем фазам) было
// выбрано правильное для этого случая направление DIRECT_DEC.
// Норма: binary (10 00 01 11)
// Дрожание фаз: binary (01 00 01 11)
if( (!(Check_Mask(FIFO_Enc, FIFO_DEC))) ||
( (!(Check_Mask(FIFO_Enc,FIFO_DEC_2))) && (direct == DIRECT_DEC) ) )
{
// Есть перемещение "-"
if( Move > MINIMUM )
Move--;
else
Move = MINIMUM; // Ограничение количества перемещений.

return (1); // Было перемещение!
}/*if -*/
//////////////////////////////////////////////////////

// Сюда попадаю, если в FIFO была принята очередная фаза,
// но условий для приращений Move пока не обнаружено.
// Возможно, созрели условия для определения направления:
// DIRECT_INC или DIRECT_DEC.

// Проверка на выбор направления DIRECT_INC по 3-м фазам.
if( !(Check_Mask( (FIFO_Enc & 0x3f), FIFO_INC_6)))
{
direct = DIRECT_INC;
}/*if*/
// Проверка на выбор направления DIRECT_DEC по 3-м фазам.
else if( !(Check_Mask( (FIFO_Enc & 0x3f), FIFO_DEC_6)))
{
direct = DIRECT_DEC;
}/*else if*/
}/*if state !=*/
}/*else*/
return (0); // Безрезультатный выход.Перемещения не выявлено.
}/*Encoder*/
/////
void main( void )
{
unsigned char tmp;

DDRC = 0xff; // индикатор перемещения (мл. байт)
PORTC = 0xff;

// Перемещение ставлю на середину диапазона.
Move = (unsigned int)((MAXIMUM + MINIMUM) / 2 );
FIFO_Enc = 0;
old_state = 0;
direct = 0;
ENCODER_DDR &= 0xfc;
ENCODER_PORT |= 0x02; // pull up
_NOP();
for(;;)
{
// Для каждого нового состояния фаз Encoder() вызывается дважды,
// с задержкой, для подавления дребезга.
// Величина задержки выбирается с учетом конкретного
// датчика и с учетом необходимой скорости чердования фаз.
tmp = Encoder();
if( tmp )
{
PORTC = (~((unsigned char)Move));
WaitMs( 999 );
}/*if*/
else WaitUs( 1000 );
}/*for*/
}


Составить ответ | Вернуться на конференцию

Ответы


Отправка ответа
Имя*: 
Пароль: 
E-mail: 
Тема*:

Сообщение:

Ссылка на URL: 
URL изображения: 

если вы незарегистрированный на форуме пользователь, то
для успешного добавления сообщения заполните поле, как указано ниже:
умножьте 2 на три:

Перейти к списку ответов | Конференция | Раздел "Электроника" | Главная страница | Карта сайта

Rambler's Top100 Рейтинг@Mail.ru
 
Web telesys.ru