تایمر کانتر ۱۴۰۵

saalek110

Well-Known Member
خاطره یادگیری شیرین مجدد تایمر کانتر بخاطر ملی شدن اینترنت ۱۴۰۵


سالک: الان نزدیک اول تیر ۱۴۰۵ است....دفعه قبلی که من تایمر کانتر کار کردم ، چند سال پیش بود ، مثلا ۳ سال پیش ... ، اون موقع برام بحث سنگینی بود...پیچیده بود و سردرد....الان برام شیرین تر شده بحث...
یادمه برای راه اندازی سروو موتور ، خیلی به دردسر افتادم ، چون فلسفه کار تایمرها را درست درک نکرده بودم.....یک برنامه برای راه اندازی سرو موتور شانسی کار کرد و سالها از همون برنامه استفاده می کردم برای چرخاندن سروو موتور...

البته اینم بگم که الکترونیک ، در این سالها ، حکم زنگ تفریح من را داشت و من رشته درسی و کارم ، چیز دیگه بود و هر وقت می خواستم تفریح کنم ، می اومدم الکترونیک کار می کردم......می خوام بگم نگید چقدر فلان بود که ۳ سال طول کشید تایمر را یاد بگیره...در این سه سال خیلی پروژه های غیرالکترونیک داشتم....لیست تاپیکهای من را اگر ببینید ، می بینید مقوله های فعالیت من ، تقریبا برابر است با تمام رشته های موجود ، البته شوخی بود مقداری این حرفم....بگذریم.

امسال ، تایمر کانتر را عمقی تر فهمیدم ....به شما هم توصیه می کنم یک منبع خوب پیدا کنید که خوب توضیح داده باشه ، تایمر را چطوری باید تنظیم کرد و هر تنظیم برای چیه.....من دانشجوی کامپیوتر نیستم که کتابهای چاپی را بشناسم و بهتون معرفی کنم....من داخل اینترنت ، هر چی گیرم بیاید مطالعه می کنم ، شاید کتابهای چاپی یی موجود باشد که خوب گفته باشه....
 

saalek110

Well-Known Member
تایمر صفر و دو ساده تر است و خوبه از اونها شروع کنید....
و متاسفانه اکثر آموزشها هم روی تایمر صفر و دو است و برای تایمر ۱ آموزش های خوبی نداریم...
 

saalek110

Well-Known Member
من هم فعلا کار زیادی نمی تونم انجام بدهم....برای تایمر یک ، مطلب خوب ندارم و خودم هم کامل مسلط نیستم....
برای تایمر صفر مطلب بیشتر است...

برنامه های شمارش با تایمر صفر هست که قابل فهم است....
ولی برنامه های موج ساز با تایمر یک ، مقداری پیچیدگی هایی دارد که کمی دقت و حوصله نیاز دارد.

من الان دنبال این نیستم خودم اینجا آموزش بدهم. یک سری فیلم هست لینک می ذارم... شاید یک روزی خودم آموزش دادم...







پیش گفتار من یعنی سالک:
تایمرها یک سری مفاهیم دارد که یک هو نمیشه همش را یاد گرفت...بهتره به تدریج فیلم ها را نگاه کنید و بعد دیدن هر فیلم ساعاتی بگذرد تا کمی جا بیافتد.


بحث تایمرها ، چیز پیچیده و غیرقابل فهمی نیست ، فقط یک کلاف مربوط به هم است....یعنی تنظیماتی که هر یک قسمتی از کار است و با تغییر هر تنظیم وارد حالتی می شویم.
چون با رجیسترها کار می کنیم ، یک مقدار کار غیر ملموس است و باید خودتان تصور مناسب را ایجاد کنید. با تنظیم هر رجیستر ، مثلا یک رجیستر دیگر وارد کار می شود یا از کار خارج می شود.
به همین دلیل ، گفتم یک کلاف مرتبط به هم است...
یا میشه یک مدار در نظر گرفت که با تنظیم هر قسمت مدار ، وارد قسمت دیگری از مدار می شویم.



کل کار ، گسترده نیست و کلا ۴ یا ۶ تا رجیستر بیشتر نیست...ولی فهم اینکه هر یک کارش چیه را باید دقیق بفهمید..چون وقتی می خواهیم کد بنویسیم دقیقا باید بدونیم داریم کدوم رجیستر را تغییر می دهیم و نتیجه این تغییر چیه.





سالک: من یک دید کلی بهتون میدهم تا در بحث های فیلم ها راحت تر باشید.

۳ تا تایمر داریم که شماره صفر و دومی هشت بیتی هستند. البته در اتمگا ۱۶ داریم میگیم.
برای هر کدوم این تایمرها رجیسترهایی داریم.
خیلی فیلم ها روی تایمر شماره صفر آموزش خود را میدهند.

رجیستر اصلی اسمش tcnt است ، پس برای تایمر شماره صفر میشه tcnt0 .
یک رجیستر دیگه هست به نام ocr که برای تایمر شماره صفر میشه ocr0 .

دو جور بررسی داریم ،
اورفلو یا سرریز
و مقایسه.

اورفلو یعنی تایمر اصلی یا tcnt0 به شماره آخر خودش میرسه که تایمر ۸ بیتی به ۲۵۵ یا ff می رسه.
و یک پرچم یا فلگ ، وقتی به انتها برسه ۱ میشه.

منطور از مقایسه ، مقایسه tcnt0 با ocr0 است. پس هر جا از مقایسه صحبت شد ، دیگه گیج نشید و منطور مقایسه این دو است.
در کدنویسی میشه به tcnt0 یا orc0 مقدار داد.
مثلا به tcnt0 مقدار اولیه بدهیم و از اونجا بشماره...
یا به ocr0 یک مقداری بدهیم و حالت مقایسه را هم روشن کنیم تا کقتی به اونجا رسید باعث بشه فلگ مقایسه روشن بشه.

رجیستر بعدی tccr است که میشه بهش رجیستر تنظیمات گفت.
۳ بیت کوچکش یعنی سمت راستش ، تعیین میکنه از کلاک داخلی استفاده بشه یا خارجی و اگر از داخلی استفاده میشه فرکانس داخلی که معمولا ۱ مگا است تقسیم بر چند بشه.
پس جدولی ۸ داریم برای این سه بیت که جدولش را بعدا در فیلم ها خواهید دید.
دو بیت دیگه داره ، برای تنظیمات دیگر که مود را تعیین می کند.
و باز دو بیت دیگه داره برای تنظیمات دیگر

راجع به مود که ۴ حالت است ، در یک فیلم فرق این مودها گفته شده. مود اول نرمال است و یک مود fast pwm و یک مود phase ... و یک مود ctc است.


بیت آخر هم کم کاربرد است.
فعلا همین که بدونید رجیستر tccr ، رجیستر تنظیمات است کافیه ، بعدا در فیلمها می فهمید بیت ها چیو تننظیم می کنه و چندتا جدول هم بر اساس تغیی. این بیت ها ایجاد میشه.

دو رجیستر timsk و tifr داریم...
که دو بیت اول برای تایمر صفرم و ۴ بیت بعدی برای تایمر یک و دو بیت آخر برای تایمر شماره دو است در هر دو رجیستر مذکور.

رجیستر timsk براتون اورفلو یا مقایسه را روشن می کنه ، در بیت اولی و دومی برای تایمر صفرم...
و رجیستر tifr بهتون میگه آیا اوفلو یا مقایسه اتفاق افتاده یا نه.
مقایسه اول مطلب گفتیم که بررسی مقدار tcnt0 و ocr0 برای تایمر صفرم بود.

این اسامی و مفاهیمی که در این نامه نوشتم را به عنوان اسکلت کاری داشته باشید تا در هر فیلم چیزی شنیدید به این اسکلت کاری بیافزایید.
 
آخرین ویرایش:

saalek110

Well-Known Member
جناب زرگر
eng zargar

tcnt ocr tccr timsk tifr




وقتی به جای کلاک داخلی ، از پایه میکروکنترلر ، پالس دریافت کنیم ، می گیم شمارنده
مثلا تعداد پالسهای خارجی را بشماریم. مثلا تعداد ضربان قلب را.
و وقتی از کلاک داخلی استفاده می کنیم ، کلمه تایمر استفاده می کنیم.

tcnt
رجیستر شمارنده مهم ترین بخش است.
یاد تی ان تی اگر بیافتید ، مهم ترین رجیستر است.

بعدی tccr است.....
یکی دیگه ocr است. برای چک کردن رجیستر اصلی tcnt است. مقایسه بهش میگیم.



در این فیلم جناب زرگر ، یک کلیتی از کار داره آموزش می دهد...این کلیت را اگر داشته باشید ، در فیلم های دیگر که وارد جزئیات میشه ، کمتر گیج میشید.


رجییستر tccr ، دارای هشت بیت است ، که با تنظیم این بیت ها ، تنظیماتی انجام می شود.
سالک: یاد رودخانه می سی سی پی بیافتید که در این رودخانه شما تنظیماتی انجام می دهید.
سه بیت اول ،
cs00 cs01 cs02 تقسیم فرکانس را بر عهده دارد. یعنی عددی تعیین میشه با این ۳ بیت تا فرکانس به این عدد تقسیم بشه.
جدولی دارد که......در جدول ....تقسیم تا ۱۰۲۴ داره و دو انتخاب آخری ، استفاده از پالس خارجی است. بر اساس قسمت بالارونده یا قسمت پایین رونده.

دو بیت
wgm داریم که تعیین کننده مود است
که باز جدول داره
اولی صفر و صفر ، حالت نرمال
صفر یک ، میشه حالت phase
یک صفر میشه حالت ctc
یک یک میشه fast

در حالت نرمال ، شمارش داریم و افزایش می یابد و به ff می رسد و اورفلو داریم و پرچم اورفلو یک میشه یا از وقفه استفاده کنیم. بعد باز صفر میشه و از اول شروع می کنه.

رجیستر
timsk....با این رجیستر با دو بیت اولش می توانیم برای تایمر صفر ، وقفه را فعال کنیم یا مقایسه را فعال کنیم.دو بیت اول برای تایمر صفر است. ۴ بیت بعدی برای تایمر ۱ است و دو بیت بعدی برای تایمر ۲ است.


رجیستر tifr....مونیتور یا نشانگر اتفاقات تایمرهاست.مثل رجیستر timsk دو بیت اول برای تایمر صفر است.۴ بیت بعدی برای تایمر یک و دو بیت آخر برای تایمر دوم.
از دو بیت اول یکی برای اورفلو است و دیگری برای مقایسه.
 

saalek110

Well-Known Member
Texin lab



جلسه نهم فیلمهای ایشان است.
از دقیقه ۵ ، فیلم را نگاه کنید ، قبلا مباحث دیگر است.

ایشان کلیات تایمرها را میگه.
و بعدش رجیسترها را نام می برد
و کار اونها را توضیح می دهد.

سالک: در این فیلم همین که ، یک تصویر از کلیات بحث تایمرها در ذهنتان شکل بگیرد ، خوب است.

ایشان فرمودند که این جداول در دیتاشیت میکروکنترلر ، در قسمت تایمر هست.

مودهای کار را ایشان در آخر فیلم توضیح دادند
که اولی نرمال بود که مقدار تایمر به ff می رسد و دوباره به صفر می رسد و فلگ اورفلو هم صفر میشه. فلگ tov برای اوفلو است.
مود دوم ctc ، در آن مقدار تایمر به حد ocr می رسد و دوباره صفر می شود.فلگ ocf برای مقایسه است.


جلسه دهم آموزشهای ایشان است. ۳۵ دقیقه.
در فیلم قبلی تئوری بود بیشتر بود.
سالک: ممکن است بعضی قسمتهای این فیلم برای شما نامفهوم یا سنگین باشد که اون قسمتها را ندیده بگیرید.
ولی این فیلم چون بعصی مفاهیم را خوب شرح داده ، در این قسمت آموزش قرار دادم. امکان برش فیلم فعلا نیست.

تا دقیقه ۹ ، ساخت ساعت با کریستال ساعت با تایمر ۲.

در ادامه فیلم ، کار با کدویزارد را گفته. که خودش تنظیم رجیسترها را انجام می دهد.

گفته کدویژن جدید را از سایت من دانلود کنید. سالک: اختیار خودتان است که دانلود کنید یا نه.



فیلم جلسه یازدهم ایشان.
از دقیقه ۴۵ تا ۵۲ به تایمرها مربوط است. قبلش راجع به موتورها بحث کرده.
عرض پالس را در مود fast pwm را گفته. گفته که با تغییر ocr میشه عرض پالس را تغییر داد. با رسم شکل این را توضسح داده.

سالک: فکر کنم برای کار با سروو موتور ، این ترفند استفاده میشه چون سرو موتور به duty cycle حساس است.
 

saalek110

Well-Known Member
جناب انوری

سالک: این فیلم بالای یک ساعت است، مفاهیم را جناب انوری بحث کرده اول فیلم. یک مقدار خوبه با حوصله این فیلم را گوش بدهید. آقای انوری تلاش خودش را کرده تا مطلب شفاف و درست ارائه بشه و خوبه استفاده بکنیم از این فیلم. یک جاهایی کمی پیچیدگی حس میشه که باید تحمل کنیم.


اتمگا ۱۶ دارای ۳ تایمر است که شماره صفر و ۲ هشت بیتی و شماره ۱ آن ۱۶ بیتی است.
تایمرکانتر...... ((محتوای)) تایمر کانتر درون این قرار می گیرد. افزایشی اصلا معمولا
tcnt0 tcnt1 tcnt2.....shomareh 1 aan 16 biti ast


محتویات این رجیستر ، با متحویات tcnt تغییر می کند
ocr0 ocr1 ocr2
و با مقایسه این دو و با مودی که ما فعال کردیم کارهایی انجام میشه.

پایه ها در اتمگا ۱۶ ، یعنی پایه های مربوط به تایمر کانتر. در فیلم پایه ها را گفته
به شکل ورودی تعریف می شوند.
پایه تی صفر و تی یک ورودی کلاک تایمر هستند.
و tocs1 و tosc2 منبع کلاک خارجی تایمر ۲ است.
و پایه oc0 و oc2 خروجی تایمرهای صفر و یک هستند و oc1b و oc1a خروجی تایمر ۱ هستند.چون تایمر یک ۱۶ بیتی است دو پایه خروجی دارد.

چهار مود تایمر کانتر داریم،
در مود نرمال ، افزایشی است تا به نهایت خودش برسد در تایمر ۸ بیتی نهایتا به ۲۵۵ می رسد...در تایمر ۱۶ بیتی تا ۶۵ هزار می رود.


فلگ tov سر ریز است. که اگر یک شود یعنی تایمر سر ریز شده...
اگر تنظیم کرده باشیم که با سر ریز کاری انجام شده باشد وقفه ای را تنظیم می کنیم.

مود بعدی ، مود مقایسه ای
....زمانی که مقایسه یکی شد ، تایمر را صفر کنیم.tcnt با ocr مقایسه میشه
فلگ ocf یک میشه اگر مقایسه مثبت باشه.
و وقفه مقایسه فعال میشه.
کاربرد در مدولاسیون فرکانس یا fm است.

مود fast pwm :
برای ایجاد موج مربعی ‌pwm با فرکانس بالا است. موج معکوس یا غیرمعکوس است.
کاربردها: در منابع تغذیه سویچینگ ، در یکسوسازی و در تبدیل سیگنال دیجیتال به آنالوگ

مود phase correct pwm:
توضیحاتی در فیلم داده شده.

رجیسترها:
رجیستر tccr ، رجیستری هشت بیتی ، ۳ بیت اولش cs00 و cs01 و cs02 است صفر بعد cs شماره تایمر است که در اینجا تایمر صفر را داریم بحث می کنیم ، این سه بیت مقدار n را برای ما تعیین میکنه. در فیلم فرمولهایی گفته شده که درش حرف n داره. و میگه با این سه بیت مقدار n را مشخص می کنیم. در فرمولهای فیلم ، فرکانس را تعیین می کردیم که یک فاکتورش همین n است.
جدول این سه بیت:
اگر هر ۳ تا صفر باشه ، یعنی اصلا تنظیمی انجام نشده
بعدی ها ، یعنی چقدر از فرکانس cpu بهش داده بشه...اینها میشن کلاک داخلی
دو تای آخری جدول هم ، کار با لبه بالا رونده یا لبه پایین رونده است.این دو تا میشن کلاک خارجی ، یعنی وصل کنیم به اون پایه های to و t1 و .... پایه های میکروکنترلر ، برای کلاک خارجی.


بیت های بعدی این رجیستر
بیت های ۳ و ۶ است که با نام wgm00 و wgm01 هستند...بیت ۶ کم ارزش و بیت ۳ پر ارزشه است.
بیت wgm01 در بیت ۳ است که بیت پر ارزش محسوب میشه.
اگر هر دو را صفر بدهیم ، مود کاری میشه نرمال
مود بعدی fast.....هر دو بیت اگر ۱ باشند میشه fast pwn
مود بعدی phase correctوقتی است که فقط wgm00 یک باشه
برای حالت ctc هم وقتی است که wgm01 یک باشه...clear timer on comape match

بیت بعدی ، شماره ۴ و شماره ۵ ...که com00 و com01 هستند.
عملکرد پایه های oc0 را مشخص می کند.
که با نگاه به این بیت ها ، چند حالت ایجاد میشه که جدول داره. یعنی خروجی این پایه ، چطوری عمل کند...که حالتهایی دارد ، گه در فیلم گفته شده....یعنی کلا چی بریزیم بیرون روی این پایه ها....
یک سری جدول برای هر حالت داره که کمی گیج کننده میشه قضیه.

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


می رسیم به وقفه ها:
قدرت وقفه ها را اگر حس کنید علاقه مند می شوید
رجیستر timsk.....یک رجیستر ۸ بیتی است....رجیستر وقفه تایمرکانتر است.
اسم انگلیسی اش: تایمرکانتر اینتراپت ماسک رجیستر است.
دو بیت اول برای تایمرکانتر صفر است
۴ بیت بعدی برای تایمرکانتر یک است
و دو بیت آخر برای تایمرکانتر ۲ است.

در زیر اسم بیت ها را من ننوشتم.
بیت صفر اگر یک شود...سر ریز ، اگر اتفاق افتد سرویس وقفه فعال می شود.
بیت یک ، زمانی که تایمر با ocr یکسان شد ، سرویس وقفه را فعال کن.
بیتهای بعدی را نمی نویسم. همین دو بیت را توضسح دادم.

رجیستر tifr :
در این رجیستر اطلاعاتی هست که به کارمون می آید. ۸ بیت دارد.
باز دو بیت اول برای تایمر صفر و ۴ بیت بعدی برای تایمر یک و دو بیت آخر برای تایمر ۲ است.
دو بیت اول یکی نشان میدهد که سر ریز اتفاق افتاده و دیگری نشان می دهد compare یا مقایسه اتفاق افتاده.

جناب انوری بعد توضیحات تئوری اولین برنامه را کار کرده...
با تایمر صفر کار کرده...با نگاه به بیت یک رجیستر tifr فهمیده چه زمانی تایمر صفر سر ریز کرده.
سالک: رجیستر tifr یک رجیستر مونیتور است یعنی اطلاعات به ما نشان می دهد....
و جناب انوری در برنامه اولش ، با نگاه به بیت اول رجیستر tifr مواقعی که سر ریز رخ داده را پیدا کرده.. ایشان تابعی ساخته که با تایمر صفر بازی می کند و اون را می دواند. و این تابع با دواندن تایمر صفر ، یک زمان را طی می کند که بعدا به عنوان تابع delay برای ایجاد تاخیر استفاده کرده. و با داشتن این تاخیر ، یک پایه میکروکنترلر را با نوشتن یک خط کد ، صفر و یک کرده.

سالک: مثالهای بعدی را شرح ندادم.
 

saalek110

Well-Known Member
تنظیمات تایمرها با کدویزارد:



در این فیلم ،
نشان داده چطور در کدویزارد ، تایمرها را تنظیم کنیم.
اگر مقداری با تایمرها آشنایی داشته باشید ، می دانید که دارید چه انتخابهایی در کدویزارد انجام می دهید.

در این فیلم تایمر صفر تنظیم شده.
در انتخاب اول ، انتخاب کرده که از کلاک داخلی استفاده کند یا از کلاک خارجی ، در مورد کلاک خارجی ، قسمت بالارونده یا قسمت پایین رونده ، قابل انتخاب است.

در انتخاد بعدی ، مقدار تقسیم فرکانس انتخاب می شود.

در مرحله بعدی ، نوع مود انتخاب می شود.

و در رانتخاب بعدی ، اینکه چیبریزیم روی پایه خروجی میکرکنترلر ، انتخاب می شود.

در پایین تر ، چکهای سرریز و مقایسه را می توانیم بزنیم.



در فیلم بالا هم ، با کدویزارد تایمر را تنظیم کرده.


فیلم بالا هم همچنین.
 

saalek110

Well-Known Member


سالک: من کد فوق را تست نکردم و نمی دونم درست عمل خواهد کرد یا نه ، ولی یک برنامه دیگر خودم داشتم که داخل حلقه while خود main می اومد به ocr1a را مثل برنامه فوق دو مقدار مختلف می داد. اون برنامه ، در عمل درست عمل می کرد و سروو موتور را خیلی خوب می چرخاند. ولی در اون برنامه هم نفهمیدم چطوری مقادیر ocr1a محاسبه شده بود.
در این برنامه ، داخل تابع وقفه به ocr1a مقدارهای مختلف داده.

در برنامه من ، وقتی داخل while تابع main ، به ocr1a مقدار می داد ، delay هم در خط بعدش می ذاشت تا سروو موتور فرصت داشته باشد بچرخد. سروو موتور با دو مقدار مختلف ocr1a به اندازه زاویه ای مثلا ۹۰ تا ۱۸۰ می چرخید و وقتی ocr1a عوض میشد ، دوباره سروو موتور همان مسیر را برمی گشت در طی زمان delay که مثلا یکی دو ثانیه بود.

ولی در برنامه فوق ، delay نداریم ، و با هر وقفه ، مقدار ocr1a عوض میشه...نمی دونم نتیجه این برنامه چی باشه ، شاید اون دو مقدار باعث بشه تاج موج و کف موج طولشان تعیین بشه ....و طول تاج و طول کف ، با اون دو عدد تعیین بشه.

البته این را هم بگم که در برنامه من فقط با ocr1a کار نشده بود و با icr1 هم کار شده بود ، در برنامه من icr1 نقشی در برنامه داشت.
در برنامه من icr1 مقدارش 19999 بود و داخل while داشتیم
ocr1a=icr1_2000;
yek delay
ocr1a=icr1-900;
yek delay baz



نکته آخر اینکه خروجی را باید روی همان پین oc1a تنظیم کنیم نه یک پین نامربوط ، پس برای همین d5 انتخاب شده.
 

saalek110

Well-Known Member
دانش


سایت خود ایشان ، لیست فیلمها:


نام فیلم : بخش بیست و دوم


در دیاگرام مقدار icr1 دیده میشه.
در ادامه جدول مودهای تایمر یک را می بینیم... بعضی به icr1 و بعضی به ocr1 نگاه می کنند.

در مود ctc حداکثر برای tcnt1 همان ocr1 خواهد بود.


بیست و سوم




قسمت بیست و چهارم ،
 

saalek110

Well-Known Member
شرح chatgpt بر برنامه:


این کد C برای میکروکنترلر AVR (احتمالاً ATmega32) نوشته شده و هدف آن تولید یک سیگنال PWM سینوسی برای خروجی OCR1A است. بیایید جزئیات آن را بررسی کنیم:

**توضیحات کد:**

1. **کامنت‌های ابتدایی (نوشته شده توسط OZHAN KD):**
* `50Hz sinusoidal PWM output on OCR1A`: خروجی PWM سینوسی با فرکانس ۵۰ هرتز روی پین OCR1A.
* `Carrier frequency = 15.68 KHz`: فرکانس حامل PWM (فرکانس سوئیچینگ) حدود ۱۵.۶۸ کیلوهرتز است. این فرکانس تعیین می‌کند که سیگنال PWM با چه سرعتی تغییر می‌کند.
* `Sine frequency = 50Hz`: فرکانس موج سینوسی که قرار است تولید شود، ۵۰ هرتز است.
* `PWM resolution = 8bit`: رزولوشن PWM هشت بیتی است، یعنی مقادیر PWM از ۰ تا ۲۵۵ (یا ۰ تا ۰xFF) متغیر هستند.
* `mega32 oscillator frequency = 8MHz`: فرکانس کاری میکروکنترلر ۸ مگاهرتز است.

2. **`#include <mega32.h>`:** این خط فایل هدر مخصوص میکروکنترلر ATmega32 را شامل می‌شود که تعاریف رجیسترها و بیت‌های مربوط به این میکروکنترلر را در خود دارد.

3. **`flash unsigned char sine[256]`:**
* یک آرایه ۲۵۶ بایتی از نوع `unsigned char` تعریف شده که داده‌های موج سینوسی را به صورت ۸ بیتی ذخیره می‌کند.
* کلمه کلیدی `flash` نشان می‌دهد که این داده‌ها در حافظه فلش (ROM) میکروکنترلر ذخیره می‌شوند تا در حافظه RAM اشغال نکنند.
* این آرایه حاوی ۲۵۶ مقدار است که یک چرخه کامل موج سینوسی (۳۶۰ درجه) را با دقت ۸ بیتی تقریب زده‌اند. مقدار `0x80` (۱۲۸ در مبنای ۱۰) معمولاً نشان‌دهنده مرکز موج (نقطه صفر یا DC offset) است و مقادیر کمتر یا بیشتر، دامنه مثبت و منفی را نشان می‌دهند.

4. **`interrupt [TIM0_COMP] void timer0_compare_isr(void)`:**
* این تابع، **ISR (Interrupt Service Routine)** برای مقایسه تایمر ۰ است. یعنی هرگاه مقدار تایمر ۰ با مقدار رجیستر `OCR0` برابر شود، این تابع اجرا خواهد شد.
* `static unsigned char index=0,x5=0;`: دو متغیر `index` و `x5` تعریف شده‌اند که `static` هستند. این یعنی مقدار آن‌ها بین فراخوانی‌های متوالی ISR حفظ می‌شود.
* `index`: برای پیمایش در آرایه `sine` استفاده می‌شود.
* `x5`: یک شمارنده برای ایجاد تأخیر یا کاهش فرکانس اجرای کد اصلی است.
* `if(++x5==5)`: این شرط بررسی می‌کند که آیا `x5` پنج بار افزایش یافته است (یعنی این ISR پنج بار اجرا شده است).
* اگر درست باشد، `x5` دوباره صفر می‌شود.
* `OCR1A=sine[index++];`: مقدار بعدی از آرایه `sine` در رجیستر `OCR1A` قرار می‌گیرد. `index++` باعث می‌شود که در فراخوانی بعدی ISR، مقدار بعدی آرایه خوانده شود. این خط، سیگنال PWM خروجی را با مقادیر سینوسی جدید آپدیت می‌کند.
* **چرا `x5==5`؟** با توجه به توضیحات اولیه (فرکانس حامل ۱۵.۶۸ کیلوهرتز و فرکانس سینوس ۵۰ هرتز)، و اینکه هر سیکل سینوس ۲۵۶ نقطه دارد (۲۵۶ × ۵۰ هرتز = ۱۲۸۰۰ هرتز یا ۱۲.۸ کیلوهرتز)، این عدد ۵ نشان می‌دهد که ISR تایمر ۰ با فرکانس بالاتری نسبت به تایمر ۱ (که PWM را تولید می‌کند) کار می‌کند و هر ۵ بار اجرای ISR تایمر ۰، یک بار PWM را آپدیت می‌کند. این کار باعث می‌شود فرکانس PWM حامل (۱۵.۶۸ کیلوهرتز) نسبت به فرکانس سینوس (۵۰ هرتز) بسیار بیشتر باشد و سیگنال سینوسی نرم‌تری تولید کند.

5. **`void main(void)`:** تابع اصلی برنامه.
* `DDRD=1<<PORTD5;`: رجیستر جهت پورت D را تنظیم می‌کند تا پین PD5 (که معمولاً با OCR1A مرتبط است) به عنوان خروجی تعریف شود.
* `OCR1A=sine[0];`: مقدار اولیه رجیستر مقایسه تایمر ۱ (که PWM را تولید می‌کند) را با اولین مقدار آرایه سینوس (که `0x80` است) تنظیم می‌کند.
* **`TCCR1A=(1<<COM1A1)|(1<<WGM10);`**: رجیستر کنترل تایمر ۱، بخش A را پیکربندی می‌کند:
* `COM1A1`: برای حالت PWM، این بیت پین OC1A (که PD5 است) را فعال می‌کند تا به صورت PWM خروجی شود.
* `WGM10`: همراه با `WGM11` (که در `TCCR1B` است) حالت PWM را تنظیم می‌کند. با `WGM10` و `WGM11` ست شده، حالت PWM 8-bit Fast PWM فعال می‌شود (اگرچه کامنت گفته Phase Correct، اما `WGM10` به تنهایی با `WGM11` ست شده، حالت 8-bit Fast PWM را فعال می‌کند. اگر منظور Phase Correct 8-bit بود، فقط `WGM10` ست می‌شد). **اشتباه در کامنت یا پیکربندی**: کامنت کد اشاره به Phase Correct دارد اما `WGM10` و `WGM11` معمولا حالت Fast PWM را فعال میکنند. اگر هدف Fast PWM 8-bit بود، `TCCR1A` باید `(1<<COM1A1)|(1<<WGM11)` و `TCCR1B` باید `(1<<WGM12)|(1<<CS10)` باشد. **اگر منظور Phase Correct 8-bit باشد،** `TCCR1A` باید `(1<<COM1A1)|(1<<WGM10)` و `TCCR1B` باید `(1<<CS10)` باشد ( که همینطور هم هست). پس کد **Phase Correct 8-bit PWM** را فعال می‌کند.
* **`TCCR1B=1<<CS10; // 8bit Phase correct PWM`**: رجیستر کنترل تایمر ۱، بخش B را پیکربندی می‌کند:
* `CS10`: این بیت، پری‌اسکالر تایمر ۱ را روی حالت No prescaling (فرکانس کلاک سیستم) تنظیم می‌کند. این باعث می‌شود تایمر با سرعت ۸ مگاهرتز شمارش کند.
* **محاسبه فرکانس حامل:**
* تایمر ۱ در حالت 8-bit Phase Correct PWM، دو بار در هر سیکل شمارش (یک بار بالا و یک بار پایین) مقدار `OCR1A` را با مقدار شمارنده مقایسه می‌کند.
* با پری‌اسکالر ۱ (8MHz)، حداکثر مقدار شمارنده ۲۵۵ است.
* فرکانس PWM = (فرکانس کلاک سیستم) / (۲ * ۲۵۶) = ۸,۰۰۰,۰۰۰ / ۵۱۲ = **۱۵,۶۲۵ هرتز** یا **۱۵.۶۲۵ کیلوهرتز**. این مقدار بسیار نزدیک به مقدار ۱۵.۶۸ کیلوهرتز ذکر شده در کامنت است.

* **`OCR0=124;`**: رجیستر مقایسه تایمر ۰ را با مقدار ۱۲۴ تنظیم می‌کند. این مقدار تعیین‌کننده فرکانس ISR تایمر ۰ خواهد بود.
* **`TCCR0=(1<<WGM01)|(1<<CS00); // CTC`**: رجیستر کنترل تایمر ۰ را پیکربندی می‌کند:
* `WGM01`: این بیت همراه با `WGM00` (که در `TCCR0` نیست، پس صفر فرض می‌شود) حالت CTC (Clear Timer on Compare Match) را برای تایمر ۰ فعال می‌کند.
* `CS00`: پری‌اسکالر تایمر ۰ را روی No prescaling (فرکانس کلاک سیستم ۸ مگاهرتز) تنظیم می‌کند.
* **محاسبه فرکانس ISR تایمر ۰:**
* در حالت CTC، تایمر ۰ تا زمانی که با `OCR0` برابر شود شمارش می‌کند و سپس ریست می‌شود.
* فرکانس ISR = (فرکانس کلاک سیستم) / (مقدار `OCR0` + ۱) = ۸,۰۰۰,۰۰۰ / (۱۲۴ + ۱) = ۸,۰۰۰,۰۰۰ / ۱۲۵ = **۶۴,۰۰۰ هرتز** یا **۶۴ کیلوهرتز**.

* **`TIMSK=1<<OCIE0;`**: رجیستر ماسک اینترپت را فعال می‌کند تا وقفه `OCIE0` (وقفه مقایسه تایمر ۰) فعال شود.
* **`#asm("sei")`**: دستور فعال کردن سراسری اینترپت‌ها در میکروکنترلر (Set Interrupts).
* **`while (1);`**: یک حلقه بی‌نهایت که پس از پیکربندی اولیه، برنامه را در حالت اجرا نگه می‌دارد و منتظر وقوع اینترپت‌ها می‌ماند.

**عملکرد کلی:**

1. میکروکنترلر با فرکانس ۸ مگاهرتز کار می‌کند.
2. تایمر ۱ برای تولید PWM با فرکانس حامل حدود ۱۵.۶ کیلوهرتز پیکربندی شده است. این PWM مستقیماً به پین PD5 خروجی داده می‌شود.
3. تایمر ۰ برای ایجاد یک اینترپت با فرکانس ۶۴ کیلوهرتز پیکربندی شده است.
4. هر بار که اینترپت تایمر ۰ رخ می‌دهد، یک شمارنده (`x5`) افزایش می‌یابد.
5. بعد از اینکه اینترپت تایمر ۰ پنج بار اجرا شد (یعنی هر ۵ بار که ۶۴ کیلوهرتز رخ داد)، یک بار مقدار رجیستر `OCR1A` (که PWM را کنترل می‌کند) با مقدار بعدی از آرایه `sine` آپدیت می‌شود.
6. این اتفاق باعث می‌شود که مقدار PWM با الگوی موج سینوسی ذخیره شده در آرایه `sine` تغییر کند و در نهایت خروجی PWM با شکل موج سینوسی ۵۰ هرتزی تولید شود.
7. **فرکانس آپدیت PWM:** از آنجایی که PWM هر ۵ بار ISR تایمر ۰ آپدیت می‌شود، فرکانس واقعی آپدیت PWM برابر است با: ۶۴,۰۰۰ هرتز / ۵ = **۱۲,۸۰۰ هرتز** یا **۱۲.۸ کیلوهرتز**.
* **محاسبه فرکانس سینوس:** با ۲۵۶ نقطه برای یک سیکل کامل سینوس و فرکانس آپدیت ۱۲.۸ کیلوهرتز، فرکانس سینوس برابر است با: ۱۲,۸۰۰ هرتز / ۲۵۶ = **۵۰ هرتز**. این با کامنت اولیه مطابقت دارد.
* **تفاوت با فرکانس حامل PWM:** فرکانس حامل PWM (۱۵.۶ کیلوهرتز) فرکانس سوئیچینگ پایه PWM است، در حالی که فرکانس آپدیت (۱۲.۸ کیلوهرتز) فرکانسی است که خودِ مقدار PWM تغییر می‌کند. این دو لزوماً یکسان نیستند و برای تولید PWM سینوسی، فرکانس آپدیت مقدار PWM باید به طور قابل توجهی کمتر از فرکانس حامل باشد.

**نکات و احتمالات:**

* **مقدار `OCR0 = 124`:** باعث فرکانس ISR دقیقاً ۶۴ کیلوهرتز می‌شود.
* **مقدار `x5 = 5`:** باعث می‌شود PWM هر ۱۲.۸ کیلوهرتز آپدیت شود.
* **کد کامنت شده در مورد `TCCR1B`:** کامنت `// 8bit Phase correct PWM` با پیکربندی `TCCR1B=1<<CS10;` مطابقت دارد (اگر `WGM10` در `TCCR1A` هم فعال باشد). اما اگر `WGM11` هم فعال شود، حالت Fast PWM فعال می‌شود. با توجه به مقادیر `0x80` تا `0xFF` (و `0x00` تا `0x7F` در نیمه دوم) در آرایه سینوس، به نظر می‌رسد هدف تولید یک موج سینوسی است که حول یک ولتاژ متوسط (معمولاً VCC/2) نوسان می‌کند، که با Phase Correct PWM هم قابل دستیابی است.

به طور کلی، این یک کد استاندارد برای تولید PWM سینوسی با استفاده از lookup table (آرایه سینوس) و تایمرهای میکروکنترلر AVR است.
 

saalek110

Well-Known Member
بحث با chatgpt : آیا روش دیگر نداریم؟

آیا تنها راه ساختن موج سینوسی با میکروکنترلر اتمگا ۳۲ ، همین چیدن اعداد در یک آرایه است یا راه صحیح تری هم دارد؟

نه، «فقط چیدن اعداد در آرایه» تنها راهِ ساخت موج سینوسی با ATmega32 نیست—اما **یکی از رایج‌ترین و ساده‌ترین** راه‌هاست. چند روش صحیح/متداول دیگر هم وجود دارد که بسته به امکانات شما (دقت، سرعت، حافظه، سخت‌افزار خروجی) انتخاب می‌شوند.

## 1) روش LUT (همان آرایه سینوسی) — رایج‌ترین
**ایده:** یک چرخه سینوسی را از قبل به صورت جدول (LUT) ذخیره می‌کنید و با یک شمارنده دوره‌ای، خروجی را به‌روزرسانی می‌نمایید.
**مزیت‌ها:**
- پیاده‌سازی ساده و قابل‌اعتماد
- کنترل دقیق شکل موج
- مناسب برای فرکانس‌های نسبتاً ثابت
**عیب‌ها:**
- مصرف حافظه فلش (ولی برای 256 نقطه معمولاً خیلی زیاد نیست)
- رزولوشن زمانی/عدد محدود است

> چیزی که در کدت هم هست: LUT + به‌روزرسانی دوره‌ای با تایمرها.

## 2) «محاسبه آنلاین» سینوس (بدون LUT بزرگ)
**ایده:** در هر گام، مقدار `sin()` را محاسبه کنید (مثلاً با روش‌های سری تیلور/بخش‌های تقریبی) و خروجی را آپدیت کنید.

**واقعیت مهم:**
ATmega32 سخت‌افزار مموری/فلوات کافی و واحد اعشاری ندارد؛ محاسبه‌ی `sin()` به صورت شناور معمولاً:
- **خیلی کند** می‌شود
- کد/دقت کنترلش سخت‌تر است

**پس اگر آنلاین می‌خواهید، معمولاً نه با سینوس واقعی float، بلکه با تقریب‌های عددصحیح** (مثلاً استفاده از تکرارهای کسری، CORDIC یا روش‌های عددصحیح).

**مزیت‌ها:**
- فضای LUT کمتر/صفر
**عیب‌ها:**
- مصرف CPU بالا
- سخت‌تر برای رسیدن به کیفیت موج خوب

## 3) استفاده از CORDIC (تقریب عددصحیح سینوس)
**ایده:** CORDIC با عملیات شیفت/جمع، سینوس و کسینوس را تقریب می‌زند.
**مزیت‌ها:**
- بدون جدول بزرگ
- کاملاً عددصحیح و سازگار با میکروکنترلر
**عیب‌ها:**
- نسبت به LUT ساده‌تر، معمولاً بار پردازشی بیشتر است
- طراحی دقیق برای دقت مطلوب لازم دارد

## 4) روش «نوسان‌ساز دیجیتال» با رابطه بازگشتی (بدون جدول)
**ایده‌ی خیلی مهم:** سینوس می‌تواند با یک معادله‌ی بازگشتی (DSP style) تولید شود؛ یعنی به جای ذخیره‌ی کل موج، فقط چند پارامتر را نگه می‌دارید و هر نمونه را از نمونه‌های قبلی می‌سازید.

نمونه‌ی کلی:
- یک حالت رزونانس/فیلتر ۲-ترتیبه می‌سازید که خروجی‌اش سینوسی شود.
- فرکانس با پارامترهایی تنظیم می‌شود که از `sin(ω)`/`cos(ω)` می‌آیند.

**مزایا:**
- حافظه خیلی کم
- کنترل فرکانس با یک سری پارامتر
**عیب‌ها:**
- دقت و پایداری عددی به طراحی حساس است
- اگر coefficient ها را ساده انتخاب کنید ممکن است اعوجاج/رانش (drift) ایجاد شود

## 5) اگر خروجی شما PWM است: راه درست‌تر «DDS + PWM/فیلتر» است
در عمل، چون ATmega32 خروجی آنالوگ واقعی مثل DAC ندارد (جز PWM)، معمولاً شما باید:
- یک **نمونه‌برداری مناسب** بسازید (مثل DDS به شکل LUT اما با فاز)
- بعد خروجی PWM را با **فیلتر پایین‌گذر** نرم کنید تا موج سینوسی‌تر شود

**DDS (Direct Digital Synthesis)**:
- یک **phase accumulator** دارید
- فاز را زیاد می‌کنید با یک `phase_step`
- سپس از LUT (یا CORDIC) مقدار سینوس را می‌گیرید

این روش نسبت به LUT ساده‌ی «index++ خطی» انعطاف بیشتری دارد (فرکانس قابل تغییر با دقت بالاتر) و فاز را تمیز نگه می‌دارد.

## جمع‌بندی سریع (کدام بهتر است؟)
- اگر **سادگی + کیفیت خوب** می‌خواهید: **LUT (همان روش شما)** بهترین گزینه است.
- اگر **حافظه خیلی محدود** است: به سراغ **CORDIC** یا **بازگشتی عددصحیح** بروید.
- اگر **می‌خواهید فرکانس را دقیق و سریع تغییر دهید** (مثلاً sweep): معمولاً **DDS با phase accumulator + LUT** (یا CORDIC) روش استانداردتر است.

---

برای اینکه دقیق بگویم «بهترین روش برای شما» کدام است، فقط 3 نکته را بگویید:
1) خروجی را **واقعاً PWM** می‌خواهید یا امکان **فیلتر RC/LC** دارید؟
2) فرکانس سینوس فقط **50Hz ثابت** است یا باید **قابل تغییر** باشد؟
3) کیفیت مدنظرتان چقدر است؟ (مثلاً THD کم، یا فقط شکل سینوسی قابل قبول برای آزمایش)
 
بالا