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

Сергей Борщ

Модератор
  • Постов

    10 908
  • Зарегистрирован

  • Посещение

  • Победитель дней

    31

Сообщения, опубликованные Сергей Борщ


  1. 1 час назад, MPetrovich сказал:

    Но это как то расточительно - шесть каналов ШИМ на три фазы, да и нет столько в МК...

    Есть их столько: OC0, OC1A, OC1B, OC1C/OC2, OC3A, OC3B, OC3C.  Даже один на плавное включение светодиода остается 🙂. И все четыре таймера можно запустить одновременно, т.е. синхронно через SFIOR.TSM.

  2. 19 часов назад, MPetrovich сказал:

    Я взял и засунул в это прерывание задержку 1мкСек

    Рука-лицо. Прерывания созданы для того, чтобы быстро отреагировать на какое-то аппаратное событие. У AVR одноуровневая система прерываний и пока это прерывание не закончится - остальные не смогут выполняться. Поэтому их стараются сделать как можно короче - чтобы минимизировать влияние одних прерываний на другие. По этой же причине и управлять транзисторами, дергая ногу в прерывании - очень плохая идея, потому что дерганье этой ноги может быть непредсказуемо задержано, если в момент возникновения запроса на прерывание выполнялся обработчик другого прерывания или прерывания были запрещены в основном цикле (а их нужно запрещать на время доступа к многобайтным переменным, используемым и в основном цикле и в прерываниях). Для дерганья ногой в строго определенные моменты времени у таймеров в модуле compare есть режимы "Clear OCnA/OCnB/OCnC on compare match" и "Set OCnA/OCnB/OCnC on compare match".

    19 часов назад, MPetrovich сказал:

    Но отчего то эта задержка отсутствует при генерации ШИМ.

    Трудно сказать, но вы учитываете, что в некоторых режимах ШИМ новое значение OCRx вступает в силу только в следующем цикле таймера?

    image.thumb.png.0b08646170b2949c9638516bfd01395b.png

    • Upvote 1
  3. 3 часа назад, Arlleex сказал:

    Ну тогда он итак знал, что возьмет вас на работу, ибо ответ в стиле

    Цитата

    Я не знаю правильный ответ, но это говнокод. Так писать нельзя и я так не пишу.

    бесспорно, мощный, но навыков не показывает.

    Однако показывает решимость получать при необходимости новые знания, а это гораздо ценнее.

  4. Модератор: Oleg.normalniy, освежите знания правил форума. Нецензурная и грубая лексика тут запрещена и требование высказываться грамматически правильно там тоже прописано. Ваши нарушающие правила сообщения скрыты.

  5. 31 минуту назад, Сергей Борщ сказал:

    Погрешность измерения периода какая? Насколько точно вы можете совместить линию с сигналом?

    Кстати, а один период ШИМ сколько получается по вашему осциллографу?

  6. 3 часа назад, MPetrovich сказал:

    Или вместо 31250 Вы предлагаете определить:

      #define F_PWM   31250  ?

    Предлагаю

    #define	PWM_TICKS	256
    #define F_PWM	((F_CPU) / PWM_TICKS)

    Но даже ваш вариант с F_PWM значительно повысил бы читаемость.

    3 часа назад, MPetrovich сказал:

    Я на осциллографе ПЕРИОД измеряю. Он поверенный, развёртка точная. Частоту я вижу на экране, но это результат 1/Т.

    Погрешность измерения периода какая? Насколько точно вы можете совместить линию с сигналом? И контроллер у вас от чего тактируется? От внешнего кварца или внутреннего RC, у которого точность +- трамвайная остановка и который для частоты, отличной от 1 МГц нужно вручную подстраивать записью константы (которую надо сначала вычитать программатором из сигнатуры) в регистр OSCCAL?

    3 часа назад, MPetrovich сказал:

    Длина таблицы 32 или 36. Я так понимаю, что чем длиннее таблица, тем меньше раз повторяется каждое значение при одинаковом шаге аккумулятора. По формуле подсчёта частоты выходит, что длина таблицы на частоту не влияет. Но так ли это я не уверен...

    Ничего не понимаю. Как не влияет? Вот полная формула подсчета: F = step * F_PWM / (table_size * 2^N). Для таблицы в 32 ячейки индекс занимает 5 бит в 16-битном фазовом аккумуляторе, 11 бит остается на дробную часть. Отсюда получается step * 8000000 / 256 / (32 * 2^11) = ваша формула  step * 31250 / 65536.

    Для размера таблицы в 36 ячеек и 16-битном аккумуляторе индекс будет занимать уже не 5, а 6 бит и 10 бит остается на дробную часть. Формула будет step * 8000000 / 256 / (36 * 2^10) и фазовый аккумулятор должен считать от 0 до 36*2^10-1, т.е. до 36863 (или от 36863 до нуля, что дает более короткий код).

    2 часа назад, MPetrovich сказал:

    Я тут подумал, может для таблицы в 36 значений вычислить другой размер фазового аккумулятора? Скажем такой: 36*1024=36864:russian_ru:

    Обязательно, иначе просто работать не будет. И еще вычесть единичку.

    2 часа назад, MPetrovich сказал:

    Только надо аккумулятор во такой сделать: 36*2048=73728

    Хозяин - барин, вы выделили 11 бит на дробную часть. Но ваш аккумулятор уже не влезает в 16 бит, под него надо выделять 32-битную переменную, все вычисления становятся 32-битными и уже с точки зрения вычислений нет никакой разницы, считать для 36 * 2^11 - 1 (73727) или для 36*2^(32-6) - 1 = 2415919103, только в последнем случае разрешение по частоте получается гораздо лучше.

    2 часа назад, MPetrovich сказал:

    Нет, не вариант. Искажается форма синуса на отрицательной полуволне.

    Что-то делаете неправильно. Показывайте код.

  7. 47 минут назад, MPetrovich сказал:

    Fpwm=8000000/2^8=31250Hz. Никакой магии)

    https://ru.wikipedia.org/wiki/Магическое_число_(программирование)#Плохая_практика_программирования

    48 минут назад, MPetrovich сказал:

    Но измеренный на осциллографе курсорами период даёт частоту на 2Гц больше при  akk_shift = 106.

    Ну это не показатель. У меня на работе agilent тоже частоту криво считает, даже при большом усреднении.

    50 минут назад, MPetrovich сказал:

    В формуле подсчёта частоты длина таблицы вообще не участвует,

    Как не участвует? А 65536? Это как раз длина таблицы *2^N, где N - количество разрядов дробной части фазового аккумулятора.

  8. Увы, у меня версии кончились. С этими памятями не работал. Может еще кто-нибудь подскажет. Если разберетесь - не сочтите за труд, отпишитесь, в чем была причина. Любопытно.

    P.S. Недавно была ситуация - залили старую программу в новую плату - потребление в спячке по сравнению со старой платой возросло на два порядка. Тоже ломал голову несколько дней. Помыли спиртом - пришло в норму, через полчаса под питанием снова полезло вверх. Бледный вид имел, монтажников про флюс пытали... Оказалось - в новой плате выкинули несколько цепей подключения неиспользуемых датчиков и настроенная на ввод нога, которая раньше через резистор соединялась с другой ногой, настроенной на вывод, оказалась висящей в воздухе. А ведь самая первая версия была - "программа та же, значит проблема в железе". Но чудес не бывает 😉. В смысле - причина в железе, но лечить надо программно. Извините, просто захотелось высказаться.

    P.P.S. Правильно писать "Ни добавление...".

  9. 50 минут назад, MPetrovich сказал:

    а шаг всегда на пару-тройку порядков  меньше аккумулятора

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

    Например, у меня был 8-битный phase and frequency correct PWM (510 тиков таймера на период ШИМ), тактовая  частота 16 МГц и таблица на 1020(510*2) точек на два периода (ну вот хотелось мне плавности, а памяти под такую таблицу даже в меге88 хватало). При генерации 400 Гц из 510 точек таблицы выбираются 78.43 (т.е. 78 точек, но в каждом периоде разные).

    50 минут назад, MPetrovich сказал:

    Нет, "в плюс".

    Странно. У вас же вроде бы получалось около 0.47 Гц на единицу приращения аккумулятора фазы? Откуда же ошибка? Ну-ка показывайте, как вы частоту считаете. У меня получается с вашими исходными данными для 50 Гц akk_shift = 106, akk_shift * 31250 / 65536 = 50.5447387, т.е. при вычислении в целых должно получиться 50 ровно. Хотя я бы умножал на 312500 и последний знак результата отделял запятой. Показывать в целых герцах на таких частотах, мне кажется, грубовато. Заказчик будет морщить нос.

    P.S. Да и "магическое число" 31250 тоже заставляет напрягаться. Вот честно-честно - лень думать, откуда оно взялось, приходится верить вам на слово. А вы через месяц сможете самому себе объяснить, откуда оно взялось? "Контрразведчик,должен знать всегда, как никто другой, что верить в наше время нельзя никому. Порой даже самому себе🤣

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

        sinus::index_t Index = sinus::index(get_phase());
        Phase_out[PHASE_A] = uint16_t(sinus::value_by_index(Index + sinus::index(sinus::PERIOD * 0 / 3)) * Tmp) / 256;
        Phase_out[PHASE_B] = uint16_t(sinus::value_by_index(Index + sinus::index(sinus::PERIOD * 1 / 3)) * Tmp) / 256;
        Phase_out[PHASE_C] = uint16_t(sinus::value_by_index(Index + sinus::index(sinus::PERIOD * 2 / 3)) * Tmp) / 256;

    Пусть у компилятора болит голова, чему именно равен период синуса "в морковках". Зато я четко вижу, что фазы сдвинуты на треть и две трети периода.

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

    8 часов назад, MPetrovich сказал:

    набегает ошибка примерно в 2Гц на 50ГЦ. И происходит это похоже из-за "некруглости" таблицы.

    Ошибка всегда "в минус"? тогда попробуйте display = ((((uint32_t)akk_shift) * 31250) + 65536 / 2)/65536;

    Конечно, можно работать и с "некруглой" таблицей, тогда надо перед каждым увеличением аккумулятора фазы проверять, что он не выскочит за пределы таблицы, и если выскочит - отнимать 2*Пи. Или, что проще - не увеличивать, а уменьшать аккумулятор фазы и перед каждым уменьшением сравнивать его с шагом. Если он строго меньше шага - прибавлять 2*Пи. При удачном стечении обстоятельств компилятор может объединить сравнение и вычитание - сделать вычитание и при обнаружении заёма добавить 2*Пи

    8 часов назад, MPetrovich сказал:

    надо иметь чёткое попадание в точки на синусе, соответствующие 30*N = (Пи/6)*N градусов

    На большой частоте эта точка таблицы может быть пропущена даже в очень большой таблице. Тут, думаю, скорее надо делать проверку if((akk_prev < table_size / 12) && (akk_cur >= table_size / 12)), т.е. если на этом шаге мы попадаем или перескакиваем искомую точку - то надо переключать. И делать аккумулятор фазы как можно большей разрядности для более точного отлова этого момента.

    P.S. Все это - мои рассуждения с дивана, их можно принимать как толчок к осмысливанию, но ни в коем случае не как безусловное руководство к действию.

    Из своего опыта могу посоветовать сделать таблицу на два периода синуса, чтобы три фазы получать методом akk + 0 * PERIOD / 3, akk + 1 * PERIOD / 3, akk + 2 * PERIOD / 3, при этом иметь "железный" сдвиг между фазами в 120 градусов и ни при каких akk в пределах [0...PERIOD) не вылететь за пределы таблицы, т.е. сэкономить проверку на выход за пределы таблицы для остальных двух фаз. 

  11. 6 часов назад, const сказал:

    Мне важно содержание регистров портов - их настройка и текущее состояние, оно не должно меняться при "мягком сбросе".

    Тут увы - любой аппаратный сброс (в том числе и через запись в SCB->AIRCR) приводит к сбросу почти всех регистров (кроме backup domain и RCC->CSR). Остается только переход на вектор сброса, но при этому нужно помнить, что вся периферия продолжает работать - например, ПДП, если была настроена, продолжает складывать данные в память, а некоторую периферию просто физически невозможно программно привести в исходное состояние (WDT невозможно остановить, снять защиту GPIO->LCKR - это первое, что пришло в голову). Так что, наверное, стоит хорошенько подумать - а надо ли вам бороться с ошибками, вызванными таким "сбросом" или лучше сразу потратить это время на отладку "боевой" программы.

  12. Посмею предположить, что к одному (или нескольким) из этих проводочков в отладке от ST оказался подключен вход какой-то другой микросхемы, который добавляет в линию небольшую емкость, которая, в свою очередь, приводит к задержке сигнала и эта задержка приводит к тому, что микросхема воспринимает команду правильно. Например, добавляет задержку между SCK и SI. Микросхемы других производителей могут быть не так критичны к этой задержке. Проверьте еще раз, правильно ли вы устанавливаете биты CPOL и CPHA при настройке SPI вашего контроллера.

  13. А просто анализировать значение фазы или тупо сделать второй массив с состояниями нижних ключей, из которого выбирать используя тот же самый фазовый аккумулятор? Или массив синуса заменить на массив структур, состоящих из значений синуса и состояния нижнего ключа? Или забить на младший бит синуса и вместо него хранить состояние нижнего ключа (у вас ведь по одному ключу на каждый выход синуса)?

  14. 9 часов назад, Tarbal сказал:

    1 Mbit в секунду вполне удовлетворит мои потребности.

    В чем состоит задача? Какие идеи вы хотите получить? Вы хотите, чтобы вам тут на форуме конспективно изложили все принципы, лежащие в основе систем с расширением спектра? Или посоветовали соответствующую литературу? Или конкретную элементную базу? Какими знаниями вы уже обладаете в этой области?

  15. В 01.08.2023 в 12:35, jcxz сказал:

    Да, например - сканируем полосу частот и видим, что на некотором канале (отрезке полосы частот) уровень сигнала упал, а на другом в этот момент - увеличился.

    Как быстро вы сможете это увидеть? Стандарт первой сотовой связи TIA/EIA/IS-95 определяет посылки длительностью 20 мс, которые скачут в полосе 1.23 МГц. Успеете? А за окном уже давно не 1995 и мне лень искать характеристики современных систем, но к гадалке не ходи - полоса там шире, а длительность посылок меньше.

    В 01.08.2023 в 12:35, jcxz сказал:

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

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

    Специалисты НТЦ "Модуль" в 2018 году со ссылкой на советскую книгу 1985 года утверждали, что "Для шумоподобных сигналов характерны высокая помехозащищенность и скрытность". Так вот, "помехозащищенность" - это и про "глушилки" в том числе. Но вы-то лучше знаете, что это неправда, да?

  16. 18 минут назад, MPetrovich сказал:

    Вот нашёл такую формулу: sin3(q) = sin(q)+1/6sin(3q). Она похоже иллюстрирует Ваш метод)

    Во всяком случае синус на выходе дает такой же:

    image.thumb.png.df885fa5887585a1247fed2a5ab0caa6.png

    Спойлер
    PERIOD = 2 * %pi;
    POINTS = 120 * 3;
    
    T = [1:POINTS];
    Phase = (T - 1) / POINTS * PERIOD;
    
    Sin1 = sin(Phase + 0 * PERIOD / 3) / 2 + 0.5;
    Sin2 = sin(Phase - 1 * PERIOD / 3) / 2 + 0.5;
    Sin3 = sin(Phase - 2 * PERIOD / 3) / 2 + 0.5;
    
    Out_A1 = sin(Phase + 0 * PERIOD / 3) + 1/6 * sin((Phase + 0 * PERIOD / 3) * 3);
    Out_A1 = Out_A1 - min(Out_A1);
    Out_A1 = Out_A1 / max(Out_A1);
    Out_B1 = sin(Phase + 1 * PERIOD / 3) + 1/6 * sin((Phase + 1 * PERIOD / 3) * 3);
    Out_B1 = Out_B1 - min(Out_B1);
    Out_B1 = Out_B1 / max(Out_B1);
    Out_C1 = sin(Phase + 2 * PERIOD / 3) + 1/6 * sin((Phase + 2 * PERIOD / 3) * 3);
    Out_C1 = Out_C1 - min(Out_C1);
    Out_C1 = Out_C1 / max(Out_C1);
    
    clf();
    a=gca(); // Handle on current axes entity 
    plot(T - 1, Sin1, ":r");
    plot(T - 1, Sin2, ":g");
    plot(T - 1, Sin3, ":b");
    plot(T - 1, Out_A1, "r");
    plot(T - 1, Out_B1, "g");
    plot(T - 1, Out_C1, "b");
    plot(T - 1, Sin1 - Sin2, ":k");
    plot(T - 1, Out_A1 - Out_B1, "--k");
    
    a.sub_ticks = [4, 1]; 
    

     

    Спасибо, пригодится.

    image.png.fcfdefbad01cba5a0666701bb49ddee4.png

    • Upvote 1
  17. Запустил scilab:

    image.thumb.png.7a7f0256a51bb76921ddfd1c7b89abc0.png

    Спойлер
    PERIOD = 2 * %pi;
    POINTS = 120 * 3;
    
    T = [1:POINTS];
    Phase = (T - 1) / POINTS * PERIOD;
    
    Sin1 = sin(Phase + 0 * PERIOD / 3) / 2 + 0.5;
    Sin2 = sin(Phase - 1 * PERIOD / 3) / 2 + 0.5;
    Sin3 = sin(Phase - 2 * PERIOD / 3) / 2 + 0.5;
    
    function [y]=phase(x)
      y = (x - 1) / POINTS * PERIOD;
    endfunction;
    
    function [y]=envelope(x)
      y = [];
    
      for i = 1 + 0 * POINTS / 3 + POINTS / 12 : 1 * POINTS / 3 + POINTS / 12;
        y(i) = sin(phase(i) + 0 * PERIOD / 3) - sin(phase(i) + x * PERIOD / 3);
      end,
      for i = 1 + 1 * POINTS / 3 + POINTS / 12 : 2 * POINTS / 3 + POINTS / 12;
        y(i) = sin(phase(i) + 2 * PERIOD / 3) - sin(phase(i) + x * PERIOD / 3);
      end,
      for i = 1 + 2 * POINTS / 3 + POINTS / 12 : 3 * POINTS / 3;
        y(i) = sin(phase(i) + 1 * PERIOD / 3) - sin(phase(i) + x * PERIOD / 3);
      end,
      for i = 1  : POINTS / 12;
        y(i) = sin(phase(i) + 1 * PERIOD / 3) - sin(phase(i) + x * PERIOD / 3);
      end,
      y = y / max(y);
    endfunction;
    funcprot(0);
    
    Out_A = envelope(0);
    Out_B = envelope(1);
    Out_C = envelope(2);
    
    clf();
    a=gca(); // Handle on current axes entity 
    plot(T - 1, Sin1, ":r");
    plot(T - 1, Sin2, ":g");
    plot(T - 1, Sin3, ":b");
    plot(T - 1, Out_A, "r");
    plot(T - 1, Out_B, "g");
    plot(T - 1, Out_C, "b");
    plot(T - 1, Sin1 - Sin2, ":k");
    plot(T - 1, Out_A - Out_B, "--k");
    
    a.sub_ticks = [4, 1]; 
    

     

    Выигрыш по амплитуде 15%

  18. 4 минуты назад, MPetrovich сказал:

    только пока не разобрался как получить эту кракозябру.

    Не стартует скачаный scilab, разбираться сейчас некогда. Попробую описать словами. Рисуете три синусоиды. Разбиваете период на три части. В каждой части вычитаете одну синусоиду из всех трех, чтобы она выродилась в прямую. На следующем участке вычитаете другую синусоиду, на третьем - третью. Я получил этот график именно так. .

     

  19. 9 минут назад, MPetrovich сказал:

    А в чём выгода? Каким образом этот режим ШИМ уменьшит вторую гармонику синуса?

    Ой, вот этого не смогу объяснить. Но при создании передатчика убедился своими глазами.

    9 минут назад, MPetrovich сказал:

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

    Тогда надо не синус в таблицу заносить, а вот такой хитрый сигнал (нарисован черным):

    post-53549-12536540738_thumb.jpg

    Сейчас scilab скачается, покажу более полную картинку.

  20. 17 минут назад, MPetrovich сказал:
    num = akk/2048;//65536/32=2048

    Кстати, компилятор умеет вычислять константные выражения на этапе компиляции, поэтому не стоило здесь выносить само выражение в комментарий. Когда-нибудь в подобной ситуации вы при очередной правке измените число, но не измените комметарий и через некоторое время будете смотреть на такую строку и долго думать "а что в ней правильно - число или комментарий?". Принцип IBM гласит: "машина должна работать, а человек - думать". Я с ними согласен, перепишите эту строку от греха подальше в 

    num = akk / (65536 / 32);

    вы ведь уже доверили (компилятору) заменить деление на 2048 на сдвиг.

  21. Позравляю. Можете еще попробовать использовать режим не простого ШИМ, а phase and frequency correct PWM. Частота ШИМ снизится почти вдвое, но вторая гармоника в спектре выходного сигнала будет существенно ниже. Не знаю, насколько для вас это критично. Возможно, двигатель станет чуть холоднее.

  22. 49 минут назад, MPetrovich сказал:

    Я думаю, что всё таки не остаток от деления, а целая часть числа

    допустим, прошло 1000000000 циклов приращения фазы. Даже не выполняя вычислений понятно, что результат вашего деления будет во много раз больше размера таблицы. Не говоря уже о том, что для хранения x потребуется переменная бесконечного размера :crazy:.

    49 минут назад, MPetrovich сказал:

    65536/размер_таблицы - это константа, её надо один раз посчитать и целую часть вставить в формулу.

    Константа считается один раз, а деление 100x/константа контроллер должен будет выполнять на каждом проходе. В случае размера таблицы в 36 ячеек это будет число 1820.4(4) - вы будете выполнять деление в числах с плавающей точкой?

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