Picproje Elektronik Sitesi

MİKRODENETLEYİCİLER => ARM => Konuyu başlatan: Mucit23 - 25 Ekim 2019, 00:19:19

Başlık: DTMF tonu üretme
Gönderen: Mucit23 - 25 Ekim 2019, 00:19:19
Selamlar

STM32 ile daha önce DTMF tonu üreten oldu mu? Nasıl bir mantık yürütmek gerekiyor? Şurda küçük bir örnek buldum ama olayı kafamda canlandıramadım.
https://github.com/robots/STM32/tree/master/dtmf

Basitçe anlatabilecek olan var mı?

Başlık: Ynt: DTMF tonu üretme
Gönderen: OptimusPrime - 25 Ekim 2019, 07:14:06
Dtmf biri yuksek digeri dusuk 2 farkli frekansin toplamindan olusan bir kodlama. Cevirmeli telefondan (darbeli aramadan) sonraki muhtesem bulus. :D

Yuksek ve alcak frekanslara ait lookup table larin olsa bunlari cikista toplayip fs ye kurdugun bir timer uzerinden dac a versen dtmf kodlu sinyali dac cikisinda gorursun.

Dtmf cozmesi biriz sikintili bir is. Ne556 nin datasina bakarsan az cok bir fikir elde edersin.
Başlık: Ynt: DTMF tonu üretme
Gönderen: mufitsozen - 25 Ekim 2019, 07:45:04
Alıntı yapılan: Mucit23 - 25 Ekim 2019, 00:19:19Basitçe anlatabilecek olan var mı?

(https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRGGXu7zwcaOfFD2ccc_3rgdVRfsI0f23p2DhjdNWV1JgLt5Qv2AbqqGuRe&s=10)
Başlık: Ynt: DTMF tonu üretme
Gönderen: LukeSkywalker - 25 Ekim 2019, 09:38:52
Bir kaç farklı yöntem var ama ben her tuşa ait sinyali 8KHz ile örnekleyip tablosunu çıkarttım. Örneklediğim frekansa denk gelecek şekilde kurduğum timer ile her tuşa karşılık gelen tablolardaki değerleri toplayıp ikiye bölerek PWM çıkışına bir alçak geçiren filtre uygulayarak hoparlöre aktardım. Daha sonra çıkan sinyali android telefon ile test ettim. Bire bir sonuç aldım.
Başlık: Ynt: DTMF tonu üretme
Gönderen: Mucit23 - 25 Ekim 2019, 10:03:06
Yöntemi anladım. Şöyle birşey yapsam nasıl olur? 128 elemanlı bir sinüs tablosu kullanarak sinüs değerlerini elde edeceğim. Tek bir sinüs üretmek basit. İki farklı sinüs'ü de iki farklı timer ile elde ederim. Timer Update rutinlerini F1 ve F2 frekanslarını üretecek şekilde kurarım. Daha sonra Update rutinlerinde İki farklı sinyalin toplanması ve DAC'ye gönderilmesi işlemini yaparım. Akşam mutlaka deneyeceğim

Edit: Yalnız faz farkını nasıl oluşturacam? Pek mantıklı gelmedi şimdi. Daha Efektif bir yöntem düşünüyorum. @LukeSkywalker Senin yöntemde güzel. Toplama ve Bölme işlemini neden yaptın onu anlayamadım. Eğer 8Khz'de örneklediysen Örneklediğin değerleri yine 8Khz de çıkışa aktarsan aynı değer çıkması lazım. Zaten sinyaller periyodik. Aslında aynı yöntemi yapabilirim. Her tuş işin ayrı bir lookup tablosu olması gerekecek. Belki hafıza açısından dezavantaj ama işlevsellik açısından daha uygun olur. 
Başlık: Ynt: DTMF tonu üretme
Gönderen: fide - 25 Ekim 2019, 12:13:22
Amacınız yazılımsal dtmf üretmek ise kolay gelsin, basit bir şekilde kullanmak ise mt8870 entegresini tavsiye ederim. 3.579khz kristal ile basit şekilde dtmf üretebilirsiniz.
Başlık: Ynt: DTMF tonu üretme
Gönderen: LukeSkywalker - 25 Ekim 2019, 12:52:46
Alıntı yapılan: Mucit23 - 25 Ekim 2019, 10:03:06Yöntemi anladım. Şöyle birşey yapsam nasıl olur? 128 elemanlı bir sinüs tablosu kullanarak sinüs değerlerini elde edeceğim. Tek bir sinüs üretmek basit. İki farklı sinüs'ü de iki farklı timer ile elde ederim. Timer Update rutinlerini F1 ve F2 frekanslarını üretecek şekilde kurarım. Daha sonra Update rutinlerinde İki farklı sinyalin toplanması ve DAC'ye gönderilmesi işlemini yaparım. Akşam mutlaka deneyeceğim

Edit: Yalnız faz farkını nasıl oluşturacam? Pek mantıklı gelmedi şimdi. Daha Efektif bir yöntem düşünüyorum. @LukeSkywalker Senin yöntemde güzel. Toplama ve Bölme işlemini neden yaptın onu anlayamadım. Eğer 8Khz'de örneklediysen Örneklediğin değerleri yine 8Khz de çıkışa aktarsan aynı değer çıkması lazım. Zaten sinyaller periyodik. Aslında aynı yöntemi yapabilirim. Her tuş işin ayrı bir lookup tablosu olması gerekecek. Belki hafıza açısından dezavantaj ama işlevsellik açısından daha uygun olur. 

Toplama isleminin sebebi ayni anda iki farkli degerin tek cikisa aktarilmasi. İki farkli sinyal seviyesini ayni anda cikisa aktarmak icin bu sekilde bir islem gerceklestirdim.
Başlık: Ynt: DTMF tonu üretme
Gönderen: z - 25 Ekim 2019, 13:11:19
Her tusa basip ornek alinca zaten iki sinyalin toplaminin ornegini almis oluyorsun.
Başlık: Ynt: DTMF tonu üretme
Gönderen: LukeSkywalker - 25 Ekim 2019, 13:27:17
Aslında yanlış söylemişim. Tuşların örneğini almamışım. Sadece DTMF frekanslarını excelde üretip değerlerini almışım.


extern const char w697[];
extern const char w770[];
extern const char w852[];
extern const char w941[];
extern const char w1209[];
extern const char w1336[];
extern const char w1477[];
extern const char w1663[];

char i=0,j=0,key=0;
 
//Place/Copy this part in declaration section
void InitTimer0(){
  T0CON = 0x88;
  TMR0H = 0xFA;
  TMR0L = 0x24;
  GIE_bit = 1;
}


void kurulum()
{
 InitTimer0();
 PWM1_Init(80000);
 PWM1_Start();
 //PWM1_Set_Duty(127);
}

void main() {
kurulum();
TMR0IE_bit = 1;
while(1)
{
i=0,j=0;
TMR0IE_bit = 1;
key=0;
delay_ms(200);
TMR0IE_bit = 0;
delay_ms(200);

i=0,j=0;
TMR0IE_bit = 1;
key=1;
delay_ms(200);
TMR0IE_bit = 0;
delay_ms(200);

i=0,j=0;
TMR0IE_bit = 1;
key=2;
delay_ms(200);
TMR0IE_bit = 0;
delay_ms(200);

i=0,j=0;
TMR0IE_bit = 1;
key=3;
delay_ms(200);
TMR0IE_bit = 0;
delay_ms(200);

i=0,j=0;
TMR0IE_bit = 1;
key=4;
delay_ms(200);
TMR0IE_bit = 0;
delay_ms(200);

i=0,j=0;
TMR0IE_bit = 1;
key=5;
delay_ms(200);
TMR0IE_bit = 0;
delay_ms(200);

i=0,j=0;
TMR0IE_bit = 1;
key=6;
delay_ms(200);
TMR0IE_bit = 0;
delay_ms(200);

TMR0IE_bit = 1;
key=7;
delay_ms(200);
TMR0IE_bit = 0;
delay_ms(200);

i=0,j=0;
TMR0IE_bit = 1;
key=8;
delay_ms(200);
TMR0IE_bit = 0;
delay_ms(200);

i=0,j=0;
TMR0IE_bit = 1;
key=9;
delay_ms(200);
TMR0IE_bit = 0;
delay_ms(2000);
}
//TMR0IE_bit = 0;
}


void Interrupt(){
  if (TMR0IF_bit){
    TMR0IF_bit = 0;

  TMR0H = 0xFA;
  TMR0L = 0x24;
    i++;
    j++;

    switch(key)
               {
                case 0: if(i==25)i=0; if(j==36)j=0; PWM1_Set_Duty(((int)w941[i]+(int)w1336[j])/2);break;
                case 1: if(i==35)i=0; if(j==33)j=0; PWM1_Set_Duty(((int)w697[i]+(int)w1209[j])/2);break;
                case 2: if(i==35)i=0; if(j==36)j=0; PWM1_Set_Duty(((int)w697[i]+(int)w1336[j])/2);break;
                case 3: if(i==35)i=0; if(j==32)j=0; PWM1_Set_Duty(((int)w697[i]+(int)w1477[j])/2);break;
                case 4: if(i==32)i=0; if(j==33)j=0; PWM1_Set_Duty(((int)w770[i]+(int)w1209[j])/2);break;
                case 5: if(i==32)i=0; if(j==36)j=0; PWM1_Set_Duty(((int)w770[i]+(int)w1336[j])/2);break;
                case 6: if(i==32)i=0; if(j==32)j=0; PWM1_Set_Duty(((int)w770[i]+(int)w1477[j])/2);break;
                case 7: if(i==28)i=0; if(j==33)j=0; PWM1_Set_Duty(((int)w852[i]+(int)w1209[j])/2);break;
                case 8: if(i==28)i=0; if(j==36)j=0; PWM1_Set_Duty(((int)w852[i]+(int)w1336[j])/2);break;
                case 9: if(i==28)i=0; if(j==32)j=0; PWM1_Set_Duty(((int)w852[i]+(int)w1477[j])/2);break;
               }

  }
}
Başlık: Ynt: DTMF tonu üretme
Gönderen: OptimusPrime - 25 Ekim 2019, 16:53:59
@Mucit23

Tek tablodan sinus uretmek ile birden fazla tablodan tek bir isaret uretmek arasinda cokda bir fark yok.  ;)

4 satir ve 4 sutun oldugunu dusun @mufitsozen hocamin verdigi tablodaki gibi. Bu durumda 8 farkli tablon var. Diyelimki 5 e basildi. 1336Hz ve 570Hz lik tablolardan birer deger cekip bunlari toplayacaksin. DAC cozunurlugune uygun olarak bolme islemi yapabilirsin. Sonra bu degerle DAC i fs ye uygun olarak ayarladigin bir timer esliginde besleyeceksin.

Zor degil. 1 saatte yaparsin  :)
Başlık: Ynt: DTMF tonu üretme
Gönderen: Mucit23 - 25 Ekim 2019, 17:04:10
Dediğiniz gibi çok zor bir şey değilmiş. Akşam birkaç deneme yapacağım.
Başlık: Ynt: DTMF tonu üretme
Gönderen: mufitsozen - 25 Ekim 2019, 18:09:02
Alıntı yapılan: Mucit23 - 25 Ekim 2019, 17:04:10Dediğiniz gibi çok zor bir şey değilmiş. Akşam birkaç deneme yapacağım.

biraz gayretle daha "bilimsel" bir uygulama yapabilirsiniz. Bu uygulamada size 8-bit resolution yetecektir diye dusunuyorum.

Kisitli hafiza/hiza sahip gomulu bilgisayar uygulamalarinda CORDIC algorithmasi kullanilir diye ogretilmisti bize 45 sene once.

"implementing fixed integer cordic sine function" diye google'larsaniz bir cok kaynak bulabileceginize eminim. (denedim About 26,800 results (0.75 seconds) dedi!  ;) )

kolay gelsin.
Başlık: Ynt: DTMF tonu üretme
Gönderen: Mucit23 - 26 Ekim 2019, 00:03:58
İlk mesajda verdiğim örneği biraz ayrıntılı inceleyince çalışmasını anladım. Aynısını Temize çekerek STM32F4'e uyarladım ve çalıştırdım.

PWM çıkışına 1K ve 100nF ile RC filtreden geçirip çıkan sinyali gözlemledim. Sonuç aşağıdaki gibi.

(https://i.postimg.cc/xTRtTnXn/20191025-224527.jpg)
RC filtreden kaynaklı oldukça fazla gürültü var sinyal üzerinde.  Bundan dolayı PWM yerine DAC kullanmak istedim Fakat DAC'yi düzgün bir şekilde çalıştıramadım. Çıkışta ya sabit sabit gerilim oluyor yada hiçbir şey alamıyorum.

DAC ayarlarım bu şekilde
void DAC_Configuration(void)
{
   // Enable clocks for PORTA and DAC
   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); 
   RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);
   
   // Set up PA.4 as DAC channel 1 output
   GPIO_InitTypeDef GPIO_InitStructure;
   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
   GPIO_Init(GPIOA, &GPIO_InitStructure);
   
   /* DAC channel 1 Configuration */
   DAC_InitTypeDef DAC_InitStructure;
   DAC_InitStructure.DAC_Trigger = DAC_Trigger_None;
   DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
   DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable;
   DAC_Init(DAC_Channel_1, &DAC_InitStructure);

   /* Enable DAC Channel 1 */
   DAC_Cmd(DAC_Channel_1, ENABLE);
}

Bu şekilde sabit değer gönderiyorum
DAC_SetChannel1Data(DAC_Align_12b_R,2048);

Vref 3V civarı dolayısıyla çıkışta Vref/2 görmeyi bekliyorum ama çıkış ya VDD ya da sıfır. Ne etkiliyor anlamıyorum. Bilgisi olan var mı?
 

Başlık: Ynt: DTMF tonu üretme
Gönderen: OptimusPrime - 26 Ekim 2019, 01:10:54
Isaretinde bir gariplik var. Tabloya bakarsan en kotu ihtimal bir isaret digerinin 2.3 kati. Ama senin cikisinda baya yuksek frekansda birseyler var gorunen  sinyalin uzerinde  ???

Fft ile bak bakalim senin frekanslar ordami. RC nin sucu gibi durmuyor bu. Veya sadece tum tablolari teker teker dene.
Başlık: Ynt: DTMF tonu üretme
Gönderen: z - 26 Ekim 2019, 03:54:21
Alıntı YapPWM çıkışına 1K ve 100nF ile RC filtreden geçirip çıkan sinyali gözlemledim. Sonuç aşağıdaki gibi.

Ripili azaltmak icin Ikinci bir 1K 100nF den daha gecir.

Ya da ornekleme frekansini daha da yukselt. Bu durumda tablo boylarin da artar ama Sin fonskiyonlarini tablo olarak tutmak zorunda degilsin. Gercek zamanli da hesaplayabilirsin.
Başlık: Ynt: DTMF tonu üretme
Gönderen: Mucit23 - 26 Ekim 2019, 10:59:09
Evet dün osiloskobun FFT'sini kullanmak aklıma gelmemişti. Hemen şimdi denedim. Doğru çalışıyor gibi.
(https://i.postimg.cc/8cv3MVvt/20191026-102039.jpg)

DC bileşeni çıkarınca aradan aşağıdaki gibi oldu. Kursörü F1 ve F2'ye getirerek tepe frekanslarını buldum.
(https://i.postimg.cc/x1ZvDNhN/20191026-102415.jpg)

F1=840Hz, F2 ise 1320Hz civarı. Şuanda dışarıda DTMF8 veriyorum. Aynı şekilde DTMF1 verdim F1=700Hz, F2=1200Hz civarı ölçtüm. DTMFD de ise 920Hz ile 1640Hz pik yaptı. Tabi osiloskobunda FFT çözünürlüğü yeterli gelmiyor gibi ama yaklaşık olarak aynı değerler pik yapıyor. Diğer değerleri denemedim ama bunlar çalıştıysa hepsi çalışır.

Çalıştırdığım kod bu şekilde. Kodu yazan AVR314 notundan faydalanmış sanırım.
/*
 * Signal generator inspired by AVR314 appnote
 */

#include "stm32f4xx.h"
#include "dtmf.h"

uint8_t dtmf_status = 0;
uint8_t dtmf_low = 0;
uint8_t dtmf_high = 0;

const uint8_t dtmf_code_high[] = {0, 79, 87, 96, 107};
const uint8_t dtmf_code_low[] = {0, 46, 50, 56, 61};

const uint8_t dtmf_sine[128] = {
64,67,70,73,76,79,82,85,88,91,94,96,99,102,104,106,109,111,113,115,117,118,
120,121,123,124,125,126,126,127,127,127,127,127,127,127,126,126,125,124,123,121,
120,118,117,115,113,111,109,106,104,102,99,96,94,91,88,85,82,79,76,73,70,67,
64,60,57,54,51,48,45,42,39,36,33,31,28,25,23,21,18,16,14,12,10,9,7,6,4,3,2,1,1,0,0,0,0,0,
0,0,1,1,2,3,4,6,7,9,10,12,14,16,18,21,23,25,28,31,33,36,39,42,45,48,51,54,57,60};


void DTMF_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
TIM_OCInitTypeDef  TIM_OCInitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;

  /* TIM2 clock enable */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
  /*GPIOA clock enable */
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

  /* GPIOC Configuration: TIM2 CH1 (PA5) */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  /* Connect TIM2 pins to AF2 */ 
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_TIM2);

  /* Time base configuration */
  TIM_TimeBaseStructure.TIM_Period = 0xFF;
  TIM_TimeBaseStructure.TIM_Prescaler = 21-1;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

  /* PWM1 Mode configuration: Channel1 */
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = 0;
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

  TIM_OC1Init(TIM2, &TIM_OCInitStructure);

  TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable);
  TIM_ARRPreloadConfig(TIM2, ENABLE);

  /* Enable the TIM2 gloabal Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

  /* TIM Interrupts enable */
  TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
  /* TIM2 enable counter */
//  TIM_Cmd(TIM2, ENABLE);
}

uint8_t Get_DTMF_Status(void)
{
return dtmf_status;
}


void DTMF_SendTone(uint16_t Tone)
{
if (Tone == 0) { 
TIM_Cmd(TIM2, DISABLE);
dtmf_status = 0;
return;
}

dtmf_low = dtmf_code_low[Tone & 0x0F];
dtmf_high = dtmf_code_high[(Tone >> 4) & 0x0F];

TIM_Cmd(TIM2, ENABLE);
dtmf_status = 1;
}

void DTMF_Update_CallBack(void)
{
static uint16_t low_val = 0;
static uint16_t high_val = 0;
uint16_t output_data;

uint8_t low_ptr;
uint8_t high_ptr;

low_val += dtmf_low;
high_val += dtmf_high;

low_ptr = ((low_val + 4) >> 3) & (0x007F);
high_ptr = ((high_val + 4) >> 3) & (0x007F);

// high + 3/4 low
output_data = dtmf_sine[high_ptr] + (dtmf_sine[low_ptr] - (dtmf_sine[low_ptr] >> 2));
TIM2->CCR1=output_data;
}



Her bir Tim Update kesmesinde DTMF_Update_CallBack fonksiyonunu koşturmak gerekiyor. Bir sonraki duty değeri burada hesaplanıyor.
Bu kodu aldığım örnek uygulamada F103'de denemişti. Bende MCU'nun 72Mhz'de çalıştığını varsayıp Timer bölücü ve period değerlerinden Tim Update Frekansını 15625Hz olarak hesapladım. F4'de tim2 84Mhz ile besleniyor. Aynı sinyali oluşturmak için Tim2 bölücü oranını 21 olarak hesapladım.(ARR=0xFF)
(TIM_UPDATE_FREQ = TIM_CLK/(TIM_PSC+1)/(TIM_ARR + 1)) 
15625Hz update frekansının kullanılmasının amacı nedir onu anlayamadım.

@z dediğin gibi ikinci bir 1K 100nf ikilisini ekleyince DC bileşen çok artıyor. Ama sinyal biraz zayıflasada baya pürüzsüz bir hale geliyor. Bunun çıkışına Seri bir 100nF ile DC biaslanmış ses sinyaline giriş yaparsam muhtemelen sadece istenilen frekansları aktarmış olacağım. Yada Direnç ve kondansatör değerleri ile biraz oynamak lazım.

Fakat DAC niye çalışmıyor? Elimin altında DAC var iki kanal ve ikisinide kullanmıyorum. DAC için eksik bir şeyler mi yapıyorum acaba bilgisi olan var mı?
Başlık: Ynt: DTMF tonu üretme
Gönderen: z - 26 Ekim 2019, 11:44:52
STM derslerindeki orneklerde DAC kullanmistik. Ordaki register bazli init islemini aynen kullanabilirsin.
Başlık: Ynt: DTMF tonu üretme
Gönderen: devrecii - 26 Ekim 2019, 14:32:46
Bunun demodulasyonu çok zor olur eğer hazır bir makina için kullanmayacaksan tek telden çok farklı yöntemler ile iletebilrisin , mesela dört farklı frkası dört farlkı duty cycle haline getirip ya da birbirinden bağımsız frkanlar üretebilrisn , mesela böyle.

(https://i.ibb.co/hMxDjhN/dfggled.png)
Başlık: Ynt: DTMF tonu üretme
Gönderen: OptimusPrime - 26 Ekim 2019, 22:14:58
O isaretin uzerindeki yuksek frekansli arkadasinin frekansi nedir? Pwm e esitmi? Fft de bunu da gorebilmen lazim.