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

ШИМ сигнал по закону синуса без ЦАП на STM32

Всем здравствуйте!
Стоит задача: нужно на выходе трех ножек(PA8-10) получить соответственно 3 фазы ШИМ, который определяется по закону синуса(3 синусоидальные фазы нужно получить).

Столкнулся с проблемой неправильной настройки. Фазу 2 и 3 вырезал, пока не разберусь с первой.

В общем: таймер 1 отвечает за вывод значений на ножки. Его частота рассчитывается по формуле: Fcpu / ((arr+1) (psc+1)) = 72*10^6 / 2402 = 29.9kHz!!!!!! <<<<
Второй таймер грузит значение в таймер 2. Его частота: Fcpu / ((arr+1) (psc+1)) = 65kHz!!!!!!!!! <<<<<<<<
В одной беседе подсказали такие формулы(они в коде). Очень большие частоты. Но формул, по которым нужно считать правильно, я не знаю. Подскажите, пожалуйста, если знаете.

Синус формировал по формуле: 2^16 / 2 * sin(T) + 2^16 / 2. т.е чтобы в отрицательную часть не заходить, сместил его на половину 2^16.


Буду очень признателен, если подскажите. где тут ошибка. Понимаю, что где-то намутил воду.... Этот сигнал потом пойдет на 3-х фазный драйвер, который уже и будет управлять ключами. Заранее спасибо!

Константы:

Скрытый текст

constexpr auto  _F_CPU              = 72000000u;                // частота процессора
constexpr auto  _SIGNAL_FREQUENCY_MAX = 50u;                    // максимальная частота синусоиды
constexpr auto  _SIGNAL_FREQUENCY_MIN = 100u;                    // минимальная частота синусоиды
constexpr auto  _DISCRETIZE         = 300u;                     // дискретизация синусоиды(количество точек)
constexpr auto  _VOLTAGE_ON_PORT    = 3.3f;                     // напряжение на порту(напряжение питания)
constexpr auto  _BITNESS            = 16u;                      // разрядность таймера[~цап]
constexpr auto  _AMPLITUDE          = ((1 << 16) - 1) / 2;      // максимальное значение таймера
constexpr auto  _ADC_MAX_VALUE      = (1 << 12) - 1;            // максимальное значение в АЦП

 

Массив значений, размером 300: 
 

Скрытый текст

static inline std::array<T, _DISCRETIZE> 
        phase_A 
        {
            32768, 33456, 34144, 34832, 35519, 36204, 36888, 37570, 38250, 38928, 39603, 40275, 40943, 41608, 42269, 
            42926, 43578, 44226, 44868, 45506, 46137, 46763, 47382, 47995, 48602, 49201, 49793, 50377, 50954, 51523, 
            52083, 52635, 53178, 53713, 54237, 54753, 55259, 55754, 56240, 56715, 57180, 57634, 58077, 58508, 58929, 
            59338, 59735, 60120, 60493, 60854, 61202, 61538, 61861, 62172, 62469, 62753, 63024, 63282, 63526, 63757, 
            63974, 64177, 64366, 64541, 64702, 64850, 64983, 65101, 65206, 65296, 65372, 65433, 65480, 65513, 65531, 
            65535, 65524, 65498, 65459, 65404, 65336, 65253, 65155, 65044, 64918, 64778, 64624, 64455, 64273, 64077, 
            63867, 63643, 63406, 63155, 62890, 62613, 62322, 62018, 61701, 61372, 61030, 60675, 60308, 59929, 59538, 
            59135, 58720, 58294, 57857, 57408, 56949, 56479, 55998, 55508, 55007, 54496, 53976, 53447, 52908, 52360, 
            51804, 51240, 50667, 50086, 49498, 48902, 48299, 47690, 47073, 46451, 45822, 45188, 44548, 43903, 43253, 
            42598, 41939, 41276, 40609, 39939, 39266, 38589, 37910, 37229, 36546, 35861, 35175, 34488, 33800, 33112, 
            32423, 31735, 31047, 30360, 29674, 28989, 28306, 27625, 26946, 26269, 25596, 24926, 24259, 23596, 22937, 
            22282, 21632, 20987, 20347, 19713, 19084, 18462, 17845, 17236, 16633, 16037, 15449, 14868, 14295, 13731, 
            13175, 12627, 12088, 11559, 11039, 10528, 10027, 9537, 9056, 8586, 8127, 7678, 7241, 6815, 6400, 
            5997, 5606, 5227, 4860, 4505, 4163, 3834, 3517, 3213, 2922, 2645, 2380, 2129, 1892, 1668, 
            1458, 1262, 1080, 911, 757, 617, 491, 380, 282, 199, 131, 76, 37, 11, 0, 
            4, 22, 55, 102, 163, 239, 329, 434, 552, 685, 833, 994, 1169, 1358, 1561, 
            1778, 2009, 2253, 2511, 2782, 3066, 3363, 3674, 3997, 4333, 4681, 5042, 5415, 5800, 6197, 
            6606, 7027, 7458, 7901, 8355, 8820, 9295, 9781, 10276, 10782, 11298, 11822, 12357, 12900, 13452, 
            14012, 14581, 15158, 15742, 16334, 16933, 17540, 18153, 18772, 19398, 20029, 20667, 21309, 21957, 22609, 
            23266, 23927, 24592, 25260, 25932, 26607, 27285, 27965, 28647, 29331, 30016, 30703, 31391, 32079
        };

 


Код инициализации таймеров:
 

Скрытый текст

void FreqConverter::timer_initialize()
{
    RCC->APB2ENR |= RCC_APB2ENR_TIM1EN; // включаем TIM1 (тактирование от APB2 - 72 MHz)
    RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_AFIOEN; // включаем тактирование портов А и В

    /* 
    Частота таймера прерываний равна = кол-во отсчетов * частоту сигнала.
    ARR = 1000 для видной скважности.
    на ARR != 1000 проверено не было!.
    */
    //TIM1->ARR = ((_F_CPU / (1 << _BITNESS)) - 1);
    TIM1->ARR = (F_CPU / (_DISCRETIZE * _SIGNAL_FREQUENCY_MIN)) - 1;
    TIM1->PSC = 0;
    //TIM1->PSC = 0;
    //TIM1->ARR = (_F_CPU / (1 << _BITNESS)) - 1;

    TIM1->CCER      |= TIM_CCER_CC1E | TIM_CCER_CC2E | TIM_CCER_CC3E;                   // включаем выход 1, 2, 3 каналов ножек как выход
    TIM1->CCER      |= (TIM_CCER_CC1P | TIM_CCER_CC2P | TIM_CCER_CC3P);                // устанавливаем норм. полярность(1 - высокий)
    TIM1->BDTR      |= TIM_BDTR_MOE;                                                    // разрешили работу выводов
    TIM1->CCMR1     |= (0b110 << TIM_CCMR1_OC1M_Pos) | (0b110 << TIM_CCMR1_OC2M_Pos);   // установили работу каналов 1,2 как PWM1
    TIM1->CCMR2     |= (0b110 << TIM_CCMR2_OC3M_Pos);                                   // установили работу канала 3 как PWM1
    //TIM1->CCMR1 = TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1;
    TIM1->CR1       &= ~TIM_CR1_DIR;
    TIM1->CR1       &= ~TIM_CR1_CMS;

    // установим выводы каналов как alternative push-pull выходы
    GPIOA->CRH &=   ~(GPIO_CRH_MODE8 | GPIO_CRH_MODE9 | GPIO_CRH_MODE10); //mode 01 - alernative push-pull
    GPIOA->CRH |=   GPIO_CRH_MODE8_1 | GPIO_CRH_MODE9_1 | GPIO_CRH_MODE10_1;
    GPIOA->CRH &=   ~(GPIO_CRH_CNF8_0 | GPIO_CRH_CNF9_0 | GPIO_CRH_CNF10_0);
    GPIOA->CRH |=   (GPIO_CRH_CNF8_1 | GPIO_CRH_CNF9_1 | GPIO_CRH_CNF10_1);//cnf 10 - mode output

    TIM1->CR1  |=   TIM_CR1_CEN;

    TIM2->ARR = ((_F_CPU / (1 << _BITNESS)) - 1);
    //TIM2->ARR = (F_CPU / (_DISCRETIZE * _SIGNAL_FREQUENCY_MIN)) - 1;
    TIM2->PSC = 0;

    TIM2->DIER = TIM_DIER_UIE;
    NVIC_EnableIRQ(TIM2_IRQn);

    TIM2->CR1 |= TIM_CR1_CEN;
}



extern "C" void TIM2_IRQHandler()
{
    if (TIM2->SR & TIM_SR_UIF)
    {
        static uint16_t 
            _counter_phase{0};
        TIM1->CCR1 = FreqConverter::phase_A[_counter_phase];
        //TIM1->CCR2 = FreqConverter::phase_B[_counter_phase];
        //TIM1->CCR3 = FreqConverter::phase_C[_counter_phase];

        if(++_counter_phase == _DISCRETIZE)
            _counter_phase = 0;
        TIM2->SR &= ~TIM_SR_UIF;
    }
}

 

 

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


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

Из сообщения непонятно, в чем конкретно проблема, и какая модель контроллера, но вот что бросилось в глаза. Таймер в выбранном режиме работает так - после перезапуска (СNT = 0) на выходе выставляется логическая единица, затем, когда таймер досчитает до значения, записанного в регистр CCRx, на выходе устанавливается логический ноль. Когда же таймер досчитает до значения в регистре ARR, он перезапускается и цикл начинается по новой. Вы же задаете частоту ШИМ, записывая в ARR значение 2400, при этом большинство значений в таблице, записываемых в CCRx, больше этого числа, и они никак не влияют на работу таймера - он перезапускается раньше. А вообще, вся работа периферии подробно описана в Reference Manual на соответствующий контроллер.

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


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

Спасибо за ответ.
Микроконтроллер - STM32F103C8T6.

По поводу ARR понял. Но как быть в таком случае?
И, все же, интересует вопрос по поводу частоты: правильно ли я посчитал, не велика ли она?

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


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

Задавать частоту значением регистра PSC. Тем более, у STM32 тут хороший бонус - можно выбрать любой предделитель от 1 до 65536.
 

Quote

И, все же, интересует вопрос по поводу частоты: правильно ли я посчитал, не велика ли она?

Ну для заданных значений - да, только в знаменателе 2400 должно быть

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


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

Какую частоту синуса вы хотите получить ?

Пускай 50 Гц.

Сделайте ваш ШИМ 8-ми битный. Тогда на период синуса у вас получится 256 отсчетов.

И пускай скважность ШИМ у вас меняется каждый период таймера. Тогда ARR можно сделать равным 256.

Остается найти частоту предделителя PSC.

PSC = 72000000/50/256 - 1= 5624.

 

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


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

22 минуты назад, dimka76 сказал:

Тогда на период синуса у вас получится 256 отсчетов.

Которые, увы, нацело не делятся на три фазы. 

Я подобную задачу решал методом прямого цифрового синтеза - https://kit-e.ru/elcomp/dds-pryamoj-czifrovoj-sintez-chastoty-2/ Таким способом можно получить частоту с очень высокой точностью как частоты так и сдвига фаз при любой, даже некратной несущей частоте ШИМ. 

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


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

9 minutes ago, Сергей Борщ said:

Которые, увы, нацело не делятся на три фазы. 

Ошибка 0.4%

А вот интересно по ГОСТ или МЭК или ISO какое допустимое отклонение на сдвиг фаз между фазами в трехфазной сети ?

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


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

33 минуты назад, dimka76 сказал:

Остается найти частоту предделителя PSC.

PSC = 72000000/50/256 - 1= 5624.

Таким образом, вместо 
 

TIM1->ARR = (F_CPU / (_DISCRETIZE * _SIGNAL_FREQUENCY_MIN)) - 1;
TIM1->PSC = 0;

я получил:

TIM1->PSC = (F_CPU / _SIGNAL_FREQUENCY_MIN / 256) - 1;
TIM1->ARR = 256;

где 256 в PSC - это значение, которое мы внесли в ARR?

 

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

Которые, увы, нацело не делятся на три фазы. 

Я подобную задачу решал методом прямого цифрового синтеза - https://kit-e.ru/elcomp/dds-pryamoj-czifrovoj-sintez-chastoty-2/ Таким способом можно получить частоту с очень высокой точностью как частоты так и сдвига фаз при любой, даже некратной несущей частоте ШИМ. 

Спасибо за информацию!

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


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

8 minutes ago, oldbrowze said:

я получил:


TIM1->PSC = (F_CPU / _SIGNAL_FREQUENCY_MIN / 256) - 1;
TIM1->ARR = 256;

где 256 в PSC - это значение, которое мы внесли в ARR?

Да.

Можно так

#define ARR_VAL (256UL)
  
TIM1->PSC = (F_CPU / _SIGNAL_FREQUENCY_MIN / ARR_VAL) - 1UL;
TIM1->ARR = ARR_VAL - 1UL;

 

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


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

Спасибо за ответы!

 

12 часов назад, dimka76 сказал:

Можно так

Можно, но предпочитаю constexpr. :)

Сделал, как сказали. 
Эта осциллограмма - и есть шим, формированный по закону синуса?
 

Скрытый текст

image.thumb.png.0a61f98d3aca1285d11adff0c6011ea8.png

 

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


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

2 hours ago, oldbrowze said:

Эта осциллограмма - и есть шим, формированный по закону синуса?

Подключите к выходу вашего ШИМ RC цепочку с частотой среза 100 Гц и смотрите осциллографом после нее.

Если все правильно, то увидите синус.

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


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

Точных номиналов на R, C нет. Приблизительно подобрал. Получается какая-то пила.

Я в правильном направлении?
Огромное спасибо за консультацию!)

Скрытый текст

image.thumb.png.2787e1180d54470d588dc519a8044f58.png

 

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


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

19 minutes ago, oldbrowze said:

 Получается какая-то пила.

Покажите вашу таблицу синуса.

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


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

Скрытый текст

static inline std::array<T, _DISCRETIZE> 
        phase_A 
        {
            128, 131, 134, 137, 141, 144, 147, 150, 153, 156, 159, 162, 165, 168, 171, 
            174, 177, 180, 183, 186, 189, 191, 194, 197, 199, 202, 205, 207, 209, 212, 
            214, 217, 219, 221, 223, 225, 227, 229, 231, 233, 235, 236, 238, 240, 241, 
            243, 244, 245, 246, 248, 249, 250, 251, 252, 252, 253, 254, 254, 255, 255, 
            255, 256, 256, 256, 256, 256, 256, 256, 255, 255, 254, 254, 253, 253, 252, 
            251, 250, 249, 248, 247, 246, 245, 243, 242, 240, 239, 237, 236, 234, 232, 
            230, 228, 226, 224, 222, 220, 218, 215, 213, 211, 208, 206, 203, 201, 198, 
            195, 193, 190, 187, 184, 181, 179, 176, 173, 170, 167, 164, 161, 158, 155, 
            152, 148, 145, 142, 139, 136, 133, 130, 126, 123, 120, 117, 114, 111, 108, 
            104, 101, 98, 95, 92, 89, 86, 83, 80, 77, 75, 72, 69, 66, 63, 
            61, 58, 55, 53, 50, 48, 45, 43, 41, 38, 36, 34, 32, 30, 28, 
            26, 24, 22, 20, 19, 17, 16, 14, 13, 11, 10, 9, 8, 7, 6, 
            5, 4, 3, 3, 2, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 
            1, 1, 1, 2, 2, 3, 4, 4, 5, 6, 7, 8, 10, 11, 12, 
            13, 15, 16, 18, 20, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 
            42, 44, 47, 49, 51, 54, 57, 59, 62, 65, 67, 70, 73, 76, 79, 
            82, 85, 88, 91, 94, 97, 100, 103, 106, 109, 112, 115, 119, 122, 125
        };

 

Генерировал в матлабе по формуле: 

Y = round(2^bitness / 2 * sin(T) + 2^bitness / 2);

 

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


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

4 minutes ago, oldbrowze said:
  Hide contents


static inline std::array<T, _DISCRETIZE> 
        phase_A 
        {
            128, 131, 134, 137, 141, 144, 147, 150, 153, 156, 159, 162, 165, 168, 171, 
            174, 177, 180, 183, 186, 189, 191, 194, 197, 199, 202, 205, 207, 209, 212, 
            214, 217, 219, 221, 223, 225, 227, 229, 231, 233, 235, 236, 238, 240, 241, 
            243, 244, 245, 246, 248, 249, 250, 251, 252, 252, 253, 254, 254, 255, 255, 
            255, 256, 256, 256, 256, 256, 256, 256, 255, 255, 254, 254, 253, 253, 252, 
            251, 250, 249, 248, 247, 246, 245, 243, 242, 240, 239, 237, 236, 234, 232, 
            230, 228, 226, 224, 222, 220, 218, 215, 213, 211, 208, 206, 203, 201, 198, 
            195, 193, 190, 187, 184, 181, 179, 176, 173, 170, 167, 164, 161, 158, 155, 
            152, 148, 145, 142, 139, 136, 133, 130, 126, 123, 120, 117, 114, 111, 108, 
            104, 101, 98, 95, 92, 89, 86, 83, 80, 77, 75, 72, 69, 66, 63, 
            61, 58, 55, 53, 50, 48, 45, 43, 41, 38, 36, 34, 32, 30, 28, 
            26, 24, 22, 20, 19, 17, 16, 14, 13, 11, 10, 9, 8, 7, 6, 
            5, 4, 3, 3, 2, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 
            1, 1, 1, 2, 2, 3, 4, 4, 5, 6, 7, 8, 10, 11, 12, 
            13, 15, 16, 18, 20, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 
            42, 44, 47, 49, 51, 54, 57, 59, 62, 65, 67, 70, 73, 76, 79, 
            82, 85, 88, 91, 94, 97, 100, 103, 106, 109, 112, 115, 119, 122, 125
        };

 

 

Значения должны быть от 0 до 255.

А у вас встречаются 256.

Y = round(((((2^bitness)-1) / 2) * sin(T)) + (((2^bitness)-1) / 2));

 

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


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

Гость
Эта тема закрыта для публикации ответов.
×
×
  • Создать...