Вопросы по библиотеке GyverTimers

fryn3

✩✩✩✩✩✩✩
18 Мар 2020
1
0
Привет ребята, спасибо за вашу работу.
При использовании GyverTimers, столкнулся с проблемой, что не могу подключить библиотеку к своей библиотеке. Возникала ошибка множественного объявления ф-ций, которые не являются inline. Для решения этой ошибки, сделал GyverTimers.cpp файл и кинул туда реализацию ф-ции setPeriod. Ф-ции setFrequency, setFrequencyFloat сделал inline. Все заработало.

Сделал ветку от вашего репозитория и выложил изменения: https://github.com/fryn3/GyverLibs.
Рано написал, что все заработало. Попробовал запустить "Простой пример с прерываниями". На осциллографе вижу частоту 30 Гц.
Не реагирует на изменение строчки:

C++:
Timer2.setPeriod(6 *  1000000);
Помогите!
 
Изменено:

Artyom_roboti

✩✩✩✩✩✩✩
22 Мар 2020
28
0
Кто разобрался с этой библиотекой, помогите мне, пожалуйста, понять её
 

AlexGyver

★★★★★★✩
Команда форума
30 Июл 2018
359
574
@fryn3, спасибо, мы тоже уже давно разделили код на h и cpp
 

fsdb

✩✩✩✩✩✩✩
4 Авг 2020
1
0
Друзья товарищи помогите с библиотекой вашей GyverTimers.h
у меня ардуино мега. как генерировать сигнал на шаговый двигатель. дайте пример пожалуйста
я думал просто 9 пин и землю использовать. куда мне теперь подключать провода. совсем не понятно. дайте скетч пожалуйста. от 1герца. целые числа для ардуино мега и куда провода цеплять
 

AlexGyver

★★★★★★✩
Команда форума
30 Июл 2018
359
574
Друзья товарищи помогите с библиотекой вашей GyverTimers.h
у меня ардуино мега. как генерировать сигнал на шаговый двигатель. дайте пример пожалуйста
я думал просто 9 пин и землю использовать. куда мне теперь подключать провода. совсем не понятно. дайте скетч пожалуйста. от 1герца. целые числа для ардуино мега и куда провода цеплять
читай описание библиотеки, все пины расписаны
 

Ягорка

✩✩✩✩✩✩✩
21 Мар 2025
13
0
Всем привет.
В общем, для моего проекта требуется меандр, с возможностью двигать фазу сигнала. Но возникла проблема: почему-то сдвиг фазы в GyverTimers работают некорректно. То есть, двигатся, но не так и не туда.
Код простой, чисто попробовать возможности библиотеки:

C++:
#include "GyverTimers.h"
void setup() {
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);

  Timer1.setFrequency(250);

  Timer1.outputEnable(CHANNEL_A, TOGGLE_PIN);
  Timer1.outputEnable(CHANNEL_B, TOGGLE_PIN);
  Timer1.outputState(CHANNEL_A, HIGH);
  Timer1.outputState(CHANNEL_B, HIGH);
  Timer1.phaseShift(CHANNEL_A, 0);
  Timer1.phaseShift(CHANNEL_B, 0);
}
void loop() {}
Меняю фазу в канале В, и на выходе какая-то ерунда: сигнал толи инвертируется, толи сдвигается на 180 град и дополнительный сдвиг, вдвое меньше указанного в скетче. Немного пояснений к фото:
Канал Б засинхронизирован от канала А
1. Канал А, фаза 0.
2. Канал Б, фаза 0.
3. Канал Б, фаза 5.
4. Канал Б, фаза 90.
5. Канал Б, фаза 180.
фазы.jpg

Надеюсь, бывалые и опытные подскажут, в чем проблема и как это исправить.
 

Bruzzer

★★★✩✩✩✩
23 Май 2020
591
177
У вас частота 250. Но это не частота меандра, а частота срабатывания (прерываний) таймера, соответственно частота меандра в 2 раза меньше 125. что и видно на фото экрана.
Вы ожидаете сдвиг фазы для частоты 125 а библиотека двигает фазу для частоты срабатывания таймера т.е. 250. Поэтому сдвиг в мс в два раза меньше.
 

Ягорка

✩✩✩✩✩✩✩
21 Мар 2025
13
0
Да, я понимаю, что частота вдвое меньше, но о том, что и фазовый сдвиг будет делиться на два, как-то не подумал. Неочевидно это у Гайвера в уроке по прерываниям. Получается, что в диапазоне 0-360 максимальный сдвиг будет 180.

Сейчас попытался представить как оно работает.
Значит число, принимаемое за фазу, это не фаза как таковая, а некое значение в которое пересчитано количество мкс до нового прерывания, относительно значения частоты. Т.е., 250 прерываний в секунду, есть сигнал с полупериодом 4000 мкс. Этот полупериод делится на 360 условных значений градусов, что есть ок. 11 мкс на условный градус. Соответственно, когда я ввожу, например, 90 градусов, то это означает, что состояние выхода будет переключено через 1000 мкс. Иначе, 1/4 от времени между прерываниями или 1/8 от полного периода, что на полном периоде выглядит как 45 град.
Соответственно, если изначальное состояние выхода "высокий уровень", то переключение в "низкий уровень" через некоторое кол-во мкс будет выглядеть как инверсия с небольшим фазовым сдвигом. А при значении 0 такого не происходит. Получается, регулировка от нуля невозможна. Нужно устанавливать на оба канала некое отличное от нуля значение фазы, которое будет относительным нулем для регулировки.

Ну, как-то так у меня в голове сложилось. Если что не так - поправьте.
 
Изменено:

Bruzzer

★★★✩✩✩✩
23 Май 2020
591
177
@Ягорка,
В предыдущем ответе я не обратил внимание на инверсию.
Разбираться с библиотекой лень. Запустил в симуляторе. Действительно библиотека глючная.
Timer1.phaseShift(CHANNEL_B, 10); в зависимости от предыдущего значения может привести к разным результатам "правильному" и инвертированному. Если сразу после старта передавать по очереди 10 потом 20 потом 30 ... то работает нормально, но при каком то условии происходит сбой. Может исправить легко, я в код не смотрел.
Код который я запускал:
#include "GyverTimers.h"
void setup() {
  Serial.begin(9600);
  Serial.setTimeout(10);
  Serial.println("--START--");

  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);

  Timer1.setFrequency(250);

  Timer1.outputEnable(CHANNEL_A, TOGGLE_PIN);
  Timer1.outputEnable(CHANNEL_B, TOGGLE_PIN);
  Timer1.outputState(CHANNEL_A, HIGH);
  Timer1.outputState(CHANNEL_B, HIGH);
  Timer1.phaseShift(CHANNEL_A, 0);
  Timer1.phaseShift(CHANNEL_B, 0);
}
void loop() {
  if (Serial.available()) {
    int i = Serial.parseInt(); // Получаем значение угла в градусах (если надо 0, то передаем -1)
    if (i == 0)       // 0 возвращается и в случае ошибки. Поэтому если надо передать 0, то передаем его как -1
      return;
    if (i == -1)      // 0 передаем как -1
      i = 0;
    Serial.println(i);  // Сообщаем какой угол будем устанавливать
    Timer1.phaseShift(CHANNEL_B, i);
  }
}

Дополнено позже. Хотя может это не глюк, а особенность, которую надо учитывать. Время прерывания ведь сдвигается правильно, а какой там получится фронт при инициализации или изменении, возможно надо дополнительно указать.
Дополнено еще позже. В этой библиотеке используется CTC режим, и если обновление OCR1B произошло в неудачное время, то добавится "лишнее" срабатывание, и сигнал инвертируется.
 
Изменено:

poty

★★★★★★✩
19 Фев 2020
3,459
986
@Ягорка, предлагаю вывести два луча или, если не поддерживает осциллограф, вывести разницу между двумя каналами. Что заметил: осциллограф настроен на срабатывание по фронту, но по факту на картинках этого не происходит. Почему? Либо он синхронизируется на что то ещё, и тогда понятна эта катавасия, либо что-то неправильно подключено.

@Ягорка, не так. Таймер работает с определенной частотой, определяемой делителями. С этой частотой изменяется счётчик. Есть несколько "событий", по которым счётчик может обнулиться. Делители - очень грубый механизм, "тюнинг" возможен с помощью двух регистров (условно "A" и "B"). Насколько я помню, регистр А используется для тюнинга (то есть, по достижению значения в А счётчик обнуляется и можно запрограммировать влияние этого события на выходной пин). Если в регистр В записать число от 0 до А, то выходной пин, привязанный к этому регистру, будет изменяться с задержкой, определяемой делителем и этим числом. Это и есть сдвиг фазы.
 

Ягорка

✩✩✩✩✩✩✩
21 Мар 2025
13
0
Казалось, я все понял, но оказалось что ничего не понял. :) Но, попытаюсь осмыслить позже, если ума хватит.:rolleyes:
@poty, Я не совсем понял, чем не понравился осциллограф. Канал Б засинхронизирован от канала А, и на картинках именно разница между А и Б, относительно А.
@Bruzzer, Мне кажется я наблюдаю такой же эффект. Дописал (как смог) регулировку угла сдвига фазы потенциометром. Двигает (хоть и не в ту сторону), но в какой-то рандомный момент во время регулировки может происходить (а может и не происходить) инвертирование сигнала. Что недопустимо.
C++:
// Генерация двух меандров, сдвинутых на 90 градусов
// Для ATmega328p Timer1 CHANNEL_A pin D9, CHANNEL_B pin D10
//CHANNEL_A pin D9 канал Y, CHANNEL_B pin D10 канал Х

#include <GyverTimers.h>

int phase_Y_in = 20; //начальная фаза канала Y - относительный 0 град
int phase_X_in = 200; //начальная фаза канала Х - относительный 0 + 180 (+90 град)
int phase_Y;   //фаза канала Y
int phase_X;  //фаза канала Х
#define GB 14 // ручка ГБ подключена в 14 пин (А0) (назначить пин 14 как GB)
int val_GB; //переменная для хранения значений с регулятора ГБ

void setup() {
  Serial.begin(9600);
  Serial.println("CHANNEL_A,CHANNEL_B");

  pinMode(9, OUTPUT);                           // настроить пин как выход (канал Y)
  pinMode(10, OUTPUT);                          // настроить пин как выход (канал X)
  pinMode(GB, INPUT);                          // настроить пин GB как вход
 
  Timer1.setFrequency(250 * 2);                 // n*2 настроить частоту в Гц и запустить таймер. Меандр.
  Timer1.outputState(CHANNEL_A, HIGH);          // начальное состояние пина D9, высокий уровень
  Timer1.outputState(CHANNEL_B, HIGH);           // начальное состояние пина D10, высокий уровень
  Timer1.outputEnable(CHANNEL_A, TOGGLE_PIN);   // в момент срабатывания таймера пин будет переключаться
  Timer1.outputEnable(CHANNEL_B, TOGGLE_PIN);   // в момент срабатывания таймера пин будет переключаться
}
void loop() { //вывод графика в плоттер
  Serial.print(digitalRead(9));
  Serial.print(',');
  Serial.println(digitalRead(10));

  Timer1.phaseShift(CHANNEL_A, phase_Y);        //сдвиг фазы
  Timer1.phaseShift(CHANNEL_B, phase_X);        //сдвиг фазы

  val_GB = analogRead(GB);              //переменной val_GB присвоено значение, считанное с аналогово входа GB
  val_GB = map(val_GB, 0, 1023, 0, 90); //диапазон 0-1023 со входа ГБ пересчитан в диапазон 0...90 (0...45град)
  val_GB = constrain(val_GB, 0, 90);    //диапазон ограничен 0...90 (0...45град)

  phase_Y = phase_Y_in + val_GB;
 }

Все же, надеюсь на рабочий совет. Конечно, можно прописать фиксированную фазу, и крутить ее внешними фазосдвигающими цепями. Но мне принципиально хочется как можно больше функций внешней аналоговой рассыпухи запихнуть внутрь МК.
Только, совет попроще, пожалуста. Для человека, который всего несколько дней назад впервые начал заниматься программированием, и так сказать, сразу "с места в карьер".
 

bort707

★★★★★★✩
21 Сен 2020
3,176
934
в какой-то рандомный момент во время регулировки может происходить (а может и не происходить) инвертирование сигнала. Что недопустимо.
не совсем понятно как можно говорить об инвертировании, если у вас положительный сигнал с заполнением 50%. Для такого сигнала это не "инвертирование", а просто сдвиг фазы на 180. Понятно, что если вы меняете фазу потенциометром, в какой-то момент фаза лостигнет 180 гр и сигнал "инвертируется", это совершенно нормально.

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

Ягорка

✩✩✩✩✩✩✩
21 Мар 2025
13
0
Не буду спорить о терминах. Факт в том, что это происходит вне зависимости от положения движка переменника, т.е. вне зависимости от выставленной переменником фазы. Но, насколько могу судить, только в момент регулировки.
И 180 градусов там нет. Разница между каналами А и Б 90 град, потенциометр двигает в пределах 45 град, так что максимальная разница только 135 градусов.
 

poty

★★★★★★✩
19 Фев 2020
3,459
986
Канал Б засинхронизирован от канала А, и на картинках именно разница между А и Б, относительно А
Тогда непонятно, что мешает вывести сразу два канала? Тогда прояснилось бы (надеюсь) в чём проблема. Сейчас мы додумываем то, что Вы предполагаете что сделали.
Timer1.phaseShift(CHANNEL_A, phase_Y); //сдвиг фазы
Timer1.phaseShift(CHANNEL_B, phase_X); //сдвиг фазы
для Atmega 328p в описании библиотеки написано, что можно менять фазу только канала B.
 

Ягорка

✩✩✩✩✩✩✩
21 Мар 2025
13
0
А как мне вывести сразу два канала на одноканальном осциллографе? Я не представляю иного способа, как только смотреть каналы по очереди, используя внешнюю синхронизацию, для того чтобы увидеть сдвиг одного относительно другого.
В описании библиотеки указано, что для 16-бит таймеров можно двигать все каналы. И в примерах Гайвера такое есть, каналы А и Б для Таймер1.
 

bort707

★★★★★★✩
21 Сен 2020
3,176
934
как мне вывести сразу два канала на одноканальном осциллографе?
никак. Такие вещи надо смотреть на двух каналах и проще всего это делать не на осциле, а на логик анализаторе, 6-канальный стоит всего-то 300-500 рублей


В описании библиотеки указано, что для 16-бит таймеров можно двигать все каналы.
Слушайте, из чистой логики между двумя величинами ВСЕГО ОДНА РАЗНИЦА. Поэтому чтобы иметь сдвиг фазы одного канала относительно другого, достаточно двигать только канал Б.

Инфа 100 % :)
 

Ягорка

✩✩✩✩✩✩✩
21 Мар 2025
13
0
Не понимаю к чему относится Ваш комментарий. Ни в коде, ни во время измерений осциллографом я не двигал канал А относительно канала Б (хотя это планировалось в будущем). Канал А использован в качестве опорного и относительно него и производился необходимый мне сдвиг фазы и соответствующие измерения.

Пожалуй, я все-таки фазовращатели на рассыпухе спаяю. Это проще и быстрее, чем разбираться в проблемах библиотеки. Тем более, что мне все-таки нужен таймер с тремя каналами (один опорный и два крутить), а на 328 такого нет.
 

bort707

★★★★★★✩
21 Сен 2020
3,176
934
нужен таймер с тремя каналами... на 328 такого нет.
на 328й три таймера, можно взять два канала с одного и один с другого. Или даже по таймеру на каждый канал.
Народ, вон трехфазный инвертор умудряется собрать на этом камне, а там 6 каналов одновременно

Если мало 328й, возьмите любой простенький СТМ32. Там таймеры 4х-канальные

Это проще и быстрее, чем разбираться в проблемах библиотеки.
я вам выше написал, сделайте вообще без библиотеки. Там нет ничего сложного
 

Bruzzer

★★★✩✩✩✩
23 Май 2020
591
177
@Ягорка,
Можно посмотреть (попробовать). Человек пишет, что сделал, с некоторыми ограничениями - нестабильность в момент изменения.
 

Ягорка

✩✩✩✩✩✩✩
21 Мар 2025
13
0
можно взять два канала с одного и один с другого.
На Таймер0 сидят функции времени, а на Таймер3 функция tone (которую я тоже планировал использовать). Чую, что понадобятся костыли, чтобы все это не конфликтовало и корректно работало одновременно с генерацией меандра.
сделайте вообще без библиотеки. Там нет ничего сложного
Вы забываете, что программированием я занимаюсь всего несколько дней, и это мой первый в жизни код. Для меня сложно все, что не есть готовое решение с подробно разжеванным объяснением. Собственно, поэтому я и пришел к урокам и библиотекам Гайвера.
 

Bruzzer

★★★✩✩✩✩
23 Май 2020
591
177
есть готовое решение с подробно разжеванным объяснением.
Наверняка в инете есть такие решения. Но их надо искать, и у них могут быть свои ограничения - особенности. Например решение которое я привел выше подробно объяснено. НО решение основано на остановке таймера его сбросе и запуске с новыми параметрами. Поэтому при смене фазы ломается меандр не только на канале B но и на канале A. Возможно библиотекой Гайвера тоже можно сделать через стоп инициализация старт, но скорее всего это недопустимо по условиям задачи.
Я не разделяю мнение bort707 , что эту задачу точно можно реализовать на 328. Зависит от дополнительных условий. Какая максимальная частота, какой джиттер допустим, в каких пределах меняется сдвиг, с каким шагом он меняется. И в результате самостоятельное программирование получается не для новичка ИМХО.
 

bort707

★★★★★★✩
21 Сен 2020
3,176
934
Я не разделяю мнение @bort707 , что эту задачу точно можно реализовать на 328.
Думаю что сдвиг двух каналов можно, причем в довольно большом диапазоне частот. Очевидно, и частота, и фаза, и джиттер - будут зависеть от возможностей таймера.

Хотя если ТС только начинает программировать, то эта задача не для него. Закажите код программисту или обратитесь к ИИ.


Насчёт трёх каналов сложнее, я бы на другом МК делал, стм32
 
Изменено: