Управление частотой и скважностью ШИМ-сигнала

sadman41
Онлайн
Зарегистрирован: 19.10.2016

Напрямую с OneWire работайте, например, а не через DallasTemperature.

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

edcop пишет:

без delay? т.к. ds18b20 не дружит с delay. хоть примерно подскажите как

можно с delay. можно и без. Смотрите пример "блинк без delay"

а что это у вас "ds18b20 не дружит с delay" - у всех дружит, у вас нет? :) Как это "не дружит" -не понимаю этой фразы... датчику пофиг

edcop
Offline
Зарегистрирован: 23.07.2016

на сколько я помню, блинк никак не может управлять скважностью

sadman41 пишет:

Напрямую с OneWire работайте, например, а не через DallasTemperature.

У меня два датчика температуры и дисплей по SPI, плюс несколько релюшек и бузер. Ног в притык хватает.

sadman41
Онлайн
Зарегистрирован: 19.10.2016

Может, если своевременно менять...

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

edcop пишет:

на сколько я помню, блинк никак не может управлять скважностью

неправильно помните

если написать блинк включенный на 2сек, а выключенный на 8с - будет скважность 20%. А если включен и выключен по 5с - скважность 50%

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

edcop пишет:

У меня два датчика температуры и дисплей по SPI, плюс несколько релюшек и бузер. Ног в притык хватает.

сорри, "ИванВасильевич, когда вы говорите - такое впечатление, что вы бредите" (с)

какая связь с количеством ног?

У меня такое впечатление, что вы в своем проекте просто ни в зуб ногой. Может сначала учебники почитать7

edcop
Offline
Зарегистрирован: 23.07.2016

Сорри, я не программист. Иду по граблям и примерам, котрые нахожу. Примеры блинк находил только для скважности 50%, а чтобы ещё с функцией от температуры, так и близко ничего подобного. Что-то похожее было в библиотеке OneTimer, но там с переменными таймер не хотел работать. Пробовал Ticker для ESP, но там также зависимость от температуры не смог прикрутить.

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

edcop пишет:

Сорри, я не программист. Иду по граблям и примерам, котрые нахожу. Примеры блинк находил только для скважности 50%, а чтобы ещё с функцией от температуры, так и близко ничего подобного. Что-то похожее было в библиотеке OneTimer, но там с переменными таймер не хотел работать. Пробовал Ticker для ESP, но там также зависимость от температуры не смог прикрутить.

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

И поэтому самый правильный путь - учиться

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

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

Будут вопросы по коду - приходите. Только вопросы конкретные, а не просто "у меня не получилось"

edcop
Offline
Зарегистрирован: 23.07.2016

Подскажите, где почитать по решению такой нетривиальной задачи? Монка и Соммера штудировал, Виктора Петина также читал. Может коллеги по форуму могут не только мокать носом и отправлять по всем известному адресу (учиться)? Может у кого-то хватит терпения и желания написать пару строк, описывающих принцип?

sadman41
Онлайн
Зарегистрирован: 19.10.2016

Хорошо, Вы сумеете на четном проходе blink-а печатать в Serial букву A?

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

edcop пишет:

Подскажите, где почитать по решению такой нетривиальной задачи?

"нетривиальной" ? - издеваетесь?

Вот Вам стандартный блинк:

const int ledPin =  13;    
// Variables will change:
int ledState = LOW;             // этой переменной устанавливаем состояние светодиода
long previousMillis = 0;
long interval = 1000;           // интервал между включение/выключением светодиода (1 секунда)
 
void setup() {
  // задаем режим выхода для порта, подключенного к светодиоду
  pinMode(ledPin, OUTPUT);     
}
 
void loop()
{
  // здесь будет код, который будет работать постоянно
  // и который не должен останавливаться на время между переключениями свето
  unsigned long currentMillis = millis();
  
  //проверяем не прошел ли нужный интервал, если прошел то
  if(currentMillis - previousMillis > interval) {
    // сохраняем время последнего переключения
    previousMillis = currentMillis; 
 
    // если светодиод не горит, то зажигаем, и наоборот
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;
 
    // устанавливаем состояния выхода, чтобы включить или выключить светодиод
    digitalWrite(ledPin, ledState);
  }
}

 

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

Теперь далее. Интервал переключения задан переменной interval  -  переменной! - запомните это слово

Смотрим на код . В строках 24-27 у нас условный оператор - при включенном светодиоде выполняется одна ветвь, при выключенном другая. И раз мы уже запомнили. что interval - это переменная, то нам ничего не помешает при каждом переключении диода менять значение интервала. чтобы при выключенно оно было одно, а при включенном - другое.

Вот и все. В стандартный пример достаточно добавить две (ВСЕГО!) строчки. "Нетривиальный" код попробуйте написать сами

edcop
Offline
Зарегистрирован: 23.07.2016

В данном случае период будет 2*интревал. Мне нужно держать постоянным период, а управлять только скважностью.

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

edcop пишет:

Интервал - это период. Мне его менять не нужно. Мне нужно менять длительность импульса.

Посмотрите внимательно в код. Попробуйте подумать еще раз, ответ неверный.

 

 

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

Либо бросать это дело - не дано оно вам.

edcop
Offline
Зарегистрирован: 23.07.2016

Поправлюсь, в данном случае период будет 2*интревал. Мне нужно держать постоянным период, а управлять только скважностью. Для одной переменной будет скважность 50%, чтобы скважность менялась, нужно минимум две переменные, причём в сумме они должны давать период.

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

edcop пишет:

В данном случае период будет 2*интревал. Мне нужно держать постоянным период, а управлять только скважностью.

У нас интервал включения и интервал выключения - не равны. Поэтому период будет не 2*интревал, а (интервалON + интервалOFF). Изменяя соотвношение одного интервала к другому, но сохраняя их сумму неизменной - мы можем менять скважность, не меняя периода.

edcop
Offline
Зарегистрирован: 23.07.2016

Я об этом и говорил - две переменные (интервалON и интервал OFF).

edcop
Offline
Зарегистрирован: 23.07.2016
#include <OneWire.h>
#include<DallasTemperature.h> 
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature DS18B20(&oneWire);

const int ledPin =  13;   
#define ONE_WIRE_BUS 4 // DS18B20 подключаем на 4-й на плате

// Variables will change:
int ledState = LOW;             // этой переменной устанавливаем состояние светодиода
long previousMillis = 0;
long interval = 6000;           // начальная длительность импульса для периода 10 с
float temp_0;

void setup() {
  DS18B20.begin();
  pinMode(ledPin, OUTPUT);  // задаем режим выхода для порта, подключенного к светодиоду  
}

 void loop()

{
  // здесь будет код, который будет работать постоянно
  // и который не должен останавливаться на время между переключениями свето

  DS18B20.requestTemperatures(); 
  temp_0 = DS18B20.getTempCByIndex(0); // Sensor 0 показания для датчика 1 в цельсиях

  unsigned long currentMillis = millis();  //проверяем не прошел ли нужный интервал, если прошел то

  if(currentMillis - previousMillis < interval) 
{
  ledState = HIGH;
  digitalWrite(ledPin, ledState);
}

  if(currentMillis - previousMillis > interval && currentMillis - previousMillis < 10000) 
{
  ledState = LOW;
  digitalWrite(ledPin, ledState);
}

previousMillis = currentMillis;    // сохраняем время последнего переключения
interval = map (temp_0*10, 840, 930, 6000, 2500); 

}

 

Почти уверен, что не правильно, но тем не менее.

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

edcop пишет:

Почти уверен, что не правильно, но тем не менее.

угадали, неправильно.

Но меня в первую очередь поражает вот что - нафига вы в код температуру засунули? Я вас просил написать блинк с разными интервалами - но вы, вместо того чтоб разобраться, как это делать - сразу полезли температуру добавлять. В результате - не справились ни с первым, ни со вторым.  У вас и работа с интервалами неверная, и код температуры вы пишете на основе библиотеки Даллас, хотя сами же несколько раз писали. что эта библиотека с точными интервалами несовместима.

В общем, если хотите, чтобы я продолжил обьяснять вам эту тему - напишите мне блинк с периодом в 1 сек и скважностью 30%. Без ерунды с температурой - только чистый блинк.

Задача - элементарнейшая, добавить 2 строчки к базовому примеру. Если не справитесь - продолжать нет смысла. В этом случае будет правильнее заказть код стороннему программисту.

 

edcop
Offline
Зарегистрирован: 23.07.2016

const int ledPin =  13;   

// Variables will change:

int ledState = LOW;             // этой переменной устанавливаем состояние светодиода

long previousMillis = 0;

long interval = 300;           // интервал между включение/выключением светодиода (1 секунда)

void setup() {

  pinMode(ledPin, OUTPUT);    // задаем режим выхода для порта, подключенного к светодиоду

}

void loop()

{

  // здесь будет код, который будет работать постоянно

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

  unsigned long currentMillis = millis();
   
  if(currentMillis - previousMillis > interval) {  //проверяем не прошел ли нужный интервал, если прошел то

  previousMillis = currentMillis;  // сохраняем время последнего переключения

   if (ledState == LOW)   // если светодиод не горит, то зажигаем, и наоборот

      ledState = HIGH;

    else

      ledState = LOW;

   digitalWrite(ledPin, ledState);   // устанавливаем состояния выхода, чтобы включить или выключить светодиод

   interval = 1000 - interval;

  }


}

так правильно?

Green
Offline
Зарегистрирован: 01.10.2015

Упрощаем. Безо всяких ledState).  digitalWrite(ledPin, !digitalRead(ledPin));

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

да, хорошо, даже лучше. чем я ожидал. Обошлись всего одной строкой, а не двумя. Надеюсь, не подглядывали?

Единственное "но" - у вас получился ШИМ со скважностью 70%, а не 30, потому что вы перепутали местами периоды.  Думаю, Вы ошиблись потому, что считаете интервал снаружи условного оператора if (ledState...) и потому упустили, к какому периоду он относится..  Для наглядности лучше было бы поместить смену интервала в каждую ветку условного оператора - тогда вы могли бы четко устанавливать, какая задержка для включения, а какая для выключения.

Помещение вычисления скважности внутрь оператора if будет удобнее и для дальнейшего добавления расчета скважности от температуры - может попробуете переписать свой пример?

 

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

Green пишет:

Упрощаем. Безо всяких ledState).  digitalWrite(ledPin, !digitalRead(ledPin));

Грин, в данном случае это вредное упрощение. Нам нужны две ветки - одна для ( ledState == HIGH), другая LOW

sadman41
Онлайн
Зарегистрирован: 19.10.2016

unsigned long previousMillis, unsigned long interval. 

edcop
Offline
Зарегистрирован: 23.07.2016

А где можно было такое подлядеть? Разве бы я надоедал здесь, если бы нашёл решение раньше?


const int ledPin =  13;   

// Variables will change:

int ledState = LOW;             // этой переменной устанавливаем состояние светодиода

unsigned long previousMillis = 0;

unsigned long interval = 300;           // интервал между включение/выключением светодиода (1 секунда)

void setup() {

  pinMode(ledPin, OUTPUT);    // задаем режим выхода для порта, подключенного к светодиоду

}

void loop()

{

  // здесь будет код, который будет работать постоянно

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

  unsigned long currentMillis = millis();
   
  if(currentMillis - previousMillis > 1000 - interval) {  //проверяем не прошел ли нужный интервал, если прошел то

  previousMillis = currentMillis;  // сохраняем время последнего переключения

   if (ledState == LOW)   // если светодиод не горит, то зажигаем, и наоборот

    ledState = HIGH;
    interval = 1000 - interval;
    
  else

      ledState = LOW;
      interval = 1000 - interval;
  }

   digitalWrite(ledPin, ledState);   // устанавливаем состояния выхода, чтобы включить или выключить светодиод
 
}

 

Green
Offline
Зарегистрирован: 01.10.2015

b707 пишет:

Грин, в данном случае это вредное упрощение. Нам нужны две ветки - одна для ( ledState == HIGH), другая LOW

Там смайлик. Но и без ledState делается 2 ветки, если на то пошло.)

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

edcop пишет:

А где можно было такое подлядеть? Разве бы я надоедал здесь, если бы нашёл решение раньше?

Вы смеетесь? Думаете вы первый решаете эту простенькую задачку?

Вот, нашел менее чем за минуту:

https://forum.arduino.cc/index.php?topic=463958.0

и таких ссылок, если посикать - думаю не один десяток

edcop
Offline
Зарегистрирован: 23.07.2016

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

Кстати Arduino IDE ругнулась на отсутствие фигурных скобок после условий, т.к. далее исполняется больше одной команды.
В остальном всё правильно?

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

edcop пишет:

 

Кстати Arduino IDE ругнулась на отсутствие фигурных скобок после условий, т.к. далее исполняется больше одной команды.
В остальном всё правильно?

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

Строчку 34 запишите в явном виде

interval = 300;

это то, что я имел в виду. чтобы снова не перепутать HIGH и LOW

В остальном правильно.

Теперь заменив строку 34 на вычисление интервала как функции от температуры - вы решите свою задачу. Строку в ветке LOW, при этом, трогать не надо.

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

и да, для периода лучше ввести переменную или дефайн, а не кодировать ее явно в тексе программы

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

b707 пишет:

edcop пишет:

Кстати Arduino IDE ругнулась на отсутствие фигурных скобок после условий, т.к. далее исполняется больше одной команды.
В остальном всё правильно?

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

Лично я, ставлю фигурные при любом количестве команд, и ТС советую.

us__007
Offline
Зарегистрирован: 26.09.2013

us__007 пишет:

Всем добрый день.
Коллеги прошу помощи в решении задачи, суть ее такова нужно генерировать ШИМ на двух пинах с зависимой регулируемой скважностью и частотой, частота изменяется от от 20 до 200 Гц скважность как на картинке. суммарно заполнение обоих импульсов всегда 100%

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

const int ledPin =  11;   
const int ledPin2 =  12;


int analogPin_dcy = A0;
int analogPin_frq = A1;
unsigned long val_1 = 0;
unsigned long val_2 = 0;
unsigned long value_1 = 0;
unsigned long value_2 = 0;

// Variables will change:

int ledState = LOW;             // этой переменной устанавливаем состояние светодиода
int ledState2 = HIGH;

unsigned long previousMicros = 0;
unsigned long previousMicros_adc = 0;
unsigned long var_period = 0;

unsigned long duty_cycle = 0;           // интервал между включение/выключением светодиода (1 секунда)
unsigned long period = 1000000;

void setup() {

  pinMode(ledPin, OUTPUT);    // задаем режим выхода для порта, подключенного к светодиоду
  pinMode(ledPin2, OUTPUT);
  
}

void loop()

{

  // здесь будет код, который будет работать постоянно

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

  unsigned long currentMicros = micros();

  if(currentMicros - previousMicros_adc > period / 100) {  //проверяем не прошел ли нужный интервал, если прошел то

  previousMicros_adc = currentMicros;
 val_1 = analogRead(analogPin_dcy);
 val_2 = analogRead(analogPin_frq);
 val_2 = map(val_2, 0, 1023, 4, 50);
 value_2 = val_2 * 1000;
 val_1 = map(val_1, 0, 1023, 10, 90);
 value_1 = val_1 * value_2 / 100;
 period = value_2;

  }
   
  if(currentMicros - previousMicros > period - duty_cycle) {  //проверяем не прошел ли нужный интервал, если прошел то

  previousMicros = currentMicros;  // сохраняем время последнего переключения

   if (ledState == LOW)   // если светодиод не горит, то зажигаем, и наоборот
{
    ledState = HIGH;
    ledState2 = LOW;
    duty_cycle = value_1;
    duty_cycle = period - duty_cycle;
}   
  else
{
      ledState = LOW;
      ledState2 = HIGH;
      duty_cycle = period - duty_cycle;
}
  }

   digitalWrite(ledPin, ledState);   // устанавливаем состояния выхода, чтобы включить или выключить светодиод
   digitalWrite(ledPin2, ledState2);

}

 

us__007
Offline
Зарегистрирован: 26.09.2013

Вот версия с dead time
 

const int ledPin =  11;   
const int ledPin2 =  12;
int st1 = 1;


int analogPin_dcy = A0;
int analogPin_frq = A1;
unsigned long val_1 = 0;
unsigned long val_2 = 0;
unsigned long value_1 = 0;
unsigned long value_2 = 0;


// Variables will change:

int ledState = LOW;             // этой переменной устанавливаем состояние светодиода
int ledState2 = LOW;

unsigned long previousMicros = 0;
unsigned long previousMicros_adc = 0;
unsigned long var_period = 0;

unsigned long duty_cycle = 25000;           // интервал между включение/выключением светодиода (1 секунда)
unsigned long period = 500000;
unsigned long dead_time = 100;

void setup() {

  pinMode(ledPin, OUTPUT);    // задаем режим выхода для порта, подключенного к светодиоду
  pinMode(ledPin2, OUTPUT);
  
}

void loop()

{

  // здесь будет код, который будет работать постоянно

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

  unsigned long currentMicros = micros();

  if(currentMicros - previousMicros_adc > period / 10) {  //проверяем не прошел ли нужный интервал, если прошел то

  previousMicros_adc = currentMicros;                       // сохраняем время последнего замера ацп
 val_1 = analogRead(analogPin_dcy);                         // измеряем переменник регулирующий скважность
 val_1 = map(val_1, 0, 1023, 10, 90);                       // масштабируем переменную скважности от 10 до 90%
 
 val_2 = analogRead(analogPin_frq);                         // измеряем переменник регулирующий частоту
 val_2 = map(val_2, 0, 1023, 4, 50);                        // масштабируем переменную частоты от 4 до 50 мс
 period = val_2 * 1000;                                    // присваеваем переменной периода переменную частоты домноженную 

 
 value_1 = val_1 * period / 100 - dead_time;                           // присваеваем переменной
 value_2 = period - value_1 - dead_time;

  }
   
  if(currentMicros - previousMicros > duty_cycle) {  //проверяем не прошел ли нужный интервал, если прошел то

  previousMicros = currentMicros;  // сохраняем время последнего переключения
switch (st1) {
    case 1:      //выполняется, когда st1 равно 1
    ledState = HIGH;
    ledState2 = LOW;
    duty_cycle = value_1;
    st1 = 2;
      break;
      
    case 2:      //выполняется когда  st1 равно 2
    ledState = LOW;
    ledState2 = LOW;
    duty_cycle = dead_time;
    st1 = 3;
      break;

    case 3:      //выполняется когда  st1 равно 3
    ledState = LOW;
    ledState2 = HIGH;
    duty_cycle = value_2;
    st1 = 4;
      break;
      
    case 4:      //выполняется когда  st1 равно 4
    ledState = LOW;
    ledState2 = LOW;
    duty_cycle = dead_time;
    st1 = 1;
      break;
  }
   
  }

   digitalWrite(ledPin, ledState);   // устанавливаем состояния выхода, чтобы включить или выключить светодиод
   digitalWrite(ledPin2, ledState2);

}