
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[216.73.216.3] |
![]() |
|
![]() |
|
|
Попробовал прикрутить энкодер к контроллеру ATTiny2313 и с его помошью изменять параметр заполнения ШИМ.
Работает, но очень криво и что самое страшное - через некоторе время контроллер может зависнуть. Кривость работы заключается в том, что например если увеличивать заполнение ШИМ, то светодиод начинает светить ярче, как и положено, НО через некоторе время он может вообще потухнуть / мигнуть / включиться на максиммум и в целом вести себя неадекватно ![]() Или может начать моргать (как бы "коротить") светодиод на другом порту, что ещё более странно. Можно было бы сослаться на дребезг, но это явно не он, т.к. пробовал подавлять его многими способами включая длительные задержки / флаги. Глюки практически не зависят от скорости вращения ручки. Схема подключения Энкодер: Канал "А" : PORTD -> PD2 (INT0) Канал "B" : PORTD -> PD3 Канал "С" : Земля Кнопка : PORTD -> PD0 Светодиод ШИМ: PORTB -> PB3 (OC1) Дополнительный светодиод: PORTB -> PB0 RESET через 10к резистор подтянут на плюс. Питание от +5 вольт с компьютера (красный/черный провода в молекс коннектора блока питания) Прошивка: ![]() ![]() #include <inttypes.h> #include <avr/io.h> #include <avr/interrupt.h> #include <avr/sleep.h> #include "iocompat.h" volatile SHORT PWMValue; // --- Переменная со значением ШИМ void setPin(uint8_t Pin, uint8_t Enable){ if(Enable) PORTB |= _BV(Pin); else PORTB &= ~_BV(Pin); } int main (void){ // --- Настройка ШИМ TCCR1A = TIMER1_PWM_INIT; TCCR1B |= TIMER1_CLOCKSOURCE; TIMSK = _BV (TOIE1); // - Прерывание по переполнению таймера OCR = 0; // - Стартовое значение ШИМ PWMValue = 0; // --- Обработка хуков настройки таймера #if defined(TIMER1_SETUP_HOOK) TIMER1_SETUP_HOOK(); #endif // --- Конфигурирование порта B на выход DDRB = _BV(PB0) | _BV(OC1); PORTB = 0x00; // --- Конфигурирование порта D на вход DDRD = ~_BV(PD0) | ~_BV(PD2) | ~_BV(PD3); // - PD 0,2,3 на вход PORTD = _BV(PD0) | _BV(PD2) | _BV(PD3); // - Подтягивающие резисторы для PD 0,2,3 // --- Настройка прерывания INT0 по изменению состояния MCUCR |= _BV(ISC00); MCUCR &= ~_BV(ISC01); GIMSK |= _BV(INT0); // - Разрешение прерываний sei(); static uint8_t flag = 0; while(1){ if(bit_is_clear(PIND, PD0) && flag == 0){ flag = 1; setPin(PB0, 1); }else if(bit_is_set(PIND, PD0) && flag == 1){ flag = 0; setPin(PB0,0); } sleep_mode(); } return (0); } //! Обработчик прерывания переполнения таймера ISR (TIMER1_OVF_vect) { OCR = PWMValue; } //! Обработчик прерыания INT0 /* первоначальный вариант ISR (INT0_vect){ static char A_State; // - Предыдущее значение канала А GIMSK &= ~_BV(INT0); // - Получаем текущее состояние каналов энкодера char _A = bit_is_clear(PIND, PD2); char _B = bit_is_clear(PIND, PD3); // - Если предыдущее значение канала А сопадает то выходим if (A_State == _A ) return; A_State = _A; // - Обработка направления вращения if ((_B != _A)) PWMValue ++; if ((_B == _A)) PWMValue --; GIMSK |= _BV(INT0); } */ ISR (INT0_vect){ volatile SHORT Value = PWMValue; if((((PIND) & (1<<PD2)) == 0) ^ (((PIND) & (1<<PD3)) == 0)){ Value++; if(Value > TIMER1_TOP) PWMValue = TIMER1_TOP; else PWMValue = Value; }else{ Value--; if(Value < 0) PWMValue = 0; else PWMValue = Value; } } Компилятор - WinAVR (avr-gcc) Параметры компиляции: ![]() ![]() avr-gcc -g -Os -mmcu=attiny2313 -c main.c avr-gcc -g -mmcu=attiny2313 -o main.elf main.o avr-objcopy -j .text -j .data -O ihex main.elf main.hex Ещё заметил странность что если убрать sleep_mode() из главного цикла то вообще всё рандомно начинает работать ![]() Если изменять значение PWMValue внутри прерывания таймера, например инкрементировать от нуля до TIMER1_TOP и декрементировать обратно, то всё работает стабильно. Чудеса начинаются при обработке INT0 прерываний. Какие есть идеи как это исправить? |
Сообщ.
#2
,
|
|
|
SHORT - он точно со знаком?
|
Сообщ.
#3
,
|
|
|
А может быть ширина импулься близка к периоду, а потом приосходит попытка увеличить её ещё больше? В результате старший разряд(ы) числа, которое хранит ширину импульса, игнорируются, и импульс получается опять коротким.
|
Сообщ.
#4
,
|
|
|
Prince, да, это я задефайнил т.к. программлю под Windows в VisualStudio и привык к типам из windows.h
![]() ![]() ![]() typedef uint8_t BYTE; typedef uint16_t WORD; typedef uint32_t DWORD; typedef int8_t CHAR; typedef int16_t SHORT; typedef int32_t LONG; typedef BYTE* PBYTE; typedef WORD* PWORD; typedef DWORD* PDWORD; typedef CHAR* PCHAR; typedef SHORT* PSHORT; typedef LONG* PLONG; Alexanbar, где в программе это может происходить? TIMER1_TOP = 1023 Тоесть заполнение может изменяться от 0 до 1023 включительно, что соотвествует 10-ти битному таймеру. (2^10-1) Если устаноить его в 0, то на выходе PD3 (OC1) установится постоянное низкое напряжение и наоборот, если установить 1023 то всегда будет высокое. Новое значение устанавливается в прерывании переполнения таймера. Границы проверяются ещё раньше. Если только компилятор чтото черезчур оптимизирует... других мыслей пока нет. Добавлено Да, ещё такой момент. Когда крутишь ручку энкодера, то контроллер греется. Добавлено Есть подозрение что глюки возникают при изменениии параметра заполнения т.к. если его не трогать, то контроллер ведёт себя стабильно. |
Сообщ.
#5
,
|
|
|
Цитата KillerXX7 @ RESET через 10к резистор подтянут на плюс. А емкостина на землю ? -Added Цитата KillerXX7 @ Да, ещё такой момент. Когда крутишь ручку энкодера, то контроллер греется. Это что то аппаратное. ![]() А блокировочные емкости имеются ? -Added Цитата KillerXX7 @ Ещё заметил странность что если убрать sleep_mode() из главного цикла то вообще всё рандомно начинает работать я не совсем понял, как все работает. Но сам бы сделал так: - если произошло изменение кода, только тогда будем менять значение ШИМ. - значение ШИМ я бы попытался менять синхронно с работой самого ШИМ-а. |
Сообщ.
#6
,
|
|
|
Цитата Есть подозрение что глюки возникают при изменениии параметра заполнения т.к. если его не трогать, то контроллер ведёт себя стабильно. Ачто, если изменять OCR в обработчике int0. Ведь OCR и так "защелкивается" только в момент, когда таймер досчитает до TIMER1_TOP. Так что обработчик таймера в таком варианте лишний как бы. ИМХО. Цитата Ещё заметил странность что если убрать sleep_mode() из главного цикла то вообще всё рандомно начинает работать А если всё убрать из главного цикла? Цитата Если только компилятор чтото черезчур оптимизирует... других мыслей пока нет. А как насчёт в эмуляторе погонять? Или этот код в AVRStudio никак не запихать? |
Сообщ.
#7
,
|
|
|
Поставил на энкодер конденцаторы между выводами C-A и C-B на 0.1 мкФ каждый
плюс поменял код прерываний на ![]() ![]() ISR (INT0_vect){ if((((PIND) & (1<<PD2)) == 0) ^ (((PIND) & (1<<PD3)) == 0)){ PWMValue+=50; setPin(PB0, 1); // - Отладка }else{ PWMValue-=50; setPin(PB0, 0); // - Отладка } if(PWMValue < 0)PWMValue = 0; if(PWMValue > TIMER1_TOP) PWMValue = TIMER1_TOP; } ISR (TIMER1_OVF_vect) { static SHORT LastPWM; if(LastPWM == PWMValue) return; LastPWM = PWMValue; OCR = PWMValue; } как посоветовал ЫукпШ и... всё заработало правильно ![]() Отладочное включение / выключение светодиода на PB0 при увеличении / уменьшении значения соотвественно, показывает небольшой дребезг только при вращении ручки против часовой стрелки (уменьшение значения) на большой скорости. Обусловлено это недостаточной точностью фиксации ручки. Похоже дело было всётаки в дребезге, только почему он приводил к зависанию контроллера - это непонятно. Также странно что в обсуждениях в интернете, были мнения что конденцаторы не нужны. Сам сначала хотел поставить, но почитав по теме, отказался ![]() Цитата ЫукпШ @ значение ШИМ я бы попытался менять синхронно с работой самого ШИМ-а. Это где/как и когда? Подробней плиз. Что касается нагревания, то оно исчезает если подтянуть входы к плюсу через 10к резисторы на 0.25Вт. Похоже тепло излучают внутренние резисторы. Добавлено Цитата Prince @ Ачто, если изменять OCR в обработчике int0. Ведь OCR и так "защелкивается" только в момент, когда таймер досчитает до TIMER1_TOP. Так что обработчик таймера в таком варианте лишний как бы. ИМХО. Попробовал так, работает. Кстати без sleep_mode тоже начал нормально работать. Получается что проблема была в аппаратной части. |
Сообщ.
#8
,
|
|
|
Цитата KillerXX7 @ Что касается нагревания, то оно исчезает если подтянуть входы к плюсу через 10к резисторы на 0.25Вт. Похоже тепло излучают внутренние резисторы. Порт можно сконфигурировать как "вход с подтяжками" или "вход без подтяжек". (Внутренние подтяжки ~100K-130K, те тоже не очень хорошо) Если подтягивающие резисторы внутри отключены, а внешних нет то получим вход вентиля с высоким входным сопротивлением. Такое включение будет чувствительно к помехам. Теоретически возможна неустойчивая работа и даже возбуждение вентиля. -Added Цитата KillerXX7 @ Похоже дело было всётаки в дребезге, только почему он приводил к зависанию контроллера - это непонятно. Если проблему удалось победить блокировками (по питанию), значит качество питания контроллера было не достаточным. ![]() Без этого работа любого процессора будет не устойчивой. Что и приводило контроллер к зависанию. Надо смотреть осциллографом. Тогда станет понятно, что происходит. -Added Цитата KillerXX7 @ Цитата ЫукпШ @ значение ШИМ я бы попытался менять синхронно с работой самого ШИМ-а. Это где/как и когда? Подробней плиз. Смысл предложения простой. У ШИМ есть некий период. А желание поменять яркость возникает в любой момент, т.е. асинхронно по отношению к генерации ШИМ. Если поменять параметр ШИМ в любой момент может получиться "рваный период". Новый параметр нужно вводить в эксплуатацию только в момент окончания периода и начало нового периода ШИМ. (соблюдается это условие в данной программе или нет я не разбирался) |
![]() |
Сообщ.
#9
,
|
|
Цитата ЫукпШ @ Новый параметр нужно вводить в эксплуатацию только в момент окончания периода и начало нового периода ШИМ. судя по всему так и есть, изменения вступают в силу по прерыванию таймера(надеюсь таймера самого шима, а не запущенного рядом TCCR1B ![]() Цитата KillerXX7 @ ![]() ![]() ISR (TIMER1_OVF_vect) { static SHORT LastPWM; if(LastPWM == PWMValue) return; LastPWM = PWMValue; OCR = PWMValue; } только проверки ИМХО тут излишние, потомучто TCNT(счетчик таймера) и так должен сбрасываться по прерыванию, на крайний случай его cамому нулить... да и не совсем поняткно к какому OCR ты присваиваешь новое значение....их там вроде 3 для каждого таймера, а ШИМ ты стартуешь на TCCR1A. еще бы увидеть чему равен TIMER1_PWM_INIT, ну то есть сам инициализатор шима... |
Сообщ.
#10
,
|
|
|
Сейчас реализовано так:
Переписал работу с ШИМ TIMER1 на макросы и сделал изменение параметра заполнения канала в обработчике INT0, освободив тем самым ресурсы, потребляемые при обработке прерывания переполнения таймера (а оно очень часто происходит). Думаю полная синхнронизация по периуду мне тут не очен нужна т.к. внешняя нагрузка имеет доольно большую инерцию и попросту не заметит "ломаного" периуда длиной несколько мс или нс. Без sleep_mode() сейчас также работает. Вывод - бороться с дребезгом нужно аппаратными методами, а конденсаторы цепи механического энкодера просто необходимы, какие бы доводы не приводились против этого. При ёмкость 0.1 кмФ пропуски щелчков заметны только при очень быстром вращении ручки. Кстати чисто "на глаз" пропуски на большинстве заводских девайсах значительно больше не той же скорости. Похоже там ещё большее подавление дребезга. Собсвтенно код тестового проекта на 2 канала ШИМ таймера TIMER1 ![]() ![]() #include <inttypes.h> #include <avr/io.h> #include <avr/interrupt.h> #include <avr/sleep.h> // ---------------------------------------------------------------------- // - Каналы PWM #define PWM_CHANNEL_OC1A COM1A1 #define PWM_CHANNEL_OC1B COM1B1 #define TIMER1_TOP 1023 // - 10 bit PWM #define TIMER1_CLOCKSOURCE _BV(CS10) // --- Инициализация PWM #define TIMER1_PWM_INIT TCCR1A = _BV(WGM10) | _BV(WGM11) // --- Включение / Выключение PWM #define TIMER1_PWM_ENABLE TCCR1B |= TIMER1_CLOCKSOURCE #define TIMER1_PWM_DISABLE TCCR1B &= ~TIMER1_CLOCKSOURCE // --- Подключение / Отключение каналов PWM для TIMER1 #define TIMER1_PWM_ENABLE_CHANNEL(Channel) TCCR1A |= _BV(Channel) #define TIMER1_PWM_DISABLE_CHANNEL(Channel) TCCR1A &= ~_BV(Channel) // --- Установка значения #define TIMER1_PWM_OC1A_SET_VALUE(Value) OCR1A = Value #define TIMER1_PWM_OC1B_SET_VALUE(Value) OCR1B = Value // --- Функция установки состояния вывода для порта B void setPin(uint8_t Pin, uint8_t Enable){ if(Enable) PORTB |= _BV(Pin); else PORTB &= ~_BV(Pin); } // ----------------------------------------------- // --- Главная функция // ----------------------------------------------- int main (void){ // --- Настройка ШИМ на TIMER1 TIMER1_PWM_INIT; TIMER1_PWM_ENABLE_CHANNEL( PWM_CHANNEL_OC1A ); TIMER1_PWM_ENABLE_CHANNEL( PWM_CHANNEL_OC1B ); TIMER1_PWM_ENABLE; // - Стартовое значение ШИМ для каналов PWMValue = 0; OCR1A = 0; OCR1B = TIMER1_TOP; // --- Обработка хуков настройки таймера #if defined(TIMER1_SETUP_HOOK) TIMER1_SETUP_HOOK(); #endif // --- Конфигурирование порта B на выход DDRB = 0xFF; PORTB = 0x00; // --- Конфигурирование порта D на вход DDRD = ~_BV(PD0) | ~_BV(PD2) | ~_BV(PD4); // - PD 0,2,4 на вход PORTD = _BV(PD0) | _BV(PD2) | _BV(PD4); // - Подтягивающие резисторы для PD 0,2,4 // --- Настройка прерывания INT0 по изменению состояния MCUCR |= _BV(ISC00); MCUCR &= ~_BV(ISC01); GIMSK |= _BV(INT0); // - Разрешение прерываний sei(); while(1){ // - Спим до следующего прерывания sleep_mode(); } return (0); } // --------------------------------------------------------------- // --- Обработчик прерывания INT0 // --------------------------------------------------------------- ISR (INT0_vect){ static SHORT LastPWM; // - Предыдущее значение ШИМ // --- Определяем направление вращения ручки if((((PIND) & (1<<PD2)) == 0) ^ (((PIND) & (1<<PD4)) == 0)){ // - Вращение вправо, увеличиваем яркость PWMValue += 10; }else{ // - Вращение влево, уменьшаем яркость PWMValue -= 10; } // - Проверка выхода за допустимые значения ШИМ if(PWMValue < 0) PWMValue = 0; if(PWMValue > TIMER1_TOP) PWMValue = TIMER1_TOP; // - Если значение не изменилось то выходим if(LastPWM == PWMValue) return; LastPWM = PWMValue; // - Устанавливаем новое значение заполнения ШИМ TIMER1_PWM_OC1A_SET_VALUE( PWMValue ); TIMER1_PWM_OC1B_SET_VALUE( TIMER1_TOP - PWMValue ); } И схемка: ![]() Работой энкодера доволен, вопрос можно считать решенным, всем спасибо! Однако обсуждение и идеи по теме приветсвуются =) Добавлено На схеме не указано, но на кнопку также желательно вешать конденсатор. |
![]() |
Сообщ.
#11
,
|
|
про емкость на сбросе сказали, а вот RC фильтра(10-100 Ом+0.1мкФ) по питанию нет....я ставлю 0805 или 0603 10 Ом, работает как предохранитель
![]() какое напряжение питания контроллера? просто нет резисторов на светиках, да и сами светики лучше развернуть, чтоб зажигать нулём гасить единицей. это чтоб уменьшить суммарную нагрузку на порты ввода вывода контроллера. |
Сообщ.
#12
,
|
|
|
Что бы я обязательно изменил в этой схеме:
1. Добавил емкость 0.1 - 1.0 с RESET на землю (вывод 1 процессора). По-хорошему в такой схеме сброса надо еще зашунтировать резистор R2 диодом в обратной полярности, а между шинами питания запаять резистор. По вкусу 1К0 - 10К0. 2. Два конденсатора питание-земля. 0.1 и 10.0x10V 3. Убрать конденсаторы с энкодера. Дребезг легко подавляется программно. В такой схеме потенциально возможно обгорание контактов. Ни к чему хорошему это не приведет. 4. 3 нагрузочных резистора 1К0 - 10К0 на выводы 2,6,8 процессора к питанию. 5. резисторы последовательно со светодиодами ! ~1К0 (Интересно,выгорели выводы 15,16 процессора или еще нет ? ![]() Возможно, это и есть причина разогрева контроллера. 6. Это не обязательно, но светодиоды я предпочитаю включать логическим 0. Традиционно драйверы включения на землю у аппаратуры посильнее будут. 7. Все свободные выводы пусть будут выходами. |
Сообщ.
#13
,
|
|
|
Цитата ElcnU @ какое напряжение питания контроллера? 5 вольт, снятых с красного провода MOLEX коннектора компьютера =)))) земля взята тамже, естественно с черного провода. Цитата ElcnU @ про емкость на сбросе сказали, а вот RC фильтра(10-100 Ом+0.1мкФ) по питанию нет....я ставлю 0805 или 0603 10 Ом, работает как предохранитель Резистор в роле предохранителя? ![]() В каких случаях он может помочь? Цитата ЫукпШ @ 3. Убрать конденсаторы с энкодера. Дребезг легко подавляется программно. В такой схеме потенциально возможно обгорание контактов. Ни к чему хорошему это не приведет. Вот именно на это самое программное подавление я и потратил целый день, прочитав похоже доводы против. Что только не пробовал, оно всёравно глючило. Поставил конденсаторы - глюки исчезли, а регулироание стало плавным. Обгарание контактов врятли будет, всётаки напряжение и ток довольно низкие, да и дребезг не очень продолжительный. Цитата ЫукпШ @ 5. резисторы последовательно со светодиодами ! ~1К0 (Интересно,выгорели выводы 15,16 процессора или еще нет ? ) Возможно, это и есть причина разогрева контроллера. Резисторы конечно нужная штука, но в тестовую схему не стал их ставить. Нагревание явно не из-за "перегруза" светодиодами, а судя по всему греются внутренние подтягивающие резисторы. Тепло выделяется в верхней части МК, примерно между 1/3, 20/18 выводами и только при вращении ручки энкодера. Вот собсвтенно кусок схемы железки, которую собираю. При помощи двух энкодеров нужно управлять двумя "высоковольными" мощьными нагрузками. Одна нагрузка - электромотор, вторая - лампа (по факту скорее всего будет светодиодной) Железка эта предназначена для авто, поэтому питание берётся с бортовой сети. Для питания низковольной части схемы используется стабилизатор, поддерживающий на выходе от 4.8 до 5.2 вольт. Номинальное выходное напряжение 5.0 вольт. (данные из даташита) Номиналы керамических кондесаторов возле стабилизатора взяты также из даташита из примера использования, плюс добавлен конденсатор на 470мкФ и диод на входе. Учел пожелания с диодом и конденсатором на сбросе. Цитата ЫукпШ @ а между шинами питания запаять резистор Для чего он нужен? Мне кажется он будет просто "греться", хотя могу ошибаться. К тому же на "боевой" схеме на выходе в стабилизаторе стоит делитель напряжения на 2 резисторах, тоесть по сути уже есть поротивление между плюм и землёй. Есть несколько вопросов по схеме: 1. Нагрузки я защитил предохранителями, однако они стоят после транзисторов. Это правильно? 2. Если использовать только внешние подтягивающие резисторы, то схема почемуто не работает, поэтому даже в тестовой схеме включал внутренние резисторы. В чем может быть проблема? Слишком большое сопротивление внешних? 3. Стоит ли на выходы энкодера поставить диоды для ограничения возможного обратного тока? 4. Стоит ли подтянуть Gate транзисторов к земле через резистор? (для исключения ситуации когда на нагрузко подано напряжение, а контроллер обесточен и Gate болтается в воздухе) 4. Что ещё можно добавить убрать в этой схеме Энкодер-Контроллер-Нагрузка Прикреплённая картинка
|
Сообщ.
#14
,
|
|
|
Цитата KillerXX7 @ Резистор в роле предохранителя? Технологически внутри смонтирована плавкая вставка - типа этого Цитата KillerXX7 @ В тех же случаях, что и предохранитель - отключение вышедшего из строя оборудования от источника питания при превышении предельного тока. В каких случаях он может помочь? ![]() Добавлено Цитата KillerXX7 @ Железка эта предназначена для авто, поэтому питание берётся с бортовой сети. Хм...смотря что за авто. Я бы еще пересмотрел (на всякий случай) алгоритм прошивки, с применением сторожевого таймера (были случаи с помехами от ВЧ части авто - ПИК 16F84A работал нестабильно - пришлось "перекраивать" алгоритм, предусмотрев сброс контроллера). ![]() |
![]() |
Сообщ.
#15
,
|
|
Цитата KillerXX7 @ а судя по всему греются внутренние подтягивающие резисторы. внутренние подтягивающие резисторы порядка 18кОм и только когда порт на вход включен, и нужно сильно постараться, чтоб их зажарить Цитата KillerXX7 @ Резисторы конечно нужная штука, но в тестовую схему не стал их ставить. без них как равило вылетают светодиоды Цитата KillerXX7 @ 5 вольт, снятых с красного провода MOLEX коннектора компьютера =)))) отсюда резисторы(если диоды типа ал307) порядка 300 Ом, потомучто оптимальный ток свечения 10мА. Цитата KillerXX7 @ 4. Стоит ли подтянуть Gate транзисторов к земле через резистор? обязательно, я так 3 DSPника по 40$ спалил ![]() |
Сообщ.
#16
,
|
|
|
Цитата medved_68 @ Технологически внутри смонтирована плавкая вставка - типа этого Интересная штука ))) Нужно будет попробовать. |
Сообщ.
#17
,
|
|
|
KillerXX7, у тебя изначально переменная PWMValue двухбайтная, а контроллер восьмиразрядный, все операции с этой переменной делаются из нескольких инструкций, младший байт -- старший байт. используешь ты ее в прерываниях. Если прерывание происходит в момент когда обрабатывается эта переменная, то в ней оказывается не верное значение и в прерывании ты его считываешь. От этого и была у тебя проблема ошибочных значений шима. Я бы сделал эту переменную размером в байт, а в прерывании сдвигом получал бы нужную разрядность. Или на время работы с этой переменной включал глобальный запрет прерываний.
Добавлено в IAR-овских библиотеках есть специальный модификатор функций для работы в подобных ситуациях, то есть ты с этой переменной работаешь только внутри специально объявленных функций. Таким образом компилятор гарантирует атомарность работы с многобайтными переменными. Tсли память не изменяет, модификатор называется MONITOR. С другой стороны, gcc достаточно мудреный компилятор и мне сдается, что он должен был выдавать тебе варнинг на эту переменную, могу ошибаться. |
Сообщ.
#18
,
|
|
|
Цитата KillerXX7 @ Вот именно на это самое программное подавление я и потратил целый день, прочитав похоже доводы против. Что только не пробовал, оно всёравно глючило. Это весьма не сложно. На конденсаторах ты делаешь интегратор. Сделаем его программно: 1. Запустим таймерную процедуру-интеррапт. Например, 1[мС]. В качестве цифрового интегратора будем использовать реверсивный двоичный счетчик. При таком периоде считать можно до 4-8. Дребезг контактов дольше, как правило, не бывает. 2. В этой процедуре смастерим двоичный реверсивный счетчик (с двумя ограничениями, сверху и снизу). Это и есть аналог интегратора. 3. По прерыванию считываем значение бита. 1 - и нет насыщения сверху - увеличиваем значение счетчика 0 - и нет насыщения снизу - уменьшаем значение счетчика (Чему именно соответствует 0 и 1 зависит от схемы) 4. Достигнутая граница сверху - кнопка нажата, выставим флаг Достигнутая граница снизу - кнопку отпустили, сбросим флаг. Вот так, силой мысли можно сэкономить кучу конденсаторов. ![]() Не знаю - нужно ли приводить исходные тексты ? Это не так уж и сложно. -Added Цитата KillerXX7 @ 4. Что ещё можно добавить убрать в этой схеме Энкодер-Контроллер-Нагрузка S силовых триодов подключить к земле, а нагрузку подключить между +12V и D силовых триодов. Если ты все-таки решил оставить емкостины для подавления дребезга, включи последовательно с контактом небольшой резистор 50-100 [ом]. Какой пиковый ток пойдет через контакт ? ![]() 5V/(сопротивление контакта и провода). Так обгорают контакты. -Added Цитата KillerXX7 @ Цитата ЫукпШ @ а между шинами питания запаять резистор Для чего он нужен? Мне кажется он будет просто "греться", хотя могу ошибаться. К тому же на "боевой" схеме на выходе в стабилизаторе стоит делитель напряжения на 2 резисторах, тоесть по сути уже есть поротивление между плюм и землёй. Рассмотрим цепи R1,VD2,C7. VD2 без резистора между +5V и землей "R5vgnd" совершенно бесполезен. Он нужен для того, чтобы емкость C7 быстрее разряжалась при выключении питания по цепи VD2->"R5vgnd". Не факт, что емкостина разрядится через источник питания. Чтобы иметь возможность выключить питание и быстро включить ставят VD2 и "R5vgnd". Если это точно не требуется на них можно сэкономить. |
Сообщ.
#19
,
|
|
|
Цитата MeG @ PWMValue двухбайтная, а контроллер восьмиразрядный, все операции с этой переменной делаются из нескольких инструкций, младший байт -- старший байт. используешь ты ее в прерываниях. Если прерывание происходит в момент когда обрабатывается эта переменная, то в ней оказывается не верное значение и в прерывании ты его считываешь. От этого и была у тебя проблема ошибочных значений шима. Я бы сделал эту переменную размером в байт, а в прерывании сдвигом получал бы нужную разрядность. Или на время работы с этой переменной включал глобальный запрет прерываний. С другой стороны именяю её значение я также только в прерываниях, а до выхода из прерывания все остальные прерывания запрещены. Компилятор никаких варнингов не выдаёт, код компилится вообще молча (что даже странно для сишной проги ![]() Возможно компилятор сам разрулиает с именением переменной и прерываниями, но не факт. Цитата ЫукпШ @ Вот так, силой мысли можно сэкономить кучу конденсаторов. Алгоритм ясен =) Именно такую реализацию не пробовал. Но всётаки осталвлю конденсаторы, очень нраится как с ними работает =))) Резисторы действительно впаяю. Слабо верится что через энкодер может протекать ток около 5 ампер, но цифра в любом случае страшная. Цитата ЫукпШ @ Чтобы иметь возможность выключить питание и быстро включить ставят VD2 и "R5vgnd". Если это точно не требуется на них можно сэкономить. Необходимости в "передергивании" питания нет. Получается что диод в таком случае можно снять, верно? |
Сообщ.
#20
,
|
|
|
Цитата KillerXX7 @ Получается что диод в таком случае можно снять, верно? Да. -Added Цитата KillerXX7 @ С другой стороны именяю её значение я также только в прерываниях, а до выхода из прерывания все остальные прерывания запрещены. Тогда и проблем нет. А если бы было необходимо править эту переменную в фоновой программе, можно было бы на время операции с ней запрещать прерывания. |
Сообщ.
#21
,
|
|
|
[офтоп]
KillerXX7, а можно вопрос? зачем понадобилось использовать энкодеры (кста, этож вроде как колесо от мыши, нет?), почему было не взять ATTiny26 (он с АЦП. ШИМ-каналов правда только 2, а не 4, но тут больше и не используется) и два обычных потенциометра? [/офтоп] |
Сообщ.
#22
,
|
|
|
[офтоп]
Колесо от мышки одна из реализация энкодера =) Те что у меня больше похожи на регуляторы громкости на музыкальных центрах / магнитолах, ну или на выбор времени на микроволновках ![]() Именно энкодеры потому что упралять или удобней и приятней чем теми же реостатами + современней и стильней смотрися и ощущается, да и вообще они ближе к цифре чем к аналогу. [/офтоп] |
Сообщ.
#23
,
|
|
|
Цитата KillerXX7 @ [офтоп] Именно энкодеры потому что упралять или удобней и приятней чем теми же реостатами [/офтоп] А я делал так - с кнопками UP и DOWN: ссылка |
Сообщ.
#24
,
|
|
|
[офтоп]
Цитата KillerXX7 @ Именно энкодеры потому что упралять или удобней и приятней чем теми же реостатами + современней и стильней смотрися и ощущается, да и вообще они ближе к цифре чем к аналогу. ясн... хотя ИМХО единственный плюс (с точки зрения разработчика) и он же минус (с точки зрения пользователя) энкодера — возможность использовать его для задания нескольких параметров (как в нынешних автомагнитолах делают)... Незнаю, может и есть кто, кому нравится, что для реглировки басов надо четыре раза нажать кнопку, глянуь на магнитолу, убедиться, что она показывает "bass", и только после этого крутить ручку... но мне кажется в миллион раз удобнее на ощупь найти ручку нужного потенциометра и крутнуть её... кстати, в твоём устройстве вроде кнопки энкодеров не задействованы? так мог тоже съэкономить один энкодер, повесив на кнопку функцию переключения управляемого канала [/офтоп] |
![]() |
|
|
Заинтересовался кодом для энкодера с этой темы-
![]() ![]() if((((PIND) & (1<<PD2)) == 0) ^ (((PIND) & (1<<PD3)) == 0)){ PWMValue+=50; setPin(PB0, 1); // - Отладка }else{ PWMValue-=50; setPin(PB0, 0); // - Отладка Я пишу на CVAVR,так же по схеме хочу соединить к меге16, вот это- PIND - не могу понять как написать, не могли бы обьяснить,что это обозначает PIND,какая это нога или ранее запомненное состояние |
Сообщ.
#26
,
|
|
|
PIND, это висьмибитный входной регистр порта D, восемь ножек этого порта соответствуют восьми битам этого регистра. Логический уровень напряжения на ножке порта соответствует значению бита в регистре, если данная ножка сконфигурирована на вход.
|
Сообщ.
#27
,
|
|
|
Вообще-то PIND не регистр. PIND адресуется непосредственно к выводам МК, независимо от того, как они сконфигурированы.
|
Сообщ.
#28
,
|
|
|
Извиняюсь,я знал,что PIND это ножка порта,я думал если написать,например if(PIND==0), то выдаст ошибку,оказывается можно, тогда попробуем на деле этот код.Получается,это обращение к любому выводу порта D
|
Сообщ.
#29
,
|
|
|
Цитата Prince @ Вообще-то PIND не регистр. PIND адресуется непосредственно к выводам МК, независимо от того, как они сконфигурированы вообще-то PIND это регистр синхронизированный с клоком если верить даташиту Атмела на ATtiny2313 http://www.atmel.com/dyn/resources/prod_documents/DOC2543.PDF на странице 54 (рисунок 25) нарисована эквивалентная схема одного пина порта. Через ключ ножка подключается к триггеру шмидта, с него на триггер защелку и далее на синхронный D-триггер (именно он и назван PINxn), то есть, сигнал с ножки доступен для считывания с задержкой в один такт. Ключ перед триггером шмидта управляется сигналом DIGITAL INPUT-ENABLE, то есть, триггер подключен к ножке в случае если порт настроен как цифровой вход. В тоже время, считывать сигнал с D-триггера пина порта (PINxn) можно независимо от того как настроен порт, на вход, на выход или как аналоговый. Если порт не настроен на вход, то, в силу подтяжки к земле перед триггером шмидта, с PINxn будет считываться ноль. С триггера шмидта выходит сигнал DIxn, он используется как входной цифровой сигнал в случае использования порта для альтернативной функции (таблица 23). |
Сообщ.
#30
,
|
|
|
Прости, был неправ. Вспомнил даташит на at90s2313, в нём никаких защелок по входу вроде бы не было. Предположил, что и тут аналогичная схема.
|
Сообщ.
#31
,
|
|
|
В программировании не очень силен, поэтому не пинайте. Как можно изменить схемку и программу, чтобы управление для двух нагрузок было одним энкодером и кнопкой, а уровень отображался на 2-х семисегментниках отдельно от 0 до 9, кнопка для переключения каналов, регулируемый канал отображался точкой возле цифры?
|