//#include <avr/wdt.h>
#include <avr/delay.h>
void frenzy_start(long frenzy_need)
{
//8MHz
int registr=4000000/frenzy_need;
cli();
OCR1A=registr;
TCCR1B=0b00001001; //Делитель 1
sei();
}
ISR(TIMER1_COMPA_vect)
{
digitalWrite(31, digitalRead(31) ^ 1);
}
ISR(INT4_vect)
{
digitalWrite(32, digitalRead(32) ^ 1);
}
//Чтение Serial порта
ISR(TIMER0_COMP_vect)
{
digitalWrite(33, digitalRead(33) ^ 1);
//SerialRead();
}
void setup() {
pinMode(31, OUTPUT);
pinMode(32, OUTPUT);
pinMode(33, OUTPUT);
pinMode(13, OUTPUT);
pinMode(12, OUTPUT);
pinMode(3,OUTPUT);
pinMode(4,INPUT);
//Serial1.begin(38400);
//Serial.begin(38400);
cli();
TIMSK =0;
ETIMSK =0;
EICRB = (1<<ISC41); // Setting it equal is good here *IF* you want to ensure all other bits are clear, in this test code we do
EIFR |= (1<<INTF4); // Write a 1 to clear any possible pending interrupt
EIMSK = (1<<INT4);
//
TCCR3A =0;
TCCR3B=0;
ETIMSK |= (1 << OCIE3A);
TCNT3 =0;
TCCR3A = 0b01000000;
OCR3A = 1562;
TCCR3B =0b00001100;
//
TCCR0 =0;
TCCR0=0;
TCNT0 =0;
TIMSK |= (1 << OCIE0);
OCR0 = 78;
TCCR0=0b00011100;
//
TCCR1A =0;
TCCR1B=0;
TCNT1 =0;
TIMSK |= (1 << OCIE1A);
TCCR1A = 0b01000000;
OCR1A = 78;
//TCCR1B=0b00001011;
TCCR1B=0b00001000;
sei();
frenzy_start(10000);
}
void loop() {}
Всем привет, сразу привожу код, строчки мигания светодиодами вставлены просто для того чтобы осциллографом постоянно не ширять по портам. Ситуация такая, таймеры запускаются и работают, строкой 71 я запускаю на лапку выход 10кГц, все работает, но если я пытаюсь подать больше, например 30кГц, то перестает работать таймер 0, точно не могу сказать с какой частоты перестает работать, но поведение странное не могу понять в чем причина, спасибо за любую помощь.
@3d_killer
Прерывания - медленная вещь. Если вам нужны сколь-заметно высокие частоты - не генерите их в прерываниях.
А вы, к тому же, запихнули в прерывание ардуиновские digitalRead() и Write(). Если уж управляете таймерами через регистры. могли бы и пины напрямую переключать, хоть немного быстрее было бы
4000000/30000=133 такта. Управляя регистрами успеть можно. Но, как указали выше, ардуиновские функции всё портят. Не помню, но там как раз сотни тактов выполняются ДиджиталВрайт и Рид.
Вы видимо не поняли, DigitalWrite я написал просто для визуальной проверки, если посмотреть как стартуются таймеры у них сразу лапы подключены на выход и осциллографом на них есть частота, INT 4 это внешнее прерывание раз в секунду на него можно не обращать внимание, с осциллографом такая же тема (строки DigitalWrite при этом закомментированы), то есть когда я повышаю частоту на первом таймере до определенного значения все хорошо, а далее например 30, 40,50 кГц он выдает эти частоты, но при этом отваливается таймер 0 и перестает работать c Serial портом, на лапе 12 (Atmega128a) импульсы просто пропадают, это происходит с какой-то частоты и все что выше
это вы не поняли. Не важно, зачем вы это написали, но если время исполнения для вас критично - не надо писать ардуиновские функции в прерываниях.
Прочтите еще раз мой самый первый комментарий и подумайте над ним. Прерывания не исполняются где-то отдельно “над остальным кодом”, как иногда думают новички. Они исполняются на том же ядре, которое у атмеги128 ОДНО. И если вы напихали в каждый таймер кучу прерываний и запустили их на высокой частоте - начиная с какой-то частоты они начнут сталкиватся друг с другом и в итоге займут все время контроллера, не давая ему делать ничего другого.
Вообще идея управлять пинами, используя прерывания на таймерах - плохая. А вы, похоже, используете прерывания в хвост и в гриву, так ведь?
Послушайте Командира - у каждого таймера есть выделенные пины, которыми он может управлять, не задействуя ядро. Используйте их.
Так я же вам говорю, когда управление портами закомментированы (как вобщем-то в коде и должно быть) и осциллографом я проверяю лапы (OC0) - 12, (OC1A) - 13, (OC3A) - 3, при этом этот код из программы удален:
Происходит точно такая же ситуация, поднимаю до определенной частоты и отваливается таймер (OC0) - 12, импульсы на лапе пропадают и если в векторе прерывания вставить чтение Serial порта оно тоже не работает (хоть с ним хоть без него импульсы пропадают)
Тут я не вполне уверен, ассемблерщики поправят, но скорее всего оптимизатор не может выкинуть обработчик прерывания, даже если он пустой. А значит время на прерывание кода, вход в обработчик и выход из него все равно тратится. То есть все проблемы, описанные в сообщении 8 - в полный рост.
Не используйте прерывания для генерации сигналов. Это неверный подход.
Теперь другая проблемка, возникла, (для теста визуально чтобы увидеть почему команды с Serial не приходят), код поправил вот так:
#include <avr/wdt.h>
#include <avr/delay.h>
#include <DS3231.h> //Часы
Time times;
DS3231 rtc(SDA, SCL);
void frenzy_start(long frenzy_need)
{
int registr=4000000/frenzy_need;
cli();
OCR1A=registr;
TCCR1B=0b00001001; //Делитель 1
sei();
}
ISR(INT4_vect)
{
wdt_reset();
}
//Чтение Serial порта
ISR(TIMER0_COMP_vect)
{
Serial1.println("123");
}
void setup() {
wdt_enable(WDTO_2S);
rtc.begin();
rtc.setOutput(OUTPUT_SQW);
rtc.setSQWRate(SQW_RATE_1);
pinMode(31, OUTPUT);
pinMode(32, OUTPUT);
pinMode(33, OUTPUT);
pinMode(13, OUTPUT);
pinMode(12, OUTPUT);
pinMode(3,OUTPUT);
pinMode(4,INPUT);
Serial1.begin(38400);
cli();
//******************************************************************
//Запуск внешнего прерывания по часам
//******************************************************************
TIMSK =0;
ETIMSK =0;
EICRB = (1<<ISC41); // Setting it equal is good here *IF* you want to ensure all other bits are clear, in this test code we do
EIFR |= (1<<INTF4); // Write a 1 to clear any possible pending interrupt
EIMSK = (1<<INT4);
//
TCCR3A =0;
TCCR3B=0;
ETIMSK |= (1 << OCIE3A);
TCNT3 =0;
TCCR3A = 0b01000000;
OCR3A = 1562;
TCCR3B =0b00001100;
//
TCCR0 =0;
TCCR0=0;
TCNT0 =0;
TIMSK |= (1 << OCIE0);
OCR0 = 78;
TCCR0=0b00011100;
//
TCCR1A =0;
TCCR1B=0;
TCNT1 =0;
TIMSK |= (1 << OCIE1A);
TCCR1A = 0b01000000;
OCR1A = 78;
//TCCR1B=0b00001011;
TCCR1B=0b00001000;
sei();
frenzy_start(60000);
}
void loop() {}
Когда строка frenzy_start(60000); раскомментирована то в монитор валятся сообщения вида 123�� без перехода на следующую строку, если эту строку закомментировать то приходит 123 каждый раз с новой строки (как должно быть)