|
Фазовое управление симисторами |
|
|
|
Aug 30 2011, 09:28
|
Группа: Новичок
Сообщений: 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
|
|
|
|
|
 |
Ответов
|
Aug 31 2011, 07:58
|
    
Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731

|
А бездумные volatile, unsigned long и *4/11 там, где достаточно 1 бита и сравнения - типа правильно? Прерывание от АЦП здесь вообще бессмысленно - с тем же успехом можно читать АЦП непосредственно там, где используется (якобы) u.
2Sadmi: у Вас в прерываниях изменяется только t, вот и оставьте его volatile. Зачем Вам нужен pch[0][] в виде {0,1,2,3,...}? Вместо "t++; if (t==25) {t=0;}" логичней будет, н-р, "if (t < 25) t++;", имхо.
|
|
|
|
|
Aug 31 2011, 10:48
|
Группа: Новичок
Сообщений: 9
Регистрация: 30-08-11
Пользователь №: 66 930

|
Цитата(xemul @ Aug 31 2011, 11:58)  у Вас в прерываниях изменяется только t, вот и оставьте его volatile. Ок, но ведь от volatile "хуже не будет"? Цитата(xemul @ Aug 31 2011, 11:58)  Зачем Вам нужен pch[0][] в виде {0,1,2,3,...}? Это в тестовом режиме - последовательно, а потом массив предполагается сортировать по возрастанию значения задержки и номера каналов в массиве будут вразброс. Цитата(xemul @ Aug 31 2011, 11:58)  Вместо "t++; if (t==25) {t=0;}" логичней будет, н-р, "if (t < 25) t++;", имхо. Т.е. t обнулять только при переходе через ноль?
|
|
|
|
|
Aug 31 2011, 15:55
|
    
Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731

|
Цитата(Sadmi @ Aug 31 2011, 14:48)  Ок, но ведь от volatile "хуже не будет"? Сравните время выполнения, н-р, ISR(TIMER0_COMP_vect). Заодно ответите на свой вопрос "Может слишком долго в обработчике прерываний ISR(TIMER0_COMP_vect) нахожусь?" Цитата Это в тестовом режиме - последовательно, а потом массив предполагается сортировать по возрастанию значения задержки и номера каналов в массиве будут вразброс. Ну если совсем заняться нечем... Цитата Т.е. t обнулять только при переходе через ноль? Я не понимаю Вашу задумку и назначение t и tz[]. Если в массиве tz[] живут задержки до следующего шага по мощности в пределах полупериода сети, то непонятно его содержимое. имхо, для бо-ме пропорциональных шагов по моще задержки должны убывать ~обратно-квадратично до половины полупериода, а после примерно также увеличиваться. Если это задержки только для половины полупериода, то t должно бегать 0, 1, ... 23, 24, 23, ... 1, 0. Для выделения 0 напряжения сети ей-ей не нужен АЦП и unsigned long f - в пределе простоты достаточно одного компаратора. От помех можно добавить к нему фильтр типа (н-р, на три отсчёта): Код uint8_t zc; zc <<= 1; if(ACO) zc |= 1; // с точностью до фазы компаратора if((zc & 0x07) == 0x03) ...;// перепад 0/1 //else if((zc & 0x07) == 0x04) // перепад 1/0
|
|
|
|
Сообщений в этой теме
Sadmi Фазовое управление симисторами Aug 30 2011, 09:28 kovigor Цитата(Sadmi @ Aug 30 2011, 12:28) Задача... Aug 30 2011, 18:31 Sadmi kovigor
Цитата(kovigor @ Aug 30 2011, 22... Aug 31 2011, 03:59 -SANYCH- CODEwhile(1){
if (u<20){
f++;
}
else{
... Aug 30 2011, 21:10 -SANYCH- ЦитатаДо, порт сбрасывается в ноль, но это происхо... Aug 31 2011, 06:35 Sadmi 2 xemul
Задумка такая: в tz[] - задержки включения... Sep 1 2011, 04:27 ARV для 6 каналов делал тупо на программном счете, т.е... Sep 1 2011, 05:45 Sadmi Цитата(ARV @ Sep 1 2011, 09:45) для 6 кан... Sep 1 2011, 07:02 ARV я делал диммер и мне нужно было обеспечить изменеи... Sep 1 2011, 08:34 domowoj Цитата(Sadmi @ Aug 30 2011, 16:28) Задача... Sep 25 2011, 15:49
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|