Задача стоит такая: организовать управление восемнадцатью лампами накаливания с плавной регулировкой мощности.
После прохода напряжения через ноль счетчик отсчитывает определенное количество тактов (в зависимости от нужной мощности) и на 100 микросекунд (считает второй таймер) включается соответствующий порт.
Использую Atmega32, AVR Studio 5. Написал код, анализирую в AVS Studio, все работает правильно, загоняю в Протеус ничего не работает. Предполагаю, что что-то не так с прерываниями делаю, но что?
Прошу помощи! Спасибо!
CODE
#include <avr/io.h>
#include <avr/interrupt.h>
volatile unsigned long u; // переменная - результат АЦП
volatile unsigned long f; // первый нуль - 1, не первый - 0
/* Таблица задержек */
volatile unsigned char tz[25]={20,30,70,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
// Массив мощностей
volatile unsigned char pch[3][17]={
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}, // Номер канала
{0,1,2,4,4,4,4,4,4,4, 4, 4, 4, 4, 4, 4, 4}, // Текущая мощность
{0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0, 0}}; // Флаг установки канала
volatile unsigned char i=0; //
volatile unsigned char t=0;
volatile unsigned char q, fl=0;
/***Обработчик прерываний по окончанию преобразования АЦП***/
ISR (ADC_vect)
{
u = (ADC*11/4);
}
/*** Обработчик прерываний по совпадению таймера ***/
ISR(TIMER0_COMP_vect)
{
//--------------------------------------------------------------------------------------------
for (i=0; i<18; i++) // Перебираем каналы и включаем нужный
{
if (pch[1][i]==t)
{
if (pch[2][i]==0) // Если еще не установлен в текущем периоде
{
pch[2][i]=1;
switch (pch[0][i]) // Определяем линию и порт для установки - 1
{
case 0: PORTD |=1<<0; break;
case 1: PORTD |=1<<1; break;
case 2: PORTD |=1<<2; break;
}
}
}
}
t++;
if (t==25) {t=0;}
OCR0=tz[t]; // Новое значение совпадения
//-------------------------------------------------------------------------------------------
TCNT0=0; //Обнуляем таймер
TCNT2=0; //Обнуляем таймер
}
/***Обработчик прерывания по совпадению таймера (длительность откывающего импульса)***/
ISR(TIMER2_COMP_vect)
{
//Выключаем канал
PORTD=0;
/* switch (t)
{
case 0: PORTD &=~(1<<0); break;
case 1: PORTD &=~(1<<0); break;
case 2: PORTD &=~(1<<2); break;
}
*/ TCNT2=0; //Обнуляем таймер
}
/***Главная функция***/
int main (void)
{
DDRD = 0xFF; // Порт на выход
PORTD = 0x00;
DDRA = 0x00;
/* Настройка АЦП */
ADCSRA = (1 << ADEN) // разрешение работы АЦП
|(1 << ADSC) // запуск преобразования
|(1 << ADATE) // непрерывный режим работы АЦП
|(1 << ADPS2)|(1 << ADPS1)|(0 << ADPS0) // предделитель на 64
|(1 << ADIE); // разрешение прерывания
ADMUX = (1 << REFS1)|(1 << REFS0) // внутренний ИОН 2,56V
|(0 << MUX3)|(0 << MUX2)|(0 << MUX1)|(0 << MUX0); // вход (ADC0) PA1
/* Настройка таймера задержки (мощность канала)*/
TCCR0|=(1<<CS00); //
TCCR0|=(0<<CS01); // Установка предделителя (1024)--------------------------------------!!!
TCCR0|=(1<<CS02); //
OCR0=tz[pch[1][t]]; // Установка значения в регистре совпадения.
TCCR0|=(0<<FOC0)|(1<<COM00)|(1<<WGM01);
TIMSK|=(1<<OCIE0); // Разрешить прерывание по совпадению.
/* Настройка таймера (время открывающего импульса 100мкс)*/
TCCR2|=(1<<CS21); //
TCCR2|=(1<<CS20); // Установка предделителя (32)--------------------------------!!!
TCCR2|=(0<<CS20); //
OCR2=50; // Установка значения в регистре совпадения.
TCCR2|=(0<<FOC2)|(1<<COM20)|(1<<WGM21);
TIMSK|=(1<<OCIE2); // Разрешить прерывание по совпадению.
sei(); //глобальное разрешение прерываний
TCNT0=0;
TCNT2=0;
while(1)
{
if (u<20)
{
f++;
}
else
{
f=0;
}
if (f==1) // Обнаружен проход через нуль
{
t=0;
for (q=0; q<18; q++) //обнуляем флаги установки каналов
{
pch[2][q]=0;
}
TCNT0=0;
TCNT2=0;
PORTD |= 1<<3;
}
else
{
PORTD &= ~(1<<3);
}
}
}
#include <avr/interrupt.h>
volatile unsigned long u; // переменная - результат АЦП
volatile unsigned long f; // первый нуль - 1, не первый - 0
/* Таблица задержек */
volatile unsigned char tz[25]={20,30,70,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
// Массив мощностей
volatile unsigned char pch[3][17]={
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}, // Номер канала
{0,1,2,4,4,4,4,4,4,4, 4, 4, 4, 4, 4, 4, 4}, // Текущая мощность
{0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0, 0}}; // Флаг установки канала
volatile unsigned char i=0; //
volatile unsigned char t=0;
volatile unsigned char q, fl=0;
/***Обработчик прерываний по окончанию преобразования АЦП***/
ISR (ADC_vect)
{
u = (ADC*11/4);
}
/*** Обработчик прерываний по совпадению таймера ***/
ISR(TIMER0_COMP_vect)
{
//--------------------------------------------------------------------------------------------
for (i=0; i<18; i++) // Перебираем каналы и включаем нужный
{
if (pch[1][i]==t)
{
if (pch[2][i]==0) // Если еще не установлен в текущем периоде
{
pch[2][i]=1;
switch (pch[0][i]) // Определяем линию и порт для установки - 1
{
case 0: PORTD |=1<<0; break;
case 1: PORTD |=1<<1; break;
case 2: PORTD |=1<<2; break;
}
}
}
}
t++;
if (t==25) {t=0;}
OCR0=tz[t]; // Новое значение совпадения
//-------------------------------------------------------------------------------------------
TCNT0=0; //Обнуляем таймер
TCNT2=0; //Обнуляем таймер
}
/***Обработчик прерывания по совпадению таймера (длительность откывающего импульса)***/
ISR(TIMER2_COMP_vect)
{
//Выключаем канал
PORTD=0;
/* switch (t)
{
case 0: PORTD &=~(1<<0); break;
case 1: PORTD &=~(1<<0); break;
case 2: PORTD &=~(1<<2); break;
}
*/ TCNT2=0; //Обнуляем таймер
}
/***Главная функция***/
int main (void)
{
DDRD = 0xFF; // Порт на выход
PORTD = 0x00;
DDRA = 0x00;
/* Настройка АЦП */
ADCSRA = (1 << ADEN) // разрешение работы АЦП
|(1 << ADSC) // запуск преобразования
|(1 << ADATE) // непрерывный режим работы АЦП
|(1 << ADPS2)|(1 << ADPS1)|(0 << ADPS0) // предделитель на 64
|(1 << ADIE); // разрешение прерывания
ADMUX = (1 << REFS1)|(1 << REFS0) // внутренний ИОН 2,56V
|(0 << MUX3)|(0 << MUX2)|(0 << MUX1)|(0 << MUX0); // вход (ADC0) PA1
/* Настройка таймера задержки (мощность канала)*/
TCCR0|=(1<<CS00); //
TCCR0|=(0<<CS01); // Установка предделителя (1024)--------------------------------------!!!
TCCR0|=(1<<CS02); //
OCR0=tz[pch[1][t]]; // Установка значения в регистре совпадения.
TCCR0|=(0<<FOC0)|(1<<COM00)|(1<<WGM01);
TIMSK|=(1<<OCIE0); // Разрешить прерывание по совпадению.
/* Настройка таймера (время открывающего импульса 100мкс)*/
TCCR2|=(1<<CS21); //
TCCR2|=(1<<CS20); // Установка предделителя (32)--------------------------------!!!
TCCR2|=(0<<CS20); //
OCR2=50; // Установка значения в регистре совпадения.
TCCR2|=(0<<FOC2)|(1<<COM20)|(1<<WGM21);
TIMSK|=(1<<OCIE2); // Разрешить прерывание по совпадению.
sei(); //глобальное разрешение прерываний
TCNT0=0;
TCNT2=0;
while(1)
{
if (u<20)
{
f++;
}
else
{
f=0;
}
if (f==1) // Обнаружен проход через нуль
{
t=0;
for (q=0; q<18; q++) //обнуляем флаги установки каналов
{
pch[2][q]=0;
}
TCNT0=0;
TCNT2=0;
PORTD |= 1<<3;
}
else
{
PORTD &= ~(1<<3);
}
}
}