در این پست می خواهیم که یک سیگنال PWM را با AVR بخوانیم. و از آن استفاده کنیم.
همانطور که می دانید برای خواندن این یک سیگنال PWM کافیست که زمان 1 بودن سیگنال را پیدا کنیم. برای فهمیدن تغییر وضعیت سیگنال ما از وقفه ی خارجی استفاده می کنیم. در ATMEGA 8 ما از وقفه ی صفر که پایه ی چهار است، استفاده می کنیم. و برای اندازه گیری زمان هم از تایمر0 استفاده خواهیم کرد.
با استفاده از برنامه کدویژن و زبان برنامه نویسی 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 می توان مُد وقفه را تعیین کرد. به عکس زیر توجه کنید.
این رجیستر را در هر بار وقفه به مُد لبه ی بالا رونده و لبه ی پایین رونده تغییر می دهیم. تا بتوانیم زمان بین این تغییر را اندازه بگیریم.
زمان یک بودن سیگنال برای ما مهم است. برای همین باید زمان بین وقتی که، بترتیب سیگنال یک می شود تا صفر می شود را بخوانیم. از این رو خواندن متغیر شمارش زمان (countTime) را در دل IF ی قرار داده ایم، که وقتی وقفه روی مُد پایین رونده باشد داخل آن می رود.
در پایان برنامه هم که زمان یک بودن سیگنال PWM را بر روی LCD نشان می دهیم.
بسیار عالی سپاس از مطالب ارزشمندتون