Перейти к содержанию
    

Функция расчета period и prescaler таймера

Требуется

Функция расчета period и prescaler таймера для пересчета в run-time. STM32


Вообще-то, период (или результирующая частота) - это исходное данное вместе с тактовой частотой.
У вас что в наличии? Ну и поделить для 32-битного ядра уж много лет, кмк, не проблема ;-)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

21.03.2022 в 02:09, Eddy_Em сказал:

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

К чему это сводится, как это написать известно. В том числе что простые тут ни причем, а причем целые. И что задача называется факторизация. И что она решается не столь примитивно (перебором, "подобрать"), что это типичная задача минимизации. Спасибо, но вопрос (если внимательно прочесть) был о готовой C функции. Дело во времени. Теплилась слабая надежда что хоть в интернете днем с огнем не найти, но может быть у кого-то из професисоналов завалялась...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Самый простой способ — тупой перебор (как здесь или здесь), а вообще, гугол по запросу "arr psc calculation" дает очень много интересного. Советую посмотреть.

Я и сам когда-то подобное делал, тоже ничего, лучше перебора, не придумал. А в задачах регулирования скорости шаговиков, делаю просто: PSC выдает максимально возможную частоту, а ARR уже вычисляется по заданной скорости. Потом происходит персчет и пользователю возвращается реальное значение скорости.

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

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

Изменено пользователем Eddy_Em

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <time.h>

uint16_t factorize1(uint32_t in, uint16_t *o1, uint16_t *o2, uint16_t *niter){
    uint16_t min = 0xffff, minI = 2, i;
    *niter = 0;
    for(i = 2; i < 0xffff; ++i){
        ++(*niter);
        uint32_t a = in/i;
        if(a > 0xffff) continue;
        uint16_t d = abs(in - i*a);
        if(d < min){
            min = d; minI = i;
        }
        if(min == 0) break;
    }
    *o1 = in/minI;
    *o2 = minI;
    return min;
}
uint16_t factorize2(uint32_t in, uint16_t *o1, uint16_t *o2, uint16_t *niter){
    if(in < 0xffff){
        *o1 = 1; *o2 = (uint16_t) in; return 0;
    }
    uint16_t x = 0x8000, d = 0;
    while(d < 2){
        d = in/x;
        x >>= 1;
    }
    if(d < x) d = x;
    uint16_t min = 0xffff, minI = 2, i;
    *niter = 0;
    for(i = d; i < 0xffff; ++i){
        ++(*niter);
        uint32_t a = in/i;
        if(a > 0xffff) continue;
        uint16_t d = abs(in - i*a);
        if(d < min){
            min = d; minI = i;
        }
        if(min == 0) break;
    }
    *o1 = in/minI;
    *o2 = minI;
    return min;
}

int main(int argc, char **argv){
    uint64_t n1 = 0, n2 = 0, p1 = 0, p2 = 0;
    double N = 0.;
    time_t t = time(NULL);
    //for(uint32_t i = 1; i < 0xffffffff; ++i){
    while(1){
        ++N;
        uint32_t i = lrand48() & 0xffffffff;
        uint16_t n, o1, o2;
        p1 += factorize1(i, &o1, &o2, &n);
        n1 += n;
        p2 += factorize2(i, &o1, &o2, &n);
        n2 += n;
        if(time(NULL) - t > 2){
            t = time(NULL);
            printf("n1=%lu, n2=%lu\n", n1, n2);
            printf("1: <p> = %g, <n> = %g\n", p1/N, n1/N);
            printf("2: <p> = %g, <n> = %g\n", p2/N, n2/N);
        }
    }
    return 0;
}

Вот, оно у меня уже больше минуты тарахтит, выдает:

n1=33788041246, n2=15611890071
1: <p> = 2.25199, <n> = 50895.8
2: <p> = 76.721, <n> = 23516.6

Т.е. среднее количество итераций в первом случае - около 51 тысячи. Во втором - около 23.5 тысяч. Однако, погрешность в первом случае лучше трех, а во втором - хуже 75! Второй "алгоритм" допускает приличную погрешность даже для небольших чисел. Но 51 тысяча операций деления и умножения — это, конечно, нечто! Надо пробовать через сдвиги как-то упрощать. В простейшем случае - использовать первую функцию, но начальный итератор вычислять, деля входное число на 0xffff. (тогда и проверку (a>0xffff) можно убрать)

Изменено пользователем Eddy_Em

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

...оно у меня уже больше минуты тарахтит, выдает... 51 тысяча операций деления и умножения


"Три дня и три ночи скакал Иван Царевич... покуда скакалку не отобрали." \-8Ж

Коэффициенты допустимы ж не на всём диапазоне...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Можно и точность задавать в явном виде:

uint16_t factorize(uint32_t in, uint16_t prec, uint16_t *o1, uint16_t *o2){
    uint16_t min = 0xffff, minI = 2, i;
    uint16_t start = (uint16_t)(in / 0xffff);
    if(start < 2) start = 2;
    for(i = start; i < 0xffff; ++i){
        uint32_t a = in/i;
        if(a > 0xffff) continue;
        uint16_t d = abs(in - i*a);
        if(d < min){
            min = d; minI = i;
        }
        if(min < prec) break;
    }
    *o1 = in/minI;
    *o2 = minI;
    return min;
}

prec можно вычислять по заданной точности и в самой функции. Скажем, если точность 1%, то prec=1+in/100

Изменено пользователем Eddy_Em

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну, в общем, всё перебором закончилось :biggrin:

24.03.2022 в 16:38, Eddy_Em сказал:

А в задачах регулирования скорости шаговиков

А вот это интересно.

С таймерами STM32 я доселе дело имел поверхностно, сигнал генерировал, но без тщания. :wink2:

Количество импульсов сигнала STEP и управление "полками" было реализовано программно. Прерывание по таймеру, все остальное программно. ISR всегда приводило уровень на выходном порте в гарантированно известное состояние, так как недопустимо потерять пол-импульса (полку), а также необходимо останавливать двигатель строго в определенных фазах микростеппинга и на определенной полке.

Хочется выдавать STEP полностью аппаратно.  Иной кандидатуры кроме как аппаратный вывод таймера пока не усматриваю.
В связи с чем и вопрос.

Таймеры STM32 это целая вселенная.  Тщательная вычитка документации, изучение либ типа Marlin сама по себе задача не на один день.
Мне бы для экономии времени получить бы добрый совет, на каком именно типе таймера сосредоточиться, какие есть методы управления и подводные камни?  Может быть на что-то глянуть, короче, нужна какая-то отправная точка с таймерами и предсказуемым управлением выходом таймера для того чтобы получать строго определенное колчество импульсов STEP ШД и приводить вывод в известное состояние.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, std сказал:

для того чтобы получать строго определенное колчество импульсов STEP ШД и приводить вывод в известное состояние.

Ну "приводить вывод в известное состояние" довольно просто - надо использовать режим ШИМ(PWM). В конце периода он в строго определенном состоянии. Строго определенное количество импульсов - подсчетом в прерывании. Я не знаю что у вас за задача, когда я писал контроллер шагового двигателя, у меня в любой момент могла прилететь команда на разгон/торможение и ждать "строго определенного количества импульсов" было просто нельзя. Поэтому я считал импульсы в прерывании сответствующего канала таймера. 

P.S. для реализации (почти) линейного разгона/торможения шагового двигателя вам может быть полезна эта статья: Generate stepper-motor speed profiles in real time.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

8 часов назад, Сергей Борщ сказал:

Ну "приводить вывод в известное состояние" довольно просто - надо использовать режим ШИМ(PWM). В конце периода он в строго определенном состоянии. Строго определенное количество импульсов - подсчетом в прерывании. Я не знаю что у вас за задача, когда я писал контроллер шагового двигателя, у меня в любой момент могла прилететь команда на разгон/торможение и ждать "строго определенного количества импульсов" было просто нельзя. Поэтому я считал импульсы в прерывании сответствующего канала таймера. 

P.S. для реализации (почти) линейного разгона/торможения шагового двигателя вам может быть полезна эта статья: Generate stepper-motor speed profiles in real time.

Спасибо!
Буду знать.
Правда если я буду подсчитывать импульсы в прерывании (я же правильно понял что каждый импульс STEP - прерывание?), то прерывания в режиме микростеппинга 1/32...1/256 идут очень часто и будут все равно грузить процессор. А я хотел этого избежать, целиком полагаясь на аппаратуру таймера.
Подсчитывать импульсы необходимо, поскольку в новом конструктиве хоть и будет угловой энкодер, часть старых конструкций в начале калибруется по оптическому датчику и затем поддерживает положение ротора ШД, полагаясь только на количество шагов.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Генерирую ШИМ: по 1 таймеру на двигатель. В прерывании CCEV считаю микрошаги, если получилось целое количество шагов, проверяю — не пора ли остановиться (нет смысла тормозить двигатель в неустойчивых положениях между шагами, а напряжение удержания я всегда снимаю: не хватало  еще, чтобы внутри оптических приборов была печка!). Вот - одна из моих недоделок (все оси пока работают независимо, для меня этого полностью хватает, но если соберусь ЧПУ делать, нужно тактировать все шаговики от одного таймера и заменить STM32F0 на F303 — иначе "мощей не хватит"). Умеет работать с USB (простой удобный текстовый протокол: просто открываешь терминал и пишешь команды/читаешь ответ) и CAN (тоже нормальный протокол, не извращенный вроде CANopen). На каждой оси сидит энкодер, позволяющий в т.ч. удерживать вал в заданном положении, если его кто-то начнет сдвигать с места. Правда, от люфтов это на гайка-винт не избавит (но линейные энкодеры дюже громоздкие и дорогие), но мне несложно в лабораторных условиях определить величину люфта и потом его программно выбирать, аналогично с гнутием осей.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 4/1/2022 at 7:14 AM, Eddy_Em said:

но если соберусь ЧПУ делать, нужно тактировать все шаговики от одного таймера и заменить STM32F0 на F303 — иначе "мощей не хватит")

а как вы собираетесь исполнять программу? есть axis manager?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Нет, этого я еще не писал. По идее, на гитхабе есть разнообразные парсеры. Другое дело, что они скорей всего для моего случая не будут годиться, в общем, наверняка придется свое писать.

Если от парсера не требовать сложных вещей (только движение по отрезкам с заданной предельной скоростью), реализуется он достаточно элементарно. Возможно, даже F0 хватит. А вот если требовать самостоятельно по коническим сечениям бегать, придется задействовать F303 и долго думать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

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

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...