سلام دوستان، ببخشید من تو مراحل ساخت پروژه م، لازم دارم که یه قطار پالس با duty cycle و فرکانس متغیر تولید کنم. کار با تایمر کانر صفر رو تا حدودی بلدم و اینو میدونم که تو مد duty cycle ،fast PWM قابل تغییره و تو مد CTC فرکانس؛ اما لازم دارم که هر دوش رو تو یه شکل موج کنترل کنم.
لازمه بگم که هر دوش باید به صورت قابل قبولی دقیق باشه. فرکانس مدار هم باید بین 1Khz تا 20KHz قابل تغییر باشه،میشه گفت که تا حدود 10Hz خطا قابل قبوله.
اگه بتونید کمکم کنید، خیلی بهم لطف کردید. ممنون
کسی نیست ما رو یه راهنمایی کنه؟؟؟
سلام، یه راهی پیدا کردم که موج بالا رو تولید کنم، ولی نمیدونم چرا جواب آخرش رو اشتباه نشون میده.
اینم کدیه که نوشتم.
کد:
#include <mega32.h>
#include <delay.h>
#include <lcd.h>
#include <stdio.h>
#asm
.equ __lcd_port=0x15
#endasm
#define xtal 8000000
unsigned long int a=0,f2=0;
unsigned char duty=0,buffer[16];
unsigned int N=0;
int round1(float d)
{
int r = d*100;
r%=100;
if(r>50) return ((int)d + 1);
else return ((int)d);
}
int round2(float d)
{
return ((int)d + 1);
}
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
if(f2<3906)
{
TCNT0=round1(256-(8000000/(64*f2)));
}
if(f2>3906)
{
TCNT0=round1(256-(8000000/(8*f2)));
}
}
void main(void)
{
PORTB=0x00;
DDRB=0x08;
TCCR0=0x6a;
TCNT0=0;
OCR0=0;
lcd_init(16);
#asm("sei")
while (1)
{
f2=2000;// به عنوان مثال
duty=10;// به عنوان مثال
if(f2<3906)// این شرط برای اینه که برای فرکانسای مختلف از تقسیم های فرکانسی مختلف استفاده کنه که دقت کار بالا بره
{
N=64;
TCCR0=0x6b;
TCNT0=round1(256-8000000/N/f2);
OCR0=round2(((duty/100)*(256-TCNT0))+1);
}
if(f2>3906)
{
N=8;
TCCR0=0x6a;
TCNT0=round1(256-(8000000/(N*f2)));
OCR0=round2((duty*(256-TCNT0))+1);
}
lcd_clear();// اینا رو هم گذاشتم تا مقدار متغیرا رو نشون بده.
lcd_gotoxy(0,0);
sprintf(buffer,"%d",TCNT0);
lcd_puts(buffer);
lcd_gotoxy(0,1);
sprintf(buffer,"%d",OCR0);
lcd_puts(buffer);
delay_ms(1500);
lcd_clear();
lcd_gotoxy(0,0);
sprintf(buffer,"%d",f2);
lcd_puts(buffer);
lcd_gotoxy(0,1);
sprintf(buffer,"%d",duty);
lcd_puts(buffer);
delay_ms(1500);
lcd_clear();
lcd_gotoxy(0,0);
sprintf(buffer,"%d",N);
lcd_puts(buffer);
delay_ms(1500);
}
}
تو رو خدا اگه کسی چیزی بلده راهنماییم کنه، پروژه م گیر ساخت همین موجه.
سلام.
متاسفانه نمی رسم با دقت چکش کنم، اما ایده ی کارتون در کلیات درست هست. منتها وقتی فرکانس رو تغییر بدید ، دیوتی سایکل ثابت نمی مونه ، یا حداقل دقتش کم و زیاد می شه ... .
برای چک کردن محاسبات پروژه رو کوچیک تر کنید و اگر بتونید روی اسیلوسکوپ چک کنید که چه بهتر ... .
تو دستورات sprintf هم بجای %d از %u استفاده کنید درست ترهه ...
کد php:
TCNT0=round1(256-8000000/N/f2);
رو هم پرانتز و ... اش رو بذارید ...
کد php:
TCNT0=round1(256-(8000000/(N*f2)));
موفق باشید.
ممنون از لطفتون
مشکل اینجاست که اصلا فرکانس تغییر نمیکنه، یعنی در واقع ریجستر TCNT0 عملا صفر به حساب میاد. تو رو خدا یه کم وقت بذارید و تو حلش کمکم کنید. خیلی دنبالش گشتم، ولی هیچ نتیجه ای نگرفتم.
اصلا بیخیال قابل تغییر بودن هم بشیم باز جواب نمیده. کد زیر رو برای فرکانس 2KHz و دیوتی سیکل 25% نوشتم. اینم خلاصه شده کد.
کد:
[align=left]
#include <mega32.h>
#define xtal 8000000
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
TCNT0=194;
}
void main(void)
{
PORTB=0x00;
DDRB=0x08;
TCCR0=0x6b;
TCNT0=194;
OCR0=15;
TIMSK=0x01;
#asm("sei")
while(1);
}
[/align]
با اسیلوسکوپ هم چکش کردم. جوابش دقیقا مثل حالتیه که TCNT0 صفر باشه، نمیدونم اشکال کار کجاس؟
طبق روابط duty cycle=OCR0/(256-TCNT0) و Fpwm=8MHz/N(256-TCNT0) هم باید جواب بده، ولی نمیدونم چرا نمیشه؟؟
راستی ممنون راجع به نکته ای که در مورد کد lcd گفتید. فک کنم بازه اعداد بیشتری رو روی lcd نشون میده نه؟
آقا مشکل ما به لطف دوستان حل شد. آقای sharin از شما هم به خاطر کمکتون خیلی ممنونم. عیب کار این بود که OCR0 رو از صفر حساب میکردم، اما باید با مقدار TCNT0 جمع میشد؛ یعنی به جای اینکه مقدار OCR0، برابر 15 باشه، باید 194+15=209 بهش داده بشه.
راستی در مورد نکته ای که راجع به lcd گفتین، یه سوال دارم. تو دستور sprintf ، وقی از دستور d% استفاده میکنم، عددهای بیشتر از حدود 30000 اشتباه نشون داده میشن. با دستور u% که شما گفتین، بازه بیشتری درست نشون داده میشه، ولی بازم اعداد مثلا 6 رقمی رو اشتباه نشون میده. خواستم بدونم کسی از دوستان چیزی تو این زمینه نمیدونه که چطور میشه عددهای بزرگ رو روی lcd نمایش داد؟؟؟
ممنون
تو اون لینکی که گذاشته بودین رفتم، ولی راجع به دستور printf بود، نه sprintf. من میخوام مقدار یه متغیر رو روی صفحه نمایش چاپ کنم.
راستش رو بخواین زیادم از چیزایی که نوشته بود سر در نیاوردم؛ ولی همه رو امتحان کردم، متاسفانه هیچکدوم جواب نداد. بازم ممنون
اینم کدی که نوشتم:
[/align]
کد:
#include <mega32.h>
#include <delay.h>
#include <lcd.h>
#include <stdio.h>
#asm
.equ __lcd_port=0x15
#endasm
unsigned char buffer[16];
unsigned long int f1;
void main()
{
DDRC=0xff;
PORTC=0x00;
lcd_init(16);
while(1)
{
f1=99999;
lcd_clear();
lcd_gotoxy(1,0);
sprintf(buffer,"f_min=%lumHz",f1);
lcd_puts(buffer);
delay_ms(1000);
}
}
[align=left]
بازم اشتباه نشون میده.
فرقی نمی کنه ... ، %u و .. ثابت هستن.
در این مورد شما بجای sprintf از تابع ()ltoa استفاده کن ببین جواب می گیری ...