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

saalek110

Well-Known Member
این موج سینوسی که این برنامه می سازد ، کاربردش کجاست؟

این برنامه موج سینوسی 50 هرتزی PWM تولید می‌کند که کاربردهای مختلفی می‌تواند داشته باشد، مخصوصاً در پروژه‌های الکترونیکی و کنترلی. چند مورد از کاربردهای احتمالی را در ادامه می‌آورم:

1. **تولید ولتاژ AC (با فیلتر):**
* اگر این PWM توسط یک فیلتر پایین‌گذر (Low-Pass Filter) مناسب (مثلاً یک فیلتر RC یا LC) عبور داده شود، می‌توان یک موج سینوسی نسبتاً تمیز در حدود 50 هرتز تولید کرد. این می‌تواند برای شبیه‌سازی منبع تغذیه AC در مقیاس کوچک، تست مدارهای AC، یا حتی ساخت منابع تغذیه قابل تنظیم (Adjustable Power Supply) در پروژه‌های تحقیقاتی یا آزمایشگاهی استفاده شود.
* **مثال:** ساخت یک منبع تغذیه کوچک برای آزمایش قطعات الکترونیکی که نیاز به ولتاژ AC دارند.

2. **کنترل موتورهای AC:**
* درایورهایی که موتورهای AC را راه‌اندازی و کنترل می‌کنند (مانند درایورهای VFD - Variable Frequency Drive)، نیاز به تولید موج سینوسی با فرکانس و دامنه متغیر دارند. این کد می‌تواند یک نقطه‌ی شروع برای ساخت یک درایور ساده‌تر باشد، جایی که فرکانس ثابت 50 هرتز مورد نیاز است.
* **مثال:** کنترل سرعت یک موتور AC کوچک (اگرچه معمولاً موتورهای AC به فرکانس متغیر حساس‌ترند، اما برای برخی کاربردهای خاص این کارایی دارد).

3. **تست تجهیزات صوتی:**
* تولید سیگنال‌های صوتی در فرکانس‌های پایین (مانند 50 هرتز) برای تست بلندگوها، آمپلی‌فایرها، یا سایر تجهیزات صوتی.

4. **سیستم‌های تست و اندازه‌گیری:**
* در سیستم‌های تست خودکار، گاهی نیاز است که یک سیگنال AC استاندارد (مانند 50 هرتز) برای تحریک دستگاه مورد آزمایش تولید شود.

5. **کاربردهای پزشکی (با دقت بالا و ایمنی):**
* برخی دستگاه‌های پزشکی یا تجهیزات توانبخشی ممکن است نیاز به تولید سیگنال‌های AC با فرکانس مشخص داشته باشند. البته در این موارد، دقت، پایداری، و ایزوله‌سازی بسیار حیاتی است و ممکن است این کد به تنهایی کافی نباشد و نیاز به سخت‌افزار و نرم‌افزار پیشرفته‌تری داشته باشد.

6. **پروژه‌های آموزشی و نمایشی:**
* این کد یک مثال عالی برای یادگیری نحوه‌ی تولید سیگنال‌های پیچیده (مانند سینوسی) با استفاده از میکروکنترلر و تکنیک‌هایی مانند PWM و جداول جستجو (Lookup Tables) است.

**نکته مهم:**
همانطور که در تحلیل کد اشاره شد، این کد یک PWM با فرکانس حامل بالا (حدود 15.6 کیلوهرتز) تولید می‌کند و سپس با استفاده از LUT، پهنای پالس‌ها را طوری تغییر می‌دهد که شکل موج کلی شبیه سینوس شود. این PWM مستقیماً یک موج سینوسی آنالوگ خالص نیست، بلکه یک موج مربعی با عرض پالس متغیر است. برای به دست آوردن یک موج سینوسی واقعی، نیاز به فیلتر کردن آن است.

اگر کاربرد خاصی مد نظرتان است، بگویید تا بتوانم دقیق‌تر راهنمایی کنم.
 

saalek110

Well-Known Member
اون اعداد آرایه را چطوری ساخته؟
سالک: ممکن است فرمولها ، درست کپی نشده باشد ، خودتان سوال زا از chatgpt بپرسید.

برای اینکه بفهمم دقیقاً آن اعداد آرایه چطور ساخته شده‌اند، نیاز به دیدن خود کد دارم. اما با توجه به اینکه در توضیحات شما به یک آرایه `sine[256]` اشاره شده و هدف تولید موج سینوسی 50 هرتز است، می‌توانم به طور کلی روش‌هایی که برای ساخت چنین آرایه‌ای استفاده می‌شود را توضیح دهم:

**روش‌های رایج برای ساخت آرایه موج سینوسی (Lookup Table - LUT):**

1. **محاسبه با استفاده از تابع سینوس در زبان‌های برنامه‌نویسی سطح بالا (مثل پایتون یا C/C++ روی کامپیوتر):**
* این متداول‌ترین و دقیق‌ترین روش است. در این روش، شما از تابع `sin()` که در کتابخانه‌های ریاضی زبان‌های برنامه‌نویسی موجود است، استفاده می‌کنید.
* **مراحل کلی:**
* تعیین کنید که موج سینوسی شما چند نقطه (نمونه) در یک چرخه کامل داشته باشد. در اینجا 256 نقطه انتخاب شده است (که با 8 بیت همخوانی دارد).
* یک چرخه کامل سینوس معادل 360 درجه یا $2\pi$ رادیان است.
* برای هر نقطه از 0 تا 255، زاویه متناظر را محاسبه کنید. مثلاً اگر $i$ اندیس آرایه باشد (از 0 تا 255):
* زاویه در رادیان: $angle = (float)i / 256.0 * 2.0 * \pi$
* زاویه در درجه: $angle\_deg = (float)i / 256.0 * 360.0$
* مقدار سینوس را برای آن زاویه محاسبه کنید: $value = \sin(angle)$
* این مقدار سینوس که معمولاً بین -1 و +1 است را به مقیاس مورد نظر برای میکروکنترلر تبدیل کنید. اگر قرار است مستقیماً در رجیستر PWM (مثلاً 8 بیتی) قرار گیرد:
* مقیاس‌بندی: $scaled\_value = (int)((value + 1.0) / 2.0 * 255.0)$
* این فرمول مقدار سینوس را که بین -1 و +1 است، به بازه [0, 255] نگاشت می‌کند. (-1 به 0، 0 به 127.5، و +1 به 255).
* این مقادیر محاسبه شده را در آرایه `sine[256]` ذخیره کنید.
* **مثال کد پایتون برای تولید اعداد:**
```python
import math

num_samples = 256
sine_wave = []

for i in range(num_samples):
# Calculate angle in radians
angle = (float(i) / num_samples) * 2.0 * math.pi
# Calculate sine value and scale it to 0-255
scaled_value = int(((math.sin(angle) + 1.0) / 2.0) * 255.0)
sine_wave.append(scaled_value)

print(sine_wave)
# This list of numbers can then be copied into the C code for AVR
```

2. **استفاده از تقریب‌های عددی (مانند سری تیلور یا CORDIC):**
* همانطور که در پاسخ قبلی گفتم، در میکروکنترلرهایی مثل ATmega32 که قدرت پردازشی محدود دارند، محاسبه مستقیم `sin()` ممکن است کند باشد. در این حالت، گاهی اعداد LUT را با استفاده از الگوریتم‌های تقریب عددی تولید می‌کنند.
* **سری تیلور:** $sin(x) = x - \frac{x^3}{3!} + \frac{x^5}{5!} - \frac{x^7}{7!} + \dots$
* **CORDIC:** یک الگوریتم کارآمد برای محاسبه توابع مثلثاتی با استفاده از شیفت و جمع.
* این روش‌ها معمولاً پیچیده‌تر هستند و نیاز به دقت در پیاده‌سازی دارند، اما اگر بخواهید اعداد را مستقیماً روی خود میکروکنترلر (یا یک ابزار محاسباتی با محدودیت) تولید کنید، گزینه‌های خوبی هستند.

3. **استفاده از ابزارهای تخصصی:**
* نرم‌افزارهایی برای طراحی سیگنال یا شبیه‌سازی وجود دارند که می‌توانند LUT موج سینوسی را با دقت دلخواه تولید کنند.

**با توجه به کد C که شما ارسال کرده بودید (یا توصیفات مربوط به آن)، احتمالاً از روش اول (محاسبه با تابع `sin()` در یک زبان سطح بالا و کپی کردن اعداد به کد C) استفاده شده است.**

اگر کد C را اینجا ارائه دهید، می‌توانم مستقیماً آرایه `sine` را ببینم و بگویم که دقیقاً چه اعدادی در آن ذخیره شده‌اند.
 

saalek110

Well-Known Member
خیلی هم عالی! تسلط بر تایمر ۰ پایه و اساس کار با تایمرهاست. تایمر ۱ در میکروکنترلر **ATmega16** برادر بزرگ‌تر و قدرتمندترِ تایمر ۰ است و برای کاربردهای حرفه‌ای‌تر طراحی شده است.

در اینجا مهم‌ترین تفاوت‌های تایمر ۱ با تایمر ۰ را به زبان ساده لیست می‌کنم:

### ۱. اندازه ثبت‌کننده (Counter Resolution)
* **تایمر ۰:** یک تایمر **۸ بیتی** است. یعنی از ۰ تا ۲۵۵ (۲۸) می‌شمارد و وقتی به ۲۵۵ رسید، دوباره از ۰ شروع می‌شود (Overflow می‌کند).
* **تایمر ۱:** یک تایمر **۱۶ بیتی** است. یعنی از ۰ تا ۶۵۵۳۵ (۲۱۶) می‌شمارد.
* **نتیجه:** تایمر ۱ می‌تواند بازه زمانی بسیار طولانی‌تری را قبل از سرریز شدن (Overflow) پوشش دهد. این یعنی دقت بالاتر و نیاز کمتر به وقفه برای شمارش زمان‌های طولانی.

### ۲. قابلیت تولید فرکانس دقیق (CTC Mode)
در تایمر ۰ شما فقط می‌توانید از حالت‌های عادی، Fast PWM و Phase Correct PWM استفاده کنید. اما تایمر ۱ علاوه بر آن‌ها، حالت **CTC (Clear Timer on Compare Match)** را دارد.
* در حالت CTC، شما می‌توانید یک مقدار مشخص (مثلاً در رجیستر OCR1A) تعیین کنید و تایمر وقتی به آن عدد رسید، صفر شود. این قابلیت برای تولید فرکانس‌های دقیق (مثلاً برای تولید موج سینوسی یا ساعت دقیق) فوق‌العاده کاربردی است. (البته تایمر ۰ در برخی میکروکنترلرهای جدیدتر CTC دارد، اما در ATmega16 کلاسیک، تایمر ۱ کامل‌تر است).

### ۳. خروجی‌های PWM (تعداد و کیفیت)
* **تایمر ۰:** فقط **۲ خروجی PWM** دارد (OC0 و OC0 که روی پین‌های B3 و B4 هستند).
* **تایمر ۱:** **۳ خروجی PWM** دارد (OC1A، OC1B و OC1C). نکته مهم اینجاست که تایمر ۱ می‌تواند PWM با رزولوشن ۸، ۹، ۱۰ بیتی تولید کند. یعنی شما می‌توانید کنترل دقیق‌تری روی توان موتور یا نور LED داشته باشید (مثلاً به جای ۲۵۵ مرحله، ۱۰۲۴ مرحله تنظیم دقت).

### ۴. واحد شمارنده فرکانس خارجی (Input Capture Unit)
این مهم‌ترین ویژگی متمایز تایمر ۱ است که تایمر ۰ ندارد!
* تایمر ۱ یک پین ورودی به نام **ICP1** (Input Capture Pin) دارد.
* **کاربرد:** فرض کنید می‌خواهید پهنای پالس (Pulse Width) یک سنسور التراسونیک یا فرکانس یک سیگنال نامشخص را اندازه بگیرید. وقتی سیگنال روی پین ICP1 تغییر وضعیت دهد، تایمر ۱ به صورت خودکار مقدار لحظه‌ای خودش را در یک رجیستر ذخیره می‌کند. این کار سرعت و دقت اندازه‌گیری را بسیار بالا می‌برد و نیازی به چک کردن مداوم پین در کد نیست.

### ۵. رجیسترهای کنترلی بیشتر
چون تایمر ۱ قابلیت‌های بیشتری دارد، رجیسترهای تنظیمات بیشتری هم دارد:
* **TCCR0:** فقط یک رجیستر برای تنظیم تایمر ۰.
* **TCCR1A و TCCR1B:** دو رجیستر برای تنظیم تایمر ۱ (یکی برای حالت‌های موج و یکی برای منبع کلاک و پیش‌تقسیم‌کننده).

### خلاصه مقایسه

| ویژگی | تایمر ۰ | تایمر ۱ |
| :--- | :--- | :--- |
| **بیتی (Bit)** | ۸ بیتی | ۱۶ بیتی |
| **حداکثر شمارش** | ۲۵۵ | ۶۵۵۳۵ |
| **تعداد خروجی PWM** | ۲ تا | ۳ تا |
| **رزولوشن PWM** | ۸ بیت | ۸، ۹، ۱۰ بیت |
| **ورودی اندازه‌گیری (ICP)** | ندارد | دارد |
| **حالت CTC** | محدود / ندارد | کامل و دقیق |

**پیشنهاد:** حالا که تایمر ۰ را بلد هستید، برای تمرین تایمر ۱، سعی کنید با استفاده از حالت CTC در تایمر ۱، یک چشمک‌زن دقیق ۱ ثانیه‌ای بسازید یا از قابلیت Input Capture آن برای اندازه‌گیری پهنای پالس یک سنسور استفاده کنید.

سوالی درباره نحوه تنظیم رجیسترهای TCCR1A یا TCCR1B داری؟
 

saalek110

Well-Known Member
تفاوت اصلی تایمر 0 و تایمر 1 در ATmega16/ATmega32 در **توانایی‌ها، دقت، اندازه شمارنده و مودهای پیشرفته** است. خلاصه اگر بخواهیم بگوییم: **Timer0 ساده و 8 بیتی است؛ Timer1 قوی، دقیق و 16 بیتی.**

در ادامه تفاوت‌ها را دقیق و مفید بر اساس کاربرد توضیح می‌دهم:

---

## 1) اندازه شمارنده
**Timer0 → 8-bit**
- از 0 تا 255 می‌شمارد.
- دقت کمتر، محدوده زمانی کوتاه‌تر.

**Timer1 → 16-bit**
- از 0 تا 65535 می‌شمارد.
- دقت بالا + حداکثر زمان شمارش بسیار بیشتر.
- مناسب کارهای حرفه‌ای.

---

## 2) قابلیت تولید PWM
**Timer0:**
- فقط 2 مود PWM:
*Fast PWM* و *Phase Correct PWM*
- دقت کم (چون 8 بیتی است)

**Timer1:**
- PWM بسیار پیشرفته‌تر:
- Fast PWM
- Phase Correct
- Phase and Frequency Correct
- *ICR1* به عنوان TOP → تنظیم فرکانس PWM با دقت بالا
- مناسب درایو موتور، سروو، اینورتر و …

---

## 3) ورودی اندازه‌گیری فرکانس / مدت‌زمان (Input Capture)
**Timer0:** ندارد.

**Timer1:** دارد → *ICP1 pin*
- می‌تواند لبه سیگنال ورودی را با دقت بسیار بالا ثبت کند.
- ایده‌آل برای اندازه‌گیری فرکانس، پالس‌هام، فاصله‌یابی اولتراسونیک و…

---

## 4) تعداد Compare Match
**Timer0:**
- یک Output Compare → OCR0

**Timer1:**
- دو واحد مستقل → OCR1A و OCR1B
- قابلیت ایجاد دو خروجی PWM هم‌زمان با فرکانس/وظیفه مختلف

---

## 5) کاربردهای معمول
### Timer0
- تاخیرهای ساده
- تولید وقفه دوره‌ای کوتاه
- PWM سبک و کم‌دقت (مثل LED دیمینگ)
- شمارنده ساده

### Timer1
- PWM دقیق (موتور، سروو)
- تایمر زمان بالا
- ورودی Input Capture (اندازه‌گیری فرکانس)
- تولید موج با فرکانس قابل‌تنظیم
- ایزوله‌سازی وظایف PWM روی A و B

---

## 6) پری‌اسکیلر
هر دو تایمر پری‌اسکیلر مشترک دارند، اما چون Timer1 بزرگ‌تر است، از پری‌اسکیلرهایش **کارآمدتر** استفاده می‌کند.

---

## جمع‌بندی کاربردی
اگر بخواهیم خیلی کوتاه بگوییم:

- **Timer0 = ساده، 8 بیت، کارهای سبک**
- **Timer1 = حرفه‌ای، 16 بیت، PWM دقیق، Input Capture**

اگر بگویی برای چه پروژه‌ای می‌خواهی استفاده کنی، بهترین تایمر و روش کانفیگ کاملش را هم برات می‌نویسم (به همراه کد C برای CodeVision یا AVR-GCC).
 

saalek110

Well-Known Member
ایا با تایمر صفر در اتمگا ۳۲ ، هم میشه سروو موتور را با موج مربعی راه انداخت یا فقط باید از تایمر یک استفاده کرد؟

deepseek:
با توجه به جستجوی انجام‌شده، پاسخ دقیق این است:

بله، از نظر تئوری راه‌اندازی سروو موتور با تایمر صفر ATmega32 ممکن است، اما در عمل با محدودیت‌های جدی همراه است و معمولاً توصیه نمیشود.

در ادامه به بررسی امکان راه‌اندازی با تایمرهای مختلف میپردازم:

· امکان استفاده از تایمر صفر و دو (8 بیتی)
از آنجایی که تایمر صفر و دو هر دو ۸ بیتی هستند، میتوان از آنها برای تولید سیگنال PWM استفاده کرد . با این حال، مشکل اصلی از آنجا ناشی میشود که سروو موتورها نیازمند فرکانس PWM پایین و مشخصی (معمولاً 50 هرتز) هستند . تایمرهای ۸ بیتی برای تولید چنین فرکانس پایینی با کلاک معمولی میکروکنترلر (مثلاً ۸ مگاهرتز) به شدت محدود هستند. برای رسیدن به فرکانس ۵۰ هرتز، باید از prescalerهای بزرگ (مثل ۱۰۲۴) استفاده کرد که نتیجه آن کاهش شدید دقت (Resolution) در کنترل عرض پالس خواهد بود و در نهایت باعث میشود نتوانید موقعیت سروو را به نرمی و دقت کنترل کنید.
· مزیت اصلی تایمر یک (16 بیتی)
مشکل ذکر شده دقیقاً دلیل اصلی استفاده گسترده از تایمر یک (16 بیتی) برای کنترل سروو موتورهاست. این تایمر علاوه بر prescaler، از رجیستر ICR1 نیز بهره میبرد که به شما اجازه میدهد مقدار TOP (سقف شمارش) را بهطور دلخواه و با دقت بسیار بالا تنظیم کنید . به همین دلیل، حتی کتابخانههای استاندارد و حرفهای مانند کتابخانه Servo در Arduino نیز برای میکروکنترلرهای AVR بهطور پیشفرض از تایمرهای ۱۶ بیتی استفاده میکنند .

نتیجهگیری:
برای پروژههایی که نیاز به کنترل دقیق و روان سروو موتور دارند، تایمر یک گزینه بسیار مناسبتری است. تایمر صفر را میتوان برای مصارف سادهتر یا زمانی که به دقت بالا نیاز ندارید (مانند کنترل یک LED یا موتور DC ساده) به کار برد، اما برای سروو موتور انتخاب ایدهآلی نخواهد بود .
 

saalek110

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

deepseek:
حق با شماست، باید دقیق‌تر توضیح می‌دادم. ببینید قضیه از این قرار است:

سروو با تایمر صفر اصلاً قاطی نمی‌کند و کاملاً قابل استفاده است. فقط دقتش پایین‌تر است، نه اینکه غیرقابل استفاده باشد.

---

تفاوت دقت در عمل چقدر است؟

سرووهای استاندارد (مثل SG90 یا MG996R):

· به پالس‌هایی با عرض ۰.۵ تا ۲.۵ میلی‌ثانیه نیاز دارند.
· هر ۱۰ میکروثانیه تغییر در عرض پالس ≈ ۱ درجه چرخش شفت.

با تایمر یک (۱۶ بیتی - حالت ایده‌آل):

· با کریستال ۸ مگاهرتز و تنظیمات بهینه، رزولوشن شما حدود ۰.۵ میکروثانیه خواهد بود.
· یعنی می‌توانید شفت را با دقت ۰.۰۵ درجه کنترل کنید (بسیار نرم).

با تایمر صفر (۸ بیتی - روش عملی و معمول):

· برای رسیدن به فرکانس ۵۰ هرتز (پریود ۲۰ میلی‌ثانیه)، مجبورید از Prescaler = 1024 استفاده کنید.
· در این حالت رزولوشن شما ۱۲۸ میکروثانیه خواهد بود.
· نتیجه: هر پله تغییر در کد شما ≈ ۱۲.۸ درجه جابجایی شفت است.

---

یعنی در عمل چه اتفاقی می‌افتد؟

تصور کنید می‌خواهید بازوی ربات را به زاویه ۹۰ درجه ببرید:

· با تایمر یک: می‌توانید روی ۹۰.۰ درجه تنظیم کنید.
· با تایمر صفر: نزدیک‌ترین زاویه‌ای که می‌توانید انتخاب کنید ۸۳ یا ۹۶ درجه است. سروو روی یکی از این دو قفل می‌کند و نمی‌تواند روی ۹۰ درجه بایستد.

پس سروو قاطی نمی‌کند، فقط «پله‌پله» و با گام‌های درشت حرکت می‌کند. برای کارهای ساده مثل باز و بسته کردن یک دریچه (فقط ۰ و ۹۰ درجه) کاملاً کافی و بی‌عیب است. اما برای ربات متعادل‌کننده یا بازوی دقیق که نیاز به حرکت پیوسته و نرم دارد، این لرزش و حرکت پله‌ای آزاردهنده و غیرقابل قبول خواهد بود.

---

یک راه حل ساده: تایمر دو رو قرض بگیر!

اگر تایمر یک را برای کار مهم‌تری (مثلاً سنسور اولتراسونیک) نیاز دارید و تایمر صفر هم بیکار است، می‌توانید تایمر صفر و تایمر دو را با هم کاسکید (Cascade) کنید تا یک تایمر ۱۶ بیتی مجازی بسازید.

· تایمر صفر (۸ بیتی) سرریز می‌شود و به تایمر دو (۸ بیتی) کلاک می‌دهد.
· دقت این روش ۳۲ برابر بهتر از تایمر صفر تنهاست و برای یک سروو عالی است.

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

saalek110

Well-Known Member
با شرح بیشتری بگو چرا prescaler برای تایمرصفر باید ۱۰۲۴ باشه؟ آیا چون تایمر صفر تا ۲۵۵ فقط می شمارد...حساب کن



دقیقاً متوجه شدید. اجازه بدهید محاسبات را گام به گام با اعداد واقعی انجام دهیم تا مشخص شود چرا مجبور به استفاده از Prescaler 1024 هستیم.

---

داده‌های مسئله

· کریستال ATmega32: 8 مگاهرتز (8,000,000 پالس در ثانیه)
· حداکثر شمارش تایمر صفر (۸ بیتی): 0 تا 255 (یعنی ۲۵۶ پله)
· فرکانس مورد نیاز سروو: 50 هرتز
· پریود مورد نیاز: 1 ÷ 50 = 20 میلی‌ثانیه

---

گام اول: بدون Prescaler (Prescaler = 1)

اگر Prescaler روی 1 باشد، تایمر با فرکانس 8MHz شمارش می‌کند:

· زمان هر پالس شمارش: 1 ÷ 8,000,000 = 0.125 میکروثانیه
· زمان یک دور کامل تایمر (256 پله): 256 × 0.125 = 32 میکروثانیه

نتیجه: تایمر هر ۳۲ میکروثانیه سرریز می‌کند، در حالی که ما به پریود ۲۰,۰۰۰ میکروثانیه نیاز داریم.
یعنی ۶۲۵ برابر سریع‌تر از آنچه نیاز داریم!

---

گام دوم: انتخاب Prescaler مناسب

ما باید سرعت شمارش را آن‌قدر کم کنیم که یک دور کامل تایمر (۲۵۶ پله) حداقل ۲۰ میلی‌ثانیه طول بکشد.
عدد Prescaler را طوری انتخاب می‌کنیم که زمان یک دور تایمر به ۲۰ میلی‌ثانیه نزدیک شود:

Prescaler فرکانس ورودی به تایمر زمان هر پله زمان یک دور کامل (۲۵۶ پله)
1 8 MHz 0.125 µs 32 µs (خیلی کم)
8 1 MHz 1 µs 256 µs (خیلی کم)
64 125 KHz 8 µs 2,048 µs ≈ 2 ms (کم)
256 31.25 KHz 32 µs 8,192 µs ≈ 8.2 ms (کم)
1024 7.8125 KHz 128 µs 32,768 µs ≈ 32.8 ms
axe file 3.jpg
---

گام سوم: چرا فقط ۱۰۲۴ جواب می‌دهد؟

با Prescaler = 1024:

· زمان یک دور کامل تایمر = ۳۲.۸ میلی‌ثانیه
· این مقدار از ۲۰ میلی‌ثانیه مورد نیاز ما بزرگ‌تر است، پس قابل قبول است (می‌توانیم با تنظیم مقدار TOP در حالت CTC آن را دقیقاً روی ۲۰ میلی‌ثانیه تنظیم کنیم).

با Prescaler = 256:

· زمان یک دور کامل = ۸.۲ میلی‌ثانیه
· این مقدار از ۲۰ میلی‌ثانیه کوچک‌تر است. یعنی حتی اگر تایمر را تا سقف ۲۵۵ بشماریم، باز هم زودتر از ۲۰ میلی‌ثانیه سرریز می‌کند و ما نمی‌توانیم پریود ۲۰ میلی‌ثانیه را تولید کنیم.

---

گام چهارم: محاسبه رزولوشن نهایی (منشأ حرکت پله‌ای)

حالا که مجبوریم از Prescaler = 1024 استفاده کنیم:

· زمان هر پله شمارش = ۱۲۸ میکروثانیه
· برای ساختن پریود ۲۰ میلی‌ثانیه (۲۰,۰۰۰ میکروثانیه) باید تایمر تا مقدار ۱۵۶ بشمارد:
20,000 ÷ 128 ≈ 156

بنابراین تایمر ما از ۰ تا ۱۵۶ می‌شمارد (۱۵۷ پله).
حالا می‌خواهیم عرض پالس سروو را بین ۰.۵ تا ۲.۵ میلی‌ثانیه تنظیم کنیم:

· ۰.۵ میلی‌ثانیه (۵۰۰ µs): 500 ÷ 128 ≈ ۴ پله
· ۱.۵ میلی‌ثانیه (۱۵۰۰ µs): 1500 ÷ 128 ≈ ۱۲ پله (مرکز)
· ۲.۵ میلی‌ثانیه (۲۵۰۰ µs): 2500 ÷ 128 ≈ ۲۰ پله

یعنی کل محدوده حرکتی سروو فقط ۱۶ پله (از ۴ تا ۲۰) است!

با ۱۶ پله برای پوشش ۱۸۰ درجه چرخش:

· هر پله ≈ ۱۱.۲۵ درجه جابجایی

این یعنی سروو نمی‌تواند روی زاویه ۹۰ درجه بایستد. یا روی ۸۴.۴ درجه می‌ایستد یا روی ۹۵.۶ درجه. برای چشم انسان این حرکت پله‌ای و زمخت دیده می‌شود.

---

جمع‌بندی تصویری

```
Prescaler 1: ████████████████████████████████████████ 32 µs (۶۲۵ برابر سریع‌تر)
Prescaler 1024: ████████████████████████████████████████ 32.8 ms (مناسب)
[0...................156] ← ۱۵۷ پله برای ۲۰ میلی‌ثانیه
[4] ← 0.5ms [12] ← 1.5ms [20] ← 2.5ms
↑ ↑ ↑
زاویه ۰° زاویه ۹۰° زاویه ۱۸۰°
فقط ۱۶ پله برای کل محدوده!
```

به همین دلیل است که تایمر صفر به تنهایی برای سروو «دقت پایین» دارد، نه اینکه «اصلاً کار نکند».

---

اگر بخواهید، می‌توانم راهکار عملی بهبود دقت با همان تایمر صفر (با استفاده از وقفه و شمارش نرم‌افزاری) را هم توضیح دهم که دقت را تا حدود ۱۰ برابر افزایش می‌دهد.
 

saalek110

Well-Known Member
سالک: پس زمخت میشه


دقیقاً. زمخت و خشک.

حرکت سروو با این تنظیمات مثل عقربه‌های یک ساعت دیواری قدیمی است که هر ثانیه یک بار می‌پرد، نه مثل عقربه‌های یک کرنومتر دقیق که نرم و پیوسته حرکت می‌کند.

چه زمانی این زمختی مشکلی ایجاد نمی‌کند؟

· باز و بسته کردن یک دریچه ساده → فقط دو حالت ۰° و ۹۰° → کاملاً قابل قبول
· چرخاندن یک دوربین مداربسته با کنترل دستی → کاربر متوجه پرش نمی‌شود → قابل قبول
· حرکت یک ربات مسیر‌یاب ساده → فرمان‌ها گسسته هستند → قابل قبول

چه زمانی این زمختی فاجعه است؟

· بازوی رباتیک که باید اشیاء را دقیق بردارد → غیرقابل قبول
· ربات متعادل‌کننده (Self-Balancing) → سروو دائماً تصحیح می‌کند و لرزش می‌کند → فاجعه
· پنل خورشیدی ردیاب خورشید → حرکت پله‌ای باعث لرزش سازه می‌شود → نامناسب

راه‌حل‌های جایگزین (بدون اشغال تایمر یک)

اگر تایمر یک برای کار مهم‌تری مثل سنسور اولتراسونیک رزرو شده و نمی‌خواهید آن را از دست بدهید، این گزینه‌ها را دارید:

روش دقت (پله/۱۸۰°) پیچیدگی مصرف CPU
تایمر یک (۱۶ بیتی) ~۲۰۰۰ کم صفر
تایمر صفر + وقفه نرم‌افزاری ~۲۰۰ متوسط ۵٪
کاسکید تایمر ۰ + ۲ ~۵۰۰ زیاد صفر
کتابخانه Software PWM ~۱۰۰ کم ۳۰٪
axe file 4.jpg
بهترین گزینه میان‌راه: تایمر صفر + وقفه نرم‌افزاری

این روش دقت را ۱۰ برابر بهتر از روش قبلی می‌کند (هر پله ≈ ۱.۲ درجه به جای ۱۱.۲ درجه) و دیگر حرکت زمخت محسوس نیست. منطق کار ساده است:

1. تایمر صفر با Prescaler = 8 تنظیم می‌شود (نه ۱۰۲۴).
2. با هر سرریز تایمر، یک متغیر شمارنده نرم‌افزاری افزایش می‌یابد.
3. وقتی شمارنده به مقدار مورد نظر رسید، پالس قطع می‌شود.

مصالحه: این روش حدود ۵٪ از توان CPU را مصرف می‌کند (هر ۲۵۶ میکروثانیه یک وقفه)، اما برای اکثر پروژه‌های دانشجویی و صنعتی سبک کاملاً قابل قبول است.

اگر مایلید، کد کامل این روش (که دقت را به ۱.۲ درجه می‌رساند و زمختی را از بین می‌برد) برای ATmega32 آماده کنم.
 

saalek110

Well-Known Member
tcnt1 را به دو بایت بالا و پایین تقسم کردن ، فایده اش چیه و کجا کاربرد داره؟

برای اینکه بتوانم به طور دقیق به سوال شما پاسخ دهم، نیاز دارم که بخش مربوط به TCNT1 و تقسیم آن به دو بایت بالا و پایین را در متن یا تصاویر ببینم.

با این حال، به طور کلی در میکروکنترلرها، تایمرها (مانند TCNT1 که احتمالاً به تایمر 16 بیتی اشاره دارد) اغلب برای شمارش رویدادها یا تولید تاخیر استفاده می‌شوند. وقتی یک تایمر 16 بیتی مانند TCNT1 به دو بایت (بایت بالا و بایت پایین) تقسیم می‌شود، دلایل و کاربردهای مختلفی می‌تواند داشته باشد:

1. **دسترسی به رجیسترها:** در برخی معماری‌های میکروکنترلر، رجیسترهای 16 بیتی ممکن است به صورت دو رجیستر 8 بیتی (یکی برای بایت بالا و یکی برای بایت پایین) قابل دسترسی باشند. این کار برای سازگاری با باس داده 8 بیتی یا برای انعطاف‌پذیری بیشتر در برنامه‌نویسی صورت می‌گیرد.

2. **خوانایی و نوشتن مقادیر:**
* **نوشتن مقدار:** برای تنظیم یک مقدار 16 بیتی در تایمر، معمولاً ابتدا بایت بالا و سپس بایت پایین نوشته می‌شود. این ترتیب مهم است تا از ایجاد مقادیر نامعتبر در حین نوشتن جلوگیری شود.
* **خواندن مقدار:** هنگام خواندن مقدار تایمر، معمولاً ابتدا بایت بالا و سپس بایت پایین خوانده می‌شود. این کار تضمین می‌کند که هنگام خواندن، مقدار تایمر تغییر نکرده باشد (یا حداقل تغییر آن به حداقل رسیده باشد).

3. **مدیریت سرریز (Overflow):** تایمرهای 16 بیتی می‌توانند تا مقدار 65535 بشمارند. پس از آن، سرریز رخ می‌دهد و به صفر بازمی‌گردند. تقسیم به بایت بالا و پایین به برنامه نویس اجازه می‌دهد تا این سرریزها را تشخیص داده و مدیریت کند (مثلاً با افزایش یک شمارنده 16 بیتی دیگر).

4. **کاربرد در حالت‌های خاص:**
* **حالت Input Capture:** همانطور که در صفحه اشاره شده، TCNT1 دارای حالت Input Capture است. در این حالت، مقدار فعلی تایمر در یک رجیستر جداگانه (مانند ICR1) ذخیره می‌شود. این رجیستر نیز 16 بیتی است و ممکن است دسترسی به بایت‌های بالا و پایین آن مطرح شود. این قابلیت برای اندازه‌گیری دقیق زمان بین دو پالس خارجی (مانند اندازه‌گیری فرکانس یا دوره تناوب سیگنال) بسیار کاربردی است.
* **حالت PWM:** در حالت تولید PWM، تایمر برای تولید سیگنال با عرض پالس متغیر استفاده می‌شود. مقادیر ثبت‌های مقایسه (مانند OCR1A/OCR1B) که عرض پالس را تعیین می‌کنند، 16 بیتی هستند و دسترسی به بایت‌های بالا و پایین آن‌ها نیز مطرح است.

**لطفاً تصویری از بخشی که TCNT1 به دو بایت تقسیم شده را نشان می‌دهد، برای من ارسال کنید تا بتوانم توضیحات دقیق‌تر و مرتبط با متن را ارائه دهم.** با دیدن متن، می‌توانم بگویم که آیا این تقسیم‌بندی به دلیل معماری خاص میکروکنترلر است، یا برای مدیریت سرریز، یا در ارتباط با حالت‌های خاصی مانند Input Capture یا PWM است.
 
بالا