برای ایجاد فرکانسهای دقیق بدون دخالت CPU از تایمرها در مد CTC استفاده میکنند. در این حالت پس از تنظیمات لازم فرکانس بر روی پایه OCx ظاهر میشود. ما در این مقاله از تایمر شماره یک (TIMER1) میکروکنترلر ATmega8A استفاده میکنیم و فرکانس خروجی روی پایه OC1A یعنی PORTB.1 ایجاد خواهد شد. به محض پیکرهبندی، تایمر جدا از سیکل اصلی برنامه شروع به نوسان میکند و هیچ پردازشی از برنامه اصلی گرفته نمیشود؛ به طور مثال حتی با قرار دادن wait در متن برنامه نیز تایمر به کار خود ادامه خواهد داد. برای خاموش کردن تایمر میتوان از دستور STOP TIMER1 استفاده کرد. کدنویسی و پیکرهبندی تایمر در مد CTC در بسکام (Bascom) کار پیچیدهای نیست اما محاسبات آن زمان بر است. طبق دیتاشیت میکروکنترلر ATmega8 برای ایجاد یک فرکانس دقیق توسط تایمر 16 بیتی شماره یک باید از فرمول زیر استفاده کنیم:
در این فرمول ƒOCnA فرکانس مورد نیاز بر روی پایه OC1A و OCRnA مقدار رجیستر Compare1A میباشد، حرف N نیز مقدار تقسیم کننده تایمر است که میتواند یکی از مقادیر مجاز 1، 8، 64، 256 یا 1024 باشد. ƒclk_I/O نیز فرکانس اسیلاتور است که پیشنهاد میشود برای ایجاد فرکانسهای دقیق حتما از کریستال خارجی استفاده شود. جایگذاری فرکانسهای مختلف کریستال و مقدار تقسیم کنندههای مختلف در فرمول بالا کمی زمانبر است. ما در این مقاله یک ماشین حساب آنلاین برای انجام دستی یا خودکار این محاسبات تدارک دیدهایم که از طریق لینک زیر میتوانید آن را مشاهده نمایید:
ماشین حساب آنلاین محاسبه تایمر AVR در مد CTC در بسکام
در قسمت زرد رنگ این ماشین حساب، هم میتوان فرکانسهای متداول را از منوی پایین افتادنی انتخاب کرد و هم با انتخاب other فرکانس جاری را بصورت دستی بر حسب هرتز وارد نمود. در منوی Prescale هم مقدار تقسیم فرکانس تایمر را میتوان به صورت دستی مشخص نمود و در فیلد بعدی فرکانسی که باید تولید شود بر حسب هرتز درج میشود. در صورتی که فرکانس مورد نیاز با تنظیمات جاری به طور دقیق قابل تولید باشد عدد محاسبه شده برای رجیستر Compare1a به طورت صحیح در جلوی آن نوشته شده و قطه کد Bascom نیز تکمیل میگردد. اگر عدد از 65535 تجاوز کند عبارت Err در جلوی Compare1a نمایش داده میشود که باید مقادری XTAL یا Prescale را تغییر داد. اگر هم عبارت Err همراه با مقدار اعشاری در جلوی Compare1a نشان داده شود به معنای اینست که با قرار دادن بخش صحیح عبارت اعشاری میتوان تا حدودی به فرکانس مورد نظر نزدیک شد اما دقیقا فرکانس به دست نمیآید. در این حالت میتوانید با جایگذاری قسمت صحیح عدد اعشاری compare1a در قسمت آبیرنگ ماشین حساب و فشردن کلید calc freq مقدار فرکانس حاصل را ببینید و با کم و زیاد کردن compare1a به فرکانس مورد نظر نزدیکتر شوید. دقت داشته باشید که عدد رجیستر compare1a نباید از 65535 بیشتر شود و حتما باید عدد صحیح مثبت بین 0 تا 65535 باشد.
در قسمت پایین کد نیز بخشی به نام Auto تدارک دیدهایم که تنها با وارد کردن فرکانس مورد نیاز بر حسب هرتز و فشار کلید Auto Calc تمام حالتهای ممکن را در کسری از ثانیه محاسبه کرده و در صورتی که فرکانس مورد نظر قابل تولید باشد لیستی از آپشنهای مختلف با کریستالها و Prescale های مختلف را نمایش میدهد تا بسته به نیاز خود از یکی از تنظیمات استفاده کنید. همچنین در این قسمت کنار کلید Auto Calc یک چکباکس به نام Exactly قرار داده شده که به صورت پیش فرض تیک خورده است و در حالت تیک خورده فقط تنظیماتی نمایش داده میشود که منجر به فرکانس دقیق شود. با این حال برای برخی از فرکانسها مثل 38000 هرتز نمیتوانید دقیقا فرکانس مورد نظر را تولید کنید و گاهی فرکانسهای نزدیک آن با چند هرتز خطا نیز قابل قبول است. برای همین منظور میتوانید تیک گزینه Exactly را در چنین مواردی بردارید و مجددا محاسبه خودکار را انجام دهید. در این حالت لیست بلندی از تنظیمات مختلف پیشنهاد شده و نزدیک ترین فرکانس با رنگ سبز هایلایت میشود و در آخر نیز فرکانس انتخابی نشان داده می شود تا اگر خط هایلایت شده شامل دو گزینه بود گزینهی مناسبتر قابل تشخص باشد. در خط مورد نظر میتوانید تنظیمات مربوط به کریستال و مقسم فرکانس و رجیستر مقایسه را ببینید و در کد خود استفاده نمایید.
در تصویر زیر فرکانس 125KHz با کریستال 4MHz و Prescale=1 و Compare1a=15 به دست آمده است:
آپدیت: 1399/12/02: بعنوان یک نکته اگر از قطعه کد زیر استفاده کنیم فرکانس بر روی پایه OC1A ظاهر می شود:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
$regfile = "m8adef.dat" $crystal = 8000000 $hwstack = 40 $swstack = 16 $framesize = 32 '1 Hz Config Timer1 = Timer , Prescale = 256 , Compare_a = Toggle , Clear_timer = 1 Compare1a = 15624 'uncommnet for stop: 'Stop Timer1 Do Loop End |
اما در صورتی که نیازی به تولید فرکانس روی پایه OC1A میکرو نداشته باشیم و صرفا بخواهیم یک لیبل در داخل برنامه فراخوانی شود باید کد را به صورت زیر بنویسیم:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
$regfile = "m8adef.dat" $crystal = 8000000 $hwstack = 40 $swstack = 16 $framesize = 32 '1 Hz Config Timer1 = Timer , Prescale = 256 , Clear_timer = 1 Compare1a = 15624 On Oc1a Ov1 Enable Oc1a Enable Interrupts 'uncommnet for stop: 'Stop Timer1 Do Loop End Ov1: 'do something Return |
در این برنامه دستور Compare_a = Toggle حذف شده تا خروجی روی پایه OC1A نداشته باشیم، همچنین سه دستور On Oc1a Ov1 و Enable Oc1a و از همه مهمتر Enable Interrupts اضافه شده و در پایان برنامه بعد از دستور End برچسب Ov1 و عبارت بازگشت Return قرار داده شده و این برچسب با فرکانس یک هرتز (یعنی دو پالس در هرثانیه) فراخوانی می شود. شاید تصور کنید که باید هر ثانیه 1 بار فراخوانی شود اما با توجه به اینکه این متد برای ایجاد فرکانس روی پایه بکار می رود و با هر بار سرریزی تایمر پایه معکوس می شود درواقع زمان محاسبه شده برای نیم سیکل می باشد و برای فراخوانی لیبل در هر ثانیه باید Prescale را دوبرابر کنید و به طور مثال در اینجا روی 1024 قرار دهید.
بازدیدها: 904