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

مدولاسیون عرض پالس یا PWM در STM32 – کنترل سرعت فن DC

در جلسات قبلی، استفاده از مبدل آنالوگ به دیجیتال (ADC) در میکروکنترلر STM32 را با هم یاد گرفتیم. در این جلسه می‌خواهیم به سراغ تکنیک PWM در این میکروکنترلر برویم و یاد بگیریم که چگونه می‌توانیم با استفاده از آن شدت نور یک LED و یا سرعت یک فن DC را کنترل کنیم.

مدولاسیون عرض پالس در میکروکنترلر STM32F103C8: کنترل سرعت فن DC

می‌دانیم که سیگنال‌ها دو نوع هستند، آنالوگ و دیجیتال. سیگنال‌های آنالوگ دارای ولتاژهایی مانند ۱ ولت، ۳ ولت و … هستند اما سیگنال‌های دیجیتال فقط مقادیر ۰ و ۱ را می‌پذیرند. یعنی ولتاژ آنها یا ۰ و یا ۱ است.

از طرفی خروجی سنسورها سیگنال‌های آنالوگ است و چون میکروکنترلرها فقط زبان دیجیتال را می‌فهمند، پس این سیگنال‌ها ابتدا به کمک مبدل‌های ADC به معادل دیجیتال خود تبدیل شده و بعد وارد مرحله‌ی پردازش با میکروکنترلر می‌شوند. اما بعد از اینکه پردازش شدند، از آنجایی که قرار است دوباره به دیوایس‌هایی بروند که آنها نیز با مقادیر آنالوگ کار می‌کنند و کنترل می‌شوند، پس مجددا باید از فرمت دیجیتال به آنالوگ برگردانده شوند. برای این تبدیل از روش‌هایی مانند PWM یا مبدل‌های دیجیتال به آنالوگ (DAC) استفاده می‌کنیم.

مدولاسیون عرض پالس یا PWM چیست؟

PWM روشی برای کنترل دیوایس‌های آنالوگ با استفاده از مقادیر دیجیتال است. مثلا کنترل شدت نور یک LED و یا کنترل سرعت یک فن DC.

این دیوایس‌ها با سیگنال‌های آنالوگ کار می‌کنند اما PWM سیگنال‌های آنالوگ خالص تولید نمی‌کند. در حقیقت پالس‌هایی با عرض بسیار کم تولید می‌کند که در مجموع شبیه به یک سیگنال آنالوگ به نظر می‌رسند. این پالس‌های کوتاه براساس duty cycle ساخته می‌شوند.

Duty cycle در PWM

منظور از duty cycle، نسبت زمانی که در آن سیگنال در وضعیت High قرار دارد، به کل زمان یک سیکل است. با این تعریف، واضح است که اگر یک سیگنال همواره یک باشد، duty cycle آن ۱۰۰ درصد  و اگر همواره صفر باشد، duty cycle آن صفر درصد است.

Duty Cycle =Turn ON time/ (Turn ON time + Turn OFF time)

PWM در میکروکنترلر STM32

این میکروکنترلر دارای ۱۵ پین PWM و ۱۰ پین ADC است. ۷ عدد تایمر نیز در داخل آن وجود دارند که هر کدام از خروجی‌های PWM توسط کانالی که به ۴ عدد از این تایمرها متصل است تولید می‌شود. رزولوشن PWM در آن ۱۶ بیتی است (یعنی ۲۱۶) و این بدان معناست که شمارنده‌ها (کانتر) و متغیرهای آن می‌‌توانند تا مقدار ۶۵۵۳۵ را بپذیرند.

فرکانس کلاک آن 72MHz است و در نتیجه حداکثر پریود زمانی خروجی‌های PWM آن می‌تواند در حدود ۱ میلی ثانیه باشد.

چند نتیجه‌ی کوتاه از پاراگراف فوق:

  • ۶۵۵۳۵ حداکثر سرعت فن DC و حداکثر شدت روشنایی LED را ایجاد می‌کند. (duty cycle : 100%)
  • به همین ترتیب اگر مقدار ۳۲۷۶۷ باشد (تقریبا نصف مقدار ۶۵۵۳۵)، سرعت فن و شدت روشنایی LED نصف مقدار فوق خواهند شد .(duty cycle :50%)
  • و مثلا مقداری مانند ۱۳۱۰۷، ۲۰ درصد حالت اول شدت روشنایی و سرعت فن می‌دهد. (duty cycle : 20%)

مدولاسیون عرض پالس در میکروکنترلر STM32F103C8: کنترل سرعت فن DC

در این پروژه ما با استفاده از یک پتانسیومتر، duty cycleهای مختلفی از سیگنال PWM تولید شده توسط STM32 را ایجاد می‌کنیم تا بتوانیم شدت نور LED و سرعت فن DC را کنترل کنیم. همچنین از یک نمایشگر LCD 16×2 هم استفاده می‌کنیم که در هر کدام از حالت‌های پتانسیومتر، مقدار ADC (عددی بین ۰ تا ۴۰۹۵) و مقدار PWM (عددی بین ۰ تا ۶۵۵۳۵) بر روی آن نمایش داده شوند.

مطلب پیشنهادی:  آموزش اتصال سروو موتور به STM32

تجهیزات مورد نیاز برای انجام پروژه

  • میکرو کنترلر STM32F103C8
  • DC fan
  • یک IC برای درایور موتور: ULN2003
  • LED قرمز رنگ
  • LCD 16×2
  • پتانسیومتر
  • برد بورد
  • باتری ۹ ولتی
  • سیم جامپر

DC Fan

در اینجا ما از یک فن BLDC که آن را از یک کامپیوتر قدیمی گرفته‌ایم استفاده می‌کنیم. از آنجایی که این فن برای کار کردن به تغذیه‌ی خارجی نیاز دارد، از باتری DC نه ولتی (9V) به همین منظور استفاده می‌کنیم.

ULN2003 Motor Driver IC

این درایور برای به حرکت درآوردن فن استفاده می‌شود و جهت حرکت آن یک طرفه است. نمای کلی این IC را در تصویر زیر می‌بینید.

مدولاسیون عرض پالس در میکروکنترلر STM32F103C8: کنترل سرعت فن DC

پین‌های IN1 تا IN7 پین‌های ورودی و OUT1 تا OUT7 خروجی‌های متناظر آنها هستند. به پورت COM هم یک منبع ولتاژ مثبت متصل می‌شود که برای خروجی‌ها لازم است.

LED

در اینجا ما از LED قرمز رنگ استفاده می‌کنیم که نور ساطع شده از آن رنگ قرمز دارد و البته اصراری بر قرمز بودن آن نیست. شما می‌توانید از هر رنگ دلخواه دیگری هم استفاده کنید.

پتانسیومتر

دو عدد پتانسیومتر نیاز داریم، که یکی برای تقسیم ولتاژ در ورودی آنالوگ ADC به میکروکنترلر و دیگری برای تنظیم duty cycle در سیگنال PWM تولید شده است.

پایه‌های میکروکنترلر STM32

مدولاسیون عرض پالس در میکروکنترلر STM32F103C8: کنترل سرعت فن DC

پین‌های PWM در نقشه‌ی فوق با علامت شکل موج (~)  قابل تشخیص هستند. می‌بینیم که ۱۵ عدد از این پین‌ها وجود دارد. پین‌های ADC هم با رنگ سبز مشخص شده‌اند که می‌بینیم ۱۰ عدد هستند. از این پین‌ها برای دریافت ورودی آنالوگ استفاده می‌شود.

نقشه مدار و اتصالات

مدولاسیون عرض پالس در میکروکنترلر STM32F103C8: کنترل سرعت فن DC

نحوه‌ی اتصال میکروکنترلر STM32 به قسمت‌های مختلف مدار به این ترتیب است.

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

پتانسیومتری که در سمت چپ مدار وجود دارد، در نقش یک رگولاتور ولتاژ برای پین ۳.۳ ولت ظاهر می‌شود. خروجی این پتانسیومتر (که از پایه‌ی وسطی آن گرفته می‌شود) به یکی از پین‌های ADC میکروکنترلر وصل می‌شود. در اینجا ما آن را به PA4 وصل می‌کنیم.

میکروکنترلر به LED

خروجی PWM میکروکنترلر (در اینجا PA9) به واسطه‌ی یک مقاومت سری و خازن به پایه‌ی مثبت LDC متصل می‌شود.

LED به خازن و مقاومت

یک مقاومت با آرایش سری و یک خازن با آرایش موازی به LED متصل می‌شوند تا سیگنال آنالوگ گرفته شده از PWM را که به صورت آنالوگ کاملی نیست، به صورتی مرتب و تصحیح شده به LED برسانند.

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

یکی از خروجی‌های PWM میکروکنترلر (در اینجا PA8) را به یکی از ورودی‌های ULN2003 (در اینجا IN1) متصل می‌کنیم و خروجی متناظر این پین یعنی OUT1 را هم به سیم منفی فن DC.

سیم مثبت فن را هم به پین COM درایور وصل می‌کنیم. باتری ۹ ولتی هم به پورت COM وصل می‌شود. پین‌های Gnd میکروکنترلر، داریور و سر منفی باتری هم همگی به یک زمین مشترک در مدار وصل می‌شوند.

میکروکنترلر به LCD

مدولاسیون عرض پالس در میکروکنترلر STM32F103C8: کنترل سرعت فن DC

یک پتانسیومتر در سمت راست مدار وجود دارد که کنتراست LCD را تنظیم می‌کند. جدول فوق چگونگی اتصال میکروکنترلر و LCD را توضیح می‌دهد.

مطلب پیشنهادی:  آموزش کار با وقفه در میکروکنترلر STM32

مدولاسیون عرض پالس در میکروکنترلر STM32F103C8: کنترل سرعت فن DC

پروگرم کردن STM32

در این آموزش هم مانند آموزش‌های قبلی، میکرو STM32 را از طریق پورت USB و با استفاده از Arduino IDE پروگرم می‌کنیم. به این ترتیب نیازی به پروگرمر FTDI نخواهیم داشت. اگر طریقه‌‌ی پروگرم کردن STM32 با استفاده از Arduino IDE را نمی‌دانید به این لینک مراجعه کنید. روال این کار درست مشابه پروگرم کردن بوردهای آردوینو است.

کد کامل این پروژه را در انتهای آموزش قرار داده‌ایم.

اما در این کد قرار است چه کاری انجام دهیم؟ می‌خواهیم یک مقدار آنالوگ را از پین PA4) ADC) بگیریم (این پین به پایه‌ی وسطی پتانسیومتر سمت چپی وصل بود) و سپس مقدار آنالوگ دریافت شده را (که در محدوده‌ی ۰ تا ۳.۳ ولت قرار دارد) به فرمت دیجیتال یا int (عددی بین ۰ تا ۴۰۹۵) تبدیل کنیم. این مقدار دیجیتال سپس تبدیل به یک خروجی PWM می‌شود که می‌توانیم به کمک آن سرعت فن (یا شدت نور LED) را تنظیم کنیم. از LCD هم برای نمایش دادن مقدار ADC و PWM متناظر با آن استفاده می‌کنیم.

ابتدا باید هدر فایل مربوط به LCD را در کد قرار دهیم و پین‌های آن را با کد زیر initialize کنیم. (درباره‌ی اتصال LCD  به STM32 در سایت نوشتیم به طور مفصل بخوانید)

#include <LiquidCrystal.h>    // include the LCD library
const int rs = PB11, en = PB10, d4 = PB0, d5 = PB1, d6 = PC13, d7 = PC14;  //mention the pin                     names to with LCD is connected to
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);  //Initialize the LCD

سپس پین‌های استفاده شده را تعریف می‌کنیم.

const int analoginput   = PA4;  // Input from potentiometer                         
const int led           = PA9;  // LED output
const int fan           = PA8;  // fan output

حال در بخش تابع ()setup باید چند پیام اولیه را نمایش دهیم و بعد از چند ثانیه آنها را از روی صفحه پاک کنیم. پین ورودی و خروجی PWM را هم مشخص می‌کنیم.

    lcd.begin(16,2);          //Getting LCD ready
    lcd.clear();          //Clears LCD
    lcd.setCursor(0,0);          //Sets cursor at row0 and column0
    lcd.print("CIRCUIT DIGEST");          //Displays Circuit Digest
    lcd.setCursor(0,1);          //Sets Cursor at column0 and row1
    lcd.print("PWM USING STM32");   //Displays PWM using STM32
    delay(2000);          // Delay Time
    lcd.clear();          // Clears LCD
    pinMode(analoginput, INPUT);          // set pin mode analoginput as INPUT
    pinMode(led, PWM);          // set pin mode led as PWM output
    pinMode(fan, PWM);          // set pin mode fan as PWM output

با استفاده از تابع pinMode(analoginput, INPUT)، پین PA4 را به عنوان ورودی تنظیم می‌کنیم و LED پین را هم با استفاده از pinMode(led, PWM) به عنوان پین PWM .PWM فن را هم به همین ترتیب تنظیم می‌کنیم، pinMode(fan, PWM).

در اینجا خروجی‌های PWM به PA9) LED) و فن (PA8) متصل هستند.

سپس در بخش تابع حلقه (()loop)، یک سیگنال آنالوگ را از پین PA4) ADC) می‌خوانیم و آن را در یک متغیر integer ذخیره می‌کنیم. این متغیر مقدار دریافت شده را با استفاده از دستور زیر، به یک مقدار دیجیتال بین ۰ تا ۴۰۹۵ تبدیل می‌کند.

 int valueadc = analogRead(analoginput);

نکته‌ای که در اینجا وجود دارد این است که خروجی‌های PWM در SM32، همان طور که گفتیم دارای رزولوشن ۱۶ بیتی هستند. یعنی مقادیر آنها بین ۰ تا ۶۵۵۳۵ است. بنابراین باید بین این دو محدوده یک تناظر برقرار کنیم که با استفاده از رابطه‌ی زیر این کار را انجام می‌دهیم.

int result = map(valueadc, 0, 4095, 0, 65535).

اگر این تبدیل را انجام ندهیم، هر چقدر هم پتانسیومتر را بچرخانیم، نمی‌توانیم حداکثر سرعت ممکن برای فن یا حداکثر شدت نور ممکن برای LED را به دست آوریم.

مطلب پیشنهادی:  اتصال استپر موتور به بورد STM32F103C8

حالا خروجی‌های هر کدام از دو PWM را به LED و فن می‌دهیم؛ دو تابع (pwmWrite(led, result و (pwmWrite(fan, result این کار را برای ما انجام می‌دهند. و در نهایت با استفاده از دستورات زیر، ورودی ADC و خروجی‌های PWM را روی نمایشگر LCD نمایش می‌دهیم.

    lcd.setCursor(0,0);          //Sets cursor at row0 and column0
    lcd.print("ADC value= ");           // prints the words “”
    lcd.print(valueadc);          //displays valueadc
    lcd.setCursor(0,1);           //Sets Cursor at column0 and row1
    lcd.print("Output =   ");          //prints the words in ""
    lcd.print(result);            //displays value result

در ادامه می‌توانید به کد کامل و ویدئویی از انجام مراحل پروژه دسترسی داشته باشید.

کد

#include <LiquidCrystal.h>     // include the LCD library
const int rs = PB11, en = PB10, d4 = PB0, d5 = PB1, d6 = PC13, d7 = PC14;  //mention the pin names to with LCD is connected to 
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);  //Initialize the LCD

const int analoginput   = PA4;  // Input from potentiometer                          
const int led           = PA9;  // LED output
const int fan           = PA8;  // fan output

void setup() 
{
    lcd.begin(16,2);     //Getting LCD ready
    lcd.clear();  //Clears LCD
    lcd.setCursor(0,0);  //Sets cursor at row0 and column0
    lcd.print("CIRCUIT DIGEST");   //Displays Circuit Digest
    lcd.setCursor(0,1);          //Sets Cursor at column0 and row1
    lcd.print("PWM USING STM32");   //Displays PWM using STM32
    delay(2000);       // Delay yime
    lcd.clear();       // Clears LCD
    pinMode(analoginput, INPUT);   // set pin mode analoginput as INPUT
    pinMode(led, PWM);           // set pin mode led as PWM output
    pinMode(fan, PWM);            // set pin mode fan as PWM output
}    
   

void loop()

   { 
    int valueadc = analogRead(analoginput);     //gets analog value from pot and store in variable,converts to digital          
    int result = map(valueadc, 0, 4095, 0, 65535); //maps the (0to4095 into 0to65535) and stores in result variable
    pwmWrite(led, result);           //puts resultin PWM form
    pwmWrite(fan, result);           //puts resultin PWM form
    lcd.setCursor(0,0);             //Sets cursor at row0 and column0
    lcd.print("ADC value= ");           // prints the words in ""
    lcd.print(valueadc);           //displays value
    lcd.setCursor(0,1);             //Sets Cursor at column0 and row1
    lcd.print("Output =   ");          //prints the words in ""
    lcd.print(result);           //displays value result
 }

ویدئو

امیدواریم آموزش «مدولاسیون عرض پالس یا PWM در STM32» برایتان مفید واقع شده باشد. در ادامه پیشنهاد می‌کنیم دیگر آموزش‌های STM32 را نیز مطالعه کنید.

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

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

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

یک دیدگاه

  1. سلام
    موقع نوشتن برنامه PWM در Arduino ide با ارور ‘PWM’ was not declared in this scope; did you mean ‘PWR’? مواجه میشوم
    ممنون میشم منو راهنمایی کنید
    با تشکر