Stm32 değişken frekanslı pwm

Karasavay

Üye
Katılım
24 Mar 2021
Mesajlar
27
Puanları
1
Yaş
30
Merhaba arkadaşlar. Yüksek lisans tezim için LLC rezonans dönüştürücü tasarlayacağım. Bunun için hem frekans modülasyonu hem de pwm modülasyonu yapmam gerekiyor.

Sorum şu; Pwm sinyali üretebiliyorum, fakat bu Pwm sinyalinin örneğin 40khz ve 80khz frekans arasında değişken olması gerekiyor. Daha önce hiç değişken frekanslı pwm üretmemiştim. Bilen arkadaşlar yardımcı olursa çok memnun olurum.

Aklıma ilk gelen Prescaler değerini değiştirmek oldu. Bu şekilde mümkün mü? Ama bu şekilde olursa da ara değerleri elde etmem mümkün değil, nasıl bir çözüm önerirsiniz ? Yanımda osiloskopum olmadığı için deneme şansım yok.


(Mesela gerektiğinde 45kHz olacak gerektiğinde 76kHz olacak gibi)

Anlatabilmişimdir umarım.
 
Şöyle yapabilirsiniz.
bir tane timer kullanın ve bu timer de iki adet compara no output seçin.birinci compare duty cyle için,ikinci compare ise frekansı ayarlamak için kullanılacak.ikinci comparede counteri sıfırlayarak sayacın tekrar saymasını saglayacan.
static void MX_TIM2_Init(void)
{

static void MX_TIM3_Init(void)
{

/* USER CODE BEGIN TIM3_Init 0 */

/* USER CODE END TIM3_Init 0 */

TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};

/* USER CODE BEGIN TIM3_Init 1 */

/* USER CODE END TIM3_Init 1 */
htim3.Instance = TIM3;
htim3.Init.Prescaler = 36000-1;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 65535;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_OC_Init(&htim3) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_TIMING;
sConfigOC.Pulse = 10000;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_OC_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
sConfigOC.Pulse = 12000;
if (HAL_TIM_OC_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM3_Init 2 */

/* USER CODE END TIM3_Init 2 */

}

void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim == &htim3 && htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1) {
HAL_GPIO_WritePin(OU5_DISK_ENB_GPIO_Port, OU5_DISK_ENB_Pin, 1);
}
if (htim == &htim3 && htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2) {
HAL_GPIO_WritePin(OU5_DISK_ENB_GPIO_Port, OU5_DISK_ENB_Pin, 0);
TIM3->CNT = 0;

}
}

//***********
sConfigOC.Pulse = 3000; bu degerleri degiştirerek nezaman intterupa girecegini yani frekans ve duty i ayarlayabilirsiniz.
Yani işin mantıgı şu şekilde:
Bir tane sayacınız var,ilk degere ulastıgında birinci interrup olusuyor(duty),ikinci degere ulastıgında ikinci interrup oluşmuş oluyor.ikinci interrupa ulaştıgı deger sizin frekansınız olmuş oluyor.ikinci interrupta sayacı tekrar sıfırlayarak baştan saymasını saglayabiliyorsunuz.
Halledemezseniz arayın yardımcı olmaya çalışayım.
 
Şöyle yapabilirsiniz.
bir tane timer kullanın ve bu timer de iki adet compara no output seçin.birinci compare duty cyle için,ikinci compare ise frekansı ayarlamak için kullanılacak.ikinci comparede counteri sıfırlayarak sayacın tekrar saymasını saglayacan.
static void MX_TIM2_Init(void)
{

static void MX_TIM3_Init(void)
{

/* USER CODE BEGIN TIM3_Init 0 */

/* USER CODE END TIM3_Init 0 */

TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};

/* USER CODE BEGIN TIM3_Init 1 */

/* USER CODE END TIM3_Init 1 */
htim3.Instance = TIM3;
htim3.Init.Prescaler = 36000-1;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 65535;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_OC_Init(&htim3) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_TIMING;
sConfigOC.Pulse = 10000;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_OC_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
sConfigOC.Pulse = 12000;
if (HAL_TIM_OC_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM3_Init 2 */

/* USER CODE END TIM3_Init 2 */

}

void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim == &htim3 && htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1) {
HAL_GPIO_WritePin(OU5_DISK_ENB_GPIO_Port, OU5_DISK_ENB_Pin, 1);
}
if (htim == &htim3 && htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2) {
HAL_GPIO_WritePin(OU5_DISK_ENB_GPIO_Port, OU5_DISK_ENB_Pin, 0);
TIM3->CNT = 0;

}
}

//***********
sConfigOC.Pulse = 3000; bu degerleri degiştirerek nezaman intterupa girecegini yani frekans ve duty i ayarlayabilirsiniz.
Yani işin mantıgı şu şekilde:
Bir tane sayacınız var,ilk degere ulastıgında birinci interrup olusuyor(duty),ikinci degere ulastıgında ikinci interrup oluşmuş oluyor.ikinci interrupa ulaştıgı deger sizin frekansınız olmuş oluyor.ikinci interrupta sayacı tekrar sıfırlayarak baştan saymasını saglayabiliyorsunuz.
Halledemezseniz arayın yardımcı olmaya çalışayım.
Öncelikle kusura bakmayın biraz geç cevap veriyorum, sınavlarım vardı. Ve teşekkür ederim genel olarak neden bahsettiğinizi anladım galiba. En azından nasıl düşünmem gerektiğini anladım.

Fakat tam anlamadığımız bir kaç husus var.

Bir tane timerdan iki kanal Compare No Output seçiyoruz. Bunlardan biri duty'yi belirleyecek bir tanesi frekansı belirleyecek Dolayısıyla ilk değerin maksimum ikinci değer kadar olması gerekiyor. Sanıyorum bunu demek istediniz. Bu iki değere göre bir PWM oluşturmuş olduk.

Fakat ben şimdi çıkış PWM sinyalini bu iki bacak haricinde bir bacaktan mı alacağım yoksa bu iki bacaktan biri master diğeri slave mantığıyla birinden mi alacağım.? Kusura bakmayın hiç kullanmadım bu modu da biraz kafam karıştı bu kısımda.

HAL_GPIO_WritePin(OU5_DISK_ENB_GPIO_Port, OU5_DISK_ENB_Pin, 0); Burdan anladığım kadarıyla başka bir bacak üzerinden PWM çıkışı alcaz.

Bir sıkıntım da şu; Söylediğiniz gibi iki tane kanaldan No output açtım ve kod oluşturdum fakat sadece bir tane "sConfigOC.Pulse =" satırı oluştu. Diğerini kendim mi eklemem gerekiyor ?

Bir de, normalde prescaler ve counter periodu önceden belirliyorduk ve bu değerlere göre frekans elde etmiş oluyorduk. Sizin anlattığınız yöntemde 84mhz'lik bir clock frekansı için 40kHZ ve 80kHZ aralıklı bir PWM elde etmek için nasıl bir hesaplama yapmak gerekiyor cubemx kısmında?

Tekrar çok teşekkür ederim...
 
Üretebileceginiz frekans sizin sayacınızın maksimum degerine ve prescaler degerine baglı olarak degişir.
diyelimki 72Mhz(72 000 000Hz) de clock frekansınız var ve önbölücü olarak 720 şeçtiniz.Bu demektirki timer counteriniz 72 000 000/72= 100 000 Hz de çalışacak(yani saniyede 100 000 artacak)
periyot degeri 65535 den büyük olamıyacagı için 100 000 degerine kadar saydırmamız mümkün degil demektir.Böyle bir durumda timer i denit yapıp yeni önbölücü degeri ile tekrar init yaparak sorunu çözebiliriz veya kalibrasyonu çok iyi ayarlayarak belli aralıklarda çalışmasını saglayabiliriz.
Sayac degerlerini siz program içinden degistirebilirsiniz.
örnegin:
htim1.Instance->CR1=10 000 yaparak timerimizin cnt degeri 10 000 e ulaşınca interrup oluşturmasını saglayabiliriz(Burada herhangibir çıkışı set ederiz)
htim1.Instance->CR2=20 000 yaparak timerimizin cnt degeri 20 000 e ulaşınca interrup oluşturmasını saglayabiliriz(Burada herhangibir çıkışı reset ederiz)Bu noktadan itibaren sayacamız ayarladıgımız maksimum degere kadar saymaya(65535) devam edecektir.Bunu tekrar bastan baslatmak için ise bir alt satırda
htim1.Instance->CNT=0; yazarak sayacımızın tekrar sıfırdan saymaya başlamasını saglarız.
bu sayede %50 duyt elde etmiş oldu.CC1 i 5000 yaparsak %25 duyt elde etmiş olacagız.
Bu bilgiler işıgında elde etmek istedigin frekansa göre kalibre edin.
Kolay gelsin.
Ben bu mantıgı Triac ile dimer yaparken kullandım.Bu sayede Pwm elde ederek triac ın ateşleme açısını degiştirdim.Bende frekans sabit duty oranı degişiyordu.Degişen birşey yok büyük ihtimalle sizin yapmak istediginizede cevap verecegini düşünüyorum.
 
Üretebileceginiz frekans sizin sayacınızın maksimum degerine ve prescaler degerine baglı olarak degişir.
diyelimki 72Mhz(72 000 000Hz) de clock frekansınız var ve önbölücü olarak 720 şeçtiniz.Bu demektirki timer counteriniz 72 000 000/72= 100 000 Hz de çalışacak(yani saniyede 100 000 artacak)
periyot degeri 65535 den büyük olamıyacagı için 100 000 degerine kadar saydırmamız mümkün degil demektir.Böyle bir durumda timer i denit yapıp yeni önbölücü degeri ile tekrar init yaparak sorunu çözebiliriz veya kalibrasyonu çok iyi ayarlayarak belli aralıklarda çalışmasını saglayabiliriz.
Sayac degerlerini siz program içinden degistirebilirsiniz.
örnegin:
htim1.Instance->CR1=10 000 yaparak timerimizin cnt degeri 10 000 e ulaşınca interrup oluşturmasını saglayabiliriz(Burada herhangibir çıkışı set ederiz)
htim1.Instance->CR2=20 000 yaparak timerimizin cnt degeri 20 000 e ulaşınca interrup oluşturmasını saglayabiliriz(Burada herhangibir çıkışı reset ederiz)Bu noktadan itibaren sayacamız ayarladıgımız maksimum degere kadar saymaya(65535) devam edecektir.Bunu tekrar bastan baslatmak için ise bir alt satırda
htim1.Instance->CNT=0; yazarak sayacımızın tekrar sıfırdan saymaya başlamasını saglarız.
bu sayede %50 duyt elde etmiş oldu.CC1 i 5000 yaparsak %25 duyt elde etmiş olacagız.
Bu bilgiler işıgında elde etmek istedigin frekansa göre kalibre edin.
Kolay gelsin.
Ben bu mantıgı Triac ile dimer yaparken kullandım.Bu sayede Pwm elde ederek triac ın ateşleme açısını degiştirdim.Bende frekans sabit duty oranı degişiyordu.Degişen birşey yok büyük ihtimalle sizin yapmak istediginizede cevap verecegini düşünüyorum.
Teşekkür ederim tekrar. Bu kısımda ilerleme kaydettim biraz.

Şuan 4 kanaldan full bridge (2 complementary-2 complementary) pwm üretiyorum. Karşılıklı çalışanlardan 2 tanesi sabit fazlı, 2 tanesi de değişken fazlı ( birbirleriyle aynı) çalışması gerekiyor. Yani Phase Shifting yapmam gerekiyor. Bu konuda bilginiz var mı acaba ? Daha doğrusu STM32 üzerince bunu nasıl gerçekleştirebilirim. Cubemx kullanıyorum
 
Eger pwm leri söyledigim metodla ürettiyseniz başlangıç ve bitiş noktalarını başka bir timer aracılıgı ile ileri geri kaydırılarak yapılabilecegini zannediyorum.
 
Burada daha basit yapımı anlatılıyor,ben biraz kulagı tersden göstermişim.
Direk ARR registerini degiştirerek frekansı degiştirebilirmişiz.
 

Forum istatistikleri

Konular
128,134
Mesajlar
915,322
Kullanıcılar
449,853
Son üye
Megaronn

Yeni konular

Geri
Üst