خواندن سیگنال PWM با AVR

در این پست می خواهیم که یک سیگنال PWM را با AVR بخوانیم. و از آن استفاده کنیم.

همانطور که می دانید برای خواندن این یک سیگنال PWM کافیست که زمان 1 بودن سیگنال را پیدا کنیم. برای فهمیدن تغییر وضعیت سیگنال ما از وقفه ی خارجی استفاده می کنیم. در ATMEGA 8 ما از وقفه ی صفر که پایه ی چهار است، استفاده می کنیم.  و برای اندازه گیری زمان هم از تایمر0 استفاده خواهیم کرد.

Use Interrupt For Reading PWM

Use Interrupt For Reading PWM

با استفاده از برنامه کدویژن و زبان برنامه نویسی C این کار را انجام خواهیم داد. در ابتدا وقفه ی خارجی را، برای میکرویی که می خواهیم از آن استفاده کنیم، فعال میکنیم. ما در اینجا از ATMEGA8 استفاده کرده ایم. در هنگام فعال کردن وقفه، آن را برای لبه ی بالا رونده تنظیم می کنیم. که با یک شدن سیگنال به ما وقفه دهد.

تایمر را هم فعال می کنیم و آن را روی هر مقداری که می خواهیم قرار می دهیم.

LCD را هم برای نمایش طول موج PWM برنامه ریزی می کنیم.

در ادامه برنامه را برای شما قرار می دهم تا با هم بررسی کنیم.

#include <mega8.h>
#include <alcd.h>
#include <delay.h>
#include <stdio.h>
// Declare your global variables here
char st[20];
unsigned long int countTime;
unsigned long int showTime;

// External Interrupt 0 service routine
interrupt [EXT_INT0] void ext_int0_isr(void)
{
// Place your code here
if (MCUCR==2)
{
 MCUCR=(0<<ISC11) | (0<<ISC10) | (1<<ISC01) | (1<<ISC00);
 showTime=countTime; 
}
else
{
 MCUCR=(0<<ISC11) | (0<<ISC10) | (1<<ISC01) | (0<<ISC00);
}
countTime=0; 
}

// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
// Reinitialize Timer 0 value
TCNT0=0x38;
// Place your code here
countTime++;
}

void main(void)
{
// Declare your local variables here

DDRD=(0<<DDD7) | (0<<DDD6) | (0<<DDD5) | (0<<DDD4) | (0<<DDD3) | (0<<DDD2) | (0<<DDD1) | (0<<DDD0);
// State: Bit7=T Bit6=T Bit5=T Bit4=T Bit3=T Bit2=P Bit1=T Bit0=T 
PORTD=(0<<PORTD7) | (0<<PORTD6) | (0<<PORTD5) | (0<<PORTD4) | (0<<PORTD3) | (1<<PORTD2) | (0<<PORTD1) | (0<<PORTD0);

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 8000.000 kHz
TCCR0=(0<<CS02) | (0<<CS01) | (1<<CS00);
TCNT0=0x38;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=(0<<OCIE2) | (0<<TOIE2) | (0<<TICIE1) | (0<<OCIE1A) | (0<<OCIE1B) | (0<<TOIE1) | (1<<TOIE0);

// External Interrupt(s) initialization
// INT0: On
// INT0 Mode: Falling Edge
// INT1: Off
GICR|=(0<<INT1) | (1<<INT0);
MCUCR=(0<<ISC11) | (0<<ISC10) | (1<<ISC01) | (1<<ISC00);
GIFR=(0<<INTF1) | (1<<INTF0);

lcd_init(16);

// Global enable interrupts
#asm("sei")

while (1)
      {
      lcd_clear();
      sprintf(st,"Flow = %d",showTime);                         // زمان را بعد از تبدیل به استیرینگ نشان می دهد
      lcd_gotoxy(0,0);
      lcd_puts(st);
      delay_ms(100);
      }
}

 

در ابتدا کتابخانه های لازم را فرا خوانی می کنیم. بعد از آن متغییر هایی را که لازم داریم تعریف می کنیم.

در داخل تابع مربوط به وقفه تایمر متغیر ما افزایش پیدا می کند. به این صورت ما می توانیم زمان را شمارش کنیم.

در داخل تابع مربوط به وقفه ی خارجی، ما این متغیر را برای نمایش بر می داریم. و آن را صفر می کنیم تا دوباره بشمارد.

همان طور که می دانید با تغییر بیت های رجیستر MCUCR می توان مُد وقفه را تعیین کرد. به عکس زیر توجه کنید.

 

Register EX Interrupt

Register EX Interrupt

این رجیستر را در هر بار وقفه به مُد لبه ی بالا رونده و لبه ی پایین رونده تغییر می دهیم. تا بتوانیم زمان بین این تغییر را اندازه بگیریم.

زمان یک بودن سیگنال برای ما مهم است. برای همین باید زمان بین وقتی که،  بترتیب سیگنال یک می شود تا صفر می شود را بخوانیم. از این رو خواندن متغیر شمارش زمان (countTime) را در دل IF ی قرار داده ایم، که وقتی وقفه روی مُد پایین رونده باشد داخل آن می رود.

در پایان برنامه هم که زمان یک بودن سیگنال PWM را بر روی LCD نشان می دهیم.

 

دیدگاه ها :

من بات نیستم

  1. TajhizKala Co. گفت:

    بسیار عالی سپاس از مطالب ارزشمندتون

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *