реклама на сайте
подробности

 
 
> Фазовое управление симисторами
Sadmi
сообщение Aug 30 2011, 09:28
Сообщение #1





Группа: Новичок
Сообщений: 9
Регистрация: 30-08-11
Пользователь №: 66 930



Добрый день. Это мой первый опыт программирования на Си вообще и под МК в частности. Прошу сразу не пинать.
Задача стоит такая: организовать управление восемнадцатью лампами накаливания с плавной регулировкой мощности.
После прохода напряжения через ноль счетчик отсчитывает определенное количество тактов (в зависимости от нужной мощности) и на 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);
}
}
}


Сообщение отредактировал IgorKossak - Aug 30 2011, 17:55
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
ARV
сообщение Sep 1 2011, 05:45
Сообщение #2


Профессионал
*****

Группа: Свой
Сообщений: 1 143
Регистрация: 30-09-08
Из: Новочеркасск
Пользователь №: 40 581



для 6 каналов делал тупо на программном счете, т.е. настраивал таймер на прерывания 250 раз в полупериод сети, в обработчике инкрементировал счетчик и сравнивал его с массивом текущих значений фаз по каналам - где нужно, там устанавливал выходные сигналы для оптронов. повторяю: для 6 каналов производительности AVR хватало, но вот для 18 каналов - это вопрос...

ноль в сети определяю самым простым способом: если нет требований по гальванической развязке конструкции, то тупо через резистор 1-1,5М подаю сигнал с сетевого провода на любой вывод, способный генерировать прерывания по фронту и спаду (пример вот тут: http://arv.radioliga.com/content/view/218/44/). это может быть встроенный компаратор, INT0 или INT1 или любой PCINT. если нужна гальваническая развязка - использую встроенный компаратор, подавая на его оба входа через резисторы сигналы прямо со вторичной обмотки питающего трансформатора. желательно, чтобы напряжение на этой обмотке было побольше, а резисторы должны ограничить ток на уровне не более 1 мА. оба способа неоднократно проверены и хорошо себя зарекомендовали.

яркость лампы меняется так же нелинейно от подводимой мощности, поэтому иметь массив с "линеаризующими" коэффициентами мне кажется бесполезным. либо уж учитывать в нем характеристику лампы - хотя зачем это может быть нужно - не представляю.


--------------------
Я бы взял частями... но мне надо сразу.
Go to the top of the page
 
+Quote Post



Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 20th July 2025 - 00:44
Рейтинг@Mail.ru


Страница сгенерированна за 0.01379 секунд с 7
ELECTRONIX ©2004-2016