Arduino Push-pull

3dmax
Offline
Зарегистрирован: 09.05.2016

Evgen пишет:

Осциллограф програмный, через звуковуху? На меньшей частоте 1-2 кГц тоже самое?

Ослик DSO-2150 USB

dimax пишет:

3dmax -код в шапке слишком примитивен, на длительность фронтов влияет прерывание таймера0.   Если нужен сигнал стабильной формы - к вашим услугам три аппаратных таймера.

то есть таким способом проблемму не решить ? :(

step64
Offline
Зарегистрирован: 01.04.2013

Дня доброго всем. Такой вопрос, залил этот скетч в уно через ардуино иде 1,06. На более новых(1,6-1,8) вообще этот код компилироваться отказывается. Короче  запустил, подключил, на экране только надпись ардуино пушпулл. Подключил осцил - на фото всё видно, ничего не регулируется переменниками((( Кто-нибудь может ещё раз проверить данный скетч на правильность или у меня одного ардуина какая-то не правильная))

renoshnik пишет:

Вот полный скетч...

#include <LiquidCrystal.h>
LiquidCrystal lcd(8,9,10,11,12,13);
void (*mas[4]) (void)={poluper1, dead_time1, poluper2, dead_time2}; 	// массив указателей функций       
volatile int val_fr = 533; 			// длительность полупериода f=18000000/val_fr/2(Гц),
volatile int dead_time = 91; 		// пауза между периодами, не должна быть меньше 92 и больше val_fr-92
byte uk=0;
int f_val, d_val; 
float rpm, dtm;
//	********************************************************************
//	********************************************************************
void setup()	{     
DDRD = B11111000; 		// нужные пины на выход
PORTD = B00000100; 		// на втором пине устанавливаем "единицу"
TCCR1A=0; TIMSK1=0; 	// сбрасываем на всякий эти регистры
//	TCCR1A=0; TIMSK=0;
TCCR1B=0; 				// мало ли что arduino IDE туда записало
TCNT1=0; 				// сбрасываем счетный регистр таймера 1
OCR1A=0; 				// задаем частоту, в Гц, по формуле f=F_CPU/OCR1A/2 где F_CPU тактовая частота 
TIMSK1|=(1<<OCIE1A); 	// разрешаем генерацию прерывания таймера 1, по совпадению с регистром OCR1A
//	TIMSK|=(1<<OCIE1A); 

//	Скетч будет работать на дуинах с atmega168/328. 
//	При использовании atmega8 меняем все TIMSK1 на TIMSK (убираем еденицу).	 
 
TCCR1B|=((1<<CS10)|(1<<WGM12)); // запускаем таймер 1 без предделителя в режиме СТС

lcd.begin(16, 2);
lcd.print("arduino PushPull");	
	}
//	********************************************************************
//	********************************************************************
void loop(){ 
	if ((PIND&(1<<2)) == 0) l_c_d();	// если на пин 2 лог 0
	}
//	********************************************************************
//	********************************************************************
ISR(TIMER1_COMPA_vect)	{
(*mas[uk])(); 							// вызываем функцию по указателю
	}
//	********************************************************************
//	********************************************************************
//	********************************************************************
void poluper1(void)	{	
PORTD&=~(1<<5); 						// на пин 5 лог 0
PORTD|=(1<<4); 							// на пин 4 лог 1, формируем первый полупериод
if(dead_time<92) {OCR1A=val_fr; uk=2;} 	// если пауза меньше 92 тогда она формироваться не будет
else {OCR1A=val_fr-dead_time; uk=1;} 	// иначе уменьшаем полупериод на длительность паузы чтоб сохранить частоту
	}
void dead_time1(void) {	
PORTD&=~(1<<4); 						// на пинах 4 и 5 лог 0, формируем dead_time паузу
OCR1A=dead_time; uk=2;
	}
void poluper2(void) {	
PORTD&=~(1<<4); 						// на пин 4 лог 0
PORTD|=(1<<5); 							// на пин 5 лог 1, формируем второй полупериод
if(dead_time<92) {OCR1A=val_fr; uk=0;}
else {OCR1A=val_fr-dead_time; uk=3;}
	}
void dead_time2(void) {	
PORTD&=~(1<<5); 						// на пинах 4 и 5 лог 0, формируем dead_time паузу
OCR1A=dead_time; uk=0;
	}
//	********************************************************************
//	********************************************************************	
void l_c_d() { 
//	работаем с частотой от 15009(533) Гц до 30075(266) Гц (f=F_CPU/OCR1A/2)
//	работаем с частотой от 20000(400) Гц до 30075(266) Гц (f=F_CPU/OCR1A/2)
f_val = analogRead(A3);     
val_fr = map(f_val, 0, 1023, 533, 266);
rpm = 16000000.0/val_fr/2.0; 				//	частота в Герцах
//	работаем со скважностью
// 	пауза между периодами, не должна быть меньше 92 и больше val_fr-91
d_val = analogRead(A2); 
int max_dt = val_fr-92;    
dead_time = map(d_val, 0, 1023, 91, max_dt);
dtm = dead_time/(val_fr/100.0);				//	скважность в процентах
if (dead_time < 92) dtm=0;

lcd.setCursor(0, 0);
lcd.print("freq          Hz");	
lcd.setCursor(5, 0);
lcd.print(rpm);
lcd.setCursor(0, 1);
lcd.print("dead time      %");	
lcd.setCursor(10, 1);
lcd.print(dtm, 1);
//delay(400);
}

 

toc
Offline
Зарегистрирован: 09.02.2013

>> ничего не регулируется переменниками
Возможно нужно притянуть пин. Строка 33.

step64
Offline
Зарегистрирован: 01.04.2013

toc пишет:
>> ничего не регулируется переменниками Возможно нужно притянуть пин. Строка 33.

Спасибо, заработало!

pdjboy
pdjboy аватар
Offline
Зарегистрирован: 22.01.2017

dimax, предлогаешь использовать таймер1 или таймер2 вместо таймер0?

4KLIN4
Offline
Зарегистрирован: 06.04.2017

Люди добрые подскажите пожалуйста а как реализовать двухтактный генератр у которого 2 выхода работают в противофазе, с регулировкой частоты от 40Гц и выше...

Буду ОЧЕНЬ благодарен за ответ.

renoshnik
Offline
Зарегистрирован: 11.04.2013

4KLIN4 пишет:

Люди добрые подскажите пожалуйста а как реализовать двухтактный генератр у которого 2 выхода работают в противофазе, с регулировкой частоты от 40Гц и выше...

Буду ОЧЕНЬ благодарен за ответ.

А выше написанное чем не подходит ?

https://www.drive2.ru/b/572409/

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

renoshnik пишет:

Evgen, спасибо всё понял, а то, что-то запутался....

ещё.

я немного изменил строки с массивом функций, всё работает но хочется узнать на сколько это правильно.

	void (*mas[4]) (void)={poluper1, dead_time1, poluper2, dead_time2}; // массив указателей функций       
	int uk=0;

вчера взял осцилограф (не Бог весть что, но лучше чем прога в компе)... Вот что получается.

volatile int val_fr = 900;
volatile int dead_time = 500;

 

 

volatile int val_fr = 900;
volatile int dead_time = 250;

теперь нормально видно, что "мёртвая зона" отрабатывается правильно, с двух сторон от полупериода.

Только при изменении дедтайма изменяется частота... 

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

В общем есть чем заниматься на выходных...

Ещё раз ОГРОМНОЕ СПАСИБО !!! за помощь...

ОГО - Это жеж ОМЛ-2М или ОМЛ-3М, я прав?

4KLIN4
Offline
Зарегистрирован: 06.04.2017

renoshnik пишет:

4KLIN4 пишет:

Люди добрые подскажите пожалуйста а как реализовать двухтактный генератр у которого 2 выхода работают в противофазе, с регулировкой частоты от 40Гц и выше...

Буду ОЧЕНЬ благодарен за ответ.

А выше написанное чем не подходит ?

https://www.drive2.ru/b/572409/

 

нее, не совсем то, мне нужно 2 выхода работающих в противофазе, с небольшой задержной относительно друг друга, дабы Н-мост не спалить, в идеале deadTime регулировать как и частоту, наверника это уже гдето реализовано, велосипед изобретать не есть хорошо

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

4KLIN4, дидтайм аппаратно умеют платы: дижиспарк, микро, про-микро, леонардо. Примеров и ардуино-френдли библиотек для лёгкой реализации вашей задумки нет(или мне не встречалось).

renoshnik
Offline
Зарегистрирован: 11.04.2013

4KLIN4 пишет:

renoshnik пишет:

4KLIN4 пишет:

Люди добрые подскажите пожалуйста а как реализовать двухтактный генератр у которого 2 выхода работают в противофазе, с регулировкой частоты от 40Гц и выше...

Буду ОЧЕНЬ благодарен за ответ.

А выше написанное чем не подходит ?

https://www.drive2.ru/b/572409/

 

нее, не совсем то, мне нужно 2 выхода работающих в противофазе, с небольшой задержной относительно друг друга, дабы Н-мост не спалить, в идеале deadTime регулировать как и частоту, наверника это уже гдето реализовано, велосипед изобретать не есть хорошо

На осцилограммах видно, что тут дедтайм регулируется...

renoshnik
Offline
Зарегистрирован: 11.04.2013

ua6em пишет:

renoshnik пишет:

Evgen, спасибо всё понял, а то, что-то запутался....

ещё.

я немного изменил строки с массивом функций, всё работает но хочется узнать на сколько это правильно.

	void (*mas[4]) (void)={poluper1, dead_time1, poluper2, dead_time2}; // массив указателей функций       
	int uk=0;

вчера взял осцилограф (не Бог весть что, но лучше чем прога в компе)... Вот что получается.

volatile int val_fr = 900;
volatile int dead_time = 500;

 

 

volatile int val_fr = 900;
volatile int dead_time = 250;

теперь нормально видно, что "мёртвая зона" отрабатывается правильно, с двух сторон от полупериода.

Только при изменении дедтайма изменяется частота... 

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

В общем есть чем заниматься на выходных...

Ещё раз ОГРОМНОЕ СПАСИБО !!! за помощь...

ОГО - Это жеж ОМЛ-2М или ОМЛ-3М, я прав?

 

Помоему да ...  :-))

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

В хороших руках техника хорошо сохраняется )))
Эпоха перестройки, годы так 1980-1986 )))
Я на таком отлаживал схему генератора трёх уровневого стробирующего импульса (для декодеров PAL)
для TDA4510

Tolik4
Offline
Зарегистрирован: 05.01.2018

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


void setup ()
{
  TCCR1A = (TCCR1A & 0x0F) | 0xB0 ; // set pin 10 inverted
  int val = 100 ;
  int dead = 2 ;
  analogWrite (9, val) ;
  analogWrite (10, val+dead) ;
}
void loop ()
{}

Регулировать нужно только скважность, никаких дополнительных наворотов кроме дедтайма не нужно. Спасибо.

renoshnik
Offline
Зарегистрирован: 11.04.2013

Tolik4 пишет:

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


void setup ()
{
  TCCR1A = (TCCR1A & 0x0F) | 0xB0 ; // set pin 10 inverted
  int val = 100 ;
  int dead = 2 ;
  analogWrite (9, val) ;
  analogWrite (10, val+dead) ;
}
void loop ()
{}

Регулировать нужно только скважность, никаких дополнительных наворотов кроме дедтайма не нужно. Спасибо.

 

бесполезно

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Tolik4, лучше взять МК с аппаратной поддержкой дид-тайма, Tiny85 например.

Tolik4
Offline
Зарегистрирован: 05.01.2018

Есть диджиспарк, его можно заставить генерировать ШИМ с дедтаймом средствани Ардуино ИДЕ?

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

Tolik4, возможно что "средства" Arduino IDE будут как раз мешать, нужно проверять. Есть примерчик под "голую" тини85.

Tolik4
Offline
Зарегистрирован: 05.01.2018

https://gist.github.com/ollewelin/4afcf202a6ff267aa70e5b289724abc2 вот нашел пример для трех фаз, можно ли из него повыбрасывать лишнее и дальше писать свой недокод как для обычного ардуино?

renoshnik
Offline
Зарегистрирован: 11.04.2013

Tolik4 пишет:

https://gist.github.com/ollewelin/4afcf202a6ff267aa70e5b289724abc2 вот нашел пример для трех фаз, можно ли из него повыбрасывать лишнее и дальше писать свой недокод как для обычного ардуино?

 

Tolik4, я не пойму в чем проблема у вас проблема ? Выше есть рабочий скетч с регулировкой дедтайма ! 

renoshnik
Offline
Зарегистрирован: 11.04.2013
Tolik4
Offline
Зарегистрирован: 05.01.2018

Проблема моя в том что программист я никакой( это если коротко.

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

А пример, ссылку на который я скинул выше - гораздо более прост для понимания. Вот изготовленный мной огрызок данного кода, рабочий, проверенный на осциллографе:

//~9  TL, PH1, TMR1, PWM data value
//~10 TH, PH1, TMR1, PWM data value

const int dead_time = 10;//10 = 0.625 us
const int half_dead_time = dead_time / 2;//
int PWM = 0;

void setup()
{
  pinMode(9, INPUT);   //PWM is set to input before PWM initialized to prevent start up short circuit
  pinMode(10, INPUT);   //PWM is set to input before PWM initialized to prevent start up short circuit
}

void update_pwm(void)
{
  //Limit the pwm_phx so it take the dead time into account so it not will swap over when reach end limit of workable PWM range
  if (PWM > (255 - half_dead_time))
  {
    PWM = (255 - half_dead_time);
  }
  if (PWM < half_dead_time)
  {
    PWM = half_dead_time;
  }

  //All The PWM will run from 0xFF to 0x00 and up again to TOP 0xFF
  //The OCRnx will automatic update when TCNTn is on TOP 0xFF by hardware
  //Therefor it is sutible to change both OCRnx pair on a place where TCNT not update to ensure that the hardware automatic update NOT occur exact when only one of the two OCRnx have changed by this code
  while (TCNT1 > 0x7F)
  {
  }
  //Now it's safe to update OCR1x pair (connect to same transistor pair)
  OCR1A = (255 - PWM + half_dead_time); //~9 TL PH1 TMR1
  OCR1B = (PWM - half_dead_time); //~10 TH PH1 TMR1
}

void loop()
{
  TCCR1A = 0xE1;//PWM, Phase Correct 8-bit TOP at 0xFF
  TCCR1B = 0x01;//clkI/O/1 (No prescaling) 31.25kHz PWM frequency
  update_pwm();

  pinMode(9, OUTPUT);   //PWM output
  pinMode(10, OUTPUT);   //PWM output


  while (1)
  {

    PWM ++;
    if(PWM>128)PWM=0;
    update_pwm();
    delay(100);//delay timer scale is screwd up by the new PWM TMR settings
   
  }
}

Делает вроде бы ровно то что мне нужно. Посмотрите пожалуйста нет ли в нем подводных камней, вроде возможности отказа стандартных ардуиновских функций и библиотек. И можно ли в нем изменить частоту на 62кГц? Что-то подсказывает что нужно заменить строчки 39,40, но вот на что?) Спасибо

renoshnik
Offline
Зарегистрирован: 11.04.2013

Tolik4 пишет:

Вот изготовленный мной огрызок данного кода, рабочий, проверенный на осциллографе:

Можно картинку, что показывает осцилограф ?

Tolik4
Offline
Зарегистрирован: 05.01.2018

https://ibb.co/me1Qpn

Пробовал вставить гиф в сообщение - не хочет(

renoshnik
Offline
Зарегистрирован: 11.04.2013

Tolik4 пишет:

https://ibb.co/me1Qpn

Пробовал вставить гиф в сообщение - не хочет(

думаете такой сигнал подойдет для пуш-пула ?

смотрите тут в теме есть осцилограммы...

Tolik4
Offline
Зарегистрирован: 05.01.2018

Я, как вы уже догадались, не специалист) Вдохновлялся этим: 

https://www.youtube.com/watch?v=bYGeAu6_c6w

zanuda364
Offline
Зарегистрирован: 27.01.2019

Доброго дня, а каким образом можно обратную связь по напряжению осуществить?

EgorKa
Offline
Зарегистрирован: 15.08.2016

renoshnik пишет:

Вот полный скетч...

#include <LiquidCrystal.h>
LiquidCrystal lcd(8,9,10,11,12,13);
void (*mas[4]) (void)={poluper1, dead_time1, poluper2, dead_time2}; 	// массив указателей функций       
volatile int val_fr = 533; 			// длительность полупериода f=18000000/val_fr/2(Гц),
volatile int dead_time = 91; 		// пауза между периодами, не должна быть меньше 92 и больше val_fr-92
byte uk=0;
int f_val, d_val; 
float rpm, dtm;
//	********************************************************************
//	********************************************************************
void setup()	{     
DDRD = B11111000; 		// нужные пины на выход
PORTD = B00000100; 		// на втором пине устанавливаем "единицу"
TCCR1A=0; TIMSK1=0; 	// сбрасываем на всякий эти регистры
//	TCCR1A=0; TIMSK=0;
TCCR1B=0; 				// мало ли что arduino IDE туда записало
TCNT1=0; 				// сбрасываем счетный регистр таймера 1
OCR1A=0; 				// задаем частоту, в Гц, по формуле f=F_CPU/OCR1A/2 где F_CPU тактовая частота 
TIMSK1|=(1<<OCIE1A); 	// разрешаем генерацию прерывания таймера 1, по совпадению с регистром OCR1A
//	TIMSK|=(1<<OCIE1A); 

//	Скетч будет работать на дуинах с atmega168/328. 
//	При использовании atmega8 меняем все TIMSK1 на TIMSK (убираем еденицу).	 
 
TCCR1B|=((1<<CS10)|(1<<WGM12)); // запускаем таймер 1 без предделителя в режиме СТС

lcd.begin(16, 2);
lcd.print("arduino PushPull");	
	}
//	********************************************************************
//	********************************************************************
void loop(){ 
	if ((PIND&(1<<2)) == 0) l_c_d();	// если на пин 2 лог 0
	}
//	********************************************************************
//	********************************************************************
ISR(TIMER1_COMPA_vect)	{
(*mas[uk])(); 							// вызываем функцию по указателю
	}
//	********************************************************************
//	********************************************************************
//	********************************************************************
void poluper1(void)	{	
PORTD&=~(1<<5); 						// на пин 5 лог 0
PORTD|=(1<<4); 							// на пин 4 лог 1, формируем первый полупериод
if(dead_time<92) {OCR1A=val_fr; uk=2;} 	// если пауза меньше 92 тогда она формироваться не будет
else {OCR1A=val_fr-dead_time; uk=1;} 	// иначе уменьшаем полупериод на длительность паузы чтоб сохранить частоту
	}
void dead_time1(void) {	
PORTD&=~(1<<4); 						// на пинах 4 и 5 лог 0, формируем dead_time паузу
OCR1A=dead_time; uk=2;
	}
void poluper2(void) {	
PORTD&=~(1<<4); 						// на пин 4 лог 0
PORTD|=(1<<5); 							// на пин 5 лог 1, формируем второй полупериод
if(dead_time<92) {OCR1A=val_fr; uk=0;}
else {OCR1A=val_fr-dead_time; uk=3;}
	}
void dead_time2(void) {	
PORTD&=~(1<<5); 						// на пинах 4 и 5 лог 0, формируем dead_time паузу
OCR1A=dead_time; uk=0;
	}
//	********************************************************************
//	********************************************************************	
void l_c_d() { 
//	работаем с частотой от 15009(533) Гц до 30075(266) Гц (f=F_CPU/OCR1A/2)
//	работаем с частотой от 20000(400) Гц до 30075(266) Гц (f=F_CPU/OCR1A/2)
f_val = analogRead(A3);     
val_fr = map(f_val, 0, 1023, 533, 266);
rpm = 16000000.0/val_fr/2.0; 				//	частота в Герцах
//	работаем со скважностью
// 	пауза между периодами, не должна быть меньше 92 и больше val_fr-91
d_val = analogRead(A2); 
int max_dt = val_fr-92;    
dead_time = map(d_val, 0, 1023, 91, max_dt);
dtm = dead_time/(val_fr/100.0);				//	скважность в процентах
if (dead_time < 92) dtm=0;

lcd.setCursor(0, 0);
lcd.print("freq          Hz");	
lcd.setCursor(5, 0);
lcd.print(rpm);
lcd.setCursor(0, 1);
lcd.print("dead time      %");	
lcd.setCursor(10, 1);
lcd.print(dtm, 1);
//delay(400);
}

 

Гуру, подскажите почему этот код не компилируется в IDE 1.8.9 ?

Ругается на строку 3

Arduino: 1.8.9 (Windows 7), Плата:"Arduino/Genuino Uno"

push_pull:3:24: error: 'poluper1' was not declared in this scope

push_pull:3:34: error: 'dead_time1' was not declared in this scope

push_pull:3:46: error: 'poluper2' was not declared in this scope

push_pull:3:56: error: 'dead_time2' was not declared in this scope

exit status 1

'poluper1' was not declared in this scope

Этот отчёт будет иметь больше информации с

включенной опцией Файл -> Настройки ->

"Показать подробный вывод во время компиляции"

zanuda364
Offline
Зарегистрирован: 27.01.2019

Not declared - не заданна переменная (не задекларирована - если дословно)

b707
Онлайн
Зарегистрирован: 26.05.2017

EgorKa пишет:

Гуру, подскажите почему этот код не компилируется в IDE 1.8.9 ?

потому что любая функция должна быть описана до первого обращения к ней. А у вас ваши функции полу_пер и прочие описаны в строчках 42-62, а первое обращение к ним - в строчке 3

Поместите сами функции или их обьявление до третьей строчки - ошибки исчезнут

EgorKa
Offline
Зарегистрирован: 15.08.2016

b707 пишет:

EgorKa пишет:

Гуру, подскажите почему этот код не компилируется в IDE 1.8.9 ?

потому что любая функция должна быть описана до первого обращения к ней. А у вас ваши функции полу_пер и прочие описаны в строчках 42-62, а первое обращение к ним - в строчке 3

Поместите сами функции или их обьявление до третьей строчки - ошибки исчезнут

Спасибо за подсказку. Но самое интересное что в IDE 1.5.7 компилируется.

Вот переделал

// 27-11-2019 переделал методом переноса текста , компилируется в IDE 1.8.9
// в железе надо проверить

#include <LiquidCrystal.h>
LiquidCrystal lcd(8,9,10,11,12,13);
volatile int val_fr = 533;      // длительность полупериода f=18000000/val_fr/2(Гц),
volatile int dead_time = 91;    // пауза между периодами, не должна быть меньше 92 и больше val_fr-92
byte uk=0;
int f_val, d_val; 
float rpm, dtm;
//  ********************************************************************
//  ********************************************************************
void poluper1(void) { 
PORTD&=~(1<<5);             // на пин 5 лог 0
PORTD|=(1<<4);              // на пин 4 лог 1, формируем первый полупериод
if(dead_time<92) {OCR1A=val_fr; uk=2;}  // если пауза меньше 92 тогда она формироваться не будет
else {OCR1A=val_fr-dead_time; uk=1;}  // иначе уменьшаем полупериод на длительность паузы чтоб сохранить частоту
  }
void dead_time1(void) { 
PORTD&=~(1<<4);             // на пинах 4 и 5 лог 0, формируем dead_time паузу
OCR1A=dead_time; uk=2;
  }
void poluper2(void) { 
PORTD&=~(1<<4);             // на пин 4 лог 0
PORTD|=(1<<5);              // на пин 5 лог 1, формируем второй полупериод
if(dead_time<92) {OCR1A=val_fr; uk=0;}
else {OCR1A=val_fr-dead_time; uk=3;}
  }
void dead_time2(void) { 
PORTD&=~(1<<5);             // на пинах 4 и 5 лог 0, формируем dead_time паузу
OCR1A=dead_time; uk=0;
  }
//  ********************************************************************

void (*mas[4]) (void)={poluper1, dead_time1, poluper2, dead_time2};   // массив указателей функций       

//  ********************************************************************
//  ********************************************************************
void setup()  {     
DDRD = B11111000;     // нужные пины на выход
PORTD = B00000100;    // на втором пине устанавливаем "единицу"
TCCR1A=0; TIMSK1=0;   // сбрасываем на всякий эти регистры
//  TCCR1A=0; TIMSK=0;
TCCR1B=0;         // мало ли что arduino IDE туда записало
TCNT1=0;        // сбрасываем счетный регистр таймера 1
OCR1A=0;        // задаем частоту, в Гц, по формуле f=F_CPU/OCR1A/2 где F_CPU тактовая частота 
TIMSK1|=(1<<OCIE1A);  // разрешаем генерацию прерывания таймера 1, по совпадению с регистром OCR1A
//  TIMSK|=(1<<OCIE1A); 

//  Скетч будет работать на дуинах с atmega168/328. 
//  При использовании atmega8 меняем все TIMSK1 на TIMSK (убираем еденицу).  
 
TCCR1B|=((1<<CS10)|(1<<WGM12)); // запускаем таймер 1 без предделителя в режиме СТС

lcd.begin(16, 2);
lcd.print("arduino PushPull");  
  }
//  ********************************************************************
//  ********************************************************************
void loop(){ 
  if ((PIND&(1<<2)) == 0) l_c_d();  // если на пин 2 лог 0
  }
//  ********************************************************************
//  ********************************************************************
ISR(TIMER1_COMPA_vect)  {
(*mas[uk])();               // вызываем функцию по указателю
  }
//  ********************************************************************
//  ********************************************************************

//  ********************************************************************  
void l_c_d() { 
//  работаем с частотой от 15009(533) Гц до 30075(266) Гц (f=F_CPU/OCR1A/2)
//  работаем с частотой от 20000(400) Гц до 30075(266) Гц (f=F_CPU/OCR1A/2)
f_val = analogRead(A3);     
val_fr = map(f_val, 0, 1023, 533, 266);
rpm = 16000000.0/val_fr/2.0;        //  частота в Герцах
//  работаем со скважностью
//  пауза между периодами, не должна быть меньше 92 и больше val_fr-91
d_val = analogRead(A2); 
int max_dt = val_fr-92;    
dead_time = map(d_val, 0, 1023, 91, max_dt);
dtm = dead_time/(val_fr/100.0);       //  скважность в процентах
if (dead_time < 92) dtm=0;

lcd.setCursor(0, 0);
lcd.print("freq          Hz");  
lcd.setCursor(5, 0);
lcd.print(rpm);
lcd.setCursor(0, 1);
lcd.print("dead time      %");  
lcd.setCursor(10, 1);
lcd.print(dtm, 1);
//delay(400);
}

 

b707
Онлайн
Зарегистрирован: 26.05.2017

EgorKa пишет:

самое интересное что в IDE 1.5.7 компилируется.

ничего "интересного" в этом нет, это печально. Просто IDE 1.5.7 делает за вас эту работу, расслабляя новичков.

Правильно - как требует IDE 1.8.9 - то есть  описывать функции до их использования

Ivan_Kornege
Offline
Зарегистрирован: 23.06.2016

Для разрешения регулировки частоты и дедтайма я так понял пин 2 на общий провод замыкать?

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

renoshnik
Offline
Зарегистрирован: 11.04.2013

как обычно, стандартные 10 кОм

tashay174
Offline
Зарегистрирован: 30.06.2013

Что поменять в скетче чтобы пределы регулирования по частоте от 1Гц до 500Гц было? 

v7a7s7
Offline
Зарегистрирован: 06.02.2019
#include <LiquidCrystal.h>
LiquidCrystal lcd(8,9,10,11,12,13);
volatile int val_fr = 533;      // длительность полупериода f=18000000/val_fr/2(Гц),
volatile int dead_time = 91;    // пауза между периодами, не должна быть меньше 92 и больше val_fr-92
byte uk=0;
int f_val, d_val; 
float rpm, dtm;
//  ********************************************************************
//  ********************************************************************
void poluper1(void) { 
PORTD&=~(1<<5);             // на пин 5 лог 0
PORTD|=(1<<4);              // на пин 4 лог 1, формируем первый полупериод
if(dead_time<92) {OCR1A=val_fr; uk=2;}  // если пауза меньше 92 тогда она формироваться не будет
else {OCR1A=val_fr-dead_time; uk=1;}  // иначе уменьшаем полупериод на длительность паузы чтоб сохранить частоту
  }
void dead_time1(void) { 
PORTD&=~(1<<4);             // на пинах 4 и 5 лог 0, формируем dead_time паузу
OCR1A=dead_time; uk=2;
  }
void poluper2(void) { 
PORTD&=~(1<<4);             // на пин 4 лог 0
PORTD|=(1<<5);              // на пин 5 лог 1, формируем второй полупериод
if(dead_time<92) {OCR1A=val_fr; uk=0;}
else {OCR1A=val_fr-dead_time; uk=3;}
  }
void dead_time2(void) { 
PORTD&=~(1<<5);             // на пинах 4 и 5 лог 0, формируем dead_time паузу
OCR1A=dead_time; uk=0;
  }
//  ********************************************************************

void (*mas[4]) (void)={poluper1, dead_time1, poluper2, dead_time2};   // массив указателей функций       

//  ********************************************************************
//  ********************************************************************
void setup()  {     
DDRD = B11111000;     // нужные пины на выход
PORTD = B00000100;    // на втором пине устанавливаем "единицу"
TCCR1A=0; TIMSK1=0;   // сбрасываем на всякий эти регистры
//  TCCR1A=0; TIMSK=0;
TCCR1B=0;         // мало ли что arduino IDE туда записало
TCNT1=0;        // сбрасываем счетный регистр таймера 1
OCR1A=0;        // задаем частоту, в Гц, по формуле f=F_CPU/OCR1A/2 где F_CPU тактовая частота 
TIMSK1|=(1<<OCIE1A);  // разрешаем генерацию прерывания таймера 1, по совпадению с регистром OCR1A
//  TIMSK|=(1<<OCIE1A); 

//  Скетч будет работать на дуинах с atmega168/328. 
//  При использовании atmega8 меняем все TIMSK1 на TIMSK (убираем еденицу).  
 
TCCR1B|=((1<<CS10)|(1<<WGM12)); // запускаем таймер 1 без предделителя в режиме СТС

lcd.begin(16, 2);
lcd.print("arduino PushPull");  
  }
//  ********************************************************************
//  ********************************************************************
void loop(){ 
  if ((PIND&(1<<2)) == 0) l_c_d();  // если на пин 2 лог 0
  }
//  ********************************************************************
//  ********************************************************************
ISR(TIMER1_COMPA_vect)  {
(*mas[uk])();               // вызываем функцию по указателю
  }
//  ********************************************************************
//  ********************************************************************

//  ********************************************************************  
void l_c_d() { 
//  работаем с частотой от 15009(533) Гц до 30075(266) Гц (f=F_CPU/OCR1A/2)
//  работаем с частотой от 20000(400) Гц до 30075(266) Гц (f=F_CPU/OCR1A/2)
f_val = analogRead(A3);     
val_fr = map(f_val, 0, 1023, 533, 266);
rpm = 16000000.0/val_fr/2.0;        //  частота в Герцах
//  работаем со скважностью
//  пауза между периодами, не должна быть меньше 92 и больше val_fr-91
d_val = analogRead(A2); 
int max_dt = val_fr-92;    
dead_time = map(d_val, 0, 1023, 91, max_dt);
dtm = dead_time/(val_fr/100.0);       //  скважность в процентах
if (dead_time < 92) dtm=0;

lcd.setCursor(0, 0);
lcd.print("freq          Hz");  
lcd.setCursor(5, 0);
lcd.print(rpm);
lcd.setCursor(0, 1);
lcd.print("dead time      %");  
lcd.setCursor(10, 1);
lcd.print(dtm, 1);
//delay(400);
}

 

Люди ДОБРЫЕ ! ПОМОЖИТЕ!   Как  этот скеч   сделать под регулировку тремя кнопками?

Пытаюсь  слямзить с этого скеча управление  , да вот мозги дымятся !!!

 

// генератор сигналов с регулировкой частоты и скважности по двум каналам.
// частота от 0 до 100 кГц, ШИМ от 0 до 255
//

//подключение библиотек *********************************************************************
#include <PWM.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd (2, 12, 4, 5, 6, 7);                      // назначение пин LCD (rs, enable, d4, d5, d6, d7)
//********************************************************************************************

//определение пинов **************************************************************************
#define OK_PIN    8                                         // кнопка ОК (можно любой пин)
#define OUT_1_PIN 9                                         // пин для генератора сигналов (не менять)
#define OUT_2_PIN 10                                        // пин для генератора сигналов (не менять)
#define LEFT_PIN  A0                                        // кнопка ЛЕВО (можно любой пин)
#define RIGHT_PIN A1                                        // кнопка ПРАВО (можно любой пин) 
//*********************************************************************************************

//объявление переменных ***********************************************************************
int PWM_1 = 200;                                            // стартовое значение ШИМ_1 от 0 до 255
int PWM_2 = 50;                                             // стартовое значение ШИМ_2 от 0 до 255
int32_t frequency = 10000;                                  // стартовое значение частоты в Гц
byte hag = 0;                                               // стартовое значение выбора режима
int mnog = 1;                                               // стартовое значение коэф. частоты
int flag = 0;                                               // стартовое флага
//*********************************************************************************************

// ********************************************************************************************
void setup()
{
  InitTimersSafe();                                         // инициализация таймеров

  //инициализация lcd *************************************************************************
  lcd.begin(16, 2);
  lcd.clear(); lcd. noCursor();
  //*******************************************************************************************
  
  // назначение портов ************************************************************************
  pinMode(OUT_1_PIN, OUTPUT);
  pinMode(OUT_2_PIN, OUTPUT);
  pinMode(LEFT_PIN, INPUT);
  pinMode(RIGHT_PIN, INPUT);
  pinMode(OK_PIN, INPUT);
  // ******************************************************************************************
  
  bool success_1 = SetPinFrequencySafe(OUT_1_PIN, frequency);                 // первоначальная установка частоты на первом выходе
  delay(50);
  bool success_2 = SetPinFrequencySafe(OUT_2_PIN, frequency);                 // первоначальная установка частоты на втором выходе
  delay(50);
  pwmWrite(OUT_1_PIN, PWM_1);                                                 // первоначальная установка ШИМ на первом выходе
  pwmWrite(OUT_2_PIN, PWM_2);                                                 // первоначальная установка ШИМ на втором выходе
  
  // вывод на экран *****************************************************************************
  lcd.setCursor(0, 0); lcd.print(frequency); lcd.print("Hz *   "); lcd.setCursor(15, 0); lcd.print(mnog);
  lcd.setCursor(0, 1);
  lcd.print("1PWM"); lcd.setCursor(4, 1); lcd.print(PWM_1);
  lcd.setCursor(9, 1);
  lcd.print("2PWM"); lcd.setCursor(13, 1); lcd.print(PWM_2);
}
  // ********************************************************************************************

 // основной цикл программы **********************************************************************
void loop()
{
  if ((digitalRead(LEFT_PIN) == HIGH) || (digitalRead(RIGHT_PIN) == HIGH)     // если нажата любая кнопка
      || (digitalRead(OK_PIN) == HIGH))
  {
    key();                                                                    // то вызов подпрограммы опроса кнопок
  }

  bool success_1 = SetPinFrequencySafe(OUT_1_PIN, frequency);                 // установка частоты на первом выходе
  delay(10);
  bool success_2 = SetPinFrequencySafe(OUT_2_PIN, frequency);                 // установка частоты на втором выходе
  delay(10);
  pwmWrite(OUT_1_PIN, PWM_1);                                                 // установка ШИМ на первом выходе
  pwmWrite(OUT_2_PIN, PWM_2);                                                 // установка ШИМ на втором выходе
}
//*************************************************************************************************

// подпрограмма опроса кнопок и установки частоты и скважности ************************************
void key()
{

  if (digitalRead(OK_PIN) == HIGH)                                          // если нажата кнопка ОК - перебор коэф. для частоты и ШИМ
  {
    switch (hag)
    {
      case 0:                                                               // выбор множителя частоты (1)
        lcd.setCursor(12, 0);
        lcd.print("   1");
        mnog = 1;
        flag = 0;
        break;

      case 1:                                                               // выбор множителя частоты (10)
        lcd.setCursor(12, 0);
        lcd.print("  10");
        mnog = 10;
        flag = 0;
        break;

      case 2:                                                               // выбор множителя частоты (100)
        lcd.setCursor(12, 0);
        lcd.print(" 100");
        mnog = 100;
        flag = 0;
        break;

      case 3:                                                              // выбор множителя частоты (1000)
        lcd.setCursor(12, 0);
        lcd.print("  1K");
        mnog = 1000;
        flag = 0;
        break;

      case 4:                                                              // выбор множителя частоты (5000)
        lcd.setCursor(12, 0);
        lcd.print("  5K");
        mnog = 5000;
        flag = 0;
        break;

      case 5:                                                              // выбор 1 канала для регулировки ШИМ
        lcd.setCursor(12, 0);
        lcd.print("1PWM");
        flag = 1;
        break;

      case 6:                                                               // выбор 2 канала для регулировки ШИМ
        lcd.setCursor(12, 0);
        lcd.print("2PWM");
        flag = 2;
        break;

      case 7:                                                                // перебор параметров по кругу
        flag = 0;
        break;
    }
    hag = hag + 1; delay(100);                                               // приращение счетчика 
    if (hag == 8) hag = 0;
  }

  if (flag == 0)                                                            // флаг выборов режима настройки ШИМ или частоты (по умолчанию флаг =0 - настройка частоты)
  {
    if (digitalRead(LEFT_PIN) == HIGH)                                      // если нажата кнопка ЛЕВО 
    {
      frequency = frequency - mnog;                                         // то уменьшение частоты на выбранный коэф.

      if (frequency < 0)                                                    // если частота меньше 0 
      {
        frequency = 0;                                                      // то частота =0
      }
      delay(100);                                                           // защита от дребезга
    }

    if (digitalRead(RIGHT_PIN) == HIGH)                                     // если нажата кнопка ПРАВО 
    {
      frequency = frequency + mnog;                                         // то увеличение частоты

      if (frequency  >= 99999)                                              // если частота больше 99 999 
      {
        frequency = 99999;                                                  // то частота = 99 999
      }
      delay(100);                                                           // защита от дребезга
    }
    lcd.setCursor(0, 0);                                                    // вывод на экран частоты
    lcd.print(frequency); lcd.print("Hz *   ");                             // вывод на экран
  }

  if (flag == 1)                                                            // флаг выборов режима настройки ШИМ 1
  {

    if (digitalRead(LEFT_PIN) == HIGH)                                       // если нажата кнопка ЛЕВО 
    {
      PWM_1 = PWM_1 - 5;                                                     // то уменьшение ШИМ на 5

      if (PWM_1 < 10)                                                        // если ШИМ меньше 10 
      {
        PWM_1 = 10;                                                          // то ШИМ = 10
      }
      delay(100);                                                            // защита от дребезга
    }

    if (digitalRead(RIGHT_PIN) == HIGH)                                      // если нажата кнопка ПРАВО то приращение ШИМ на 5
    {
      PWM_1 = PWM_1 + 5;

      if (PWM_1 > 255)                                                       // если ШИМ больше 255 
      {
        PWM_1 = 255;                                                         // то ШИМ = 255
      }
      delay(100); //Serial.print("PWM1= "); Serial.println(PWM_1);           // защита от дребезга
    }
  }

  if (flag == 2)                                                              // флаг выбора режима настройки ШИМ 2
  {

    if (digitalRead(LEFT_PIN) == HIGH)                                        // аналогично ШИМ первого канала
    {
      PWM_2 = PWM_2 - 5;
      if (PWM_2 < 10)
      {
        PWM_2 = 10;
      }
      delay(100);
    }

    if (digitalRead(RIGHT_PIN) == HIGH)
    {
      PWM_2 = PWM_2 + 5;
      if (PWM_2 > 255)
      {
        PWM_2 = 255;
      }
      delay(100);
    }
  }
  // вывод на экран ШИМ 1,2 ***************************************************************************
  lcd.setCursor(4, 1);
  if (PWM_1 < 100)
  {
    lcd.print("0"); lcd.print(PWM_1);
  }
  else
  {
    lcd.print(PWM_1);
  }

  lcd.setCursor(13, 1);
  if (PWM_2 < 100)
  {
    lcd.print("0"); lcd.print(PWM_2);
  }
  else
  {
    lcd.print(PWM_2);
  }
  //***************************************************************************************************
}