Собственно суть проблемы. К ногам тиньки 5 и 6 (РВ0 и РВ1) подключены две кнопки. Инициализированы прерывания PCINT0 и, в качестве источника прерываний, определены две ноги: Спойлер
Код:
#define BUTTON_LUX_MEMORY PB1 //вход определения нажатой кнопоки 1 #define BUTTON_SYGNAL PB0 //вход определения нажатой кнопоки 0
if bit_is_clear (PINB,BUTTON_LUX_MEMORY) { MEM_value_LUX = read_adc(LUX_IN_PIN); eeprom_write_word(&LUX_MEM,MEM_value_LUX); //измеряем уровень освещенностиeeprom, записываем в }
if bit_is_clear (PINB,BUTTON_SYGNAL) { NUM_SYGNAL+=1; while (NUM_SYGNAL == 7) {NUM_SYGNAL=0x01;} eeprom_write_byte(&SYGNAL_MEM,NUM_SYGNAL); switch (NUM_SYGNAL) { case 1: SYGNAL=0xAA; break; case 2: SYGNAL=0xCC; break; case 3: SYGNAL=0xF0; break; case 4: SYGNAL=0x63; break; case 5: SYGNAL=0xD4; break; default: SYGNAL=0xE6; break; } }
в симулятора 7 студии все отрабатывает без вопросо. Но в железе у меня получается бесконечный цикл вызова прерыания, при этом виновником является вход РВ1 (BUTTON_LUX_MEMORY). Если програмно я не определяю этот вход как источник прерывания (PCMSK |= (1<<BUTTON_SYGNAL);), то кнопка на РВ0 (BUTTON_SYGNAL) работает без нареканий. Заходим в прерывание, выполняем нужное действие, возвращаемся в основной цикл. Осциллограмма на РВ1 в норме, напряжение питания стоит, никаких дерганий уровня не видно. Может у кого есть идеи, в какую сторону копать?
Это - лишнее. Прерывания глобально и так запрещаются при входе в ISR, а флаг прерывания сбрасывается по выходу. Вы нигде PB1 не дергаете случаем из программы? Ну вот, например, чему равно LED_OUT_PIN? Ну и чтение АЦП и запись в EEPROM из ISR - очень плохая идея. В прерывании просто поднимайте флаг (переменная), что надо это сделать. А сам замер + запись делайте в основном коде. Там уже предварительно перед записью в EEPROM отключив временно глобально прерывания через cli(), а потом включив через sei().
что прерывания глобально запрещаются, а флаги сбрасываются -- знаю. Но вряд-ли эти строки загоняют контроллер в цикл с прерываниями. Но для красоты кода -- уберу. Т.е. вы считаете, что в цикл падаю из-за чтения adc и записи в eeprom ? Ок, как рабочую версию приму, проверю. Спасибо
Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ очень важен контроль процесса заряда и разряда для избегания воздействия внешнего зарядного напряжения после достижения 100% заряда. Инженеры КОМПЭЛ подготовили список таких решений от разных производителей.
Компания EVE выпустила новый аккумулятор серии PLM, сочетающий в себе высокую безопасность, длительный срок службы, широкий температурный диапазон и высокую токоотдачу даже при отрицательной температуре.
Эти аккумуляторы поддерживают заряд при температуре от -40/-20°С (сниженным значением тока), безопасны (не воспламеняются и не взрываются) при механическом повреждении (протыкание и сдавливание), устойчивы к вибрации. Они могут применяться как для автотранспорта (трекеры, маячки, сигнализация), так и для промышленных устройств мониторинга, IoT-устройств.
В тиньке13 PCINT на что реагирует? На смену уровня или на уровень? Если на уровень, то так и не будете вылезать из прерывания, пока не сменится уровень на ноге.
В тиньке13 PCINT на что реагирует? На смену уровня или на уровень? Если на уровень, то так и не будете вылезать из прерывания, пока не сменится уровень на ноге.
PCINT реагирует на любое изменение уровня на ноге.
В тиньке13 PCINT на что реагирует? На смену уровня или на уровень?
Только на смену.
Land писал(а):
аргументируйте, плз.
В любом учебнике, во многих мануалах это написано - обработчик прерывания должен быть как можно более коротким. По разным причинам. Хотя бы потому что в это время у вас не будут выполняться другие прерывания, зато потом "выстрелят" отложенно и можете на этом поиметь грабли.
Land писал(а):
Т.е. вы считаете, что в цикл падаю из-за чтения adc и записи в eeprom ? Ок, как рабочую версию приму, проверю. Спасибо
Это не может быть прямой причиной, но вот много всяких граблей бывает из-за долгой обработки прерывания. Лучше сразу привыкайте никогда так не делать, даже когда кажется, что в данном случае неважно. Опять же в read_adc() и при работе с LUX_IN_PIN нигде не можете затрагивать скажем весь регистр PORTB? Случайно где-нибудь вместо R-M-W сделали присваивание может... Ну или приведите весь код в конце концов.
А я вот вижу сброс вачдога, сброс флага INT0....либо это сделано со знанием дела, но сия тайна великая есть, либо это откуда-то "нахапано" кусками. Пока я склоняюсь к версии
Цитата:
затрагивать скажем весь регистр PORTB?
Цитата:
В любом учебнике, во многих мануалах это написано - обработчик прерывания должен быть как можно более коротким.
Это кто-то придумал, а другие тупо скопипастили. Старые тиньки никак не предназначены для обработки прерывания вне его - флаги сбрасываются в прерывании, поэтому надо свои вводить, если обработчик пустой. Либо же лупом проверять флаги постоянно...Вообщем, костыльные микры...
Опять же в read_adc() и при работе с LUX_IN_PIN нигде не можете затрагивать скажем весь регистр PORTB? Случайно где-нибудь вместо R-M-W сделали присваивание может... Ну или приведите весь код в конце концов.
я же не случайно написал, что программное отключение генерации прерывания по РВ1 убирает проблему. Если бы где-то затрагивался весь регистр PORTB, то...
А я вот вижу сброс вачдога, сброс флага INT0....либо это сделано со знанием дела, но сия тайна великая есть, либо это откуда-то "нахапано" кусками. Пока я склоняюсь к версии
Цитата:
затрагивать скажем весь регистр PORTB?
думаете wdr зацикливает в прерывании? Или сброс флага INT0 вызывает сбой? Само-собой, как у каждого, у меня есть свои куски кода и я пользуюсь копи-пастом... пока объем памяти позволяет. Если не позволяет -- перехожу на asm.
По умолчанию INT0 сидит на прерывании по уровню. Если разрешить на INT0 прерывание, то, как я и говорил, из прерывания вылезать не будем при нуле на этом пине. Если обработчика вообще нет, то компилятор GCC выполнение кода по вектору уводит на ресет...
Собственно суть проблемы. К ногам тиньки 5 и 6 (РВ0 и РВ1) подключены две кнопки. Инициализированы прерывания PCINT0 и, в качестве источника прерываний, определены две ноги:
Попробуй… прошивка для тини13… кнопки на РВ0 и РВ1… светики на РВ3 и РВ4… Фьюзы прошивать не нужно, тактируется на заводских установках (1,2 МГц).
Вложение:
Test_INT.hex
Нажал кнопку – светик загорелся. Нажал повторно – потух.
я же не случайно написал, что программное отключение генерации прерывания по РВ1 убирает проблему. Если бы где-то затрагивался весь регистр PORTB, то...
То что "то"? То нет. Вы можете остальные пины и не менять, программа по другим пинам будет как надо работать.
parovoZZ писал(а):
Это кто-то придумал, а другие тупо скопипастили. Старые тиньки никак не предназначены для обработки прерывания вне его - флаги сбрасываются в прерывании, поэтому надо свои вводить, если обработчик пустой. Либо же лупом проверять флаги постоянно...Вообщем, костыльные микры...
Не совсем. Это стандартная практика. Никаких проблем нет вести свои флаги, их можно вполне расширить и не просто тупо копировать о срабатывании прерывания. Дело не в этом.
1 - кнопки это человекоинтерфейс. Реакция человека десятки, сотни миллисекунд. Реакция микроконтроллера, если кнопка повешана на прерывание - несколько тактов. Хочется спросить, куда вы так торопитесь, все равно не успеете. На прерывание есть смысл вешать кнопки только в случае энергосбережения, спящего режима. Ещё в случае экономии ввода вывода. И то варианты. 2 - дребезг контактов. 3 - режим внешнего прерывания, по уровню или фронту. Как здесь уже правильно подметили, могут быть неучтенные отложенные прерывания. Вывод, разберитесь что такое дребезг контактов. Какие режимы внешнего прерывания, как правильно инициализировать внешние прерывания. И нужно ли вешать кнопки на внешние прерывания, если нет энергосбережения.
я же не случайно написал, что программное отключение генерации прерывания по РВ1 убирает проблему. Если бы где-то затрагивался весь регистр PORTB, то...
То что "то"? То нет. Вы можете остальные пины и не менять, программа по другим пинам будет как надо работать.
то, что если бы что-то писалось в PORB тупо в лоб, то это бы вызывало в том числе и прерывание по PB0. А здесь проблема в РВ1. POTB упоминается в коде 7 раз:
Что самое забавное, зацикливание происходит даже при простой инициализации входа PB1 в качестве источника прерывания. В обработчике ISR можно вообще все закомментить, относящееся к обработке этого пина. Если кому не лень в чужом коде колупаться, листинг под катом. Ткните меня носом. Только, умоляю, не в wdr Спойлер
// Analog Comparator: Off //ADCSRA |= (1<<ADPS0) | (1<<ADPS1); ADCSRB &= ~(1<<ADTS2) & ~(1<<ADTS1) & ~(1<<ADTS0); ADMUX |= (1<<AIN0D) | (1<<AIN1D); // Digital input buffer on AIN0: Off Digital input buffer on AIN1: Off
MEM_value_LUX = eeprom_read_word(&LUX_MEM); //читаем из памяти сохраненное значение уровня освещенности } /*====================*/
uint16_t read_adc(int adc_input) { TCCR0B = 0; //останов таймера ADMUX= adc_input | ADC_VREF_TYPE; _delay_us(10); // Delay needed for the stabilization of the ADC input voltage ADCSRA|=(1<<ADEN)|(1<<ADSC); //Запускаем преобразование while ((ADCSRA & (1<<ADIF))==0); //Wait for the AD conversion to complete ADCSRA|=(1<<ADIF); // сброс флага прерывания ADCSRA &= ~(1<<ADEN); //останавливаем преобразование return ADCW; }
if (value_VCC < 0x239) {SYGNAL=0xA8;} else //если напряжение ниже 1.6В (3.2В/2), то выставляем сигнал аларма, иначе {NUM_SYGNAL = eeprom_read_byte(&SYGNAL_MEM); //читаем значение номера сигнала из EEPROM switch (NUM_SYGNAL) { case 1: SYGNAL=0xAA; break; case 2: SYGNAL=0xCC; break; case 3: SYGNAL=0xF0; break; case 4: SYGNAL=0x63; break; case 5: SYGNAL=0xD4; break; default: SYGNAL=0xE6; break; } } return SYGNAL; }
if bit_is_clear (PINB,BUTTON_LUX_MEMORY) { PORTB &= ~(1<<LED_OUT_PIN); //MEM_value_LUX = read_adc(LUX_IN_PIN); //измеряем уровень освещенности //eeprom_write_word(&LUX_MEM,MEM_value_LUX); // записываем в память eeprom }
if bit_is_clear (PINB,BUTTON_SYGNAL) { NUM_SYGNAL+=1; while (NUM_SYGNAL == 7) {NUM_SYGNAL=0x01;} eeprom_write_byte(&SYGNAL_MEM,NUM_SYGNAL); switch (NUM_SYGNAL) { case 1: SYGNAL=0xAA; break; case 2: SYGNAL=0xCC; break; case 3: SYGNAL=0xF0; break; case 4: SYGNAL=0x63; break; case 5: SYGNAL=0xD4; break; default: SYGNAL=0xE6; break; } }
Разрешать прерывания логическим ИЛИ не совсем хорошо. ]
вы говорите, что в регистр GINSK нельзя писать через "или"? Откровенно в первый раз об этом слышу. Ну и потом, для пина PB0 такая конструкция работает. Попробовать 6 ногу лучше пропаять?..
вы говорите, что в регистр GINSK нельзя писать через "или"?
Ну а зачем так делать? Сразу целиком писать весь регистр без его предварительного чтения. Ведь какие прерывания необходимы, а каие нет - известно. Тоже самое и регистрами флагов. Там всего 2 флага. Ну так и пиши туда сразу 0xFF. Зачем его читать???
Старые тиньки никак не предназначены для обработки прерывания вне его - флаги сбрасываются в прерывании, поэтому надо свои вводить, если обработчик пустой. Либо же лупом проверять флаги постоянно...Вообщем, костыльные микры...
Старые, это какие? в 13, 2313 и прочих, с которыми я работал можно и без прерываний флаги читать, программно сбоасывать... т.е. тело прерывания и разрешение прерывания совсем необязательны чтобы работать с флагами событий.
_________________ Просто не учи физику в школе, и вся твоя жизнь будет наполнена чудесами и волшебством Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Это 8-ми битки, кроме: xmega, серия DA, 0-ая и 1-ая серия. В трёх последних флаги в прерываниях не сбрасываются, либо сбрасываются после выполнения определённых условий. Появились два уровня приорита прерываний, карусель прерываний... Это некая коллаборация mega и xmega.
Старые тиньки никак не предназначены для обработки прерывания вне его - флаги сбрасываются в прерывании, поэтому надо свои вводить, если обработчик пустой. Либо же лупом проверять флаги постоянно...Вообщем, костыльные микры...
в 13, 2313 и прочих, с которыми я работал можно и без прерываний флаги читать, программно сбоасывать... т.е. тело прерывания и разрешение прерывания совсем необязательны чтобы работать с флагами событий.
Флаги можно читать в любых МК. Они абсолютно независмы и отражают наступление какого-либо события. Речь о другом: выйти из сна в AVR можно только с помощью разрешённого прерывания, а его обработчик сбросит флаги автоматом.
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 24
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения