Работа с PWM для ПУш-ПУЛ.
- Войдите на сайт для отправки комментариев
Пнд, 16/05/2016 - 23:02
Здравствуйте уважаемые форумчане, прошу сильно не пинать я только начина в этом разбираться. Постараюсь покроче. На просторах интернета нашёл сделующий скетч, вопрос следующий, как сделать еще один (3-й) сигнал, с той же частотой что и первые два, такой же фазы как и первый но чтобы можно было независимо меняеть его скважность.
поснительная картинка к тексту, если не понятно.
https://yadi.sk/i/xkpfXXWhrm5o3
#define PIN_PRI_A 9 // OCR1A - high-active primary drive
#define PIN_PRI_B 10 // OCR1B - low-active primary drive
#define PUSH_PULL false // false = OCR1A only, true = OCR1A + OCR1B
#define TIMER1_PRESCALE 1 // clock prescaler value
#define TCCR1B_CS20 0x01 // CS2:0 bits = prescaler selection
#define PERIOD_US 5.1
#define PERIOD_TICKS (microsecondsToClockCycles(PERIOD_US / 2) / TIMER1_PRESCALE)
int count=0;
int duty=2;
float Verror=0;
float Vset=512.0;
float Vact;
unsigned long last=0;
unsigned long wait=20;
boolean first=true;
void setup()
{
// pinMode(A0, INPUT); //input tensione НЕ знаю что это но без него работает.
//digitalWrite(A0, LOW);
analogWrite(PIN_PRI_A,128); // let Arduino setup do its thing
analogWrite(PIN_PRI_B,128);
TCCR1B = 0x00; // stop Timer1 clock for register updates
// Clear OC1A on match, P-F Corr PWM Mode: lower WGM1x = 00
TCCR1A = 0x80 | 0x00; //128 |
// Configure Timer 1 for Freq-Phase Correct PWM
// Timer 1 + output on OC1A, chip pin 15, Arduino PWM9
// Timer 1 - output on OC1B, chip pin 16, Arduino PWM10
// If push-pull drive, set OC1B on match
TCCR1A |= 0x30; //48
ICR1 = PERIOD_TICKS; // PWM period
OCR1A = duty; // ON duration = drive pulse width//ucita 9
OCR1B = duty+156; // ditto - use separate load due to temp buffer reg //usita 10
TCNT1 = OCR1A - 1; // force immediate OCR1x compare on next tick
// upper WGM1x = 10, Clock Sel = prescaler, start Timer 1 running
TCCR1B = 0x10 | TCCR1B_CS20;
}
void loop() ///////// Тут дальше меняем скважность
{ OCR1A = duty+count;
OCR1B = duty+36-count;
if(first)
{
//delay(2000);
first=false;
}
Vact=analogRead(A0);
Verror=100.0*(Vset-(float)(Vact))/Vset;
if(millis()-last>=wait)
{
last=millis();
if(Verror<0) count--;
if(Verror>0) count++;
if(count<0) count=0; //min duty 2%
if(count>=15) count=15; //max duty 95%
}
}
сейчас частота 200 кГц. Можно ли включить 2-й таймер синхронно первому?
Это как пытаться синхронизировать часы, нужна логика сверки показаний. Не видел что-бы на практике кто-то делал, проще взять другой МК.
3dmax, в принципе можно.
Но без глубинного понимания работы таймеров вы не настроите таймеры на одну частоту. Тем более на 200кГц может полноценно работать только таймер1. И то, не совсем полноценно. Сколько градаций регулировки скважности будет на такой частоте? Не трудно подсчитать 16000000 /2 / 200000 = 40 шагов. Думаю реально запустить в синхроне -на 8 битах ( 62,5 кГц) в режиме FastPWM.
А можно ли на еще один выход продублировать показания с другого ?
ведь частота мне нужна та же, только фазу сдвинуть и скважность поменять.
3dmax, нет ничего дублировать невозможно. Есть простой способ сделать любое кол-во выводов всего на одном таймере - это программная генерация ШИМ. Но будут недостатки, -невысокая частота, дрожание фазы,сильная загрузка контроллера. Лучше всего взять ардуино с трех-канальными таймерами, как вам уже советовали в первом посте.
какой максимальной частоты я могу достигнуть используя 2 таймера ?
#define PIN_PRI_A 9 // OCR1A - high-active primary drive #define PIN_PRI_B 10 // OCR1B - low-active primary drive #define PIN_PRI_C 5 // OCR0B - low-active primary drive #define TIMER1_PRESCALE 1 // clock prescaler value #define TCCR0B_CS20 0x01 // CS2:0 bits = prescaler selection #define TCCR1B_CS20 0x01 // CS2:0 bits = prescaler selection #define PERIOD_US 5.1 #define PERIOD_TICKS (microsecondsToClockCycles(PERIOD_US / 2) / TIMER1_PRESCALE) //#define OFFSET PERIOD_TICKS /2 int count = 0; int duty = 2; // float Verror = 0; // float Vset = 512.0; // float Vact = 0.0; void setup() { // analogWrite(PIN_PRI_A, 128); // let Arduino setup do its thing // analogWrite(PIN_PRI_B, 128); pinMode(PIN_PRI_A, OUTPUT); pinMode(PIN_PRI_B, OUTPUT); pinMode(PIN_PRI_C, OUTPUT); // TIMER-1 Mode 8 PWM ICR1 - WGM13 TCCR1B = 0x00; // stop Timer1 clock for register updates TCCR1A = 0x80; //0x1000 0000 <- COM1A1 // COM1A1 COM1A0 COM1B1 COM1B0 – – WGM11 WGM10 TCCR1A |= 0x30; //0x0011 0000 <- COM1B1 COM1B0 ICR1 = PERIOD_TICKS; // PWM period TCCR1B = 0x10 | TCCR1B_CS20; //0x0001 0000 <- WGM13 Mode 8 PWM ICR1 //ICNC1 ICES1 – WGM13 WGM12 CS12 CS11 CS10 // TIMER-0 Mode 5 PWM OCRA - WGM02& WGM00 TCCR0B = 0x00; // stop Timer1 clock for register updates TCCR0A = 0x21; //0x1000 0001 <- COM0B1 (pin 5) & WGM00 //COM0A1 COM0A0 COM0B1 COM0B0 – – WGM01 WGM00 OCR0A = PERIOD_TICKS; // PWM period TCCR0B = 0x08 | TCCR0B_CS20; //0x0000 1000 <- WGM02 Mode 5 PWM //FOC0A FOC0B – – WGM02 CS02 CS01 CS00 GTCCR = (1<<TSM) | (1<<PSRASY) | (1<<PSRSYNC); //остановить таймер 0 & 1 //... произвести настройку таймеров, обнулить все счётные регистры итд итп TCNT0 = 0; TCNT1 = 0; GTCCR=0; // Запустить все таймеры одновременно } void loop() ///////// Тут дальше меняем скважность { OCR1A = duty + count; OCR1B = duty + 36 - count; OCR0B = duty + count; // Vact = analogRead(A0); // Verror = 100.0 *(Vset - Vact) /Vset; // if(Verror < 0) count--; // if(Verror > 0) count++; count = analogRead(A0) /16; if(count < 0) count = 0; //min duty 2% if(count >= 15) count = 15; //max duty 95% }MagicianT, в чём мой коммент не верный? 0 и 1 таймер сбрасываются битом PSRSYNC, второй битом PSRASY
Попробуйте залить этот скетч, увидите что все три таймера молотят синхронно такт в такт:
void setup() { pinMode (11,OUTPUT); pinMode (9,OUTPUT); pinMode (6,OUTPUT); GTCCR=(1<<TSM)|(1<<PSRASY)|(1<<PSRSYNC); TCNT0=0; TIMSK0=0; TCCR0A=(1<<COM0A1)|(1<<WGM00)|(1<<WGM01); TCCR0B=(1<<CS00); OCR0A=127; TCNT1=0; TIMSK1=0; TCCR1A=(1<<WGM10)|(1<<COM1A1); TCCR1B=(1<<WGM12)|(0<<WGM13)|(1<<CS10); ICR1=0; OCR1A=127; TCNT2=0; TIMSK2=0; TCCR2A=(1<<COM2A1)|(1<<WGM20)|(1<<WGM21); TCCR2B=(1<<CS20); OCR2A=127; GTCCR=0; } void loop() {}И как вы обьясните что в моём примере есть оффсет, может фаза-коррект мода виновата, она в два раза медленнее вроде?
И зачем сбрасывать прескаллер, если он равен 1? У автора таймер на максимуме 16МГц крутится?
MagicianT, таймер1 в моём скетче работает в 5 моде(fastpwm), wgm13 не ставится, он же =0, просто забыл стереть.Почему у вас фазы разъехались -это нужно изучать исходный скетч, (лень:) скорее всего таймеры работают в разных режимах. Должны в одинаковом.
Да, сейчас нашёл, действительно мода 5. Если ему в эту моду, то все 3 таймера придётся задействовать, канал А будет определять частоту а Б дрыгать пин. Я поигрался ещё, и удостоверился что с таймерами 0 и 2 такой проблемы нет, если у них мода - 7, задавая TCNT можно сдвигать начальный оффсет фазы. Таймер-1 считает то ICR1, и иа-за этого похоже все проблемы, он напрочь отказывается синхронизироваться и в 14 моде фаст-PWM, не только в 8-ой где фаза-коррект, оффсет может быть 1, а если в коде что-нибудь поменять - то непредсказуемый.
void setup() { pinMode( 9, OUTPUT); // A pinMode(10, OUTPUT); // B //pinMode( 6, OUTPUT); // A pinMode( 5, OUTPUT); // B //pinMode(11, OUTPUT); // A pinMode( 3, OUTPUT); // B GTCCR=(1<<TSM)|(1<<PSRASY)|(1<<PSRSYNC); TCNT0 = 0; TIMSK0 = 0; TCCR0A = (1<<COM0B1) | (1<<WGM00) | (1<<WGM01); // Moda 7 Fast PWM OCRA BOTTOM TOP TCCR0B = (1 << CS00) | (1<<WGM02); OCR0A = 40; OCR0B = 20; TCNT1 = 0; TIMSK1 = 0; TCCR1A = (1<<COM1A1) | (1<<COM1B1) | (1<<COM1B0) | (1<<WGM11 ); TCCR1B = (1 << CS10) | (1<<WGM12 ) | (1<<WGM13 ); // Moda 14 Fast PWM ICR1 BOTTOM TOP ICR1 = 40; OCR1A = 20; OCR1B = 20; TCNT2 = 0; TIMSK2 = 0; TCCR2A = (1<<COM2B1) | (1<<WGM20) | (1<<WGM21); // Moda 7 Fast PWM OCRA BOTTOM TOP TCCR2B = (1 << CS20) | (1<<WGM22); OCR2A = 40; OCR2B = 20; GTCCR=0; } void loop() {}Ох, прошу прощения за моё невежество, но я столько всего не знаю.
MagicianT в предыдущем вашем скетче в посте 8, все как надо за исключением того что задние фронты сильно прыгают, о чем кажеться и предупреждал dimax . А в последнем я растерялся и не знаю где меняеться частоста и скважность сигналов. Хотя с самими сигналами все просто прекрасно !
В любом случае, ребята спасибо вам большое !!!
Нет нет нет -- у меня никаких притензий, я ж говорю : "большо спасибо!!" Я уже поковырялся в последнем коде и почти все что надо понял. Это даже больше, чем я ожидал! Спасибо !!!
Ну тогда ладно, а то я подумал претензии какие. Ради любопытства я полазил по и-нету, и накопал что с разницей на единицы фазы (62.5 микросек) таймеров 0-2 и первого сталкивались, но обьяснения этому нету. Впрочем как и в ДШ атмеловском, если кратко - глюк, или недокументированные возможности....
http://www.openmusiclabs.com/learning/digital/synchronizing-timers/
Переписал скетч с поста 8, там был таймер-0, что как я писал не есть хорошо. Теперь на таймере-2, пин-3 дублирует пин-9 точно, пришлось подобрать стартовое значение таймера-2 = 17. Почему 17 не спрашивайте. Вобщем получилось как вам и надо, на 3-ем скважность регулируется независимо, а частота а фаза те-же что и на 9-ом.
#define PIN_PRI_A 9 // OCR1A - high-active primary drive #define PIN_PRI_B 10 // OCR1B - low-active primary drive #define PIN_PRI_C 3 // OCR2B - low-active primary drive #define TIMER1_PRESCALE 1 // clock prescaler value #define TCCR1B_CS20 0x01 // CS2:0 bits = prescaler selection #define TCCR2B_CS20 0x01 // CS2:0 bits = prescaler selection #define PERIOD_US 5.1 #define PERIOD_TICKS (microsecondsToClockCycles(PERIOD_US / 2) / TIMER1_PRESCALE) int count = 0; int duty = 2; // float Verror = 0; // float Vset = 512.0; // float Vact = 0.0; unsigned long last = 0; unsigned long wait = 20; void setup() { pinMode(PIN_PRI_A, OUTPUT); pinMode(PIN_PRI_B, OUTPUT); pinMode(PIN_PRI_C, OUTPUT); cli(); GTCCR=(1<<TSM)|(1<<PSRASY)|(1<<PSRSYNC); // TIMER-1 Mode 8 PWM ICR1 - WGM13 TCCR1A = 0x80; //0x1000 0000 <- COM1A1 TCCR1A |= 0x30; //0x0011 0000 <- COM1B1 COM1B0 // COM1A1 COM1A0 COM1B1 COM1B0 – – WGM11 WGM10 TCCR1B = 0x10 | TCCR1B_CS20; //0x0001 0000 <- WGM13 Mode 8 PWM ICR1 //ICNC1 ICES1 – WGM13 WGM12 CS12 CS11 CS10 TIMSK1 = 0; TCNT1 = 0; ICR1 = PERIOD_TICKS; // PWM period // TIMER-2 Mode 5 PWM OCRA - WGM22& WGM20 TCCR2A = 0x21; //0x0010 0001 <- COM2B1 (pin 3) & WGM20 //COM2A1 COM2A0 COM2B1 COM2B0 – – WGM21 WGM20 TCCR2B = 0x08 | TCCR2B_CS20; //0x0000 1000 <- WGM22 Mode 5 PWM //FOC2A FOC2B – – WGM22 CS22 CS21 CS20 TIMSK2 = 0; TCNT2 = 17; OCR2A = PERIOD_TICKS; // PWM period GTCCR=0; sei(); } void loop() ///////// Тут дальше меняем скважность { OCR1A = duty + count; OCR1B = duty + 36 - count; OCR2B = duty + count; // Vact = analogRead(A0); // Verror = 100.0 *(Vset - Vact) /Vset; // if(Verror < 0) count--; // if(Verror > 0) count++; count = analogRead(A0) /16; if(count < 0) count = 0; //min duty 2% if(count >= 15) count = 15; //max duty 95% }Спасибо за труды, мне не ловко говорить, но в последнем коде задние фронты скачут :(
https://yadi.sk/i/tMguclcXrnxuu
Код смотрели? Там на аналог-0 напряжение подать надо, а у вас куда подключено? И ещё там я убрал часть, можете вернуть назад - теперь таймер-2 и милис() не вопрос.
Вауу, если бы вы не сказали я бы и не знал что такое
count = analogRead(A0) /16;Ок, вечером проверю. Спасибо !!!
Подал 5 вольт с RX на A0 --- все дребезги фронтов пропали !!! :)
Вопрос:
что вот это cli(); и sei(); ???
Вопрос:
что вот это cli(); и sei(); ???
Запрет и разрешение прерываний.
не знаю что оно запрещает, но рабатет и без него :)
Вроде бы самое главное для себя нашел! Сдвиг фаз, скважность все есть !!
MagicianT огромное вам спасибо !!!! :)
На здоровье. Я и для себя что то новое открыл.
обнаружил непонятную штуку, с помощью кнопок пытаюсь менять PERIOD_TICKS или PERIOD_US, но частота не меняеться :(
на мониторе значения перемиенных меняються но частота -нет.
с частотой разобрался.
Здравствуйте уважаемые форумчане, прошу сильно не пинать я только начина в этом разбираться. Постараюсь покроче. На просторах интернета нашёл сделующий скетч, вопрос следующий, как сделать еще один (3-й) сигнал, с той же частотой что и первые два, такой же фазы как и первый но чтобы можно было независимо меняеть его скважность.
поснительная картинка к тексту, если не понятно.
https://yadi.sk/i/xkpfXXWhrm5o3
#define PIN_PRI_A 9 // OCR1A - high-active primary drive #define PIN_PRI_B 10 // OCR1B - low-active primary drive #define PUSH_PULL false // false = OCR1A only, true = OCR1A + OCR1B #define TIMER1_PRESCALE 1 // clock prescaler value #define TCCR1B_CS20 0x01 // CS2:0 bits = prescaler selection #define PERIOD_US 5.1 #define PERIOD_TICKS (microsecondsToClockCycles(PERIOD_US / 2) / TIMER1_PRESCALE) int count=0; int duty=2; float Verror=0; float Vset=512.0; float Vact; unsigned long last=0; unsigned long wait=20; boolean first=true; void setup() { // pinMode(A0, INPUT); //input tensione НЕ знаю что это но без него работает. //digitalWrite(A0, LOW); analogWrite(PIN_PRI_A,128); // let Arduino setup do its thing analogWrite(PIN_PRI_B,128); TCCR1B = 0x00; // stop Timer1 clock for register updates // Clear OC1A on match, P-F Corr PWM Mode: lower WGM1x = 00 TCCR1A = 0x80 | 0x00; //128 | // Configure Timer 1 for Freq-Phase Correct PWM // Timer 1 + output on OC1A, chip pin 15, Arduino PWM9 // Timer 1 - output on OC1B, chip pin 16, Arduino PWM10 // If push-pull drive, set OC1B on match TCCR1A |= 0x30; //48 ICR1 = PERIOD_TICKS; // PWM period OCR1A = duty; // ON duration = drive pulse width//ucita 9 OCR1B = duty+156; // ditto - use separate load due to temp buffer reg //usita 10 TCNT1 = OCR1A - 1; // force immediate OCR1x compare on next tick // upper WGM1x = 10, Clock Sel = prescaler, start Timer 1 running TCCR1B = 0x10 | TCCR1B_CS20; } void loop() ///////// Тут дальше меняем скважность { OCR1A = duty+count; OCR1B = duty+36-count; if(first) { //delay(2000); first=false; } Vact=analogRead(A0); Verror=100.0*(Vset-(float)(Vact))/Vset; if(millis()-last>=wait) { last=millis(); if(Verror<0) count--; if(Verror>0) count++; if(count<0) count=0; //min duty 2% if(count>=15) count=15; //max duty 95% } }Всем здравствуйте. я в этом деле новичок, подскажите как собрана плата для этого скетча. собираю индукционный котел и мне надо чтоб частота фиксированная была 47.9391 а скважность менялась. силовую плату собрал на игбт 25n120 полный мост. и хотелось бы лсд запустить на плате. лсд1602 у меня с кнопками
Думаю, через годика полтора это будет тебе под силу. Если книги читать прилежно будешь. А счас пока - забуть.
так хочется отопление запустить
так хочется отопление запустить
А мне Ламборджини на огороде из металлолома выстругать, да, еще сварочник есть и эта, кувалда.)))