Ну раз всего проекта нет, то давай по кускам .... расскажу, что я надумал .. а Вы уж проверяйте - Вы проект пишете, а я только на код смотрю.
Повторюсь ... я не вникаю в алгоритм ... так-что смотрите внимательно.
Код
if (ACSR==0x4C)
m++;
if (ACSR==0x4F)
{
if (a==0)
{
TCCR0 = 0x02; //start timer, делитель на 8, 1 тик = 1 мкС
a=1;//признак включенного таймера
}
else
{
TCCR0 = 0x00; //stop timer
a=0;//признак выключенного таймера
b=1;//признак завершения измерения периода
};
};
Судя по коду ACSR принимает только два значения ... значит можно проверять только один бит байта, который принимает разные значения. if (ACSR & 0x01){}else{} вместо двух if. Выигрыш в проверки одного бита вместо двух сравнений чисел.
Изм. периода. Идея ... насколько понял ...
нач. условие: таймер выключен, счетчик сброшен, b==0.
первое прерывание - запускаем таймер
второе прерывание - останавливаем таймер и поднимаем флаг b
Вопрос: "для чего вы в А дублируете состояние таймера? Проверяйте if(TCCR0 & 0x02 )"
Второй вопрос: "зачем вам знать, включен он или нет" ... может вместо "если включен, то выключить, иначе включить" .. просто написать "изменить состояние" => TCCR0 ^ 0x02; ... если правильно поставить нач. условия, то всё отработает красиво.
Код
interrupt [ANA_COMP] void ana_comp_isr(void)
{
//а если ACSR=0x4C то считаем к-во прерываний
//Если ACSR=0x4F то считаем период,
if (ACSR & 0x01) // (ACSR==0x4F)
{
TCCR0 = TCCR0 ^ 0x02; // переключили таймер
if (!(TCCR0 & 0x02)) //если таймер выключен - значит подсчет закончен
b=1;//признак завершения измерения периода
}
else // (ACSR==0x4C)
m++;
}
ЗАПОМНИЛИ .... в осн. цикле нужно инициализировать B, TCCR0, ACSR, TCNT0
Код
// *** БЛОК ПРОВЕРКИ ПОСТОЯННОЕ-ПЕРЕМЕННОЕ ***
// Interrupt on Output Toggle (прерываемся при любом изменении состояния компаратора)
ACSR=0x4C;
// Global enable interrupts
#asm("sei")
delay_ms(45); //время проведения измерения
#asm("cli") //выключаем прерывания чтоб не отвлекать АЛУ
if (m>=3) //если зарегистрировано 3 и больше перепадов за 45 мс, то считаем что
//меряем переменку
{
ACDC=1; //устанавливаем признак переменки
m=0; //обнуляем счетчик
}
else
{
ACDC=0; //устанавливаем признак постоянки
m=0; //обнуляем счетчик
};
Тут всё просто.
Код
// *** БЛОК ПРОВЕРКИ ПОСТОЯННОЕ-ПЕРЕМЕННОЕ ***
ACSR=0x4C; //(прерываемся при любом изменении состояния компаратора)
m = 0; //это дело обнулим одо его подсчета .. кстати .. зачем ДВА раза это писать.
#asm("sei")
delay_ms(45); //время проведения измерения
#asm("cli") //выключаем прерывания чтоб не отвлекать АЛУ
ACDC = 0; // такой вариант вместо if-else дает выигрыш в слово :)
if (m>4)
ACDC = 1;
дальше ...
___
P.S.
Цитата
Повторюсь - вместо того, чтобы сжимать до немыслимых пределов Сишную прогу, лучше заложить МК с бОльшими ресурсами - себе дешевле выйдеть
А как же ТВОРЧЕСТВО ?! :-)
Код
// *** БЛОК ИЗМЕРЕНИЯ ПЕРИОДА ***
ACSR=0x4F;
b = 0;
TCNT0 = 0;
#asm("sei")
while (!b); //точно не помню, но CVAVR при ( ==0) умудряется ставить сравнение с константой
#asm("cli")
F=1/TCNT0*1000000; //вычисляем значение частоты ВОТ ЗДЕСЬ БОЛЬШАЯ ПОТЕРЯ!!! но это уже нужно алгоритм крутить. а не код оптимизировать
ACSR.7=0;
По блоку измерения напруги ... опишите словами .. зачем два измерения ... Вы так интересно закрутили флагами и переменными, не хочу въежать ... и потом ... зачем Вам здесь вообще прерывание?
Всё равно Вы сидите delay_ms(50) -- ждете, пока отработают прерывания
Можно в главном цикле просто мониторить флаг окончания преобразования ... какой выигрыш: нет процедуры прерывания, нет delay_ms(50)
И еще ... в CVAVR по умолчанию сохраняет все регистры при переходе на прерывание ... уже не помню, посмотрите в справке. помойму он сохраняет регистры, которые и так не использует никогда - это тоже слов 20 даст размера.
ну и с индикацией тоже не ясно, что используется и т.д. .. посему посоветовать ничего не могу.
Пробуйте - поведаете насколько получилось сжать и сколько еще нужно :-)
____
P.S.
Вариант с измерением напряжения без прерывания ADC
Код
ADMUX=ADC_VREF_TYPE;
ADCSR=0xCE;//включить АЦП, начать преобразование
while (пока не закончилось преобразование - флаг не помню)
adc_data =ADCW;
ADCSR.6=1; //запустить преобразование
while (пока не закончилось преобразование - флаг не помню)
U=ADCW;
while (пока не закончилось преобразование - флаг не помню)
if (adc_data > U)
U = adc_data;
if (ACDC==1)
U = U/1.414; //!!!!!!!!!!!!!!!!!!!!! U -> целое!!! И что мы получим?
// прерывание ADС, c, adc_data_max убрать за ненадобностью.
______
P.P.S
U => точно надо с знаком INT ... может UNSIGNED CHAR подойдет?
Проверьте типы переменных ... если не нужен знак - перейдите на беззнаковые переменные