PWM çıkış ile sinüs üretmek

semih_s

Kıdemli Üye
Katılım
16 Aralık 2020
Mesajlar
1,455
Bu koda bir de analog değer eklemek istiyorum ama nasıl ya da ne yapmam gerektiğini bilmiyorum. Aslında PWM çıkışı verdiğim portun birine bir kondansatör ile sinüs çıktı alabilirim sanırım. Bu noktada tavsiye iyi olur.

Tavsiye olmadı bu pek. muhtemelen işinize de bu haliyle yaramaz, yalnız tamamen interruptlarla çalışıyor ve loop size kalıyor.

sünüs:
byte adim=0;
char yon=1;
byte genlik[128];
float buffer_f;

ISR(TIMER2_COMPA_vect)
{
  // sinüs dalga için
  OCR1B=genlik[adim];
  adim++;
  if(adim>118)adim=0; // serinin başına döner
 
  /*
  // üçgen dalga için
  OCR0B=adim+1;
  adim+=yon;
  if(adim==100)yon=-1;
  if(adim==0)yon=1;
  */
}
 
void setup() {
  // 360 dereceyi 3 dercelik adımlarla örnekleyerek sinüsü simüle etmeye çalışacağım.
  // sin0 ila sin357 değerleri lazım sonra seri yeni baştan. 119 değer yapıyor.
 
  for(byte i=0;i<119;i++)
  {
    buffer_f= i*3;          // hesaplanacak açı
    buffer_f=buffer_f * M_PI / 180; //açı radyana çevrilir
    // i açısının sinüsünü 0-100 arasında yayar. ofseti 2,5V olan bir sinüs bekliyorum.
    genlik[i]=sin(buffer_f)*50+50; 
    
  }
  //Timer 0 ile pwm ve analog sinyal üretimi
  pinMode(10,OUTPUT);
  pinMode(6,OUTPUT);
  //Arduino defaultlarını iptal eder
  TCCR1B=0;
  TCCR1A=0;
  TIMSK1=0;
 
  TCCR1A|= 1<<COM1B1 | 1<<WGM11 | 1<<WGM10; // keyfi PWM periyodu(OCR0Aile ayarlanır)PWM çıkışı OC0B
  TCCR1B|= 1<<WGM12 | 1<<WGM13;
  OCR1A=100;                                // PWM çözünürlüğü 100;
  OCR1B=50;                                 // Başlangı. için %50 duty
  TCCR1B|=0b1;                              // PRSCL=1;
 
  delay(5000);
  // timer2 ile dalga formu üretimi
  //arduino defaultlarını 0'la
  TCCR2A=0;
  TCCR2B=0;
  TIMSK2=0;

  TCCR2A|=1<<WGM21;   // CTC modda OCR2A üst değer, sinyal frekansını bu belirleyecek
  TIMSK2|= 1<<OCIE2A; // sayacın OCR2A ile eşleşmesinde interrupt üretir.
  TCCR2B|=0b101;
  OCR2A=100;          // dalga formunun frekansını belirler, ters orantılı 1 ila 255
  // put your setup code here, to run once:

}

void loop() {
 

 
  // put your main code here, to run repeatedly:

}

Bu kod arduino uno D10 pininden 10kOhm ve 220nf lowpass filtre ile sinüs üretiyor.
timer1 ile pwm üretip timer2 ile duty cycle tayin ediyor. OCR2A ile frekans değiştirilebiliyor.

Ekran Görüntüsü (59).png

exelde baya bir sinüse benziyordu. sonra kodladım.

IMG20230228013516.jpg


üstteki sarı sinyal pwm ile sinüsü ürettim. Bunun kusursuz bir sinüs dalgadan ne kadar farklı olduğunu nasıl ölçerim?

Yalnız böyle sinüs üretmek pek iyi değil, frekansı arttırdıkça genlik düşüyor. yalnız gerekli frekansa göre kod ve devre düzenlenerek daha yüksek frekanslar elde edilebilir herhalde.

Bu iyi geldi, meşgale arıyordum :) .
 

Ekler

  • sünüs deneme.zip
    30.2 KB · Görüntüleme: 89
Osiloskobun FFT fonksiyonunu kullanabilirsiniz. Mükemmel bir sinüste tek pik görürsünüz. Diğer pikler ne kadar yüksekse sinüs o kadar bozuktur.
IMG20230228022847.jpg


Biraz kurcalayınca böyle bir grafik çıkardı. Bilgisayara bağlamalı osiloskobu, fotoğrafla iyi olmuyor. Konuyu dağıtmış olmayayım, ben biraz araştırayım.
 
@semih_s Hocam hiç uğraştırmayayım şu videoyu izleyin bütün incelikleri anlatılıyor.


Özet olarak sinüsü göremeyecek kadar sıklaştıracak şekilde zaman knobunu ayarlarsanız neredeyse düzgün bir spektrum görüntüsü görmeye başlıyorsunuz. Amaç ölçümü yaparken kullandığı örnekleme yapacağı nokta sayısını arttırmak diye biliyorum. Şu an ekranda 7 tepe noktası var 50-60 tane olsa görüntü güzelleşecek aslında. Videoda düzgün okumak için ortalama almak vb. bir iki numara daha öğretiyor.
 
Osiloskopta THD (total harmonic distortion) ölçme fonksiyonu da olabilir. THD sinüsteki bozulma için iyi bir ölçüdür.

Bu arada online UPS'lerde sinüs üretimi de aynen buradaki gibi PWM bazlıdır. İkinci inverter'deki IGBT'ler PWM ile sürülür, çıkıştaki PWM de bir alçak geçiren LC filtre ile sinüs hale getirilir.
 
Son düzenleme:
Urettiginiz sinyalin turevini alin. Temiz bir sinusel sinyalin turevi de temiz bir sinuseldir.

Aksi halde turetilmis sinyal cok bozuk olacaktir.
 
Evet osiloskop yenilenmiş, hayırlı olsun :tamam1 Pişman etmeyecek bir cihazdır.
 
Ben de aşağıdaki kaynaktaki kodu denedim.


C++:
int F = 2;
int Fs = 500;
int n = 500;
float t;
int sampling_interval;
byte samples[500];

void setup() {
  pinMode(10, OUTPUT);
  for (int n = 0; n < 500; n++) {
    t = (float)n / Fs;
    samples[n] = (byte)(127.0 * sin(2 * 3.14 * t) + 127.0);
  }
  sampling_interval = 1000000 / (F * n);
}

void loop() {
  for (int j = 0; j < 500; j++) {
    analogWrite(10, samples[j]);
    delayMicroseconds(sampling_interval);
  }
}

Kodun çıkışındaki PWM sinyali.

ScreenImg.png


Sitedeki şemada direnç olmadığı için oradaki şemeya göre ilerlerseniz aşağıdaki sinyal görüntüsü ile karşılaşıyorsunuz.

ScreenImg(1).png


Şemaya alçak geçirgen olacak şekilde 10k direnç eklediğinizde sinyal aşağıdaki gibi oluyor.

ScreenImg(2).png
 
@semih_s in kodu kesmelerle çalışıyor o yüzden muntazam örnekleme yapılmış oluyor. Bu da sinüsün daha temiz olması anlamına gelir.
 
@semih_s in kodu kesmelerle çalışıyor o yüzden muntazam örnekleme yapılmış oluyor. Bu da sinüsün daha temiz olması anlamına gelir.
Yazdığım kod zamanlama olarak ideale yakın, ama dalga formunu daha iyi temsil edecek şekilde düzenlenmesi gerekebilir. PWM çözünürlüğünü ve örnekleme sayısını artırarak daha iyi bir sinüs elde edilebilir. Benim kodda yuvarlama hataları da daha yüksek, biraz daha dikkatli çalışmak lazım. @Sercan uyguladığınız kodda 500 örnek var. Üzerinde daha çok çalışılmış gibi duruyor. Ama bu sinyali kullanacak işlemler, seri monitör'e yazdırma vb. işin içine girerse dalga formu çarpılmaya başlayacak. interrupt ile bu büyük ölçüde önleniyor. Hatta kodda delay fonksiyonu bile kullanılsa dalga formu bozulmaz.
 
Aynı koşullarda @semih_s in yazdığı kodun görüntüsü de aşağıdaki gibi. Diğerine çok benziyor.


ScreenImg(3).png
 
Urettiginiz sinyalin turevini alin. Temiz bir sinusel sinyalin turevi de temiz bir sinuseldir.

Aksi halde turetilmis sinyal cok bozuk olacaktir.
IMG20230228195431.jpg


Türevi böyle oldu. (sinx)'=cosx ve görünüşe göre de öyle. Ama "dx 0.4 div " olarak ayarlı mevcut parametreyi değiştirince türev grafiği bulanıklaşıyor. bunu yorumlayamıyorum. hesabı nasıl yapıyor cihaz, bu parametre neyi değiştiriyor anlamadım.
 
Aynı koşullarda @semih_s in yazdığı kodun görüntüsü de aşağıdaki gibi. Diğerine çok benziyor.

Şimdi 2 Hz lik sinyal üretiyorsun, tabi bu durumda zamanlama ile ilgili değişkenlikler çok küçük olur. Ama mesela 1 kHz kare dalga üretirsen, o zaman interruptlu ve interrupt suz arasında bariz fark olur. İnterruptlu kodda zamanlama tam ve muntazamdır, çünkü doğrudan hardware garantiliyor doğru timing'i. Ama interruptsuz yaparsan o zaman istenen zamanlamayı çoğu zaman sağlayamazsın, çünkü frekansı biraz arttırayım diye bir imkan yok. Komutların işleyiş timing'i orada seni kısıtlar.
 

Çevrimiçi üyeler

Forum istatistikleri

Konular
5,659
Mesajlar
97,343
Üyeler
2,438
Son üye
İbrahimSönmez

Son kaynaklar

Son profil mesajları

cemalettin keçeci wrote on HaydarBaris's profile.
barış kardeşim bende bu sene akıllı denizaltı projesine girdim ve sensörleri arastırıyorum tam olarak hangi sensör ve markaları kullandınız yardımcı olabilir misin?
m.white wrote on Altair's profile.
İyi akşamlar.Arabanız ne marka ve sorunu nedir.Ben araba tamircisi değilim ama tamirden anlarım.
* En mühim ve feyizli vazifelerimiz millî eğitim işleridir. Millî eğitim işlerinde mutlaka muzaffer olmak lâzımdır. Bir milletin hakikî kurtuluşu ancak bu suretle olur. (1922)
Kesici/Spindle hızı hesaplamak için SpreadSheet UDF'leri kullanın, hesap makinesi çok eski kalan bir yöntem :)
Dr. Bülent Başaran,
Elektrik ve Elektronik Mühendisi
Yonga Tasarım Özdevinimcisi
Üç güzel "çocuk" babası
Ortahisar/Ürgüp/Konya/Ankara/Pittsburgh/San Francisco/Atlanta/Alaçatı/Taşucu...

Back
Top