|
|
  |
Внешние переменные при обработке прерываний, Помогите найти косяк |
|
|
|
Mar 31 2011, 11:10
|
Группа: Новичок
Сообщений: 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
|
|
|
|
|
Mar 31 2011, 12:24
|
Группа: Новичок
Сообщений: 5
Регистрация: 31-03-11
Пользователь №: 64 024

|
Цитата(rezident @ Mar 31 2011, 15:17)  Квалификатор extern замените на volatile. Заменил. Все равно не получается. Может это Proteus меня дурит?
|
|
|
|
|
Mar 31 2011, 13:51
|

Частый гость
 
Группа: Участник
Сообщений: 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
|
|
|
|
|
Mar 31 2011, 18:22
|
Группа: Новичок
Сообщений: 5
Регистрация: 31-03-11
Пользователь №: 64 024

|
vopros1.rar ( 68.22 килобайт )
Кол-во скачиваний: 101Вот, выкладываю весь пример проекта. Но, как мне кажется, программно устанавливать бит в 1 не имеет смысла, т. к антидребезг отрабатывается нормально. Самое интересное начинается далее - переменной key_pressed даже присваиваеся единица. Однако потом она опять обнуляется без моего ведома. Где, когда и почему это происходит я пытаюсь понять.
|
|
|
|
|
Mar 31 2011, 20:58
|
Группа: Новичок
Сообщений: 5
Регистрация: 31-03-11
Пользователь №: 64 024

|
Цитата(_Pasha @ Mar 31 2011, 22:19)  Все выполняется. протез7.7сп2 б.9089 На нехватку ресурсов не матюкаиццо  , т.е. все в самом что ни на есть реальном времени У меня идентичный Протеус. То есть Вы хотите сказать, что строчка "PORTD=i_Regim; " у Вас выполняется? Если да, то значит дело не в алгоритме, а в Протеусе и мне надо разбираться в настройках последнего.
|
|
|
|
|
Apr 1 2011, 04:12
|

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

|
Цитата(Zloy_Paulik @ Mar 31 2011, 23:58)  У меня идентичный Протеус. То есть Вы хотите сказать, что строчка "PORTD=i_Regim; " у Вас выполняется? Если да, то значит дело не в алгоритме, а в Протеусе и мне надо разбираться в настройках последнего.  Прошу прощения, но подмыло... У меня создается впечатление, что Вы, уважаемые, не свой код отлаживаете, а тестируете Протеус  Вот Вы не знаете, в чем проблема - в Вашей программе или это глюки Протеуса. Вопрос: и зачем такой инструмент нужен? Лично я всегда отлаживаю в "железе" и никогда не пользовался симуляторами, типа Протеуса. Сперва я пользовался только самодельным программатором, стареньким осциллографом, и COM-портом. Если у чипа нет UART, но есть хоть одна свободная нога, использовал программный UART (а что делать?). Потом, когда поделки превратились в изделия, купил себе JTAGICE, хотя пользуюсь им в последнее время крайне редко, в основном с маленькими камешками - сильно выручает debugwire. Не буду говорить про мозг, как основную тулзовину при отладке
|
|
|
|
|
Apr 1 2011, 07:22
|
Группа: Новичок
Сообщений: 5
Регистрация: 31-03-11
Пользователь №: 64 024

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

Частый гость
 
Группа: Участник
Сообщений: 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-битный порт, обычно не делается, или делается не так. Вот так рождаются трудноуловимые баги  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
Кроме того, как мы видим, оптимизатор посчитал, что в цикле ничего не происходит и выбросил его вовсе (какой маладэц  ) И после объявления volatile uint8_t key_pressed. Обратите внимание на строку, помеченную !!!!!!!!! И цикл наш появился  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), но это не наш метод  Вот так выглядят грабли, на которые Вы наступили. 4. Ключевое слово extern используютя для объявления переменных, которые уже ранее объявлены в другом файле проекта, при этом инициализация переменной не происходит, и Вашем случае переменные i_Regim и key_pressed имеют неопределенные значения (key_pressed получает потом значение в функции main(), а i_Regim - нет). Компилятор на это делает предупреждение (Warning), но это не является фатальной ошибкой. Хотя это - ошибка: у Вас переменная i_Regim изначально имеет неопределенное значение и результат будет непредсказуем. Вроде все... Если есть еще вопросы, или что-то я непонятно изложил, пишите, обсудим
Сообщение отредактировал nk@ - Apr 2 2011, 11:59
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|