آموزش راه اندازی بخش qei در lpc1768
سلام دوستان
همون طور که ساعاتی قبل قول داده بودم آموزش راه اندازی پریفرال QEI رو در این تاپیک می نویسم تا مرجعی باشه برای دوستانی که برای کاربرد های مختلف، می خوان از این امکان موجود در LPC1768 استفاده کنند.
این اولین مرتبه هست که دارم یه آموزش رو به صورت مجزا در اینترنت می نویسم. و اگه اشکالی در نوشتار هست به بزرگی خودتون ببخشید. (در این نوشته سعی می کنم تا حد امکان مطلب رو ساده، قدم به قدم و با ذکر مثال خدمتتون عرض کنم.)
QEI به چه درد می خوره؟
QEI مخفف Quadrature Encoder Interface هست. تعریف ساده اون عبارت است از ابزاری که شفت موتور وصل می شه تا نشون بده موتور چند درجه چرخیده.
انکودر ها دو دسته اند:
1- سنسور اثر هال: که اگر حال دارید به فیزیک الکترونیک مراجعه کنید و دربارش بخونید و من واردش نمی شم!:mrgreen::mrgreen:
2- انکودرهای نوری: که از 1- یک صفحه واقع واقع بر شفت (با تعدادی سوراخ روی آن)، 2- یک یا دو لیزر و 3- سنسور نوری تشکیل شده. بدین صورت که سوراخ ها روی دیسک قرار دارد. ومنبع و سنسور در دوطرف سوراخ ها با فواصل مشخص ثابت شده اند. و با چرخش شفت و به تبع اون با چرخش دیسکِ متصل به شفت با عبور نور از سوراخ ها و دریافت اون توسط سنسور ها متوجه می شیم که شفت چقدر چرخیده.
توی این لینک می تونین اطلاعات بیشتری در مورد چیستی (!) QEI پیدا کنید:
[Dear Guest/Member you can't see link before replyclick here to register]
پریفرال QEI سه تا ورودی داره: A, B, index
A و B ورودی های سنسور های نوری هستند که به میکرو اعلام می کنند شفت موتور به اندازه معین چرخیده.
نحوه قرارگیری سوراخ ها این شکلی هست: (مناطق سیاه در دایره کوچک سوراخ های A و مناطق سیاه در دایره بزرگ، سوراخ های B هستند.)
[Dear Guest/Member you can't see link before replyclick here to register]
کارکرد ورودی های A و B طبق شکل زیر هست:
[Dear Guest/Member you can't see link before replyclick here to register]
اگر در پالس های بالا دقت کنید، متوجه می شید که چطور میکرو تشخیص می ده که جهت چرخش عوض شده. این تغییر جهت، در شکل بالا با عدد منفی یک نشون داده شده است.
در مورد index که سوال شد بایستی عرض کنم که خیلی از اوقات توی سیستم های servo چند بار رفت و برگشت داشته ایم و یا یه جاهایی پالس ها خراب بوده و یا به هر دلیلی پوزیشنر نمی دونه که کجاست؟!
یا این که توی مسیر برگشت، موقعیت منفی شده و می خواهیم یه مرجعی برای پوزیشن صفر، داشته باشیم. می تونیم توی مختصات x مشخص، یه سنسور بگذاریم و اون رو به index وصل کنیم که هر وقت پوزیشنر به اون نقطه رسید یه پالس به میکرو بده و بدون اعمال وقفه، شمارنده موقعیت رو صفر کنه. و از اون جا شمارش آغاز بشه.
البته می شه تنظیمات رو طوی انجام داد که وقتی پوزیشنر به سنسور برسه، وقفه هم اعمال بشه که در این صورت . که خوب بی شباهت با تعریف وقفه خارجی نیست!
به روز رسانی(در مورد سیگنال index):
توی یه سایت خارجکی خوندم:
INDEX REFERENCE/SIGNAL
The index is a is a once-per-rev output used to establish a reference or return to a known starting position. It is a separate output generated by a special track which produces a single cycle (or transition change) at a unique position or positions such as center, home, zero, or reset point. Sometimes referred to as a marker pulse
یعنی علاوه بر چیز هایی که خدمتتون عرض کردم. می شه یه سنسور گذاشت و به index وصل کرد که به ازای هر دور دیسک انکودر، یه پالس بده!
خوب دیگه من خیلی حرف زدم تا دارم لیوان آب رو می خورم یه صلوات بفرستید.(جدی می گم کارم گیره به خدا)
:125::125:
1 فایل پیوست
آموزش راه اندازی بخش qei در lpc1768
بریم سر مثال. قراره آموزش رو همراه با یه مثال براتون بگذارم.
توی کامنت ها هم سعی کرده ام، به دیتاشیت 1768 رفرنس بدم. و اونجاهایی که می بینید نوشته امpage منظورم صفحه خود دیتاشیت هست.
راه اندازی این بخش به راحتی خوردن یک هلو هست:
در تابع main می نویسیم:
[PHP]
//Basic Configuration:
//Power Control (page 63 Table 46):
LPC_SC->PCONP |= (1<<18);
//configuration for clock in QEI(datasheet,page 57 Table 41.):
LPC_SC->PCLKSEL1 |= (0x01); /*PCLK_QEI = CCLK*/
//configuration for the pins:
LPC_PINCON->PINSEL3 &=~((3<<8)|(3<<14)|(3<<16));
LPC_PINCON->PINSEL3 |=((1<<8)|(1<<14)|(1<<16)); /*PH A&B (p1.20-p1.23)& index(p1.24)*/
[/PHP]
بخش های بالا رو توضیح نمی دم و همه استاد بنده هستید. و برای همه پریفرال ها تقریباً یکسان است.
برای تنظیم نحوه عملکرد انکودر باید رجیستر QEICONF رو دستکاری کرد. نحوه تنظیم این رجیستر در جدول 485 صفحه 550 دیتاشیت اومده:
[Dear Guest/Member you can't see link before replyclick here to register]
برای شروع، کاری به بیت های 1 و 3 نداشته باشید. چون تا جایی که من می دونم برای مسیر برگشت هست.
بیت شماره 1 (SIGMODE): نحوه کارکرد انکودر رو تعیین می کنه:
برای استفاده این پریفرال باید مقدار این رجیستر صفر باشه. تا وظیفه این پریفرال خوندن ورودی های انکودر باشه.(و نه تولید پالس!)
بیت شماره 2 (CAPMODE):
در صورتی که این بیت با 1، مقدار دهی بشه پالس های هر دو ورودی PhA و PhB خونده می شه. که دقت بالایی داره.
اما بعضی وقت ها پیش میاد که ما می خوایم که به ازای هر ورودی انکودر یه وقفه ایجاد بشه و امکان داره روال وقفه اینقدر طول بکشه که در حین اون، انکودر بعدی هم پالس بده و کار رو خراب کنه! در این صورت مقدار این رجیستر رو 0 می گذاریم. در این صورت فقط پالس های وارد شده از PhA خونده می شه و کاری به PhB نداره. هرچند که در این صورت دقت پایین میاد. اما برای موتورهای خیلی سریع مجبوریم این کار رو بکنیم. همچنین شمارنده پالس هم عدد کوچکتری رو نشون می ده و دردسر های احتمالی overflow شمارنده برای تعداد دور بالا رو نخواهیم داشت.
یه نکته ای رو که داشتم فراموش می کردم اینه که هرچند که فقط PhA خونده می شه. اما سیم PhB هم باید به میکرو وصل باشه. و هر دو ورودی باید به میکرو وصل باشند. (این اتصال به میکرو کمک می کنه بفهمه که موتور داره کدوم طرفی می چرخه!)
حالا من به دلخواه می نویسم:
[PHP]
LPC_QEI->QEICONF =(1<<2);/*PhA and PhB function as quadrature encoder inputs.(4x)-(Page 550 Table 485)*/
[/PHP]
که معنی خط بالا اینه که ما هردو ورودی A و B رو داریم می شمریم.
:125::125:
1 فایل پیوست
New آموزش راه اندازی بخش qei در lpc1768
ادامه کدها به شرح زیر هست:
[PHP] LPC_QEI->QEICON = 0x02; /*Control register: Reset position counter on index.(RESPI)*/
LPC_QEI->QEIMAXPOS = 0x693BA; /* 693BA(431034)*58nm~=2.5 cm */
LPC_QEI->CMPOS0 = 0x00; /*Position Compare register */
LPC_QEI->CMPOS1 = 0x00; /*Position Compare register */
LPC_QEI->CMPOS2 = 0x00; /*Position Compare register */
LPC_QEI->INXCMP = 0x00; /*QEI Index Compare registe */
LPC_QEI->QEILOAD = 9999999; /*QEI Timer Reload registe */
LPC_QEI->VELCOMP = 0x00; /*QEI Velocity Compare register */
LPC_QEI->FILTER = 0x10; /* C(12)*8*10ns=0.96us */
[/PHP]
توضیحات سایر رجیستر ها:
QEICON بر اساس جدول زیر تعیین می شه.
[Dear Guest/Member you can't see link before replyclick here to register]
در حالتی که مقدار بیت صفرم، یک بشه. مقدار رجیستر موقعیت صفر می شه. و از این به بعد شمارش موقعیت آغاز می شه.
در حالتی که مقدار بیت یکم، یک بشه. درصورتی که سیگنال index رخ بده، مقدار رجیستر موقعیت صفر می شه. و از این به بعد شمارش موقعیت آغاز می شه.(رجیستر موقعیت در برگیرنده موقعیت فعلی انکودر هست)
در حالتی که مقدار بیت دوم، یک بشه. مقدار رجیستر سرعت، صفر می شه. و از این به بعد شمارش موقعیت آغاز می شه. (رجیستر سرعت، در برگیرنده سرعت فعلی انکودر هست)
در حالتی که مقدار بیت سوم، یک بشه. مقدار رجیستری که تعداد پالس های index رو می شمره صفر می شه. و از این به بعد شمارش index ها مجدداً از سر گرفته می شه.
در مثال فوق، در صورتی که پالس index اعمال بشه، مقدار موقعیت صفر می شه!
مقدار رجیستر QEIMAXPOS در برگیرنده بیشترین مقدار تعریف شده برای موتور هست. مثلا با توجه به این که در دستگاه من فاصله بین 2 سوراخ انکودر، 58 نانو متر هست، تعریف کرده ام که هر وقت مقدار رجیستر position به 431034 (که معادل 2.5 سانتی متر حرکت است) رسید، سرریز شود. و مقدار آن صفر شود (در این صورت تعریف یک وقفه هم امکان پذیر است! که بعداً به آن می پردازم)
رجیستر های CMPOS0-2 رجیستر های مقایسه موقعیت position هستند.
می توانیم آنها را مقدار دهی کنیم. و بعدا تنظیمات وقفه مربوط به آنها را فعال کنیم که هر وقت پوزیشن به هر یک از 3 موقعیت خاص رسید، وقفه ای اعمال شود.
البته من این سه رجیستر رو مقدار دهی نکرده ام. و می توانستم اصلا ننویسم! اما نوشتم که جنبه آموزشی داشته باشد. و مقدار دهی صفر، در صورتی که وقفه های مربوط به آن فعال نشود؛در روال برنامه تأثیری نخواهد داشت.
رجیستر INXCMP نشان دهنده تعداد دفعات index اعمال شده است. مثلا اگر مقدار این رجیستر 4 باشد، با فعال کردن وقفه مربوط به index، پس از چهارمین پالس index اعمالی،می توانیم روال مشخص وقفه مورد نظر را اجرا کنیم!
رجیستر QEILOAD :
قبل از پرداختن به این رجیستر، به این نکته اشاره کنم که مقدار تایمری که زمان بین پالس های انکودر را می شمارد، به صورت نزولی تغییر می کند. (این مقدار در رجیستر QEITIME ذخیره می شود). بعد از هر بار صفر شدن QEITIME، مقدار آن برابر QEILOAD می شود.
راستی در صورتی QEITIME به اندازه کافی بزرگ باشد، میکرو با تقسیم تعداد پالس های اعمال شده در طی زمان QEILOAD، بر مقدار این رجیستر، میزان سرعت را در رجیستر QEIVEL نمایش می دهد.
رجیستر VELCOMP هم شبیه رجیسترهای CMPOS0-2 عمل می کند بدین صورت که در صورتی که مقدار رجیستر سرعت (QEIVEL) کمتر از این رجیستر شود، و در صورتی که وقفه مربوط به آن فعال شده باشد، وارد روال وقفه می شویم.
رجیستر FILTER یک فیلتر نرم افزاری برای حذف نویز های ناشی از لرزش های موتوور و یا نویز های الکتریکی دستگاه است.
بدین صورت که که ما می دانیم که پالس های ورودی انکودر، حتماً طولانی تر از 16 پالس میکرو هست. بنابراین با استفاده از خط آخر نوشته شده در کد من، پالس های کوتاه تر از آن را به عنوان نویز حساب کرده و فیلتر می کنیم.(یعنی انگار که اصلا وجود ندارد)
یه سری نکات و وقفه و تنظیمات دیگه هست که انشالله برای بعد براتون می نویسم.
در صورتی که احساس میکنید. که باید لحن نوشتار رو تغییر بدم یا نکته ای رو رعایت کنم، بهم فیدبک بدین.
همچنین بنده رو دعا کنید که هرچه زودتر پایان نامه ام تموم بشه!
ممنون
:125::125::125:
سید امیر عباس حجازی
2 فایل پیوست
موزش راه اندازی بخش qei در lpc1768
سلام مجدد دوستان!
امیدوارم که مطالب قبل رو پسندیده باشید!
قبل از اینکه به ادامه بحث بپردازم یه چیزی رو اضافه کنم. که در یه سایت خارجکی یه چیزی راجع به index خوندم که به منظور جلوگیری از پراکندگی مطالب، اون رو به انتهای پست اول اضافه می کنم. (بخونید بد نیست)
همچنین اصلاح می کنم که:
رجیستر VELCOMP هم شبیه رجیسترهای CMPOS0-2 عمل می کند بدین صورت که در صورتی که مقدار رجیستر سرعت (QEIVEL) کمتر از این رجیستر شود، و در صورتی که وقفه مربوط به آن فعال شده باشد، وارد روال وقفه می شویم.
خــب! تنظیمات مربوط به انکودر انجام شد.
حالا بریم سر بحث وقفه های مربوط به انکودرها:
در بحث وقفه انکودرها هم مانند بقیه اجزا موجود در میکرو کنترولر یک سری Status register، یک سری Set register، Clear register ، Enable register و یکسری Enable Set register و Enable Clear register داریم. نامگذاری هر کدام از رجیستر ها طبق جدول زیر انجام شده:
هر کدام از رجیستر ها شامل بیت هایی مثل جدول زیر است، که بعداً به توضیح آن خواهم پرداخت:
QEIINTSTAT فقط خواندنی است و وضیت وقفه را نشان می دهد. و شامل بیت هایی برای تنظیم وقفه های مختلف می باشد در صورتی که بیت متناظر با هر کدام یک باشد. یعنی این که وقفه مورد نظر اعمال شده است.
QEIIES حاوی بیت هایی است که با یک کردن هر بیت، وقفه متناظر با آن فعال می شود.
QEIIEC حاوی بیت هایی است که با یک کردن هر بیت، وقفه متناظر با آن غیرفعال می شود.
و احتمالاً به خاطر دارید که در هندلر وقفه بایستی بیت متناظر با وقفه موردنظر پاک شود. برای این کار بیت مورد متناظر با وقفه مورد نظر در رجیستر QEICLR ست می شود. تا وقفه پاک شود.
راستی می دانید کاربرد دقیقQEISET چیست؟ من که نمی دانم! و البته تا به حال به آن نیاز پیدا نکرده ام! دی:
برویم سراغ بیت های جدول دوم.
INX_Int وقفه مربوط به اعمال پالس index هست.
TIM_Int وقفه مربوط به سر ریز تایمر است.(یعنی تایمر به عدد صفر رسیده است!)
VELC_Int وقفه مربوط به این مسأله است که سرعت انکودر کمتر از رجیستر VELCOMP شده.
DIR_Int وقفه مربوط به تغییر جهت حرکت است.
ERR_Int نمایانگر خطای فاز در انکودر است. این اتفاق معمولاً هنگامی می افتد که دو سیگنال برای مقطعی با هم یکی باشند.(و یا این که 180 درجه با هم اختلاف فاز داشته باشند.)(البته این مسئله در زمان هایی که به دلیل سرعت بالا و ضعف سنسور، زمان افت و صعود سیگنال های A و B با هم همپوشانی دارند، رایج است!!)
ENCLK_Int نمایانگر این وقفه است که پالس انکودر اعمال شده!(یعنی این که یک لبه بالا رونده و یا پایین رونده در A یا B اتفاق افتاده است.)
POSx_Int وقفه مربوط به برابری مکان با مکان مشخص شده در رجیستر CMPOSx است.
یعنی اگر مکان با این رجیستر، برابر شد وقفه اعمال می شود.
REV_Int یعنی تعداد سیگنال های index اعمالی، به مقدار دخیره شده در رجیستر INXCMP رسیده است.
POSxREV_Int اعمال همزمان وقفه های POSx_Int و REV_Int (که البته نمی دانم چه زمان هایی به درد می خورد؟!)
در پست بعد یک مثال از گفته های این پست می زنم.
با ما همراه باشید و البته: :125::125:
موزش راه اندازی بخش qei در lpc1768
برای تنظیمات داریم :
[PHP]NVIC_EnableIRQ(QEI_IRQn); /*enable the interrupt*/
NVIC_SetPriority (QEI_IRQn, 0); /*Highest priority*/
LPC_QEI->QEICLR = 0xFFFFFFFF;
LPC_QEI->QEIIEC = 0xFFFFFFFF;
LPC_QEI->QEIIES = (1<<5)|(1<<0); /* enable ENCLK_EN +index pulse */
[/PHP]
دو سطر اول که برای فعال سازی اصلی وقفه انکودر و تعیین اولویت هست.
در دو سطر بعدی تمامی وقفه های قبلی رو به ترتیب پاک و غیر فعال می کنیم.
و نهایتاً در سطر آخر تعیین می کنیم که چه اتفاق هایی رو می خواهیم رصد کنیم و به عنوان وقفه استفاده کنیم.
در روال وقفه می نویسیم:
[PHP]
void QEI_IRQHandler(void){
if((LPC_QEI->QEIINTSTAT & 32)==32){ /* if any pulses accurs */
/*کارهایی رو انجام بده!*/
}
if((LPC_QEI->QEIINTSTAT & 1)==1){ /* if index pulse accurs */
/*کارهایی رو انجام بده!*/
}
LPC_QEI->QEICLR = 0xFFFFFFFF;
}
[/PHP]
و با if مشخص می کنیم که دقیقاً کدوم وقفه مورد نظره!
و در پایان هندلر، پرچم مربوط به وقفه ها رو با استفاده از QEICLR پاک می کنیم.
بحث تموم شد. سوال و ابهامی بود، در خدمتم!
ممنون که مطلب رو تا انتها خوندید.:hi:
التماس دعا
سید امیر عباس حجازی
:125::125::125: