در قسمت دهم از آموزش STM32 با توابع LL، ابتدا ADC را بررسی کردیم و گفتیم که یک ADC چه مشخصهها و پارامترهایی دارد و درنهایت واحد ADC در میکروکنترلرهای STM32 را بهصورت عملی راهاندازی کردیم و ولتاژ میکروکنترلر را با استفاده از این واحد قرائت کردیم. در این قسمت میخواهیم در رابطه با DAC یا همان مبدل دیجیتال به آنالوگ در میکروکنترلرهای STM32 صحبت کنیم و در دو حالت مختلف این واحد را راهاندازی کنیم. از قبل میدانیم که ADC با ساز و کار خاصی یک ولتاژ آنالوگ را به یک ولتاژ دیجیتال تبدیل میکند. حال کاری که DAC انجام میدهد، دقیقا برعکس کاری است که ADC انجام میداد. یعنی تبدیل یک سیگنال دیجتال به یک سیگنال آنالوگ.
مبدل دیجیتال به آنالوگ (DAC)
مبدل دیجیتال به آنالوگ، یا همان DAC عنصری است که یک سیگنال دیجیتال را بهعنوان ورودی دریافت میکند، و در خروجی معادل آنالوگ همان سیگنال دیجیتال را تولید میکند. برای ساخت DAC چندین روش مختلف وجود دارد، اما عملکرد همهی این روشها یکسان است. یعنی تبدیل یک سیگنال دیجیتال به یک سیگنال آنالوگ.
R-2R و Binary Weighted دو روش معروف برای ساخت DAC هستند که روش R-2R به نسبت روش بهتر و کارآمدتری است. برای ساخت این دو روش از یک سری اصول پایهای ساده الکترونیکی استفادهشده است که برای درک عملکرد DAC بهتر است نحوهی ساخت این دو روش را در اینترنت بخوانید. DAC ها هم مانند ADC ها چندین مشخصه مهم واصلی دارند که در ادامه این مشخصات را بررسی میکنیم.
در ADCها سه مشخصهی رزولوشن، فرکانس نمونهبرداری و مقدار زمانی که طول میکشید تا یک نمونه دیجیتال را در خروجی داشته باشیم، از مشخصات اصلی ADC بودند. این مشخصات را تقریبا با همان تعاریفی که در آنجا گفتیم، در DACها هم داریم. این تعاریف را در ادامه، زمانی که میخواهیم مبدل دیجیتال به آنالوگ را در میکروکنترلرهای STM32 شرح بدهیم، همره با مقادیرشان بررسی خواهیم کرد.
رابطه بین ولتاژ خروجی، ولتاژ رفرنس، رزولوشن و ورودی دیجیتال DAC به صورت زیر است:
برای بدست آوردن حداقل ولتاژ خروجی تولید شده توسط DAC، باید Digital Number Input را در فرمول بالا برابر با عدد 1 قرار بدهید.
کاربرد DAC
از کاربردهای DAC میتوان به پردازش سیگنال، کارهای صوتی و ویدئویی، رادیو نرمافزاری و … اشاره کرد. مثلاً زمانی که یک سیگنال آنالوگ را به یک سیگنال دیجیتال تبدیل میکنیم تا بر روی آنکارهای پردازشی انجام بدهیم، درنهایت ممکن است که بخواهیم سیگنال پردازششده را به یک سیگنال آنالوگ تبدیل کنیم، در این مواقع باید از DAC استفاده کنیم و اینیکی از کاربردهای DAC است.
DAC در میکروکنترلرهای STM32
ابتدا این نکته را بگویم که در این قسمت به دلیل اینکه میکروکنترلر STM32F103CBT6 فاقد واحد DAC است، پس از نمیتوانیم از برد blue pill که در قسمت چهارم معرفی کردیم استفاده کنیم، و باید از میکروکنترلری استفاده کنیم که دارای واحد DAC باشد. به همین جهت در این قسمت از میکروکنترلر STM32F103RET6 که دارای واحد DAC است، استفاده میکنیم و با استفاده از یک برد مبتنی بر این میکروکنترلر تستهای عملی را انجام خواهیم داد.
در میکروکنترلر STM32F103RET6 دو واحد DAC وجود دارد که هرکدام از این DAC ها دارای یک کانال خروجی هستند.
ولتاژ رفرنس یا مرجع DAC از پایه +VREF که با ADC مشترک است تأمین میشود.
حداکثر sampling rate این DAC برابر با 1Ms/s و حداکثر کلاکی که میتوانیم به واحد DAC اعمال کنیم برابر با 36MHZ که همان حداکثر کلاک بأس APB1 است.
مبدل دیجیتال به آنالوگ (DAC) دارای رزولوشن 12 بیت است که این 12 بیت میتواند بهصورت right-aligned یا left-aligned درون رجیستر مربوطه قرار بگیرد. البته این DAC در حالت 8 بیتی هم میتواند پیکرهبندی بشود که این 8 بیت تنها میتواند بهصورت right-aligned درون رجیستر مربوطه قرار بگیرد.
چینش right-aligned و left-aligned درون رجیسترها به صورت زیر است:
چون دیتا نمیتواند به صورت مستقیم در رجیستر خروجی نوشته شود، ابتدا باید به صورت right-aligned یا left-aligned درون رجیستر DHR نوشته بشود و سپس به صورت خودکار و یا با استفاده از تریگر که میتواند نرمافزاری یا سختافزاری باشد، درون رجیستر DOR قرار بگیرد. سومین پارامتر مهم DAC هم مقدار زمانی است که طول میکشد تا معادل آنالوگ دیتای دیجیتالی که درون رجیستر DOR قرار دارد، بر روی پین میکروکنترلر مسقر شود. این زمان در دیتاشیت با نام زمان SETTLING آورده شده است که معادل فارسی آن زمان استقرار است. این DAC علاوه بر تولید سیگنال دلخواه ما، قابلیت تولید خودکار سیگنال نویز و سیگنال مثلثی را هم دارد.
در ادامه هرکدام از این روشها را مفصلاً شرح خواهم داد.
انواع سیگنالهای تولید شده توسط DAC در میکروکنترلرهای STM32
سیگنال دلخواه
فرض کنید میخواهیم با استفاده از DAC یک سیگنال متناوب دلخواه را تولید کنیم. برای این کار ابتدا نمونههای دیجیتال یک دوره تناوب را درون یک آرایه قرار داده و سپس عضوهای این آرایه را به ترتیب درون رجیستر DHR قرار میدهیم. پسازاینکه هر عضو آرایه را درون رجیستر DHR قراردادیم، باید عملیاتی صورت بگیرد تا محتوای رجیستر DHR به رجیستر DOR منتقل و درنهایت بر روی پین خروجی مستقر بشود.
برای اینکه محتوای رجیستر DHR به رجیستر DOR منتقل بشود، بستگی به فعال بودن تریگر دارد. اگر تریگر فعال نباشد این کار بهصورت خودکار مانند شکل زیر انجام خواهد شد.
همانطور که در شکل بالا مشاهده میکنید محتوای رجیستر DHR، پس از یک سیکل کلاک APB1 به رجیستر DOR منتقل میشود. اما اگر تریگر فعال باشد دو حالت مختلف پیش میآید.
حالت اول این است که تریگر را بر روی حالت نرمافزاری تنظیم کرده باشیم. در این صورت هنگامیکه ما بهصورت نرمافزاری تریگر را فعال میکنیم، پس از یک سیکل کلاک APB1، محتوای رجیستر DHR به رجیستر DOR منتقل خواهد شد. در این حالت هم مانند زمانی که تریگر را کلاً فعال نکرده باشیم، انتقال دیتا پس از یک سیکل کلاک APB1 انجام خواهد شد، اما با این تفاوت که برای انتقال دیتا باید تریگر بهصورت نرمافزاری رخ بدهد.
در این حالت پسازاینکه ما تریگر را بر روی حالت نرمافزاری قراردادیم، پس از قرار دادن محتوا درون رجیستر DHR باید یک بیت را در رجیستر SWTRIGR فعال بکنیم تا محتوای رجیستر DHR به رجیستر DOR منتقل بشود. پسازاینکه محتوای مربوطه منتقل شد، بیت SWTRIGR بهصورت خودکار توسط سختافزار غیرفعال یا ریست خواهد شد.
برای درک بهتر عملکرد این حالت به شکل زیر توجه کنید:
حالت دوم هم این است که تریگر را بر روی حالت سختافزاری تنظیم کرده باشیم. تریگرهای سختافزاری شامل تایمرها و یک وقفه خارجی هستند. در این صورت هنگامیکه با استفاده از تایمر یا وقفه خارجی، تریگر رخ بدهد، پس از سه سیکل کلاک APB1، محتوای رجیستر DHR به رجیستر DOR منتقل خواهد شد.
در شکل زیر منابع مختلف تریگر، که شامل تایمرها، یک وقفه خارجی و یک حالت نرمافزاری است را مشاهده میکنید:
برای تنظیم تریگر در هرکدام از حالتهای بالا، پس از فعال کردن بیت TEN در رجیستر CR، باید بیتهای [2:0]TSEL در رجیستر CR را مطابق حالت دلخواه تنظیم کنیم.
سیگنال نویز
دومین نوع سیگنالی که DAC قادر است برای ما تولید کند، سیگنال نویز است. مبدل دیجیتال به آنالوگ با توجه به یک الگوریتم سختافزاری قادر است که یک سیگنال نویز را در خروجی خود برای ما تولید کند.
شکل زیر الگوریتمی است که باعث ایجاد سیگنال نویز میشود:
همچنین این سیگنال نویز در 12 حالت مختلف میتواند تولید بشود. این 12 حالت با توجه به تنظیماتی است که ما از قبل تعیین میکنیم. در این تنظیمات ما میتوانیم هرکدام از 12 بیت موجود را ماسک کنیم.
محتوای الگوریتم بالا در رجیستر LFSR ذخیره میشود که با رخ دادن تریگر با رجیستر HDR جمع میشود و به رجیستر ODR منتقل خواهد شد.
توجه کنید که اگر حاصلجمع دو رجیستر LFSR و HDR بیش از 12 بیت باشد، این مورد به صورت خودکار توسط سختافزار کنترل خواهد شد و سرریز رخ نمیدهد.
خب پسازاینکه تعیین کردیم الگوریتم بالا با چه پارامترهایی سیگنال نویز را تولید کند، کافی است تا تریگر آن بهصورت نرمافزاری یا سختافزاری فعال شود تا دیتا به رجیستر ODR منتقل و درنهایت سیگنال نویز در پین خروجی تولید شود.
در حالت سیگنال نویز، چون بهصورت خودکار محتوای رجیستر LFSR نمیتواند به رجیستر ODR منتقل بشود، پس حتماً باید تریگر را بر روی یکی از حالتهایی که گفتیم تنظیم کنیم، یعنی باید بیت TEN در رجیستر CR فعال باشد.
سیگنال مثلثی
سومین نوع سیگنالی که مبدل دیجیتال به آنالوگ قادر است برای ما تولید کند، سیگنال مثلثی است. واحد DAC قادر است تا یک سیگنال موج مثلثی با دامنه کم را به یک سینال DC، یا یک سیگنال با تغییرات کم اضافه کند. دامنه این سیگنال مثلثی هم مانند سیگنال نویز در 12 حالت مختلف قابل تنظیم است. در حالت سیگنال مثلثی هم مانند توضیحاتی که در حالت سیگنال نویز دادیم، محتوا بهصورت خودکار نمیتواند به رجیستر ODR منتقل بشود و تریگر حتماً باید بهصورت نرمافزاری یا سختافزاری فعال شود.
در حالت سیگنال مثلثی یک کانتر یا شمارنده وجود دارد که با هر بار رخ دادن تریگر، یک واحد به آن اضافه میشود و این اضافه شدن تا قبل از اینکه به ماکسیمم دامنهای که تعیین کردیم برسیم، ادامه خواهد داشت. پسازاینکه کانتر به ماکسیمم دامنه تعیینشده توسط ما رسید، روند نزولی پیدا خواهد کرد تا دوباره به صفر برسد. محتوای کانتر در این حالت هم با رجیستر HDR جمع میشود و با هر بار تریگر به رجیستر ODR منتقل میشود بدون اینکه سرریزی رخ بدهد.
موج مثلثی که توسط DAC تولید میشود مانند شکل زیر است:
البته این شکل موج یک مرحله قبل از این است که بر روی پین میکروکنترلر مستقر شود. اگر رجیستر HDR برابر با 0 باشد دقیقاً همین شکل موج، و در غیر این صورت، این شکل موج با رجیستر HDR جمع میشود و بر روی پین میکروکنترلر مستقر خواهد شد. برای تعیین اینکه کدامیک از سه سیگنالی که در بالا ذکر کردیم فعال باشد، باید در رجیستر CR، بیتهای [1:0]WAVE را متناسب باحالتی که میخواهیم تنظیم کنیم.
همچنین برای ماسک کردن بیتهای الگوریتم سیگنال نویز و یا تعیین دامنه سیگنال موج مثلثی باید بیتهای MAMP2[3:0] را مانند زیر تنظیم کنیم:
- 0000: بیت 0 از LFSR بدون ماسک / دامنه موج مثلثی برابر با 1
- 0001: بیتهای [1:0] از LFSR بدون ماسک / دامنه موج مثلثی برابر با 3
- 0010: بیتهای [2:0] از LFSR بدون ماسک / دامنه موج مثلثی برابر با 7
- 0011: بیتهای [3:0] از LFSR بدون ماسک / دامنه موج مثلثی برابر با 15
- 0100: بیتهای [4:0] از LFSR بدون ماسک / دامنه موج مثلثی برابر با 31
- 0101: بیتهای [5:0] از LFSR بدون ماسک / دامنه موج مثلثی برابر با 63
- 0110: بیتهای [6:0] از LFSR بدون ماسک / دامنه موج مثلثی برابر با 127
- 0111: بیتهای [7:0] از LFSR بدون ماسک / دامنه موج مثلثی برابر با 255
- 1000: بیتهای [8:0] از LFSR بدون ماسک / دامنه موج مثلثی برابر با 511
- 1001: بیتهای [9:0] از LFSR بدون ماسک / دامنه موج مثلثی برابر با 1023
- 1010: بیتهای [10:0] از LFSR بدون ماسک / دامنه موج مثلثی برابر با 2047
- ≥1011: بیتهای [11:0] از LFSR بدون ماسک / دامنه موج مثلثی برابر با 4095
توجه کنید که این بیتها حتماً باید قبل از فعال کردن DAC تنظیم بشوند تا مؤثر باشند. یک نکته مهم دیگر هم مانده است، این نکته را بگویم و سایر مراحل را در نرمافزار شرح خواهم داد. در واحد DAC این قابلیت وجود دارد که خروجی آنالوگ را قبل از اینکه بر روی پین میکروکنترلر مستقر بشود، بافر بکنیم. بافر کردن باعث کاهش امپدانس خروجی میشود و ما میتوانیم بار را بهصورت مستقیم به پین میکروکنترلر متصل کنیم.
بافر خروجی در بیت BOFF رجیستر CR فعال میشود. توجه کنید که این بافر با نوشتن 0 در این بیت فعال و با نوشتن 1 غیرفعال خواهد شد.
برای تاثیر بافر بر ولتاژ خروجی ابتدا به شکل زیر توجه کنید:
همانطور که از قسمت بالا این تصویر قابلمشاهده است، اگر خروجی را بافر نکرده و آن را به بار متصل کنیم، ولتاژ در مقایسه بازمانی که خروجی به بار متصل نیست، بهشدت افت خواهد کرد. اما در قسمت پایین تصویر، وقتی خروجی را بافر میکنیم، حتی زمانی که خروجی به بار متصل است، ولتاژ در مقایسه بازمانی که خروجی به بار متصل نیست، بدون تغییر باقی میماند. پس توصیه میکنیم که حتماً بافر خروجی را در برنامه فعال کنید. اکنون میخواهیم با استفاده از مبدل دیجیتال به آنالوگ یک سیگنال پالس و یک سیگنال مثلثی ایجاد کنیم.
نرمافزار STM32CubeMX را بازکرده و کلاک را مانند گذشته تنظیم میکنیم. در قسمت Analog، مانند تصویر زیر، DAC را برای سیگنال پالس تنظیم میکنیم:
در این حالت، یعنی حالت سیگنال پالس، ابتدا یکی از کانالهای خروجی مبدل دیجیتال به آنالوگ (DAC) را فعال کرده و در تنظیمات کانال هم بافر خروجی را فعال میکنیم و تریگر را بر روی None قرار میدهیم. همانطور که گفتیم در حالت سیگنال دلخواه، تریگر هم میتواند بهصورت خودکار باشد و هم توسط یکی از منابع تریگر که قبلاً گفتیم. وقتی تریگر را بر روی None قرار میدهیم، انتقال دیتا بهصورت خودکار انجام میشود و نیازی به تریگ شدن توسط منابع تریگر نیست. اما در حالت سیگنال نویز و سیگنال مثلثی، عمل تریگ حتماً باید با استفاده از منابع تریگر رخ بدهد. برای همین وقتی تریگر را بر روی None قرار میدهیم، تنظیمات مربوطه برای ما نمایش داده نمیشود.
پس در اینجا ما تریگر را بر روی None قرار میدهیم تا انتقال دیتا بهصورت خودکار انجام بشود. پس از تنظیمات بالا، کد را برای نرمافزار Keil ایجاد میکنیم.
در نرمافزار Keil ابتدا باید در main برنامه DAC را توسط تابع LL_DAC_Enable فعال بکنیم:
1 | LL_DAC_Enable(DAC1, LL_DAC_CHANNEL_1); |
سپس در while برنامه کد زیر را مینویسیم:
1 2 3 4 | LL_DAC_ConvertData12RightAligned(DAC1, LL_DAC_CHANNEL_1, 0xFFF); LL_mDelay(1); LL_DAC_ConvertData12RightAligned(DAC1, LL_DAC_CHANNEL_1, 0x000); LL_mDelay(1); |
در کد بالا با استفاده از تابع LL_DAC_ConvertData12RightAligned مقدار 0xFFF که بیشترین مقدار، و مقدار 0x000 که کمترین مقدار است را در حالت 12-bit right aligned درون رجیستر DHR قرار میدهیم تا یک پالس ایجاد بشود. چون تریگر غیرفعال است نیاز به هیچ کار اضافهی دیگری نیست و دیتا بهصورت خودکار از رجیستر DHR به درون رجیستر ODR منتقل میشود.
همچنین ما از تابع LL_mDelay که برای ایجاد تأخیر است هم استفاده کردهایم. ما در اینجا از تأخیر 1 میلیثانیه استفاده کردیم اما شما برای تغییر فرکانس و دیوتی سایکل پالس خودتان، میتوانید این مقدار را تغییر بدهید.
کد را کامپایل و پروگرام میکنیم. پس از اجرای کد بر روی میکروکنترلر، نتیجهی زیر بر روی اسیلسکوپ قابلمشاهده است:
اکنون میخواهیم یک سیگنال مثلثی را با استفاده از DAC ایجاد کنیم.
ابتدا باید در نرمافزار STM32CubeMX کانال خروجی را مانند زیر تنظیم کنیم:
در این حالت مانند قبل کانال و بافر خروجی را فعال میکنیم. اما این بار تریگر را بر روی Software trigger قرار میدهیم. با فعال کردن تریگر مشاهده خواهید کرد که تنظیمات مربوط به سیگنال نویز و سیگنال مثلثی هم فعال خواهند شد. در ادامه سیگنال مثلثی را انتخاب و ماکسیمم دامنه آن را عدد 4095 تعیین خواهیم کرد و درنهایت کد را برای نرمافزار Keil ایجاد میکنیم.
main برنامه شبیه قبل است، اما در while برنامه باید کد زیر را بنویسیم:
1 | LL_DAC_TrigSWConversion(DAC1, LL_DAC_CHANNEL_1); |
با هر بار اجرای تابع LL_DAC_TrigSWConversion به صورت نرمافزاری تریگر رخ میدهد و مجموع محتوای کانتر و رجیستر HDR، به رجیستر ODR منتقل میشود.
کد را کامپایل و پروگرام میکنیم. پس از اجرای کد بر روی میکروکنترلر، نتیجهی زیر بر روی اسیلوسکوپ قابل مشاهده است:
در قسمت دوازدهم در رابطه با تایمرها صحبت خواهیم کرد.
سلام دوست عزیز .
آموزش های بسیار عالی بودند . خدا خیرتون بده
اگر میتونید حتما ادامه بدید .
سلام آتیلا جان. خوشحالم از اینکه این مجموعه مقالات برای شما مفید بوده است. در همین هفته احتمالا قسمت بعد که مربوط به تایمرها است را منتشر خواهم کرد.
سلام
آموزشتون بسیار عالی هست
مثل یک استاد تمام با ده ها سال سابقه آموزش میدید .
من که خیلی لذت بردم و تمام این 11 بخش رو توی یک روز خوندم !
بی صبرانه منتظر بخش های بعدی هستم.
سلام سعید جان. سپاس از لطفی که به بنده دارید. و خوشحالم از اینکه این مجموعه مقالات برای شما مفید بوده است.
اما سعی کنید وقتی یک قسمت را میخوانید، همزمان با آن کدها را هم خودتان بنویسید و تستهای عملی را انجام بدهید، سپس سراغ مقاله بعدی بروید.
سلام .
اقا دمت گرم
سلام علی جان. سپاس از شما.