مهندس موفق الکترونیک

مبدل آنالوگ به دیجیتال میکروکنترلرهای LPC1768

اگر جلسات قبلی آموزش میکروکنترلرهای LPC1768 را دنبال کرده باشید میدانید که در جلسه قبلی پورت های ورودی و خروخی LPC1768 را برسی کردیم و یادگرفتیم چطوری پورت ها را بعنوان ورودی/ خروجی تعریف کنیم و مقادیر را روی آنها بنویسیم و یا بخوانیم و همه این کارها را با توابع CMSIS انجام دادیم. در این جلسه به برسی مبدل آنالوگ به دیجیتال lpc17xx_adc.h می پردازیم.

مبدل آنالوگ به دیجیتال lpc17xx_adc.h

مبدل آنالوگ به دیجیتال یا ADC چیست ؟

فرض کنید یک سنسور دما مانند LM35 داریم که به ازای هر درجه سانتی گراد 10mV خروجی دارد.مثلا اگر دما 1درجه سانتیگراد باشد ولتاژ خروجی سنسور 10mV میشه. برای اینکه مقدار دمای این سنسور را بصورت دیجیتالی(روی سون سگمنت ، نمایشگر ال_سی_دی و..) نمایش دهیم باید این مقدار آنالوگ را به دیجیتال تبدیل کنیم.

آیسی های مبدل آنالوگ به دیحیتال یا ADC این کار را برای ما انجام میدهند. روی میکروکنترلرهای ARM و خیلی دیگر از میکروکنترلرها یک ADC نسبتا خوب پیش بینی شده که در موارد زیادی میتواند کارراه انداز باشد.

مشخصات ADC میکروکنترلر LPC1768

  • دقت 12 بیتی (هر مقدار آنالوگ در 12 بیت ذخیره میشود.)
  • بازه یا محدوده اندازه گیری از VREFN تا VREFP میباشد.
  • دارای حالت کاهش توان میباشد.
  • ورودی این ADC مالتی پلکس شده روی 8 پین از پورت های ورودی/خروجی میکروکنترلر
  • سرعت نمونه برداری 200KSPS یا 200000 نمونه در ثانیه
  • هر کانال ورودی دارای یک رجیستر مخصوص جهت نگهداری آخرین وضعیت

مراحل تنظیم و راه اندازی ADC

  1. فعال سازی بیت توان از قسمت ادوات جانبی از رجیستر PCONP
  2. فعال سازی بیت PDN در رجیستر AD0CR
  3. تنظیم کلاک ADC با بیت های 24 و 25 در رجیستر PCLKSEL0
  4. انتخاب حالت ADC برای پین های مورد نظر از رجیستر های PINSEL
  5. تنظیم وقفه های ADC
  • نکته : حداکثر کلاک قابل اتصال به واحد مبدل آنالوگ به دیجیتال 13مگاهرتز میباشد.
  • نکته : دقت یا رزولیشن مبدل برابر است با 0.8mV
مطلب پیشنهادی:  آموزش میکروکنترلرهای ARM سری STM32F4

پایه های ADC روی میکروکنترلر

دو نوع پایه روی میکروکنتلر برای ADC وجود دارد یکی پایه های تغذیه و رفرنس (VDDA,VSSA.VREFN,VREFP) دیگری پایه های کانال ها از ADC0[0-7]

پایه های رفرنس و تغذیه ADC روی میکروکنترلر باید به ولتاژ مناسب وصل شود.معمولا VREFP را به VDD و VREFN را به GND  وصل میکنن و همچنین پایه های تغذیه VDDA را به 3.3 ولت و VSSA را هم به زمین وصل میکنن.

پین های کانال های ADC

کانال ADC
پورت و پین
عملکرد های دیگر پین
AD0 P0.23 0-GPIO, 1-AD0[0], 2-I2SRX_CLK, 3-CAP3[0]
AD1 P0.24 0-GPIO, 1-AD0[1], 2-I2SRX_WS, 3-CAP3[1]
AD2 P0.25 0-GPIO, 1-AD0[2], 2-I2SRX_SDA, 3-TXD3
AD3 P0.26 0-GPIO, 1-AD0[3], 2-AOUT, 3-RXD3
AD4 P1.30 0-GPIO, 1-VBUS, 2- , 3-AD0[4]
AD5 P1.31 0-GPIO, 1-SCK1, 2- , 3-AD0[5]
AD6 P0.3 0-GPIO, 1-RXD0, 2-AD0[6], 3-
AD7 P0.2 0-GPIO, 1-TXD0, 2-AD0[7], 3-

توابع کار با ADC در داخل lpc17xx_adc.h

تابع ADC_Init

این تابع برای پیکربندی اولیه ADC ، اتصال کلاک و تنظیم فرکانس ADC

void ADC_Init(LPC_ADC_TypeDef *ADCx, uint32_t rate);

وروی های تابع :

  • اولی باید LPC_ADC باشه (اشاره گر از نوع LPC_ADC_TypeDef )
  • دومی فرکانس کاری ADC میباشد که حداکثر میتونه 200000 باشه

تابع ADC_IntConfig

تنظیم وقفه ADC

void ADC_IntConfig (LPC_ADC_TypeDef *ADCx, ADC_TYPE_INT_OPT IntType, FunctionalState NewState);
  • ورود اول که باید LPC_ADC باشه
  • ورودی دوم شماره کانالی است که وقفه مربوط به آن را میخواهید فعال کنید.
  • ورودی سوم برای فعال سازی یا غیر فعال سازی وقفه مربوطه هست که با SET فعال و با RESET غیر فعال میشه.
مطلب پیشنهادی:  ارسال و دریافت SMS با STM32 و ماژول SIM800c

تابع ADC_ChannelCmd

void ADC_ChannelCmd (LPC_ADC_TypeDef *ADCx, uint8_t Channel, FunctionalState NewState);

این تابع کانال های ADC را فعال یا غیر فعال میکنه.

  • ورود اول که باید LPC_ADC باشه 🙂
  • ورودی دوم شماره کانال
  • ورودی سوم فعال و غیر فعال سازی با ENABLE فعال و با DISABLE غیر فعال میشه

تابع ADC_StartCmd

void ADC_StartCmd(LPC_ADC_TypeDef *ADCx, uint8_t start_mode);

ورود اول که باید LPC_ADC باشه

ورودی دوم حالت نمونه برداری میباشد که میتونه پیوسته نمونه برداری کنه و یا فقط یک نمونه برداره و موارد دیگر که در زیر همه موارد هستن و عملکرد هر کدام را میتونید تحقیق کنید و ما فعلا با ADC_START_NOW کار کنیم و بعدا میریم سراغ بقیه.

*                 - ADC_START_CONTINUOUS
*                 - ADC_START_NOW
*                 - ADC_START_ON_EINT0
*                 - ADC_START_ON_CAP01
*                - ADC_START_ON_MAT01
*                - ADC_START_ON_MAT03
*                - ADC_START_ON_MAT10
*                - ADC_START_ON_MAT11

تابع ADC_ChannelGetStatus

FlagStatus ADC_ChannelGetStatus(LPC_ADC_TypeDef *ADCx, uint8_t channel, uint32_t StatusType);

این تابع وضعیت پرچم تبدیل های انجام شده را میخونه

  • ورودی اول تابع که LPC_ADC هست
  • ورودی دوم تابع شماره کانال
  • ورودی سوم تابع ، اگر یک باشه پرچم DONE را میخونه و اگر 0 باشه پرچم BURST را میخونه.

تابع ADC_ChannelGetData

uint16_t ADC_ChannelGetData(LPC_ADC_TypeDef *ADCx, uint8_t channel);

این تابع مقدار ADC را میخونه

  • ورودی اول LPC_ADC است
  • ورودی دوم شماره کانال مورد نظر میباشد

تابع ADC_DeInit

void ADC_DeInit(LPC_ADC_TypeDef *ADCx)

این تابع هم ADC را غیر فعال میکنه.

مثال راه اندازی ADC میکروکنترلر LPC1768

چندتا نکته قبل از مثال گفتی است که اولا روش های مختلفی برای خواندن مقدار ADC وجود دارد که ما از روش سرکشی یا POLLING استفاده کردیم که بعدا در موارد پیشرفته بحث میکنیم و برای سادگی بحث زیاد وارد این جور چیزا نمیشیم.

مطلب پیشنهادی:  آموزش میکروکنترلرهای LPC1768 جلسه دوم: برسی امکانات LPC1768

نکته دوم اینکه همانطور که میدانید شاید یک پین میکروکنترلر چندین عملکرد داشته باشد که در جلسه قبلی بحث کردیم.برای انتخاب حالت ADC  عملکرد پین مورد نظر از کتابخونه lpc17xx_pinsel.h استفاده میکنیم که در زیر نحوه پیکر بندی آن آمده است.

پین استفاده شده AD0[5] میباشد. که روی پایه P1[31] قرار دارد.

//begin pinsel confing
	PINSEL_CFG_Type PinCfg;
	PinCfg.Funcnum = 3;
	PinCfg.OpenDrain = PINSEL_PINMODE_NORMAL;
	PinCfg.Pinmode = PINSEL_PINMODE_TRISTATE;
	PinCfg.Pinnum = 31;
	PinCfg.Portnum = 1;
	PINSEL_ConfigPin(&PinCfg);
	 //end pinsel confing

مثال

#include "lpc17xx.h"
#include "lpc17xx_adc.h"
#include "lpc17xx_pinsel.h"
#include "debug_frmwrk.h"


 void delay(void){
  uint32_t i=0;
  for(i=0;i<9999999;i++);
 }
uint16_t read_adc(adc_channel_number)
{
//this function writed by Melec.ir	 
	uint16_t adc_value;

	//adc init
	ADC_Init(LPC_ADC, 100000);
	//adc interrupt DISABLE
	ADC_IntConfig(LPC_ADC,adc_channel_number,DISABLE);
	//adc channel on
	ADC_ChannelCmd(LPC_ADC,adc_channel_number,ENABLE);

		// Start conversion
		ADC_StartCmd(LPC_ADC,ADC_START_NOW);
		//Wait conversion complete
		while (!(ADC_ChannelGetStatus(LPC_ADC,adc_channel_number,ADC_DATA_DONE)));
		//read adc channel
		adc_value = ADC_ChannelGetData(LPC_ADC,adc_channel_number);
	return adc_value;
}


int main (void){
    uint16_t V;
	//begin pinsel confing
	PINSEL_CFG_Type PinCfg;
	PinCfg.Funcnum = 3;
	PinCfg.OpenDrain = PINSEL_PINMODE_NORMAL;
	PinCfg.Pinmode = PINSEL_PINMODE_TRISTATE;
	PinCfg.Pinnum = 31;
	PinCfg.Portnum = 1;
	PINSEL_ConfigPin(&PinCfg);
	 //end pinsel confing 
	 SystemInit();
	 	debug_frmwrk_init();
		
		while(1){

		V=read_adc(5);
		  
		_DBG("ADC= ");
	   	_DBD32(V);
		_DBG("\n");
		delay();
		}

   return 1;
 }

برای راحتی کار یک تابع به اسم uint16_t read_adc(adc_channel_number) نوشتن ورودی آن شماره کانال و خروجی آن مقدار ADC میباشد. بطور مثال در کد بالا با فراخوانی   V=read_adc(5)  مقدار ولتاژ روی کانال 5 را میریزه داخل متغیر V و با توابع  _DBG مقدار تابع را میفرستیم روی پورت  UART0

خروجی روی پورت سریال

مبدل آنالوگ به دیجیتال lpc17xx_adc.h

پایان جلسه ششم 🙂 دوستان عزیز برای تهیه هر جلسه از این آموزش ها کلی نفر ساعت کار میکنیم با رعایت کپی رایت و معرفی وبسایت ما به دوستانتان با ما در این راه شریک باشید.

اگر این نوشته‌ برایتان مفید بود لطفا کامنت بنویسید.

مطالعه دیگر جلسات این آموزش<< جلسه قبلی                    جلسه بعدی >>

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

12 دیدگاه

  1. مطمئن هستین کد درست هست.
    مثلا تو قسمت uint16_t read_adc(adc_channel_number) نباید type آرگمان ورودی مشخص بشه؟
    کامپایلر من keil هست و خطا میگیره از برنامه شما .

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

  3. سلام خسته نباشید.
    مثال بخش آموزش آنالوگ به دیجیتال lpc17xx_adc.h موبه مو اجام دادم ولی با ارور زیر مواجه میشم لطفا راهنمایی بفرمایید.
    adc.axf: Error: L6218E: Undefined symbol check_failed (referred from lpc17xx_adc.o).

  4. سلام آقا من گاها دیدم adc میکر lpc 1768 اعداد نا معقولی نشون می ده تحقیق کردم اثر نویز بیرونی هم نیس از خود میکرو است حالا چطور میشه این مشکل رو حل کرد . واقعا خیلی بده

    • میلاد جهاندیده

      سلام، ولتاژ مرجع صاف صاف و فیلتر‌های مناسب برای ADC و برای تغذیه میکروکنترلر را درست و در جای مناسب تعبیه کنید. با اسیلوسکوپ نویز تغذیه و ADC را چک کنید. اگر بازم مشکلتون حل نشد که برای منم فک کنم چنین اتفاقی چند سال پیش امد از فیلتر‌های دیجیتال که با برنامه نویسی پیاده می‌شن استفاده کنید. مثلا در ساده ترین حالت میانگیر گیری.

      • متاسفانه از فیلتر های دیجیتال استفاده کردن باعث افزایش حجم محاسبات و اینکه من قصد دارم با تبدیل فوریه تا چند هارمونیک رو محاسبه کنم ، و این حجم محاسبات میکرو رو کاملا درگیر کرده و توان محاسبات برای این میکرو دیگه کافی نیست ، باید سعی کنم میزان محاسبات هرچه بیشتر کاهش پیدا کنه و بنظرم باید دنبال ماژول جدا برای اندازه گیری باشم

  5. سلام ببخشید سوالم ابتدایی هست ولی من این فایل های هدر رو پیدا نمیکنم توی نت
    #include “lpc17xx_adc.h”
    #include “lpc17xx_pinsel.h”
    #include “debug_frmwrk.h”

    چندتا پک هم اضافه کردم به keil ولی بازم ارور میده

  6. علی شریفی

    سلام ببخشید من کتابخونه ها رو هم اضافه کردم آژور ها رفته فقط تو تابع تنظیم وقفه ایراد می خوره و ارور میده یعنی خطی که میگه (ADC_IntConfig(LPC_ADC,adc_channel_number,DISABLE
    که فکر میکنم مشکل از پارامتر وسطی هست و هر نوعی هم بهش میدم ارور رفع نمیشه توی فایل هدر از نوع ADC_TYPE_INT_OPT هست که خودش قبلا define شده و این نوع هم باز قبول نمی کنه … کلا پیچیده شده … میخواستم بدونم الآن شما تست کردین بدون ارور اوکی بوده ؟ چون من دیگه مغزم جواب نمیده برای این ارور …

    • میلاد جهاندیده

      سلام علی جان اگر KEIL عوض شده باشه یا لایبری ها تغییر کرده باشن و غیره را من نمیدونم چون چندسال پیش فک کنم 96 این متن را نوشتم…ولی کد بالا با روشی که در جلسه اول نوشتم جواب میداد. آرگومان دوم هم عدد هست فک کنم 8 تا کانال داره که میشه بجاش مثلا 1 بذاری…