در قسمت قبل از سری آموزش STM32 با توابع HAL، در مورد تایمرهای نگهبان مستقل و پنجرهای (IWDG و WWDG)، صحبت شد. در این قسمت، تایمر در حالت Encoder و کاربرد آن را بررسی میکنیم. با سیسوگ همراه باشید.
یک نمونه Rotary Encoder
Rotary Encoder ها جزو دستهای از گروه بزرگتری از دستگاههای الکترونیکی، یعنی Encoder ها هستند. Encoder ها دستهای از وسایل الکترونیکی هستند که در کاربردهای مختلف و بهمنظورهای مختلفی مثل شمارش و یا اندازهگیری موقعیت، سرعت و جهت حرکت، استفاده میشوند. Encoder ها به دو دسته کلی Encoder های خطی (Linear) و چرخشی (Rotary) تقسیم میشوند. همچنین هر یک از این 2 دسته، براساس نوع اندازهگیری (Absolute یا Incremental) و یا تکنولوژی مورداستفاده (مثلاً مغناطیسی، لیزر، مکانیکی، نوری و..) شامل انواع مختلفی از Encoder ها میشوند.
انواع Encoder
روش اندازهگیری در این نوع Encoder متفاوت است که این امر موجب میشود هرکدام کاربردهای خودشان را داشته باشند. Absolute Encoder، میتواند موقعیت را بدون نیاز به نقطه مرجع گزارش کند، درحالیکه Incremental Encoder، تنها تغییرات را اندازه میگیرد و برای بهدست آوردن موقعیت نیاز به یک مرجع دارد. Absolute Rotary Encoder میتواند برای اندازهگیری موقعیت زاویهای بهکار رود. درحالیکه Incremental Rotary Encoder برای شمارش، اندازهگیری موقعیت خطی و اندازهگیری سرعت، کاربرد دارد.
Encoderهای Abolute و Incremental
نحوه عملکرد Incremental Encoder بدینصورت است که شفت این دستگاه به یک قسمت دایرهای شکل شفاف و کدر، مانند یک چرخ، متصل شده است. در یک سوی آن، یک فرستنده اشعه و در قسمت دیگر یک دریافتکننده قرارداد. با چرخیدن محور دستگاه، پالسهای الکتریکی تولید میشوند که سپس میتوانند در مقیاس مناسب قرار گیرند و برای محاسبات مختلف توسط برنامه استفاده شوند.
نحوه کارکرد Incremental Encoder
در مقابل شفت Absolute Encoder، به صفحهای متصل است که برای مشخص کردن موقعیتهای زاویهای مختلف، روی آن شکافهای قوس مانندی بهصورت کد شده ایجادشده است. یک قسمت دیگر از طریق ارسال و دریافت اشعهی از میان صفحه در حال گردش، موقعیت زاویهای شفت را مشخص میکند. ذکر این نکته دارای اهمیت است که در هنگام خاموش شدن این نوع Encoder، برخلاف Incremental Encoder، موقعیت دریافت شده قبلی، حفظ میشود و در زمان روشن شدن مجدد دستگاه قابل دریافت است.
نحوه کارکرد Absolute Encoder
تا اینجای کار بهصورت کلی با Encoder ها آشنا شدیم. Encoder مورداستفاده در این قسمت آموزش، یک Incremental Rotary Encoder است که در ادامه، جزییات ساختار و کاربرد آن را بیشتر بررسی میکنیم.
تولید دو سیگنال پالس مربعی در خروجی A و B توسط otary Encoder
در این نوع Encoder، در زمان چرخش دستگیره یا همان شفت، دو سیگنال موج مربعی با اختلاففاز 90 درصد روی دو خروجی A و B تولید میشود. اختلاففاز این دو سیگنال بدینصورت است که اگر چرخش بهصورت ساعتگرد باشد، سیگنال A از B جلوتر خواهد بود و در صورت پادساعتگرد بودن چرخش، وضعیت دو سیگنال A و B برعکس میشود و سیگنال B جلوتر قرار میگیرد.
بنابراین برای یافتن جهت حرکت به هر دو خروجی نیاز خواهیم داشت. درحالیکه برای اعمالی مثل شمارش، یافتن موقعیت یا میزان حرکت و همچنین یافتن سرعت حرکت، تنها به یکی از خروجیها نیاز داریم.
کاربردهای زیادی برای این Encoder وجود دارند که از میان آنها میتوان شمارش وسایل یا محصولات در حال حرکت روی یک غلتک و یا برش ورقههای فلزی در حال حرکت توسط یک ماشین، اشاره کرد.
یک کاربرد نمونه از Incremental Rotary Encoder در برش ورقههای فلزی
سنسور یا همان Rotary Encoder مورداستفاده در این بخش، مانند تصویر نشان دادهشده در زیر است که به دو صورت بدون بورد و مونتاژ شده روی بورد وجود دارد؛
Encoder مورد استفاده
مدار استفادهشده در این بورد بهصورت نشان دادهشده در شکل زیر است:
مدار استفاده شده در بورد Encoder
اکنونکه تا حدود با جزییات و مکانیزم Rotary Encoder آشنا شدهایم، به سراغ ایجاد و توسعه یک پروژه نمونه برای بهکار بردن این قطعه میپردازیم.
در این پروژه نیز مانند گذشته بخشهای کلاک، دیباگ و USART1 را تنظیم میکنیم و یک پایه (مثلاً PA2) را نیز بهعنوان ورودی و در حالت Pull-up، برای اتصال به پایه SW موجود روی Encoder، قرار میدهیم. همانطور که در مدارهای مربوط به Encoder مورداستفاده نشان دادهشده است، این پایه مربوط به کلید فشاری است که در صورت فشرده شدن، پایه SW به زمین متصل میشود.
حالا باید یک تایمر (TIM2) را در حالت Encoder تنظیم کنیم.
تنظیم 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 */ |
پس از کامپایل و دانلود، میتوانیم نتیجه اجرا را در ترمینال سریال ببینیم:
نتیجه تغییرات Encoder در ترمینال سریال
همچنین میتوانیم با اضافه کردن کد شرطی زیر، در هنگام فشرده شدن کلید، مقدار شمارنده را در حد وسط آن یا صفر برگردانیم (البته روش صحیح این است که این عمل در وقفه خارجی صورت گیرد):
1 2 3 4 | if(!pinState) { TIM2->CNT = 32767; } |
در این قسمت از سری آموزش STM32 با توابع HAL، حالت Encoder تایمر و کاربرد آن را بررسی کردیم. در قسمت بعدی، در مورد نحوه استفاده از تایمر برای خواندن سنسور Hall صحبت خواهیم کرد. با ما همراه باشید.
با عرض سلام و خسته نباشید…
واقعا دمتون گرم با این آموزش های خوبی که گذاشتید برای STM32، مشتاقانه منتظر ادامه آموزش ها هستیم و امیدوارم ادامه دار باشه
ممنون از سایت خوب سیسوگ و سیاوش عزیز بابت زحمت هاش
نویسنده شو !
سیسوگ با افتخار فضایی برای اشتراک گذاری دانش شماست. برای ما مقاله بنویسید.