Уважаемые посетители! Форум CQHAM.RU существует исключительно за счет показа рекламы. Мы будем благодарны, если Вы не будете блокировать рекламу на нашем Форуме. Просим внести cqham.ru в список исключений для Вашего блокировщика рекламы.
Страница 2 из 4 ПерваяПервая 1234 ПоследняяПоследняя
Показано с 11 по 20 из 34

Тема: Си и валкодер

  1. #11
    Цитата Сообщение от ra3rbe Посмотреть сообщение
    У вас же совершенно нет никакой защиты от дребезга контактов.
    Дребезга там нет. Оптический валкодер, на LM358, с триггерным эффектом. Кроме того, я ведь уже писал, что с включением функции записи частоты в обработчик прерывания, никаких перескоков нет. Все обрабатывается четко через шаг. Внизу этот валкодер, справа снятый экран. Оптопара от мышки.
    Миниатюры Миниатюры Нажмите на изображение для увеличения. 

Название:	WP_000216_1.JPG 
Просмотров:	856 
Размер:	207.1 Кб 
ID:	233824  


  2. #12
    Аватар для vadim_d
    Регистрация
    29.10.2006
    Адрес
    Санкт-Петербург
    Сообщений
    14,916
    Цитата Сообщение от Владимир_К Посмотреть сообщение
    Кроме того, я ведь уже писал, что с включением функции записи частоты в обработчик прерывания, никаких перескоков нет
    Возможно, две ошибки взаимно компенсируют друг друга . Вообще, "разделяй и властвуй" - великий инженерный принцип, хоть и придуманный не инженерами . Вам правильно подсказывают, по прерыванию делается минимум, определяется инкремент или декремент и добавляется со знаком к первичному счетчику шагов. А вот уже в main запрещаются прерывания, берется значение первичного счетчика, туда пишется нуль, прерывания разрешаются, а уже потом спокойно вычисляется новое значение частоты. Если интересно, могу поискать отлаженный фрагмент под Атмегу8 в старом синтезаторе Константина Иванова, где я развлекался с gcc, даже написал сопрограммную многозадачность, но так все и бросил за невостребованностью . Проверялось, кстати, с валкодером старой мыши, но там было 4 отсчета на зуб, прерывания генерились по обоим перепадам логического уровня на каждом входе
    Вадим

  3. #13
    Цитата Сообщение от vadim_d Посмотреть сообщение
    Если интересно, могу поискать отлаженный фрагмент под Атмегу8 в старом синтезаторе Константина Иванова
    Добрый вечер, Вадим. Да, если не трудно, сбросьте. Никакие теории не дают столько полезного, что можно увидеть из примеров..

  4. #14
    Первое сдвиг фаз 90 градусов, проверьте осциллографом. Сидеть долго в прерывании не есть хорошо, вам же непредсказуемые глюки не нужны?
    Попробуйте сделать так:
    #define enc_a PIND.4 //пины энкодера
    #define enc_b PIND.5
    unsigned long int freq=3650000; // частота которую хотите вывести на дисплей и в синтез
    char enc_flag=0; //флаг прерывания

    Обработка прерывания , у меня по спаду на int0

    // External Interrupt 0 service routine
    interrupt [EXT_INT0] void ext_int0_isr(void)
    {
    enc_flag=1; // Установили флаг
    if(enc_b==0)freq+=f_ step; //посмотрели уровень на втором выходе энкодера если 0 увеличили частоту на величину шага f_step.
    else freq-=f_step; //Иначе, уменьшили частоту на величину шага f_step. Обработка заняла три строчки
    }

    В основном цикле проверяем флаг прерывания enc_flag, если установлен сбрасываем,
    готовим код для чипа и грузим,
    и только потом выводим на индикатор.

  5. Спасибо от Владимир_К

  6. #15
    Владимир, постарайтесь поступить кардинально, и по возможности уйти от обработки валкода в прерывании. Вам ведь не надо отслеживать скорость вращения под десятки - сотни оборотов в секунду. При меньшей скорости вполне справляется простой опрос состояния ног валкодера в основном цикле программы.
    Пример с опросом валкодера приложил. Дребезг погашен программно. Ноги в примере назначены от фонаря.
    Украдено у уважаемого ЛИ.
    Теперь про возможные ошибки в алгоритме. Я читал по диагонали, но очевидные вещи отметил.
    Первое, и главное. Сама постановка вопроса работы с прерываниями неверна. Вам уже правильно сказали, что программа в обработчике прерываний должна совершать минимум действий и быстренько оттуда вываливаться.
    То есть для конкретного случая, должен только фиксироваться факт поворота и направление вращения.Все остальное нужно уже делать в основном теле программы.
    Далее, методологические ошибки, связанные с применением языка.
    Все переменные, которые обрабатываются в прерывании, если их область видимости не ограничена только обработчиком прерывания, обязательно должны быть объявлены с атрибутом volatile (изменчивый). Это инструкция компилятору.
    Хотя обычно объявляют все переменные как volatile, если они используются в обработчике, независимо от их области видимости (за исключением static конечно).
    Переменные , занимающие 2 байта и более, обрабатываются процессором за несколько команд,причем сначала переменная из выденной под нее области оперативной памяти переписывается в регистры процессора. Поэтому если такая переменная, обрабатываемая в основной программе, может изменять значение в обработчике прерывания, то результат может быть плачевным при включенных прерываниях: основная программа еще не успела обработать все быйты переменной, а в прерывании они уже изменились, поэтому часть переменной может быть взята старая, а часть -от нового значения, и результат будет неверен. Ведь прерывание может случиться в произвольный момент, в частности между командами пересылки многобайтной переменной из оперативной памяти в регистры процессора, и начали посылать первый байт от одного значения, случилось прерывание, произошло переключение на обработчик, а он изменил значение следующего байта, сидящего в памяти. Результат получился неверный.
    Поэтому такие переменные нужно обрабатывать с отключенными прерываниями.
    Это делается с помощью atomic block или врукопашную объявляется фрагмент между cli/sei.Но этот фрагмент тоже должен быть минимальной длины, там следует как правило делать только пересылку значения из одной volatile переменной в другую,не используемую в обработчике прерывания, чтобы сократить время бездействия прерываний.
    Отклоняться от этого правила не следует даже при использовании однобайтных переменных, тк их волатильность(изменч ивость),при определенных условиях, будет сказываться в работе.
    Общие рекомендации.
    Поэтому старайтесь в обработчике прерываний использовать однобайтные переменные, ограничивайте их область видимость в основном обработчиком прерывания, а наружу выносите только переменные типа флагов (однобайтных), а также величины изменения какой-либо величины,которые можно впихать в один байт, в данном случае - количество щелчков валкодера +/-(0-127). Старайтесь не использовать в обработчике прерывания вызова каких-либо функций, либо, при необходимости использования, объявляйте эти функции с атрибутом inline, тогда компилятор вставит тело функции в обработчик прерывания, и не будет лишних сохранений регистров в стеке в обработчике прерываний.
    Вложения Вложения

  7. Спасибо от Владимир_К

  8. #16
    Цитата Сообщение от Кукин Николай Николаевич Посмотреть сообщение
    Все переменные, которые обрабатываются в прерывании, если их область видимости не ограничена только обработчиком прерывания, обязательно должны быть объявлены с атрибутом volatile (изменчивый). Это инструкция компилятору.
    Добрый день! Возможно вот это, скорее всего, и есть основная причина. Честно говоря, я толком не дочитал о понятии "volative" и с этому относился наплевательски... Вы меня направили на путь истинный.. Пока я об этом, честно говоря, понятия не имел.

  9. #17
    Аватар для vadim_d
    Регистрация
    29.10.2006
    Адрес
    Санкт-Петербург
    Сообщений
    14,916
    Цитата Сообщение от Владимир_К Посмотреть сообщение
    Никакие теории не дают столько полезного, что можно увидеть из примеров..
    Про volatile мысль очень правильная, если у Вас переменная, модифицируемая в обработчике прерывания, так объявлена не была, то при оптимизации после ее первого чтения в коде больше обращения к ней не происходит, в ассемблерном листинге это легко увидеть. В архиве последние эксперименты в UI_tst и UI2, там уже оттачивалось одновременное нажатие двух кнопок, драйвер валкодера enc_drv.c, должен быть с измерением скорости и выбором шага в зависимости от нее, многозадачность (громко сказано) работала, и математика там по сравнению с оригинальной gcc оптимизирована по размеру, в Атмеге8 не разгуляешься
    Вложения Вложения
    Вадим

  10. Спасибо от Владимир_К

  11. #18
    Ну в общем, перелопатил я программу, сделал так, как предложил Кукин Николай Николаевич, ну не совсем, но алгоритм тот же. Теперь получил дополнительный бонус в том, что на каждый сектор диска валкодера получил 4-шага, теперь можно применить валкодер с оптопарами АОТ-137, работающими на отражение, которые плохо работали с мелкими секторами.. Все четко, никаких пропусков, никаких непонятных моментов, которые сам не мог объяснить даже теоретически.
    С кодом о Вадима пока надо разобраться, с моим опытом это быстро не получается.
    Теперь вот мысля такая - вывод на экран, расчет частоты и ввод частоты в м/с синтезатора, делать по таймеру, например через каждые 10 мс. и делать это не по прерыванию, а по флагу переполнения таймера. То есть не в непредсказуемый момент, а из основного цикла. Во-первых не надо затрачивать время на эти операции и тормозить валкодер (а сейчас опрос клавиатуры, положения переключателя диапазонов и валкодера занимает 8 мксек, при тактовой процессора - 8 мгц), во-вторых получаем типа интеллектуального валкодера, чем быстрее крутим, тем больше шаг. Скорее всего это так и делается (а может по-другому) и это что-то типа изобретения велосипеда. Но хотелось бы услышать мнения о таком алгоритме. Да и оно проще написать несколько строк, чем разбираться в чужом коде. Знаю, что у Г. Завидовского это все есть, но, в хитросплетениях его кода, мне разобраться не так просто..
    Сейчас так..
    switch(EncState)
    {
    case 2:
    {
    if(New == 3) bufEnc++;
    if(New == 0) bufEnc--;
    break;
    }

    case 0:
    {
    if(New == 2) bufEnc++;
    if(New == 1) bufEnc--;
    break;
    }
    case 1:
    {
    if(New == 0) bufEnc++;
    if(New == 3) bufEnc--;
    break;
    }
    case 3:
    {
    if(New == 1) bufEnc++;
    if(New == 2) bufEnc--;
    break;
    }
    }
    EncState = New;
    return 0;
    Последний раз редактировалось Владимир_К; 13.05.2016 в 12:52.

  12. #19
    Аватар для Genadi Zawidowski
    Регистрация
    22.07.2004
    Адрес
    Санкт-Петербург
    Сообщений
    11,100
    Записей в дневнике
    20
    Позывной
    UA1ARN
    Выделил специально из "хитросплетений" обработчик прерываний по любому фронту от сигналов с валкодера (при работе по опросу ничего не меняется).
    Код:
    // dimensions are:
    // old_bits new_bits
    static const int_fast8_t graydecoder [4][4] =
    {
    	{
    		+0,		/* 00 -> 00 stopped				*/
    		-1,		/* 00 -> 01 rotate left			*/
    		+1,		/* 00 -> 10 rotate right		*/
    		+0,		/* 00 -> 11 invalid combination */		
    	},
    	{
    		+1,		/* 01 -> 00 rotate right		*/
    		+0,		/* 01 -> 01 stopped				*/
    		+0,		/* 01 -> 10 invalid combination */
    		-1,		/* 01 -> 11 rotate left			*/
    	},
    	{
    		-1,		/* 10 -> 00 rotate left			*/
    		+0,		/* 10 -> 01 invalid combination */
    		+0,		/* 10 -> 10 stopped				*/
    		+1,		/* 10 -> 11 rotate right		*/
    	},
    	{
    		+0,		/* 11 -> 00 invalid combination */
    		+1,		/* 11 -> 01 rotate right		*/
    		-1,		/* 11 -> 10 rotate left			*/
    		+0,		/* 11 -> 11 stopped				*/
    	},
    };
    
    static uint_fast8_t old_val;
    
    void spool_encinterrupt(void)
    {
    	const uint_fast8_t new_val = hardware_get_encoder_bits();	/* Состояние фазы A - в бите с весом 2, фазы B - в бите с весом 1 */
    
    	position1 += graydecoder [old_val][new_val];
    	old_val = new_val;
    }
    То есть, то же самое что и в виде case у Вас. Начальное состояние old_val должно соотвтствовать тому что в валкодере сейчас (чтобы при включении ложных шагов не возникало). Вам надо аналогично с EncState поступить - при инициализации прочитать в него состояние валкодера.

    ps: Александр далее тоже неплохой вариант предложил - для всех 16 комбинаций старого и нового состояний есть четыре приращения и четыре уменьшения - можно и в виде единственного switch с восемью case написать.
    Последний раз редактировалось Genadi Zawidowski; 13.05.2016 в 14:06.
    ... Я там глубину сам промерял!

  13. Спасибо от Владимир_К


  14. #20
    Цитата Сообщение от Владимир_К Посмотреть сообщение
    Ну в общем, перелопатил я программу, сделал так, как предложил Кукин Николай Николаевич, ну не совсем, но алгоритм тот же. Теперь получил дополнительный бонус в том, что на каждый сектор диска валкодера получил 4-шага, теперь можно применить валкодер с оптопарами АОТ-137, работающими на отражение, которые плохо работали с мелкими секторами.. Все четко, никаких пропусков, никаких непонятных моментов, которые сам не мог объяснить даже теоретически.
    Это же квадратурный анализатор, так и должно быть.
    Теперь вот мысля такая - вывод на экран, расчет частоты и ввод частоты в м/с синтезатора, делать по таймеру, например через каждые 10 мс. и делать это не по прерыванию, а по флагу переполнения таймера.
    Зачем каждые 10 мс делать расчет, если валкодер не крутили?
    А если по флагу, то все равно нужно будет постоянно крутиться в цикле и ждать переполнения.
    Легко при других обработках пропустить это событие.
    и это что-то типа изобретения велосипеда
    Именно так

    Нужно сделать прерывание по таймеру с периодом 1 мс.
    По этому прерыванию опрашивать валкодер, делать квадратуру и если надо прибавлять флаг шага в нужную сторону.
    И все.
    А в программе, когда дойдет до этого очередь, смотреть на флаг и обрабатывать его если нужно.

    Сейчас так..
    switch(EncState)
    {
    case 2:
    {
    if(New == 3) bufEnc++;
    if(New == 0) bufEnc--;
    break;
    }

    case 0:
    {
    if(New == 2) bufEnc++;
    if(New == 1) bufEnc--;
    break;
    }
    case 1:
    {
    if(New == 0) bufEnc++;
    if(New == 3) bufEnc--;
    break;
    }
    case 3:
    {
    if(New == 1) bufEnc++;
    if(New == 2) bufEnc--;
    break;
    }
    }
    EncState = New;
    return 0;
    Это тоже накручено. Кукин написал же как нужно сделать. Нужно загнать 2 бита предыдущего состояния и 2 бита текущего в переменную И потом анализировать ее.
    Лучше всего CASE, и не делать каждый раз IF
    switch(EncState)
    {
    // положительные шаги
    case b11100001:
    {
    Plus_Step ++;
    break;
    }
    case b11100111:
    {
    Plus_Step ++;
    break;
    }
    case b11101110:
    {
    Plus_Step ++;
    break;
    }
    // отрицательные шаги
    case b11100010:
    {
    Minus_Step ++;
    break;
    }
    case b11101011:
    {
    Minus_Step ++;
    break;
    }
    case b11101101:
    {
    Minus_Step ++;
    break;
    }
    case b11100100:
    {
    Minus_Step ++;
    break;
    }
    Ну примерно так, в синтаксисе мог наврать, не умею я писать на этом языке.
    С уважением
    Александр. (RA3RBE)
    http://www.r3r.ru
    http://ra3rbe.r3r.ru

  15. Спасибо от Владимир_К

Страница 2 из 4 ПерваяПервая 1234 ПоследняяПоследняя

Информация о теме

Пользователи, просматривающие эту тему

Эту тему просматривают: 1 (пользователей: 0 , гостей: 1)

Похожие темы

  1. Самодельный валкодер
    от RA6LRW в разделе Технический кабинет
    Ответов: 214
    Последнее сообщение: 04.04.2020, 20:58
  2. Валкодер IC-7400
    от RW6AUR в разделе IC-746 (IC-7400)
    Ответов: 4
    Последнее сообщение: 03.01.2017, 01:11
  3. ic-820 валкодер
    от R1BBJ в разделе Icom
    Ответов: 12
    Последнее сообщение: 20.10.2011, 19:49
  4. Валкодер-энкодер
    от francua в разделе TS-430
    Ответов: 7
    Последнее сообщение: 23.08.2011, 21:57
  5. Валкодер IC 756pro
    от Vlad A.Mikchailov в разделе Трансиверы, приемники КВ/УКВ
    Ответов: 7
    Последнее сообщение: 20.01.2009, 12:28

Ваши права

  • Вы не можете создавать новые темы
  • Вы не можете отвечать в темах
  • Вы не можете прикреплять вложения
  • Вы не можете редактировать свои сообщения
  •