реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> Внешние переменные при обработке прерываний, Помогите найти косяк
Zloy_Paulik
сообщение Mar 31 2011, 11:10
Сообщение #1





Группа: Новичок
Сообщений: 5
Регистрация: 31-03-11
Пользователь №: 64 024



Я только начинаю программировать AVR , поэтому сильео не пинайте.
МК ATMega 16. К 5-му биту регистра А подключена кнопка. В ненажатом состоянии на ножку подается высокий уровень. Для отсеживания нажатий на кнопку я хочу использовать флаг, который устанавливается в обработчике прерываний от таймера и сбрасывается в основном цикле программы после выполнения нужных мне действий. Вся проблема в том, что будучи сброшенным один раз этот флаг уже в 1 не устанавливается. Точнее говоря устанавливается, но только в теле функции обработки прерывания, а в ф-ию main передается ноль. Где косяк? Уже всю голову сломал.

Собственно программа

#include <avr/io.h>
#include <string.h>
#include <stdio.h>
#include <util/delay.h>
#include <stdlib.h>
#include <avr/interrupt.h>



unsigned char temp;
extern int key_pressed=0;
extern int i_Regim=0;



extern void Timer_init (void) { // инициализация таймера опроса кнопок

TCCR1A = 0x00;
TCCR1B = (0 << CS12)|(1 << CS11)|(0 << CS10)|(1 << WGM12); //предделитель clk/8, режим таймера СТС
TCNT1=0x00;
OCR1A=780*3; // выбор коэффициента деления
TIMSK = (1 << OCIE1A); // разрешение прерывания по совпадению

temp = 0b00000000; // Присвоение начального значения

asm ("sei"); // Разрешение прерываний


}



ISR (TIMER1_COMPA_vect) { // обработка прерывания от таймера 1

// обработка нажатия кнопки "Режим"
if (!bit_is_set(PINA,5)) temp++; //начало антидребезг
else if (!(temp==0)) temp--;

if (temp > 10) {
temp=0; // конец антидребезга
key_pressed=1;
i_Regim++; // переходим к следующему режиму
}




}


int main( void ){



PORTA = 0x00; // сброс порта А
DDRA= 0x00; // все выводы порта - входы

PORTD = 0x00; // сброс порта D
DDRD= 0xFF; // все выводы порта D - выходы


i_Regim=0; // устанавливаем режим номер 0 - "работа"

Timer_init (); // инициализация таймера для работы с кнопками

key_pressed=1; // для первоначального отображения информации

while( 1 ){ // основной цикл

if (key_pressed) {

PORTD=i_Regim; // ЭТА СТРОЧКА НЕ ВЫПОЛНЯЕТСЯ !!!
key_pressed=0;
}
} // конец основного цикла


return 0;
} // конец main



Go to the top of the page
 
+Quote Post
rezident
сообщение Mar 31 2011, 11:17
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Квалификатор extern замените на volatile.
Go to the top of the page
 
+Quote Post
Zloy_Paulik
сообщение Mar 31 2011, 12:24
Сообщение #3





Группа: Новичок
Сообщений: 5
Регистрация: 31-03-11
Пользователь №: 64 024



Цитата(rezident @ Mar 31 2011, 15:17) *
Квалификатор extern замените на volatile.

Заменил. Все равно не получается.

Может это Proteus меня дурит?
Go to the top of the page
 
+Quote Post
Marian
сообщение Mar 31 2011, 13:51
Сообщение #4


Частый гость
**

Группа: Участник
Сообщений: 148
Регистрация: 23-02-07
Пользователь №: 25 618



Цитата(Zloy_Paulik @ Mar 31 2011, 14:24) *
Заменил. Все равно не получается.

Может это Proteus меня дурит?

Так и выложите проект для Протеуса.

Код
if (!bit_is_set(PINA,5)) temp++; //начало антидребезг


попробуйте
Код
PORTA = 0b00100000;
if (bit_is_set(PINA,5)==0) temp++; //начало антидребезг


Сообщение отредактировал Marian - Mar 31 2011, 14:03
Go to the top of the page
 
+Quote Post
Zloy_Paulik
сообщение Mar 31 2011, 18:22
Сообщение #5





Группа: Новичок
Сообщений: 5
Регистрация: 31-03-11
Пользователь №: 64 024



Прикрепленный файл  vopros1.rar ( 68.22 килобайт ) Кол-во скачиваний: 101


Вот, выкладываю весь пример проекта. Но, как мне кажется, программно устанавливать бит в 1 не имеет смысла, т. к антидребезг отрабатывается нормально. Самое интересное начинается далее - переменной key_pressed даже присваиваеся единица. Однако потом она опять обнуляется без моего ведома. Где, когда и почему это происходит я пытаюсь понять.
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Mar 31 2011, 19:19
Сообщение #6


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Все выполняется. протез7.7сп2 б.9089
На нехватку ресурсов не матюкаиццо sm.gif, т.е. все в самом что ни на есть реальном времени
Go to the top of the page
 
+Quote Post
Zloy_Paulik
сообщение Mar 31 2011, 20:58
Сообщение #7





Группа: Новичок
Сообщений: 5
Регистрация: 31-03-11
Пользователь №: 64 024



Цитата(_Pasha @ Mar 31 2011, 22:19) *
Все выполняется. протез7.7сп2 б.9089
На нехватку ресурсов не матюкаиццо sm.gif, т.е. все в самом что ни на есть реальном времени


У меня идентичный Протеус. То есть Вы хотите сказать, что строчка "PORTD=i_Regim; " у Вас выполняется? Если да, то значит дело не в алгоритме, а в Протеусе и мне надо разбираться в настройках последнего.
Go to the top of the page
 
+Quote Post
nk@
сообщение Apr 1 2011, 04:12
Сообщение #8


Частый гость
**

Группа: Участник
Сообщений: 78
Регистрация: 8-12-09
Пользователь №: 54 138



Цитата(Zloy_Paulik @ Mar 31 2011, 23:58) *
У меня идентичный Протеус. То есть Вы хотите сказать, что строчка "PORTD=i_Regim; " у Вас выполняется? Если да, то значит дело не в алгоритме, а в Протеусе и мне надо разбираться в настройках последнего.

bb-offtopic.gif Прошу прощения, но подмыло...
У меня создается впечатление, что Вы, уважаемые, не свой код отлаживаете, а тестируете Протеус smile3046.gif Вот Вы не знаете, в чем проблема - в Вашей программе или это глюки Протеуса. Вопрос: и зачем такой инструмент нужен?
Лично я всегда отлаживаю в "железе" и никогда не пользовался симуляторами, типа Протеуса. Сперва я пользовался только самодельным программатором, стареньким осциллографом, и COM-портом. Если у чипа нет UART, но есть хоть одна свободная нога, использовал программный UART (а что делать?). Потом, когда поделки превратились в изделия, купил себе JTAGICE, хотя пользуюсь им в последнее время крайне редко, в основном с маленькими камешками - сильно выручает debugwire. Не буду говорить про мозг, как основную тулзовину при отладке sm.gif
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Apr 1 2011, 05:35
Сообщение #9


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Цитата(nk@ @ Apr 1 2011, 07:12) *
bb-offtopic.gif Прошу прощения, но подмыло...
У меня создается впечатление, что Вы, уважаемые, не свой код отлаживаете, а тестируете Протеус smile3046.gif Вот Вы не знаете, в чем проблема - в Вашей программе или это глюки Протеуса. Вопрос: и зачем такой инструмент нужен?

Для отладки без глюков biggrin.gif
Там глюков намного меньше, чем кажется. Просто новое ничего на нем не надо осваивать. Ввиду полной неясности картины.
Go to the top of the page
 
+Quote Post
Zloy_Paulik
сообщение Apr 1 2011, 07:22
Сообщение #10





Группа: Новичок
Сообщений: 5
Регистрация: 31-03-11
Пользователь №: 64 024



Цитата(nk@ @ Apr 1 2011, 07:12) *
bb-offtopic.gif Прошу прощения, но подмыло...
У меня создается впечатление, что Вы, уважаемые, не свой код отлаживаете, а тестируете Протеус smile3046.gif Вот Вы не знаете, в чем проблема - в Вашей программе или это глюки Протеуса. Вопрос: и зачем такой инструмент нужен?
Лично я всегда отлаживаю в "железе" и никогда не пользовался симуляторами, типа Протеуса. Сперва я пользовался только самодельным программатором, стареньким осциллографом, и COM-портом. Если у чипа нет UART, но есть хоть одна свободная нога, использовал программный UART (а что делать?). Потом, когда поделки превратились в изделия, купил себе JTAGICE, хотя пользуюсь им в последнее время крайне редко, в основном с маленькими камешками - сильно выручает debugwire. Не буду говорить про мозг, как основную тулзовину при отладке sm.gif


Ну так это же подфорум для начинающих, и я в самом начале ветки написал, что я новичек и слезно просил не пинать ногами. А если Вы такой гуру - помогли бы лучше советом.
Go to the top of the page
 
+Quote Post
nk@
сообщение Apr 2 2011, 11:39
Сообщение #11


Частый гость
**

Группа: Участник
Сообщений: 78
Регистрация: 8-12-09
Пользователь №: 54 138



Цитата(Zloy_Paulik @ Apr 1 2011, 10:22) *
Ну так это же подфорум для начинающих, и я в самом начале ветки написал, что я новичек и слезно просил не пинать ногами. А если Вы такой гуру - помогли бы лучше советом.

1. Забыть Протеус. Отлаживать в железе. Вы можете не покупать фирменный JTAGICE или Dragon, а изготовить своими руками, например такой http://www.scienceprog.com/avrjtag-clone-in-action/
2. Не объявляйте переменные как int, без необходимости. Объявляйте их как unsigned char (я обычно пишу uint8_t, так и короче, и понятней). Дело в том, что int, по умолчанию, занимает 2 байта - а это совершенно неоправданный (в Вашем примере) расход ресурсов процессора. Кроме того в случае вывода в порт, чтоб результат был предсказуемым, необходимо сделать приведение типов:
PORTD = (uint8_t ) i_Regim;
Хотя выпихивание 16-битной, к тому же еще и знаковой, переменной в 8-битный порт, обычно не делается, или делается не так. Вот так рождаются трудноуловимые баги sm.gif
3. Правило: Все глобальные переменные, которые изменяются в обработчиках прерываний, объявлять как volatile:
volatile uint8_t key_pressed=0; это заставит компилятор генерировать загрузку переменных в регистры из памяти внутри циклов, в противном случае хитрый оптимизатор сделает это перед запуском цикла, что мы и имеем.
Вот как это выглядит на практике (в Вашем случае):
CODE

61: Timer_init ();
+00000079: 940E003E CALL 0x0000003E Call subroutine
63: key_pressed=1;
+0000007B: E081 LDI R24,0x01 Load immediate
+0000007C: 93800060 STS 0x0060,R24 Store direct to data space
71: PORTD=i_Regim;
+0000007E: 91800061 LDS R24,0x0061 Load direct from data space
+00000080: BB82 OUT 0x12,R24 Out to I/O location
+00000081: CFFF RJMP PC-0x0000 Relative jump

Кроме того, как мы видим, оптимизатор посчитал, что в цикле ничего не происходит и выбросил его вовсе (какой маладэц sm.gif )

И после объявления volatile uint8_t key_pressed. Обратите внимание на строку, помеченную !!!!!!!!! И цикл наш появился sm.gif
CODE

61: Timer_init ();
+00000079: 940E003E CALL 0x0000003E Call subroutine
63: key_pressed=1;
+0000007B: E081 LDI R24,0x01 Load immediate
+0000007C: 93800060 STS 0x0060,R24 Store direct to data space
71: PORTD=i_Regim;
+0000007E: 91900061 LDS R25,0x0061 Load direct from data space
69: if (key_pressed==1)
+00000080: 91800060 LDS R24,0x0060 Load direct from data space !!!!!!!!!!!!! Появилась инструкция загрузки регистра из SRAM
+00000082: 3081 CPI R24,0x01 Compare with immediate
+00000083: F7E1 BRNE PC-0x03 Branch if not equal
71: PORTD=i_Regim;
+00000084: BB92 OUT 0x12,R25 Out to I/O location
72: key_pressed=0;
+00000085: 92100060 STS 0x0060,R1 Store direct to data space
+00000087: CFF8 RJMP PC-0x0007 Relative jump !!!!!!!!!!! И цикл тоже теперь есть
72: key_pressed=0;

Как вариант, можно отключить оптимизацию (-O0), но это не наш метод sm.gif
Вот так выглядят грабли, на которые Вы наступили.
4. Ключевое слово extern используютя для объявления переменных, которые уже ранее объявлены в другом файле проекта, при этом инициализация переменной не происходит, и Вашем случае переменные i_Regim и key_pressed имеют неопределенные значения (key_pressed получает потом значение в функции main(), а i_Regim - нет). Компилятор на это делает предупреждение (Warning), но это не является фатальной ошибкой. Хотя это - ошибка: у Вас переменная i_Regim изначально имеет неопределенное значение и результат будет непредсказуем.

Вроде все... Если есть еще вопросы, или что-то я непонятно изложил, пишите, обсудим beer.gif

Сообщение отредактировал nk@ - Apr 2 2011, 11:59
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 18th July 2025 - 03:55
Рейтинг@Mail.ru


Страница сгенерированна за 0.02834 секунд с 7
ELECTRONIX ©2004-2016