Haberler:

Forum kuralları güncellendi LÜTFEN  okuyunuz:  https://bit.ly/2IjR3ME

Ana Menü

DTMF tonu üretme

Başlatan Mucit23, 25 Ekim 2019, 00:19:19

Mucit23

#15
Evet dün osiloskobun FFT'sini kullanmak aklıma gelmemişti. Hemen şimdi denedim. Doğru çalışıyor gibi.


DC bileşeni çıkarınca aradan aşağıdaki gibi oldu. Kursörü F1 ve F2'ye getirerek tepe frekanslarını buldum.


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ı?

z

STM derslerindeki orneklerde DAC kullanmistik. Ordaki register bazli init islemini aynen kullanabilirsin.
Bana e^st de diyebilirsiniz.   www.cncdesigner.com

devrecii

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.


OptimusPrime

O isaretin uzerindeki yuksek frekansli arkadasinin frekansi nedir? Pwm e esitmi? Fft de bunu da gorebilmen lazim.
https://donanimveyazilim.wordpress.com || Cihân-ârâ cihân içredir ârâyı bilmezler, O mâhîler ki deryâ içredir deryâyı bilmezler ||