Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Внешние переменные при обработке прерываний
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > MCS51, AVR, PIC, STM8, 8bit
Zloy_Paulik
Я только начинаю программировать 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



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

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

Может это Proteus меня дурит?
Marian
Цитата(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++; //начало антидребезг
Zloy_Paulik
Нажмите для просмотра прикрепленного файла

Вот, выкладываю весь пример проекта. Но, как мне кажется, программно устанавливать бит в 1 не имеет смысла, т. к антидребезг отрабатывается нормально. Самое интересное начинается далее - переменной key_pressed даже присваиваеся единица. Однако потом она опять обнуляется без моего ведома. Где, когда и почему это происходит я пытаюсь понять.
_Pasha
Все выполняется. протез7.7сп2 б.9089
На нехватку ресурсов не матюкаиццо sm.gif, т.е. все в самом что ни на есть реальном времени
Zloy_Paulik
Цитата(_Pasha @ Mar 31 2011, 22:19) *
Все выполняется. протез7.7сп2 б.9089
На нехватку ресурсов не матюкаиццо sm.gif, т.е. все в самом что ни на есть реальном времени


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

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

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


Ну так это же подфорум для начинающих, и я в самом начале ветки написал, что я новичек и слезно просил не пинать ногами. А если Вы такой гуру - помогли бы лучше советом.
nk@
Цитата(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
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.