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

semih_s

Hobici
Katılım
16 Aralık 2020
Mesajlar
1,969
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.

Kod:
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

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.


Kod:
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.
 
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.
 

Forum istatistikleri

Konular
7,234
Mesajlar
122,413
Üyeler
2,923
Son üye
birisim

Son kaynaklar

Son profil mesajları

Freemont2.0 herbokolog Freemont2.0 wrote on herbokolog's profile.
nick iniz yakıyor
:D
Freemont2.0 posta Freemont2.0 wrote on posta's profile.
Merhabalar :)
az bilgili çok meraklı
Prooffy semih_s Prooffy wrote on semih_s's profile.
Merhaba, sizden DSO2C10 hakkında bilgi rica ettim. Yanıtlarsanız sevinirim...
Unal taydin Unal wrote on taydin's profile.
Timur Bey, Arduino kontrollü bir akü şarj cihazı yapmaya çalışıyorum. Aklımdaki fikri basit bir çizim olarak konu açmıştım. Özellikle sizin fikirlerinizi çok önemsiyorum.
Back
Top