Здравствуйте форумчане, может кто подсказать как организовать использования двух типов прерываний на одном МК.
Используются внешние прерывания для определения перехода фазы через ноль.
За его обработку у меня отвечает INT0 Спойлер
Код:
//настройка внешнего прерывния INT0 void int0_init( void ) { //настраиваем на срабатывание INT0 по переднему фронту MCUCR |= (1<<ISC01)|(0<<ISC00); //разрешаем внешнее прерывание INT0 En_INT0 }
ISR(INT0_vect) { int i=100; int tempMS=(value+1); for (;;) { i--; _delay_us(10); if (i<=tempMS) { break; } } int k; for(k=0; k<5; k++) { PORTB |= (1<<1); _delay_us(2); PORTB &= ~(1<<1); _delay_us(2); } }
Внутрение прерывания которые отвечают за индикацию используют Таймер Т0.
Спойлер
Код:
void init_io() { //порт, к которому подкл. сегменты PORTA = 0xff; DDRA = 0xff; //порт, к которому подкл. катод DDRB |=(1<<0)|(1<<1)|(1<<2); PORTB =0x00; //инициализация таймера Т0 TIMSK = (1<<TOIE0); TCCR0B = (1<<CS02)|(0<<CS01)|(1<<CS00); // правка на 461 TCNT0L = T0_TICKS; //правка на 461 //иницилизация прерываний
}
//прерывания таймера Т0 - вывод на индикатор ISR(TIMER0_OVF_vect) //правка на 461 { static unsigned char count = 0; TCNT0L += T0_TICKS; //правка на 461 //гасим оба разряда PORTB |=(1<<PB0); PORTB |=(1<<PB2); PORTA = 0b11111110; //зажигаем следующий разряд if (count == 0) { segchar(data2); PORTB &= ~(1<<2); } if (count == 1) { segchar(data1); PORTB &= ~(1<<0); } count++; if (count == 2) count = 0; }
Но при испытаниях в протеусе , при внешних прерываниях в 100гц. Складывается такое ощущения что обработка кнопок сильно зависает от прерываний по INT0.
Можно ли сделать на МК ATTINY461 организовать подобие много поточности. Чтобы 2 типа прерываний оказывали друг на друга минимальное влияние ?..
void segchar (unsigned char seg) { switch (seg) { case 1: PORTA = 0b01111100; break; case 2: PORTA = 0b10000100; break; case 3: PORTA = 0b01000100; break; case 4: PORTA = 0b01101000; break; case 5: PORTA = 0b01000010; break; case 6: PORTA = 0b00000010; break; case 7: PORTA = 0b01110100; break; case 8: PORTA = 0b00000000; break; case 9: PORTA = 0b01000000; break; case 0: PORTA = 0b00010000; break; } }
void init_io() { //порт, к которому подкл. сегменты PORTA = 0xff; DDRA = 0xff; //порт, к которому подкл. катод DDRB |=(1<<0)|(1<<1)|(1<<2); PORTB =0x00; //инициализация таймера Т0 TIMSK = (1<<TOIE0); TCCR0B = (1<<CS02)|(0<<CS01)|(1<<CS00); // правка на 461 TCNT0L = T0_TICKS; //правка на 461 //иницилизация прерываний
}
//прерывания таймера Т0 - вывод на индикатор ISR(TIMER0_OVF_vect) //правка на 461 { static unsigned char count = 0; TCNT0L += T0_TICKS; //правка на 461 //гасим оба разряда PORTB |=(1<<PB0); PORTB |=(1<<PB2); PORTA = 0b11111110; //зажигаем следующий разряд if (count == 0) { segchar(data2); PORTB &= ~(1<<2); } if (count == 1) { segchar(data1); PORTB &= ~(1<<0); } count++; if (count == 2) count = 0; }
void handle_button(int key) { int bit; switch (key) { case KEY_POWER: bit = POWER_BIT; break; case KEY_UP: bit = UP_BIT; break; case KEY_DOWN: bit = DOWN_BIT; break; default: return; }
if (bit_is_clear(BUTTON_PIN, bit)) { if (_pressed == 0) { _delay_ms(DEBOUNCE_TIME); if (bit_is_clear(BUTTON_PIN, bit)) { _pressed |= key;
// key action switch (key) { case KEY_POWER: process_power(); break; case KEY_UP: process_up(); break; case KEY_DOWN: process_down(); break; } } } } else { _pressed &= ~key; } }
Чтобы прерывания оказывали друг на друга минимальное влияние их обработка должна занимать как можно меньше времени. А у вас в обработчике delay, который за зря тратит время.
Это просто моя наработка для регулирования яркостью лампы через симистор путем путем детектирования нуля при переходе фазы через нейтраль. а дальше отсчет времени на включение симистра по процентам. Конечно дальше хотел заменить делай на таймеры и записывать значение в переменные т1 и т2 - это 2 перехода Через ноль. А включение высчитывать по формуле (т2-n1)/100 - это и есть 1% мощности.
Походу надо в целом пересмотреть подход. Хотя еще думаю о вложенных прерываниях но это кажется как то не очень разумно.
Во-первых, у вас в прерываниях сплошь и рядом обращения к функциям, причем даже к библиотечным. Это не кошерная практика. Как минимум, сделайте все функции, к которым идут обращения из прерываний, static, но лучше обойдитесь без них вообще. Во-вторых, логика у вас сильно хромает. Делать обработку кнопок поочередно?! Впервые такое встречаю. Ну и по остальному коду то же самое - зачем в синхронизации с 0 у вас какие-то циклы, задержки? Логика фазового управления (для диммера) должна быть такой или очень похожей на такую: в момент перехода через 0 (в обработчике прерывания то есть) запускаем таймер на отсчет нужной фазы. Когда таймер отсчитает фазу, по его прерыванию включаем импульс управления тиристором и перезапускаем таймер на интервал длительности импульса, по истечению интервала импульс отключаем, таймер останавливаем. Не забывайте о том, что схема может сильно влиять на поведение программы: как у вас цепь синхронизации с сетью сделана?
Советы общего плана, как и вопрос ваш не очень конкретный...
_________________ если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе при взгляде на многих сверху ничего не меняется...
Качественное и безопасное устройство, работающее от аккумулятора, должно учитывать его физические и химические свойства, профили заряда и разряда, их изменение во времени и под влиянием различных условий, таких как температура и ток нагрузки. Мы расскажем о литий-ионных аккумуляторных батареях EVE и нескольких решениях от различных китайских компаний, рекомендуемых для разработок приложений с использованием этих АКБ. Представленные в статье китайские аналоги помогут заменить продукцию западных брендов с оптимизацией цены без потери качества.
Компания EVE выпустила новый аккумулятор серии PLM, сочетающий в себе высокую безопасность, длительный срок службы, широкий температурный диапазон и высокую токоотдачу даже при отрицательной температуре.
Эти аккумуляторы поддерживают заряд при температуре от -40/-20°С (сниженным значением тока), безопасны (не воспламеняются и не взрываются) при механическом повреждении (протыкание и сдавливание), устойчивы к вибрации. Они могут применяться как для автотранспорта (трекеры, маячки, сигнализация), так и для промышленных устройств мониторинга, IoT-устройств.
по схеме тоже предлагаю подумать я бы на вашем месте отказался от того огорода с транзисторами, что вы сделали для синхронизации с сетью, а просто со вторичной обмотки трансформатора завел бы через резисторы на входы аналогового компаратора МК сигналы, и вместо INT0 использовал бы прерывание от компаратора.
ну или точно так же без всяких транзисторов завел бы сигнал на INT0... хотя первый вариант мне нравится больше
_________________ если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе при взгляде на многих сверху ничего не меняется...
Насчет предлагаемых вами изменениях конечно подумаю , если честно не рассматривал с данного ракурса. Но пока охота все-таки через прерывания по ИНТ0 все это сделать. Эхх первый проект и должен быть таким тяжелым, и лишь тогда что то останется в голове.
Пока решил по изучать датишь на 128мегу( единственный что мне попался на русском). А пока буду его читать заодно по анализирую ответы на форуме.
можно обойтись и без прерываний INT0 - ждем пока на ноге порта не будет лог. "0" (переход сетевого напряжения через 0), на таймере организуем задержку, в нужное время подаем импульс на УЭ симистора.
А есть у кого примеры фазо импульсного управления на аттини ? или примеры димеров ?
допустим, у меня есть. на тини13. я даже многократно схему приводил:
можете посмотреть, как синхронизация с сетью реализована - 2 резистора всего-навсего. хоть схема и не от устройства-диммера, сделать диммер - будет точно такая же схема.
_________________ если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе при взгляде на многих сверху ничего не меняется...
взглянуть можно, но вряд ли вы разберетесь... Спойлер
Код:
/* * main.c * * Created on: 05.09.2010 * Author: ARV */ #include <avr/io.h> #include <avr/interrupt.h> #include <avr/wdt.h> #include <avr/pgmspace.h> #include <avr/eeprom.h> #include <avr/sleep.h> #include <util/delay.h> #include <avr_helper.h> #include "rc5.h"
/// рабочий порт для выхода на симистор #define OUTPORT PORTB /// выходной пин порта для управления симистором #if defined(__AVR_ATtiny2313__) #define OUT _BV(PB7) #else #define OUT _BV(PB4) #endif /// длительность выходного импульса управления симистором #define PULSE_LEN 50 /// действие по совпадению канала А #define do_comp_A() if(on) OUTPORT &= ~OUT /// действие по совпадению канала В #define do_comp_B() OUTPORT |= OUT
/** Прерывание по переполнению таймера. * Таймер без делителя, прерывание возникает каждые 256 тактов. * Обработчик прерыания реализует виртуальный 16-битный таймер с регистрами сравнения и т.п. */ ISR(TIM0_COMPA_vect){ COUNTER++; // ведем программный таймер if(COUNTER == COMP_A){ do_comp_A(); } if(COUNTER == COMP_B){ do_comp_B(); } if(COMP_C){ if(!--COMP_C){ // проанализируем число принятых бит switch(count){ case RC5_CODELEN-1: // если принято на 1 бит меньше, чем нужно - дополняем нулем code <<= 1; case RC5_CODELEN: // если принято нормальное число бит - обновляем код rc_code = ignore_toggle(code); default: // что бы ни было принято - всегда обнуляется счетчик бит // который является признаком готовности к новому приему count = 0; } } } }
/** Прерывание по изменению состояния синхро-пина. * Возникает по фронту и спаду синхроимпульса. * Реализует синхронизацию с сетью. */ ISR(PCINT0_vect){ uint8_t tmp = COUNTER; // запоминаем счетчик
// настройка периферии wdt_enable(WDTO_1S); // сторожа разрешим для страховки ACSR = _BV(ACD); // компаратор отключается для экономии энергии DDRB = OUT | SND; // выходной пин PORTB = OUT; MCUCR = _BV(ISC01); // запрос прерывания по падающему фронту TCCR0A = _BV(WGM01); // режим СТС OCR0A = CTC; // порог сброса TCCR0B = TIMER_CLK_DIV(TMR_DIV); // делитель таймера
TIMSK0 = _BV(OCIE0A); // прерывания по сбросу таймера PCMSK = _BV(PCINT0); // 0-й пин используется для синхронизации с сетью GIMSK = _BV(INT0) | _BV(PCIE); // разрешаем внешний запрос и прерывание по смене уровня пина
только показанный код немного от другого проекта - от проекта диммера с RC5-дистанционным управлением, т.е. схема, что ранее показал, несколько отличается. К сожалению, саму схему я утерял, но принцип синхронизации точно такой же, как и на схеме, и как я текстом описывал.
_________________ если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе при взгляде на многих сверху ничего не меняется...
можно листинг на Си и немного теории подсмотреть в документе от Микрочип "PICDIM Lamp Dimmer for the PIC12C508" 1997 года, хоть и для пика, но Си он и в Африке Си. Там диаграмки и схема есть. Прерываний нет.
Опытным путем и научным методом тыка переделал немного программку, таким образом как думаете вот такой димер если правильно рассчитать время переполнения таймера. Имеет право на жизнь ?
void segchar (unsigned char seg) { switch (seg) { case 1: PORTA = 0b01111100; break; case 2: PORTA = 0b10000100; break; case 3: PORTA = 0b01000100; break; case 4: PORTA = 0b01101000; break; case 5: PORTA = 0b01000010; break; case 6: PORTA = 0b00000010; break; case 7: PORTA = 0b01110100; break; case 8: PORTA = 0b00000000; break; case 9: PORTA = 0b01000000; break; case 0: PORTA = 0b00010000; break; } }
void init_io() { //порт, к которому подкл. сегменты PORTA = 0xff; DDRA = 0xff; //порт, к которому подкл. катод DDRB |=(1<<0)|(1<<1)|(1<<2); PORTB =0x00; //инициализаци¤ таймера “0 TIMSK = (1<<TOIE0); TCCR0B=(0<<CS01)|(1<<CS00); // правка на 461 TCNT0H=0x00; TCNT0L=0xff; //правка на 461 //иницилизаци¤ прерываний
}
volatile unsigned char lvl=0; //прерывани¤ таймера “0 - вывод на индикатор ISR(TIMER0_OVF_vect) //правка на 461 { //cli(); TCNT0L=0xff; //правка на 461 if (sw==1) { lvl++; if (lvl==(value)) { for(int k=0; k<5; k++) { PORTB |= (1<<1); _delay_us(10); PORTB &= ~(1<<1); _delay_us(1); } }
} }
void handle_button(int key) { int bit; switch (key) { case KEY_POWER: bit = POWER_BIT; break; case KEY_UP: bit = UP_BIT; break; case KEY_DOWN: bit = DOWN_BIT; break; default: return; }
if (bit_is_clear(BUTTON_PIN, bit)) { if (_pressed == 0) { _delay_ms(DEBOUNCE_TIME); if (bit_is_clear(BUTTON_PIN, bit)) { _pressed |= key;
// key action switch (key) { case KEY_POWER: process_power(); break; case KEY_UP: process_up(); break; case KEY_DOWN: process_down(); break; } } } } else { _pressed &= ~key; } }
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 26
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения