در قسمت قبل از سری آموزش STM32 با توابع HAL، در مورد تایمرهای نگهبان مستقل و پنجرهای (IWDG و WWDG)، صحبت شد. در این قسمت، تایمر در حالت Encoder و کاربرد آن را بررسی میکنیم. با سیسوگ همراه باشید.
Rotary Endcoder چیست و چگونه کار میکند؟
Rotary Encoder ها جزو دستهای از گروه بزرگتری از دستگاههای الکترونیکی، یعنی Encoder ها هستند. Encoder ها دستهای از وسایل الکترونیکی هستند که در کاربردهای مختلف و بهمنظورهای مختلفی مثل شمارش و یا اندازهگیری موقعیت، سرعت و جهت حرکت، استفاده میشوند. Encoder ها به دو دسته کلی Encoder های خطی (Linear) و چرخشی (Rotary) تقسیم میشوند. همچنین هر یک از این 2 دسته، براساس نوع اندازهگیری (Absolute یا Incremental) و یا تکنولوژی مورداستفاده (مثلاً مغناطیسی، لیزر، مکانیکی، نوری و..) شامل انواع مختلفی از Encoder ها میشوند.
تفاوت Encoder های Absolute و Incremental
روش اندازهگیری در این نوع Encoder متفاوت است که این امر موجب میشود هرکدام کاربردهای خودشان را داشته باشند. Absolute Encoder، میتواند موقعیت را بدون نیاز به نقطه مرجع گزارش کند، درحالیکه Incremental Encoder، تنها تغییرات را اندازه میگیرد و برای بهدست آوردن موقعیت نیاز به یک مرجع دارد. Absolute Rotary Encoder میتواند برای اندازهگیری موقعیت زاویهای بهکار رود. درحالیکه Incremental Rotary Encoder برای شمارش، اندازهگیری موقعیت خطی و اندازهگیری سرعت، کاربرد دارد.
نحوه عملکرد Incremental Encoder بدینصورت است که شفت این دستگاه به یک قسمت دایرهای شکل شفاف و کدر، مانند یک چرخ، متصل شده است. در یک سوی آن، یک فرستنده اشعه و در قسمت دیگر یک دریافتکننده قرارداد. با چرخیدن محور دستگاه، پالسهای الکتریکی تولید میشوند که سپس میتوانند در مقیاس مناسب قرار گیرند و برای محاسبات مختلف توسط برنامه استفاده شوند.
در مقابل شفت Absolute Encoder، به صفحهای متصل است که برای مشخص کردن موقعیتهای زاویهای مختلف، روی آن شکافهای قوس مانندی بهصورت کد شده ایجادشده است. یک قسمت دیگر از طریق ارسال و دریافت اشعهی از میان صفحه در حال گردش، موقعیت زاویهای شفت را مشخص میکند. ذکر این نکته دارای اهمیت است که در هنگام خاموش شدن این نوع Encoder، برخلاف Incremental Encoder، موقعیت دریافت شده قبلی، حفظ میشود و در زمان روشن شدن مجدد دستگاه قابل دریافت است.
ساختار Incremental Rotary Encoder و کاربرد آن
تا اینجای کار بهصورت کلی با Encoder ها آشنا شدیم. Encoder مورداستفاده در این قسمت آموزش، یک Incremental Rotary Encoder است که در ادامه، جزییات ساختار و کاربرد آن را بیشتر بررسی میکنیم.
در این نوع Encoder، در زمان چرخش دستگیره یا همان شفت، دو سیگنال موج مربعی با اختلاففاز 90 درصد روی دو خروجی A و B تولید میشود. اختلاففاز این دو سیگنال بدینصورت است که اگر چرخش بهصورت ساعتگرد باشد، سیگنال A از B جلوتر خواهد بود و در صورت پادساعتگرد بودن چرخش، وضعیت دو سیگنال A و B برعکس میشود و سیگنال B جلوتر قرار میگیرد.
بنابراین برای یافتن جهت حرکت به هر دو خروجی نیاز خواهیم داشت. درحالیکه برای اعمالی مثل شمارش، یافتن موقعیت یا میزان حرکت و همچنین یافتن سرعت حرکت، تنها به یکی از خروجیها نیاز داریم.
کاربردهای زیادی برای این Encoder وجود دارند که از میان آنها میتوان شمارش وسایل یا محصولات در حال حرکت روی یک غلتک و یا برش ورقههای فلزی در حال حرکت توسط یک ماشین، اشاره کرد.
سنسور یا همان Rotary Encoder مورداستفاده در این بخش، مانند تصویر نشان دادهشده در زیر است که به دو صورت بدون بورد و مونتاژ شده روی بورد وجود دارد؛
مدار استفادهشده در این بورد بهصورت نشان دادهشده در شکل زیر است:
اکنونکه تا حدود با جزییات و مکانیزم Rotary Encoder آشنا شدهایم، به سراغ ایجاد و توسعه یک پروژه نمونه برای بهکار بردن این قطعه میپردازیم.
ایجاد پروژه
در این پروژه نیز مانند گذشته بخشهای کلاک، دیباگ و USART1 را تنظیم میکنیم و یک پایه (مثلاً PA2) را نیز بهعنوان ورودی و در حالت Pull-up، برای اتصال به پایه SW موجود روی Encoder، قرار میدهیم. همانطور که در مدارهای مربوط به Encoder مورداستفاده نشان دادهشده است، این پایه مربوط به کلید فشاری است که در صورت فشرده شدن، پایه SW به زمین متصل میشود.
حالا باید یک تایمر (TIM2) را در حالت Encoder تنظیم کنیم.
اکنون تنظیمات موردنیاز برای راهاندازی اولیهی Encoder انجامشده است. پس پروژه را ذخیره میکنیم و وارد کد میشویم.
نوشتن کد پروژه
مانند پروژههای پیشین، ابتدا اعمال مربوط به ریتارگت کردن stdio را انجام میدهیم. سپس در تابع int main دو متغیر زیر را برای ذخیره حالت کلید و شمارنده تعریف میکنیم:
1 2 3 4 | /* USER CODE BEGIN 1 */ uint8_t pinState = 0; uint32_t counterValue = 0; /* USER CODE END 1 */ |
سپس هردو کانال Encoder مربوط به TIM2 را راهاندازی میکنیم:
1 | HAL_TIM_Encoder_Start(&htim2, TIM_CHANNEL_ALL); |
اکنون کد زیر را در حلقه while(1) مینویسیم تا در هنگام چرخش دستگیره Encoder یا فشرده شدن کلید آن، تغییر وضعیت در پورت سریال چاپ شود:
1 2 3 4 5 6 7 8 9 10 11 12 | /* USER CODE BEGIN WHILE */ while (1) { if((pinState != HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_2)) || (counterValue != TIM2->CNT)) { pinState = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_2); counterValue = TIM2->CNT; printf("Switch state: %s \t Counter value: %lu \r\n", pinState ? "Not Pressed" : "Pressed", counterValue); } /* USER CODE END WHILE */ |
پس از کامپایل و دانلود، میتوانیم نتیجه اجرا را در ترمینال سریال ببینیم:
همچنین میتوانیم با اضافه کردن کد شرطی زیر، در هنگام فشرده شدن کلید، مقدار شمارنده را در حد وسط آن یا صفر برگردانیم (البته روش صحیح این است که این عمل در وقفه خارجی صورت گیرد):
1 2 3 4 | if(!pinState) { TIM2->CNT = 32767; } |
در این قسمت از سری آموزش STM32 با توابع HAL، حالت Encoder تایمر و کاربرد آن را بررسی کردیم. در قسمت بعدی، در مورد نحوه استفاده از تایمر برای خواندن سنسور Hall صحبت خواهیم کرد. با ما همراه باشید.
با عرض سلام و خسته نباشید…
واقعا دمتون گرم با این آموزش های خوبی که گذاشتید برای STM32، مشتاقانه منتظر ادامه آموزش ها هستیم و امیدوارم ادامه دار باشه
ممنون از سایت خوب سیسوگ و سیاوش عزیز بابت زحمت هاش