Сетевой ФИ димер - временнОе реле.

AlexPython
Offline
Зарегистрирован: 14.02.2020

Доброго времени суток.)

Мужики, подскажите, что не так. Третий вечер мозг ломаю и уже не знаю что не знаю.

нужно сделать симисторный диммер, который каждые 12 часов будет вкл/выкл нагрузку в сети 220В на треть мощности.

по железу

есть датчик ноля на 814(работает. при пересечении ноля - выдает импульс. сампаялопал)

"драйвер" симистора на МОС-ьке(работает, как и симистор. сампаялопал)

PRO Mini 5V 16MHz x2(разные кварцы, большой и маленький, ВовГат и еще-что)

ЛАТР

под рукой осциллограф 1канал 0-16МГц

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

по программе.

на сколько понял, логика простая. но есть несколько(много) способов реализации. решил пробовать делать так:

ловим импульс на INT0 от датчика ноля  и в прерывании запускаем таймер, прерывания которого будут повыше в приоритете в таблице векторов - т.е. второй(третий) таймер.

в прерывании таймера2 считаем задержку до подачи импульса на управляющий электрод симистора и длительность импульса. после чего останавливаем таймер. чем больше задержка до подачи импульса, тем, соответственно, меньше мощность в нагрузке. длительность импульса от 10мкс до 150мкс в зависимости от симистора.

ну и сам опытный образец проги (простите за не причесанность))


volatile unsigned int timer2count;
volatile unsigned int dimmingLVL = 1; //1 == 0.00001c 1000==10ms задержка до импульса на УЄ
volatile unsigned int pulseToTriac = 2; //1 == 0.00001c длительность импульса на УЭ симистора

void setup() {

  //enable global interrupt
  sei();

  pinMode(2, INPUT); //ZD input
  pinMode(13, OUTPUT); //Triac
  attachInterrupt(0, zerroDetect, RISING); //zeroDetect ловим импульс от датчика ноля и перемещаемся по прерыванию в zerroDetect()


  //********TIMER2 Configuration**********
  //activate CTC mode
  bitSet(TCCR2A, WGM01);                   //TCCR2A |= (1 << WGM01);

  //set value to compare register
  OCR2A = 0b10100000;                   //160

}

/////////////////////////////////////////////////////////////
void loop() {

}

//////////////////////////////////////////////////////////////////
void zerroDetect() {
  //reset register value
  TCNT2 = 0b00000000; //чистим считалку на всякий случай
  //enable compare match interrupt on TIMER2
  bitSet(TIMSK2, OCIE2A); //разрешаем прерывания по совпадению таймера2
  //prescaller configuration. start timer.
  TCCR2B |= (1 << CS20);//no presc //запускаем таймер2 без прескаллера и ждем прерывание уже от него
}
/////////////////////////////////////////////////////////////////
//TIMER2 CTC interrupt handller
ISR (TIMER2_COMPA_vect)
{
  timer2count++; //считаем количество срабатываний if (timer2count == dimmingLVL) { //подаем импульс на симистор 
//start pulse 
digitalWrite (13, HIGH); 
} 
if (timer2count == dimmingLVL + pulseToTriac) { //считать наверное лучше отдельно в переменную и подставлять сюда ее длясравнения 

//end of pulse 
digitalWrite (13, LOW); 

//disable TC2 
bitClear(TCCR2B, CS20); //set no clock sorce mode 

//disable compare match interrupt on TIMER2 
bitClear(TIMSK2, OCIE2A); timer2count = 0; } 

}
частота срабатываний(тиков таймера) 16МГц / 160(OCR2A)  = 100 000Гц 1/100 000 = 0,000010 т.е.10микросекунд
на один полупериод синусоиды будет приходится 0,010 / 0,000010 = 1000 тиков 
это и должно быть разрешением регулировки Pload/1000tik мне хватит

только вот программа странно работает. если верить осцилографу то цифра один в переменной pulseToTriac в реальности равна 2 миллисекунды, а цифра 2 - 4 миллисекунды

т.е. осцил на ноге 13 показывает меандр с периодом 10мс и длину управляющего импульса 4мс если в pulseToTriac записать 2. а должно быть 20 микросекунд потому что таймер должен тикать с частотой 16МГц / 160(OCR2A) = 100 000 Гц даже  без предварительного деления частоты. 

по ходу что-то не так с кварцем, или ардуино как-то перенастроило АВР-ку. в общем, я уже не знаю что еще попробовать. 

аппаратное прерывание работает. моргал светодиодом каждые 100 полупериодов. а таймер чет не осилю. 

подскажите, что я упустил, что я не знаю?) 

P.S. разработчик редактора этого форума явно не знает что такое когнитивное искажение - "проклятие знания" и подобные.

остальные надеюсь, поймут.

 

 

AlexPython
Offline
Зарегистрирован: 14.02.2020

блть в строке 42 две строки. происки редактора форума. почему первый пост нельзя отредактировать?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Таймер ДО Вас настраивает среда Ардуино. Например, в регистр TCCR2B она пихает бит CS22. Вы же потом по ИЛИ добавляете туда ещё CS20 и получаете делитель не 1, как ожидаете, а 128. Вот и Ваша ошибка как раз в сто раз - всё точно, как доктор прописал.

Кстати, в TCCR2A она пихает WGM20, который Вам, как я понимаю, тоже там нахрен не нужен.

Настраивайте таймер полностью, прописывая все биты - не надейтесь, что там нули. Тогда всё получится.

Кстати, в строке №17 замените на WGM21. На скорость не влияет, но неаккуратненько :-)

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

AlexPython пишет:

блть в строке 42...

Ознакомьтесь вот с этой темой :-)

AlexPython
Offline
Зарегистрирован: 14.02.2020

ЕвгенийП пишет:

Ознакомился

простите если было не приятно, я не хотел.) 

 

по поводу строки 17... эх, стыдоба. прост я начинал с нулевого таймера. фантомные боли..))

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Да, нет, Вы чего - это тут шутки такие (как и та тема сама по себе) :-)))

Получилось с таймером?

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

https://playground.arduino.cc/Main/ACPhaseControl/

#include <avr/io.h>
#include <avr/interrupt.h>

#define DETECT 2  //zero cross detect
#define GATE 9    //TRIAC gate
#define PULSE 4   //trigger pulse width (counts)
int i=483;

void setup(){

  // set up pins
  pinMode(DETECT, INPUT);     //zero cross detect
  digitalWrite(DETECT, HIGH); //enable pull-up resistor
  pinMode(GATE, OUTPUT);      //TRIAC gate control

  // set up Timer1 
  //(see ATMEGA 328 data sheet pg 134 for more details)
  OCR1A = 100;      //initialize the comparator
  TIMSK1 = 0x03;    //enable comparator A and overflow interrupts
  TCCR1A = 0x00;    //timer control registers set for
  TCCR1B = 0x00;    //normal operation, timer disabled


  // set up zero crossing interrupt
  attachInterrupt(0,zeroCrossingInterrupt, RISING);    
    //IRQ0 is pin 2. Call zeroCrossingInterrupt 
    //on rising signal

}  

//Interrupt Service Routines

void zeroCrossingInterrupt(){ //zero cross detect   
  TCCR1B=0x04; //start timer with divide by 256 input
  TCNT1 = 0;   //reset timer - count from zero
}

ISR(TIMER1_COMPA_vect){ //comparator match
  digitalWrite(GATE,HIGH);  //set TRIAC gate to high
  TCNT1 = 65536-PULSE;      //trigger pulse width
}

ISR(TIMER1_OVF_vect){ //timer1 overflow
  digitalWrite(GATE,LOW); //turn off TRIAC gate
  TCCR1B = 0x00;          //disable timer stopd unintended triggers
}

void loop(){ // sample code to exercise the circuit

i--;
OCR1A = i;     //set the compare register brightness desired.
if (i<65){i=483;}                      
delay(15);                             

}

 

bwn
Offline
Зарегистрирован: 25.08.2014

AlexPython пишет:

почему первый пост нельзя отредактировать?

Премудрые студиозы, получив решение курсового, редактировали его в ноль. И оставались висящие между небом и землей темы.((((

AlexPython
Offline
Зарегистрирован: 14.02.2020

на самом деле что-то пошло не так... я психанул, нашел несколько кандёров для конденсаторного БП на время, пока буду разбираться с симистором. 

сейчас же достаточно просто вкл/выкл симистор, а кандеры гасят лишнее. так-что можно перейти к часам и расписанию по которому этот симистор вкл/выкл.

это некая костяшка программки которая удовлетворяет минимальные требования. время считаю от внешнего кварца. старался делитель выставить максимально большим что бы больше времени основной программе оставить.  фазо-импульсную регулировку и модуль RTC оставлю для версии 1.1)) хах)) 

в общем, буду счастлив, если кто ни будь глянет.. может я накосячил фатально-фундаментально и часы будут кривыми как && мои руки?)

16МГц/1024(предделитель)=15625/125(OCR2A=124)=125Гц = 1с; или я что-то напутал?

главное что бы часы шли ровно. если основная программа где-то чуть еле подвиснет то это не страшно.

volatile byte timer2CTCInterruptCount;
volatile byte secondCount;
volatile byte minuteCount;
volatile byte hourCount;
volatile byte dayCount;

byte nowSecond = 0;
byte nowMinute = 0;
byte nowHour = 0;
byte nowDay = 0;

byte valueForPWM = 0;

void setup() {
  pinMode(13, OUTPUT);
  //SET CLOCK// установка текущего времени. значения для начала отсчета
  timer2CTCInterruptCount = 0;//предварительный сброс счетчика одной секунды 
  secondCount = 13;
  minuteCount = 16;
  hourCount = 23;
  dayCount = 0;
   
  //TIMER2 CTC INTERRUPT CONFIG
  //activate CTC mode for TC2
  TCCR2A = 0b00000010; //COM2A1 COM2A0 COM2B1 COM2B0 – – WGM21 WGM20               
    //set value to compare register
  OCR2A = 0b01111100;//124(125)
    //reset register value //prepare register to count
  TCNT2 = 0b00000000;
    //enable compare match interrupt for TIMER2//CTC Mode
  TIMSK2 = 0b00000010;//– – – – – OCIE2B OCIE2A TOIE2 //
    //q_freg prescaller configuration. start timer.
  TCCR2B = 0b00000111;//ON//1024 // FOC2A FOC2B – – WGM22 CS22 CS21 CS20
    //reset timer control register//OFF// CS22&&CS21&&CS20 == 0 -  TC2
  //TCCR2B = 0b00000000; //OFF//FOC2A FOC2B – – WGM22 CS22 CS21 CS20

  sei();
}

ISR (TIMER2_COMPA_vect)
{
  //timer tik increment
  timer2CTCInterruptCount++;
  
  if(timer2CTCInterruptCount == 125){//
    secondCount++;
    timer2CTCInterruptCount = 0;
  }
  if(secondCount == 60){
    minuteCount++;
    secondCount = 0;
  }
  if(minuteCount == 60){
    hourCount++;
    minuteCount = 0;
  }
  if(hourCount == 24){
    dayCount++;
    hourCount = 0;
  }

}

void loop() {
  //bufering MC Clock Values
  valueForPWM = timer2CTCInterruptCount;//0...125
 
  nowSecond = secondCount;
  nowMinute = minuteCount;  
  nowHour = hourCount;
  nowDay = dayCount;

//Day Plan
  if(nowHour == 0){
    digitalWrite(13, LOW);
  }
  if(nowHour == 1){
    digitalWrite(13, LOW);
  }
  if(nowHour == 2){
    digitalWrite(13, LOW);
  }
  if(nowHour == 3){
    digitalWrite(13, LOW);
  }
  if(nowHour == 4){
    digitalWrite(13, LOW);
  }
  if(nowHour == 5){
    digitalWrite(13, LOW);
  }
  if(nowHour == 6){
    digitalWrite(13, HIGH);
  }
  if(nowHour == 7){
    digitalWrite(13, HIGH);
  }
  if(nowHour == 8){
    digitalWrite(13, HIGH);
  }
  if(nowHour == 9){
    digitalWrite(13, HIGH);
  }
  if(nowHour == 10){
    digitalWrite(13, HIGH);
  }
  if(nowHour == 11){
    digitalWrite(13, HIGH);
  }
  if(nowHour == 12){
    digitalWrite(13, HIGH);
  }
  if(nowHour == 13){
    digitalWrite(13, HIGH);
  }
  if(nowHour == 14){
    digitalWrite(13, HIGH);
  }
  if(nowHour == 15){
    digitalWrite(13, HIGH);
  }
  if(nowHour == 16){
    digitalWrite(13, HIGH);
  }
  if(nowHour == 17){
    digitalWrite(13, HIGH);
  }
  if(nowHour == 18){
    digitalWrite(13, LOW);
  }
  if(nowHour == 19){
    digitalWrite(13, LOW);
  }
  if(nowHour == 20){
    digitalWrite(13, LOW);
  }
  if(nowHour == 21){
    digitalWrite(13, LOW);
  }
  if(nowHour == 22){
    digitalWrite(13, LOW);
  }
  if(nowHour == 23){
    digitalWrite(13, LOW);
  }
}

я вот не рискну браться. может не знаю где лежит.. как вообще выглядит корректная инициализация, настройка таймера на СТС прям по пунктам по порядку? или тут нет однозначности? каждый как-то делает по своему что-ли. срачи разводят..

  

SLKH
Offline
Зарегистрирован: 17.08.2015

AlexPython пишет:

нужно сделать симисторный диммер, который каждые 12 часов будет вкл/выкл нагрузку в сети 220В на треть мощности.

что за нагрузка?

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

А зачем с таймером мутить если уже есть millis(). Используйте его для учета секунд/минут/часов.

AlexPython
Offline
Зарегистрирован: 14.02.2020

SLKH, что за вопрос?)

asam, ну я тут несколькими постами выше словил граблями в виде высокого уровня абстракции. чуть ниже - чуть интересней.) ну и более гибко, явно, если писать понятно.  может мне лучше на форум где сидят в атмел студио?) или как||куда?)

тут порог вхождения ниже, но мне кажется что все стремительно скатывается к AVR

часы то хоть ровные получились?))
а тут есть некий toggle pin? как адекватней вывести частоту срабатывания прерываний от таймеров на ножку что бы осциллом частоту посмотреть?

 

 

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

AlexPython пишет:
а тут есть некий toggle pin? как адекватней вывести частоту срабатывания прерываний от таймеров на ножку что бы осциллом частоту посмотреть?

PORTB &= ~(1 << 5); // низкий уровень на выводе PB5 (D13)

PORTB |= (1 << 5); // высокий уровень на выводе PB5 (D13)

 

asam
asam аватар
Offline
Зарегистрирован: 12.12.2018

AlexPython пишет:

asam, ну я тут несколькими постами выше словил граблями в виде высокого уровня абстракции. чуть ниже - чуть интересней.)

 

Ну это не от уровня абстракции проблема, а от незнания матчасти. 

 

Цитата:
 может мне лучше на форум где сидят в атмел студио?) или как||куда?)

Флаг вам в руки.

AlexPython
Offline
Зарегистрирован: 14.02.2020

на сколько я понимаю, события, вызванные прерыванием, при равных условиях, должны "возникать" с частотой прерываний. мне кажется через If-ы будет криво. или я не прав? стесняюсь спросить, вы мне намекаете каждое срабатывание подвигать что-то типа unsigned long = 010101010101.....010101 на ноге?

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

ну это не плохо. это хорошо если уметь этим пользоваться.

 

 

 

AlexPython
Offline
Зарегистрирован: 14.02.2020

а что если

byte val = 0b0000 0000;

ISR (TIMER2_COMPA_vect){

val = ~val;//поразрядная инверсия 

PORTB = val;

}

грубовато, но по идее должно быть ровненько.))

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

AlexPython пишет:

а тут есть некий toggle pin? 

В даташите написано:

14.2.2 Toggling the Pin
Writing a logic one to PINxn toggles the value of PORTxn, independent on the value of DDRxn. Note that the
SBI instruction can be used to toggle one single bit in a port.
Yurik
Offline
Зарегистрирован: 02.03.2020

Добрый вечер AlexPython

На 4й странице в схожей теме

"Устройство ФИУ на симисторе (диммер) для Ардуино"

есть схема и скетч по вашему вопросу.