پروژه انتقال صدا در بستر شبکه


مقدمه

امروزه شبکه های مختلف مخابراتی، به جزئی مهم و حیاتی از زندگی روزمره تبدیل شده اند. هر روزه برای تطبیق با نیازها و کاربردهای مختلف صورت پیشرفته تر و پیچیده تری از شبکه های مخابراتی با امکانات و ویژگی های جدید معرفی می شوند. به عنوان نمونه کنفرانس های تلفنی و سرویس های انتقال تماس از نیازهای مبرم و البته به نسبت هزینه بر در شبکه های مخابراتی می باشد.
بستر اینترنت، کمک شایانی به رفع مشکلات مربوط به شبکه های مخابراتی کرده است و امکان برقراری ارتباط موفقیت آمیز در اشکال مختلف، یکی از دستاوردهای انکارناپذیر اینترنت می باشد. زمانی که دیتای منتقل شده در یک شبکه صوت باشد، مفهوم VOIP مطرح می شود. (Voice Over Internet Protocol)

شرح مختصر پروژه

در این پروژه ابتدا صدا ورودی توسط میکروفن تقویت و سپس به یک سطح ولتاژ مناسب برای مبدل آنالوگ به دیجیتال میکروکنترلر تبدیل میشود.سپس با استفاده از تایمر، مبدل ADC در یک زمان مشخص تریگ میشود تا نمونه برداری از صدا با یک فرکانس مشخص انجام شود.پس از این که صدا در یک بافر به صورت دیجیتالی ذخیره شد توسط شبکه به کامپیوتر ارسال میگردد.در کامپیوتر با استفاده از نرم افزار C# صدا دریافتی به بلندگو های کامپیوتر ارسال میگردد.

سخت افزار پروژه

سیگنال خروجی میکروفون های متداول به صورت سیگنالی با دامنه در حد میلی ولت می باشد که در قسمت موج منفی نیز وارد می شود. به همین دلیل نیاز به تغییر سطح ولتاژ و نیز تقویت دامنه آن وجود دارد. در این پروژه آپ امپ مورد استفاده برای کاهش نویز صدا و نیز تغییر سطح ولتاژ به نحوی که امکان اعمال سیگنال صوتی به واحد ADC میکروکنترلر فراهم شود، آپ امپ TLV2442 از شرکت Texas Instruments می باشد.

این ماژول میکروفون در کنار برد آموزشی STM32F107 نامینیک که بخش مربوط به لایه فیزیکال شبکه را نیز شامل می شود. سخت افزار پروژه را تشکیل می دهند.

در شکل زیر مدار تقویت و تغییر سطح سیگنال مربوط به سمت راست میکروفون را ملاحظه می کنید. همین آرایش برای سیگنال سمت چپ نیز استفاده می شود. ( به شکل مجزا )

برد مدار چاپی ماژول میکروفون را در این شکل ملاحظه می کنید.

با استفاده از پتانسیومتر 100 کیلواهمی می توان تغییر سطح ولتاژ را متناسب با نوع میکروفون و کاربرد مدنظر تغییر داد

شرح نرم افزار سمت میکروکنترلر 

صدای دریافت شده به صورت استریو توسط دو کانال واحد ADC میکروکنترلر، نمونه برداری می شود. از آنجا که در این پروژه وظیفه اصلی میکروکنترلر پروسه انتقال صدا تحت شبکه می باشد. به منظور کم کردن بار کاری پردازنده، و بهبود در فرآیند نمونه برداری، از واحد DMA میکروکنترلر استفاده می شود، بدین شرح که DMA پس از پیکربندی اولیه وظیفه دارد یک بافر 1400 تایی از واحد ADC با نرخ مشخص 32 کیلوهرتز را ذخیره کند. با انجام این کار مشکلی در که در پروژه پیش آمد، عدم پیوستگی در صدای ارسالی به شبکه بود به این دلیل که در مدت زمانی که بعد از اتمام نمونه برداری ADC، دیتا به شبکه ارسال می شود، در مدت مشخصی، مثلا 10 میلی ثانیه وقفه در عمل نمونه برداری می افتد و منجر به رخداد وقفه هایی در صدا شبیه صدای ” تیک” می شود. به همین دلیل با استفاده از یک تکنیک نرم افزاری از دو بافر به شکل الاکلنگی استفاده شد، بدین صورت که بافر اول که پر می شود، تحت شبکه ارسال می شود و در همین حین توسط واحد DMA بافر دیگری نیز در حال پر شدن است که این بافر ثانویه در ارسال بعدی توسط شبکه مورد استفاده قرار می گیرد. و این رویه به طور مدام انجام می شود تا دیگر وقفه ای در نمونه برداری صدا ایجاد نشود و صدا به صورت آنلاین به شبکه ارسال شود. البته تاخیری در حدود 10 میلی ثانیه در انتقال صدا با پروتکل TCP مشاهده می شود که با استفاده از پروتکل UDP این تاخیر به مقدار یک میلی ثانیه کاهش یافت.

در ادامه بخش های مختلف نرم افزار نوشته شده در محیط Keil شامل کتابخانه نمونه برداری صدا و توابع ارسال به شبکه تشریح می شود.

شرح کتابخانه soundlib

در ابتدا تعاریف مورد نیاز برای دو کانال مورد استفاده از واحد ADC انجام می شود.

 /* Private define ------------------------------------------------------------*/
#define ADC1_DR_Address    ((uint32_t)0x4001244C)
#define ADCChannel_Line1   8   //ADC1 CHANEEL 8 ON PB.0
#define ADCChannel_Line2   9   //ADC1 CHANEEL 9 ON PB.1


__IO uint8_t  ADC_SoundRight[1400];

در تابع ledkeyInit  کلیدهای فشاری و LED های برد آموزشی پیکربندی می شوند

در تابع RCC_Configuration کلاک واحدهای مورد نیاز فعال می شود، به عنوان نمونه در این پروژه از واحد DMA برای خواندن مقادیر از ADC استفاده می کنیم، فعال کردن کلاک این واحد بدین صورت می باشد:

/* Enable DMA1 clock */
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

در تابع TIMER_Configuration تنظیمات تایمر برای نمونه برداری از واحد ADC با نرخ 32 کیلوهرتز انجام می شود، کلاک واحد تایمر 72 مگاهرتز می باشد و برای تنظیم تایمر در حالتی که با نرخ 32 کیلوهرتز واحد ADC را تریگ کند، باید مقادیر تقسیم کننده و دوره تناوب تایمر بدین شکل تنظیم شود:

TIM_TimeBaseStructure.TIM_Period = 2249;    //this is for 32khz audio sampling ---> 2249 = 32khz 
TIM_TimeBaseStructure.TIM_Prescaler = 0;

در تابع DMA_Configuration پیکربندی واحد DMA انجام می شود: واحد ADC به عنوان مبدا انتقال می باشد و بافر ADC_SoundRight در فضای RAM داخلی میکروکنترلر، مقصد انتقال می باشد.


DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADC_SoundRight;

در تابع ADC_Configuration واحد ADC به صورت تریگ با تایمر فعال می شود

        ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;

همچنین دو کانال مورد نیاز از واحد ADC در حالت Scan و به صورت معمول ADC پیکربندی می شوند

 

        ADC_InitStructure.ADC_ScanConvMode = ENABLE;
        ADC_InitStructure.ADC_NbrOfChannel = 2;
       /* ADC1 regular channelconfiguration */
        ADC_RegularChannelConfig(ADC1, ADCChannel_Line1, 1, ADC_SampleTime_28Cycles5);
        /* ADC1 regular channelconfiguration */
        ADC_RegularChannelConfig(ADC1, ADCChannel_Line2, 2, ADC_SampleTime_28Cycles5);

از آنجا که برای خواندن مقدار ADC از واحد DMA استفاده می کنیم، برای فعال کردن این واحد از دستور زیر استفاده می کنیم

        /* Enable ADC1 DMA */
        ADC_DMACmd(ADC1, ENABLE);	

همچنین تریگر واحد ADC با استفاده از تایمر می باشد و به همین دلیل با استفاده از دستور زیر این فرمان را اعمال می کنیم

        /* Enable ADC1 external trigger */
        ADC_ExternalTrigConvCmd(ADC1, ENABLE);

واحد ADC با استفاده از این دستور فعال می شود

        /* Enable ADC1 */
        ADC_Cmd(ADC1, ENABLE);

نکته مهم در کار با واحدهای آنالوگ نیاز به کالیبراسیون آن می باشد که با استفاده از تکه کد زیر انجام می شود

        /* Enable ADC1 reset calibaration register */
        ADC_ResetCalibration(ADC1);
        /* Check the end of ADC1 reset calibration register */
        while(ADC_GetResetCalibrationStatus(ADC1));

        /* Start ADC1 calibaration */
        ADC_StartCalibration(ADC1);
        /* Check the end of ADC1 calibration */
        while(ADC_GetCalibrationStatus(ADC1));	

توضیح تابع main

در این پروژه برای راه اندازی شبکه از کتابخانه TCPnet بسته نرم افزاری RL-ARM استفاده می کنیم. در مورد جزئیات راه اندازی شبکه در کتاب “میکروکنترلر های ARM STM32 به همراه پروژه های کاربردی” شرکت نامینیک توضیحات مبسوط ارائه شده است. در این قسمت با رویکرد کاربردی به مفاهیم و راه اندازی شبکه خواهیم پرداخت.

آدرس IP میکروکنترلر و کامپیوتر بدین شکل تنظیم می شود

        while(ADC_GetCalibrationStatus(ADC1));
U8 	IP_PC[4] ={192,168,0,104};
U8	IP_UC[4] ={192,168,0,101};

در تابع udp_SendData با استفاده از توابع کتابخانه TCPnet به شرح زیر، عبارتی با طول مشخص با استفاده از پروتکل UDP ارسال می شود.

/*----------------------------------------------------------------------------
  UDP Sendig packet
 *----------------------------------------------------------------------------*/
void udp_SendData (U8 *udp_msg, U16 len)
{
	U8 *sendbuf;
	U16 i;

	sendbuf = udp_get_buf(len);

	memcpy (sendbuf, udp_msg, len);

	udp_send(socket_udp, IP_PC, PORT_NUM, sendbuf, len);
}	

در تابع send_datalog با استفاده از توابع کتابخانه TCPnet به شرح زیر، عبارتی با طول مشخص با استفاده از پروتکل TCP ارسال می شود.

/*----------------------------------------------------------------------------
  TCP Sendig packet
 *----------------------------------------------------------------------------*/
BOOL send_datalog (U8 *data_buf,U16 number) {
  U8 *sendbuf;
  U16 maxlen;

  if (tcp_check_send (socket_tcp)) {
    /* The socket is ready to send the data. */
    maxlen = tcp_max_dsize (socket_tcp);
    sendbuf = tcp_get_buf (maxlen);
    memcpy (sendbuf, data_buf,number);
    tcp_send (socket_tcp, sendbuf, number);
    return (__TRUE);
  }
  return (__FALSE);
}

تابع tcp_callback  ، در زمان دریافت دیتایی با پروتکل TCP از شبکه فراخوانی می شود

برنامه اصلی

در ابتدا با استفاده از  تابع init_TcpNet پروتکل شبکه که از کتابخانه RL-ARM انتخاب شده، آغازسازی می شود.

در گام بعدی یک سوکت از نوع TCP باز می شود و اگر این سوکت با موفقیت باز شد، سوکت باز شده در حالت tcp_listen قرار می گیرد.

  /* Initialize TCP Socket and start listening */
  socket_tcp = tcp_get_socket (TCP_TYPE_SERVER, 0, 10, tcp_callback);
  if (socket_tcp != 0) {
    tcp_listen (socket_tcp, PORT_NUM);
  }

سپس با استفاده از تابع StartSampling فرآیند نمونه برداری واحد ADC آغاز می شود.

در حلقه بی نهایت برنامه با استفاده از تابع send_datalog بافری که دیتای نمونه برداری شده از واحد ADC در آن ذخیره شده است، یعنی ADC_SoundRight به شبکه ارسال می شود.

تابع main_TcpNet برای نظارت و مدیریت رخدادهای شبکه استفاده می شود و باید به مدت هر 100 میلی ثانیه اجرا شود تا در عملکرد شبکه اختلالی ایجاد نشود.


در تصویر زیر نمایی از نرم افزاری شسمت رایانه که با سی شارپ نوشته شده است ملاحظه می کنید.

جمع بندی

در این پروژه پروسس اصلی میکروکنترلر ارسال داده های خوانده شده از واحد ADC توسط واحد شبکه میکروکنترلر می باشد. به همین دلیل با استفاده از واحد های تایمر، ADC و DMA بدون نیاز به درگیر کردن پردازنده، دیتای مدنظر در بافر های ارسالی به شبکه قرار می گیرند. زمانی که بافر به طور کامل پر شد با فراخوانی وقفه مربوط به اتمام کار DMA، دستور ارسال داده ها به شبکه انجام می شود.

فایل شماتیک و برد مدارچاپی ماژول میکروفون

فایل سورس پروژه با نرم افزار Keil

 


کانال تلگرام نامینیک

گروه تلگرام نامینیک ARM STM32


 

Tags: , , , , , , , , , , , , ,