Главная  
18.05.2012 г.
Главная
Проекты
Статьи
Начинающим
Архив новостей
Ссылки
Контакты
Поиск
Файлы
Форум
Карта сайта
Авторизация





Забыли пароль?
Ещё не зарегистрированы? Регистрация
Поддержи наш сайт!
Через WebMoney

 R785211844650
 Z210696637574
 E368177590409

Простые устройстваОтличные товары по превосходным ценамОтличные товары по превосходным ценам
Форум ARV Research
Добро пожаловать, Гость
Пожалуйста Вход или Регистрация.
Забыли пароль?
Приращение переменной, при внешних прерываниях (1 просматривает)
_GEN_GOTOBOTTOM Ответить

TOPIC: Приращение переменной, при внешних прерываниях

#6657
ARV (Администратор)
Администратор
Постов: 2027
graph
В ответ на: Приращение переменной, при внешних прерываниях 25.07.2011 13:50 Репутация: 167  
ну так установите свежий в древнем и багов немало было, свеженький все ж получше будет...
Не стыдно не знать, стыдно не учиться
  Для добавления сообщений Вы должны зарегистрироваться или авторизоваться.
#6665
Spacelabus (Пользователь)
Новичок
Постов: 10
graphgraph
В ответ на: Приращение переменной, при внешних прерываниях 27.07.2011 03:02 Репутация: 0  
Не буду создавать новую тему, столкнулся с новой проблемой:

Code:

 #define F_CPU 1000000UL // 1 MHz #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> volatile unsigned int a=0; ISR(INT0_vect) { _delay_ms(100); a+=100; if (a>=1000) {a=0;} } int main(void)  { GICR=1<<INT0; MCUCR=1<<ISC01|0<<ISC00; DDRD=128; PORTD=255; DDRB=255; PORTB=0; DDRC=255; PORTC=0; while(1) { sei(); PORTB=(1<<PB0); _delay_ms(a); PORTB=(0<<PB0); _delay_ms(a); if (a>=0) {PORTC=0;} if (a>=100) {PORTC=1;} if (a>=200) {PORTC=2;} if (a>=300) {PORTC=3;} if (a>=400) {PORTC=4;} if (a>=500) {PORTC=5;} if (a>=600) {PORTC=6;} if (a>=700) {PORTC=7;} if (a>=800) {PORTC=8;} if (a>=900) {PORTC=9;} } }


Я пока решил приделать индикатор ко всему этому чуду. Нашел дешифратор, в общем с горем пополам он у меня приращевается на сотую часть, вместе с инкрементом. То есть когда задержка 100 пишет единицу, когда 200-2 и т.д.
Но вот вместе с ним вскрылась проблема дребезга контактов. И вот я не могу придумать. куда воткнуть задержку, если ставить в цикле прерывания то она только задерживает результат приращения, но не избавляет от дребезга.
Надеюсь на вашу подсказку, как это все оформить)
  Для добавления сообщений Вы должны зарегистрироваться или авторизоваться.
#6666
ARV (Администратор)
Администратор
Постов: 2027
graph
В ответ на: Приращение переменной, при внешних прерываниях 27.07.2011 08:54 Репутация: 167  
я бы имел наглость посоветовать вам начать не сразу писать программы, а немного навостриться в продумывании алгоритмов. программирование - это 99% алгоритм и 1% код. попробую пояснить необходимость думать именно над алгоритмом на примере вашего же кода, к которому с точки зрения синтаксиса языка практически нет претензий.
1.
Code:

 ISR(INT0_vect){    _delay_ms(100);    a+=100;    if (a>=1000) {a=0;} }

вот вы представьте себе: возникло прерывание и 0,1 секунды микроконтроллер зависает в обработчике прерывания... 0,1 секунды - это ОЧЕНЬ МНОГО по меркам МК. а если у вас был дребезг контакта, то пока вы там зависаете в задержке, установился флажок прерывания снова, и как только вы закончите эту паузу, тут же снова попадете в обработчик и снова зависните... кошмар! В ОБРАБОТЧИКАХ ПРЕРЫВАНИЙ НЕДОПУСТИМО ДЕЛАТЬ ДОЛГИЕ ЗАДЕРЖКИ!
2. вы уже долго бьетесь над задержкой, которую можно делать по значению переменной, упорно пихая ПЕРЕМЕННУЮ в функцию _delay_ms(), хотя я вам уже говорил, что делать это не надо. а ведь решение на поверхности:
Code:

 void my_delay(int wait_ms){    for(; wait_mswait_ms--){       _delay_ms(1);    } }

проанализируйте эту функцию, и вы поймете, что она позволяет сделать регулируемую задержку без того, чтобы пихать ПЕРЕМЕННУЮ в стандартную функцию задержки. то есть и задача решена, и правила не нарушены.
3. рассмотрите участок кода
Code:

 if (a>=0) {PORTC=0;} if (a>=100) {PORTC=1;} if (a>=200) {PORTC=2;} if (a>=300) {PORTC=3;} if (a>=400) {PORTC=4;} if (a>=500) {PORTC=5;} if (a>=600) {PORTC=6;} if (a>=700) {PORTC=7;} if (a>=800) {PORTC=8;} if (a>=900) {PORTC=9;}

ведь очевидно, что в PORTC выводится число СОТЕН в значении переменной а. для чего же писать столько операторов if?!
Code:

 PORTC 100;

этот единственный оператор заменяет все ваши.

это все с беглого взгляда на программу. однако, если покопаться, можно и еще задать вопросы, например, почему а увеличивается сразу на 100, хотя толку от этого нет никакого, вполне можно было бы и на 1 ее увеличивать, но в 100 раз реже...

я хочу сказать, что все эти очевидности вам пока не заметны, а ведь они путают, сбивают с мысли и, главное, не воспитывают привычку оптимизировать. то есть если мысли растрепанные, то и программа кривая. причешите мысли - и программа станет лучше. тем более вы и сами как-то не очень довольны ее качеством (сами говорите - "с горем пополам").
Не стыдно не знать, стыдно не учиться
  Для добавления сообщений Вы должны зарегистрироваться или авторизоваться.
#6667
Spacelabus (Пользователь)
Новичок
Постов: 10
graphgraph
В ответ на: Приращение переменной, при внешних прерываниях 27.07.2011 14:30 Репутация: 0  
Поправил, все и правда стало выглядеть приятнее.
Code:

     #define F_CPU 1000000UL  // 1 MHz    #include <avr/io.h>    #include <util/delay.h>    #include <avr/interrupt.h>    volatile unsigned int a=0;  ISR(INT0_vect) { _delay_ms(10); a+=100; _delay_ms(10);   if (a>=1000)    {a=0;}} void delay(int a) {for(;a;a--) {_delay_ms(1); }} int main(void)               { GICR=1<<INT0; MCUCR=1<<ISC01|0<<ISC00; DDRD=128; PORTD=255; DDRB=255; PORTB=0; DDRC=255; PORTC=0; while(1) { sei(); PORTB=(1<<PB0); delay(a); PORTB=(0<<PB0); delay(a); PORTC=a/100; }}


Ну и полегчало без переменной в задержке более чем внушительно - на 800 байт. Осталось 300) Но вот проблема с дребезгом так и не решена. Я пытался решить проблему с помощью примера, как в этой
книжке. Писал примерно так:
Code:

  ISR(INT0_vect) { if (INT0==0) {_delay_ms(10); if (INT0==0) {a+=100; _delay_ms(10); }}   if (a>=1000)    {a=0;}}


Не помогает. И вообще правильно ли то, что я обращаюсь к INT0, или все таки следует обращаться к PORTD, когда я опрашиваю прерывания? Хотя в любом случае ничего толкового не получается. Как я понял можно еще каким то образом использовать таймер, чтобы заблокировать кнопку на время после нажатия? Но гугл мне с этим не помог.
  Для добавления сообщений Вы должны зарегистрироваться или авторизоваться.
#6668
ARV (Администратор)
Администратор
Постов: 2027
graph
В ответ на: Приращение переменной, при внешних прерываниях 27.07.2011 16:04 Репутация: 167  
давайте для начала определимся, что такое INT0 с точки зрения компилятора? если найти его определение где-то в глубинах хидеров, то окажется, что это просто какое-то число, обозначающее номер бита в регистре. предположим (я точно не знаю), это число 5. как вы считаете, что будет в вашем случае с оператором if(5==0) ? правильно, это никогда не будет выполняться
поэтому, если вы хотите что-то определять на порту, то и работать надо с портом, а не с какими-то цифрами или буквами.
однако, теперь надо разобраться, что такое дребезг и как с ним бороться. дребезг - это случайное замыкание и размыкание механических контактов прежде, чем цепь полностью замкнется или разомкнется. для большинства коммутирующей аппаратуры дребезг длится не более 10-15 миллисекунд. то есть в течение этого времени нет однозначности в состоянии контакта. поэтому борьба с дребезгом заключается в следующем: как только мы обнаруживаем изменение уровня сигнала, следует запомнить его (уровень), подождать время, достаточное для завершения процесса дребезга, а затем снова определить уровень сигнала и сравнить его с запомненным. если оба уровня одинаковы - это означает, что дребезг успешно подавлен и значение уровня и есть правильное, если уровни окажутся разными - эту ситуацию надо игнорировать: то ли дребезг не успел завершиться, то ли это было не замыкание контакта, а помеха, то ли еще что-то не то...
ну, а теперь давайте подумаем, как же быть в том случае, если сигнал с дребезгом подается на вход запроса прерывания. как я уже говорил, долгие задержки в обработчике прерываний - это очень плохо. как же быть? вариантов может быть несколько.
1. отказаться от обработки сигнала по прерыванию. это очень часто не только возможно, но и более верно. прерывание нужно для обеспечения МГНОВЕННОЙ РЕАКЦИИ на событие, а часто ли это нужно? например, если это кнопка, которую жмет человек, то задержка в реакции до 0,1 секунды практически никогда им замечена не будет.
2. если же все-таки необходимо работать по прерываниям, то так же может быть несколько путей. один из них - делать как вы, т.е. в обработчике прерываний ждать 10-15 миллисекунд и затем снова проверять уровень на входе. только не следует забывать, что пока не произошел выход из обработчика, новые импульсы могут снова установить флаг запроса прерывания, поэтому ОБЯЗАТЕЛЬНО надо принудительно сбрасывать флаг запроса перед выходом из обработчика, иначе вы будете "задваивать" свои нажатия.
другой способ работы по прерываниям подразумевает использование таймера. то есть по прерыванию от кнопки вы запоминаете уровень сигнала и запускаете таймер на 10 мс, после чего, сблросив флаг, завершаете обработку. получается очень быстро. когда таймер истечет - он тоже вызывает прерывание, в обработчике которого вы смотрите на состояние входа и сравниваете его с ранее запомненным. короче, далее - по обстоятельствам. то есть изменение вашей переменной будет происходить уже в обработчике прерывания таймера. разумеется, вам надо предусмотреть ситуацию, когда приходит запрос INT0 в то время, пока таймер еще не отсчитал предыдущий интервал - в этом случае можно либо перезапускать таймер, либо игнорировать событие - это уже смотря по тому, какие последствия этих действий вас устроят больше.
Не стыдно не знать, стыдно не учиться
  Для добавления сообщений Вы должны зарегистрироваться или авторизоваться.
#6669
Spacelabus (Пользователь)
Новичок
Постов: 10
graphgraph
В ответ на: Приращение переменной, при внешних прерываниях 27.07.2011 21:28 Репутация: 0  
Спасибо за такой подробный ответ.
Что то вроде стало получаться, прерывания теперь выглядят так:
Code:

  ISR(INT0_vect) {if (PORTD==255;) {_delay_ms(10); if (PORTD==255;) {a+=100; PORTD=0; _delay_ms(2); PORTD=255;}} if(a>=1000) {a=0;}}


Но вот получается одна непотребность, приближаясь в большей задержке - индикатор начинает отображать числа медленнее. Точнее он загорается в то же мгновение, что и светодиод. Но я так понимаю - это потому что программа стоит - пока идет delay. Но числа он считает вроде бы верное, т.е. если нажму 9 раз подряд - 9 засветит, но через какое то время, где то пол секунды, но глазу заметно и не приятно. Думаю теперь познакомиться с таймером и сделать для сравнения и на нем, надо все это дело обгуглить.
Может быть у вас найдется в закромах схожее применение таймера? Да или вообще самое элементарное, буду рад ознакомиться)
  Для добавления сообщений Вы должны зарегистрироваться или авторизоваться.
#6670
Spacelabus (Пользователь)
Новичок
Постов: 10
graphgraph
В ответ на: Приращение переменной, при внешних прерываниях 28.07.2011 00:00 Репутация: 0  
В итоге я зашел в тупик. Не понимаю самого принципа. Как мой таймер увидит, что я нажму на кнопку? Или надо будет убирать с внешних прерываний и инициализировать вместо них таймер, который будет вызывать прерывания?
Если да, то вопросов очень много. Почему везде в примерах я вижу только регистр TCCR0, ведь TCCRA & TCCRB отличаются по назначению? Как это вообще все будет выглядеть? Я так понял временем я могу оперировать только с помощью тактовой частоты? т.е. TCCRB=0b101; Судя по табличке это деление на 1024, т.е деление тактовой частоты? Например она стала ~1000 после того как поделил(Хотя вообще не понятно как инициализировать именно канал B, если везде пишут TCCR0), т.е. таймер "тикает" примерно 1 раз в милисекунду? И когда он дотикает до нуля например, или до какого либо значения(Определяется TIMSK как я понял?переполнение и совпадение), прерывания опять станут доступны? Совершенно не понятно с какого конца подойти

Содержимое поста отредактировано: Spacelabus, в: 28.07.2011 00:02
  Для добавления сообщений Вы должны зарегистрироваться или авторизоваться.
#6673
ARV (Администратор)
Администратор
Постов: 2027
graph
В ответ на: Приращение переменной, при внешних прерываниях 28.07.2011 08:01 Репутация: 167  
подходить всегда надо с вдумчивого чтения документации, ну или на крайний случай - какой-то книжки. TCCR0 - это регистр управления таймером 0, этот таймер 8-битный и имееет у многих микроконтроллеров всего один регистр управления - TCCR0. TCCR1A и TCCR1B - это пара регистров управления таймером 1, который 16-битный и есть не во всех тиньках. ну а в продвинутых микроконтроллерах семейства мега может быть и три и более регистров управления таймером. так что если вы везде встречаете упоминание TCCR0 - это лишь означает, что речь идет о 0-ом таймере - он есть во всех МК семейства AVR.
то есть регистры управления принято обозначать так: сначала идет TCCR (Timer-Counter Control Register), затем идет номер таймера (0, 1, 2 и т.д.), а затем, если нужно, буквенное обозначение конкретного регистра (A, B, C и т.д.).

если у вас есть вопросы по работе периферии AVR, следует задавать соответствующие конкретные вопросы в разделе для начинающих, чтобы не превращать тему в свалку разнородных вопросов и ответов.
Не стыдно не знать, стыдно не учиться
  Для добавления сообщений Вы должны зарегистрироваться или авторизоваться.
_GEN_GOTOTOP Ответить
© Copyright 2007 Best of Joomla, Работает на FireBoardполучить последние сообщения прямо на Ваш рабочий стол