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

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

1 hour ago, oldbrowze said:

Убрал. Осциллограмма вида не изменила

Неправильно я вам предделители насоветовал.

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

PSC = F_CPU/50; // т.к. частота синуса 50 Гц
PSC /= 256; // т.к. 256 отсчетов на период
PSC /= 256; // т.к. по амплитуде 256 уровней
PSC -= 1;

Но тут частота точно 50 Гц не получается. Получается 52.6 Гц.

 

Не поленился набросал на своей макетке программку.

Вот, что получилось

image.thumb.png.67ef7544408f4d17772b3261c0ed1516.png

 

Spoiler

static const uint8_t sin_tbl[256] = {
		128, 131, 134, 137, 140, 143, 146, 149, 152, 156, 159, 162, 165, 168, 171,
        174, 176, 179, 182, 185, 188, 191, 193, 196, 199, 201, 204, 206, 209, 211,
        213, 216, 218, 220, 222, 224, 226, 228, 230, 232, 234, 235, 237, 239, 240,
        242, 243, 244, 246, 247, 248, 249, 250, 251, 251, 252, 253, 253, 254, 254,
        254, 255, 255, 255, 255, 255, 255, 255, 254, 254, 253, 253, 252, 252, 251,
        250, 249, 248, 247, 246, 245, 244, 242, 241, 239, 238, 236, 235, 233, 231,
        229, 227, 225, 223, 221, 219, 217, 215, 212, 210, 207, 205, 202, 200, 197,
        195, 192, 189, 186, 184, 181, 178, 175, 172, 169, 166, 163, 160, 157, 154,
        151, 148, 145, 142, 138, 135, 132, 129, 126, 123, 120, 117, 113, 110, 107,
        104, 101, 98, 95, 92, 89, 86, 83, 80, 77, 74, 71, 69, 66, 63,
        60, 58, 55, 53, 50, 48, 45, 43, 40, 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, 9, 11, 12,
        13, 15, 16, 18, 20, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39,
        42, 44, 46, 49, 51, 54, 56, 59, 62, 64, 67, 70, 73, 76, 79,
        81, 84, 87, 90, 93, 96, 99, 103, 106, 109, 112, 115, 118, 121, 124, 127
};

volatile uint32_t counter;

void TIM1_UP_IRQHandler(void)
{
	if (TIM1->SR & TIM_SR_UIF)
	{
		TIM1->CCR1 = sin_tbl[counter];

		++counter;
		counter &= 0xFF;
	}
	TIM1->SR = 0;
}


/*******************************************************************************
* Function Name  : main.
* Description    : Main routine.
* Input          : None.
* Output         : None.
* Return         : None.
*******************************************************************************/
int main(void)
{
	Set_System();

	// Timer1 Init
	/* Enable GPIOA and TIM1 clock */
	RCC->APB2ENR |= (RCC_APB2ENR_IOPAEN) | (RCC_APB2ENR_TIM1EN);
	// установим выводы каналов как 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->ARR  = 255;
	TIM1->PSC  = 21UL - 1UL;
	TIM1->CNT  = 0;
	TIM1->CCR1 = 100; // Скважность ШИМ = 50%
	//  On - OCx signal is output on the corresponding output pin.
	TIM1->CCER = TIM_CCER_CC1E;
	TIM1->CCMR1 =((6<<4) | /* PWM mode1 */
			  	  TIM_CCMR1_OC1PE ); 					/* preload enable */
	TIM1->BDTR = TIM_BDTR_MOE;
	TIM1->CR1 = TIM_CR1_ARPE;
	TIM1->EGR = TIM_EGR_UG; // Set UG - Update Generation

	TIM1->CR1 = 0;
	TIM1->DIER = TIM_DIER_UIE;
	NVIC_EnableIRQ(TIM1_UP_IRQn);

	TIM1->CR1 |= TIM_CR1_CEN;

	while(1)
	{

	}
}

 

 

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


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

Господи, свершилось!
Снизил частоту дискретизации до 100 точек, на выходе 50.2 Гц.

Спасибо Вам огромное за ваш труд!Человеческое спасибо!

Теперь, чтобы менять амплитуду сигнала, нужно умножать значение из таблицы, которое будет загружаться в CRx, на определенный коэффициент?

И, поскольку данный сигнал будет подаваться на драйвер транзисторов, нужно этот сигнал разделить на полуволны: положительную и отрицательную. 
Аппаратный dead-time мой драйвер поддерживает, а посему сложностей с ним не будет.

У меня приблизительный вариант, как я хочу сделать: Условно, в первый проход мы будем отрисовывать положительную полуволну в прерывании, во второй - менять полярность на ноге, и отрисовывать уже сигнал с той же таблицы, но уже в противофазе.
Либо, насколько я понимаю, TIM1 - продвинутый таймер с поддержкой комплементарных выводов. На как тогда сделать на одной ноге(PA8, CR1) вывод как положительной, так и отрицательной волны?

Если Вам не трудно, проясните, пожалуйста.

Еще раз - человеческое огромное спасибо!) 

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


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

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

Несущая должна быть 12800 Гц. Т.е эта RC цепь должна гасить несущую в 128 раз.

Значит не получилось 12800 Гц, если она так отчетливо видна на осциллограмме.

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


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

41 minutes ago, oldbrowze said:

Спасибо Вам огромное за ваш труд!Человеческое спасибо!

Пожалуйста ;-)

41 minutes ago, oldbrowze said:

Теперь, чтобы менять амплитуду сигнала, нужно умножать значение из таблицы, которое будет загружаться в CRx, на определенный коэффициент?

Да. Только умножать надо на коэффициент от 0 до 1. А чтобы не использовать плавучку лучше работать с числами с фиксированной точкой.

Т.к. у вас разрядность ШИМ 8 бит, то ваш коэффициент будет лежать от 0/256 до 256/256.

Т.е. умножаете содержимое таблицы синуса на число от 0 до 255 и от результата берете только старший байт.

Вот так

union{
  uint8_t byte[2];
  uint16_t word;
}data;

uint16_t volume; // это коээфициент амплитуды от 0 до 255
uint8_t sin_tbl[256]; // ваша таблица синуса

data.word = volume * sin_tbl[i];
TIM1->CCR1 = data.byte[1];
41 minutes ago, oldbrowze said:

Либо, насколько я понимаю, TIM1 - продвинутый таймер с поддержкой комплементарных выводов. На как тогда сделать на одной ноге(PA8, CR1) вывод как положительной, так и отрицательной волны?

Лучше использовать этот вариант. У него взаимодополняющая пара выходов: TIM1_CH1 и TIM1_CH1N.

На выводе TIM1_CH1N аппаратно реализуется инверсный сигнал.

Т.о. нагрузка на микроконтроллер снижается. Не надо обслуживать инверсный синус. 

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


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

Благодарю.
Как я понял из примера с объединения: мы берем старший байт. Т.е я могу, в принципе, и не использовать объединение, а просто сдвинуть значение?

И еще вопрос по поводу комплементарной пары: Т.к мне нужно на одной ноге формировать положительную полуволну, а на второй - только отрицательную, то как же это тогда сделать то с помощью этотй пары?
Ведь мне сигнал на второй ноге(отрицательной) нужен сигнал тогда, когда положительная полуволна зашла на 0?
т.е примерно как-то так:
 

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

image.png.852342a11de08d5ab056169cdf3cd6cc.png

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

Буду очень признателен, если наведете на мысль!

Спасибо Вам!

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


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

23 минуты назад, oldbrowze сказал:

И еще вопрос по поводу комплементарной пары: Т.к мне нужно на одной ноге формировать положительную полуволну, а на второй - только отрицательную, то как же это тогда сделать то с помощью этотй пары?

Прочитайте уже наконец-то мануал на таймер! Чтобы чушь не нести.

Парафазные сигналы нужны для управления 2-тактными ключами. Когда есть 2 транзистора: один коммутирует на шину GND, другой - VCC. Примеров в инете = вагон + маленькая тележка.

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


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

18 minutes ago, oldbrowze said:

Как я понял из примера с объединения: мы берем старший байт. Т.е я могу, в принципе, и не использовать объединение, а просто сдвинуть значение?

Тут уже надо смотреть как лучше компилятор соптимизирует.

 

18 minutes ago, oldbrowze said:

И еще вопрос по поводу комплементарной пары: Т.к мне нужно на одной ноге формировать положительную полуволну, а на второй - только отрицательную, то как же это тогда сделать то с помощью этотй пары?

Не надо отдельно полуволны формировать.

Все тоже самое как и было до этого. Только дополнительно вы настраиваете ножку TIM1_CH1N и dead-time, если надо. И все, больше ничего не надо.

29 minutes ago, oldbrowze said:

но, насколько я понял, этот сдвиг между одной ногой и второй называется deadtime. 

deadtime - это когда оба канала (прямой и инверсный) (TIM1_CH1  и TIM1_CH1N) находятся в неактивном состоянии. Это время не большое по сравнению с периодом сигнала.

И оно служит для предотвращения протекания сквозных токов силовых ключей, которыми посредством драйвера эти выводы таймера управляют.

Сквозные токи в силовых ключах возникают из-за того, что один еще не успел закрыться, а второй уже начал открываться.

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


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

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