در این جلسه به برسی مبدل آنالوگ به دیجیتال lpc17xx_adc.h میپردازیم.
مبدل آنالوگ به دیجیتال یا ADC چیست؟
فرض کنید یک سنسور دما مانند LM35 داریم که به ازای هر درجه سانتی گراد 10mV خروجی دارد. مثلا اگر دما 1درجه سانتیگراد باشد ولتاژ خروجی سنسور 10mV میشه. برای اینکه مقدار دمای این سنسور را بصورت دیجیتالی(روی سون سگمنت ، نمایشگر ال_سی_دی و..) نمایش دهیم باید این مقدار آنالوگ را به دیجیتال تبدیل کنیم.
آیسیهای مبدل آنالوگ به دیحیتال یا ADC این کار را برای ما انجام میدهند. روی میکروکنترلرهای ARM و خیلی دیگر از میکروکنترلرها یک ADC نسبتا خوب پیش بینی شده که در موارد زیادی میتواند کارراه انداز باشد.
مشخصات ADC میکروکنترلر LPC1768
- دقت 12 بیتی (هر مقدار آنالوگ در 12 بیت ذخیره میشود.)
- بازه یا محدوده اندازهگیری از VREFN تا VREFP میباشد.
- دارای حالت کاهش توان میباشد.
- ورودی این ADC مالتی پلکس شده روی 8 پین از پورتهای ورودی/خروجی میکروکنترلر
- سرعت نمونه برداری 200KSPS یا 200000 نمونه در ثانیه
- هر کانال ورودی دارای یک رجیستر مخصوص جهت نگهداری آخرین وضعیت
مراحل تنظیم و راهاندازی ADC
- فعال سازی بیت توان از قسمت ادوات جانبی از رجیستر PCONP
- فعال سازی بیت PDN در رجیستر AD0CR
- تنظیم کلاک ADC با بیتهای 24 و 25 در رجیستر PCLKSEL0
- انتخاب حالت ADC برای پینهای مورد نظر از رجیسترهای PINSEL
- تنظیم وقفههای ADC
- نکته : حداکثر کلاک قابل اتصال به واحد مبدل آنالوگ به دیجیتال 13مگاهرتز میباشد.
- نکته : دقت یا رزولیشن مبدل برابر است با 0.8mV
پایههای 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 غیر فعال میشه.
تابع 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 استفاده کردیم.
نکته دوم اینکه همانطور که میدانید شاید یک پین میکروکنترلر چندین عملکرد داشته باشد که در جلسه قبلی بحث کردیم. برای انتخاب حالت 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
خروجی روی پورت سریال
منبع: میکرودیزاینرالکترونیک