بـــه نـــام خــدا : حافظه و مدیریت حافظه میکروکنترلر
متغییرها رو به 2 دسته کلی تقسیم بندی میکنیم : 1-متغییرهای محلی 2-متغییر های سراسری
متغییرهای محلی : فقط در همان تابعی که ساخته میشود شناخته شده است .
متغییر های سراسر : در بالای همه توابع تعریف میشود و در همه توابع میتوان از ان استفاده کرد.
سعی کنید از متغییر های سراسری توی برنامه تون کمتر استفاده کنید، این متغییرها حافظه بیشتر رو اشغال میکنند. به طور مثال یه متغییر سراسری توی php حدود 140 برابر بیشتر حافظه اشغال میکند نسبت به متغییر محلی اش.
توجه : برای این مورد زیر میتویند مطلب مقابل رو بخویند : روش های ارسال متغییر به تابع در C
اگر بخواهیم مقادیری رو از یک تابع برگردونیم میتونیم از روش های زیر استفاده کنیم:
- پوینترها
- برگردوندن استراکچر (stract)
- متغییر های سراسری
این سری از توابع را برای اجرا بایست صدا بزنیم تا مقدار را به محلی که صداش زدیم برگردوند که دراین باره این توابع بحث نمیکنیم.( stract )
ولی یک سری توابع اند که در صورت فعال شدن پرچم فراخوانی میشوند و اگر بخواهیم مقداری رو از این توابع برگردونیم نمیتونیم از Return استفاده کنیم و در اینجاست که اغلب از متغییرهای سراسری استفاده میکنیم. ولی این کار رو میتونیم با پوینترها انجام دهیم به نوعی پوینترها بهترین جایگزین برای متغییر های سراسری اند.به کد زیر دقت کنید.
استفاده از متغییر سراسری :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
#include <mega8.h> #include <alcd.h> #include <stdio.h> #define xtal 1000000 unsigned char sec,min,hour; // Timer1 overflow interrupt service routine interrupt [TIM1_OVF] void timer1_ovf_isr(void) { TCNT1H=0xC2F7 >> 8; TCNT1L=0xC2F7 & 0xff; sec++; if(sec==60) {sec=0;min++;} if(min==60) {min=0;hour++;} if(hour==24) {hour=0;} } void main(void) { char buffer[16] ; // Timer/Counter 1 initialization // Clock source: System Clock // Clock value: 15.625 kHz // Input Capture on Falling Edge // Timer Period: 1s // Timer1 Overflow Interrupt: On TCCR1A=(0<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (0<<COM1B0) | (0<<WGM11) | (0<<WGM10); TCCR1B=(1<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (0<<WGM12) | (0<<CS12) | (1<<CS11) | (1<<CS10); TCNT1H=0xC2; TCNT1L=0xF7; ICR1H=0x00; ICR1L=0x00; OCR1AH=0x00; OCR1AL=0x00; OCR1BH=0x00; OCR1BL=0x00; // Timer(s)/Counter(s) Interrupt(s) initialization TIMSK=(0<<OCIE2) | (0<<TOIE2) | (0<<TICIE1) | (0<<OCIE1A) | (0<<OCIE1B) | (1<<TOIE1) | (0<<TOIE0); // Global enable interrupts #asm("sei") lcd_init(16); while (1) { if(sec==59)lcd_clear(); sprintf(buffer,"%d:%d:%d",hour,min,sec); lcd_gotoxy(0,0); lcd_puts(buffer); } } |
و اطلاعات برنامه کامپایل شده.
همون برنامه ولی با پوینتر ها :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
#include <mega8.h> #include <alcd.h> #include <stdio.h> #define xtal 1000000 // Timer1 overflow interrupt service routine interrupt [TIM1_OVF] void timer1_ovf_isr(void) { static unsigned char sec@0x60,min@0x61,hour@0x62; TCNT1H=0xC2F7 >> 8; TCNT1L=0xC2F7 & 0xff; sec++; if(sec==60) {sec=0;min++;} if(min==60) {min=0;hour++;} if(hour==24) {hour=0;} } void main(void) { char buffer[16]; unsigned char *sec,*min,*hour; sec = (unsigned char * )0x60; min = (unsigned char * )0x61; hour = (unsigned char * )0x62; // Timer/Counter 1 initialization // Clock source: System Clock // Clock value: 15.625 kHz // Input Capture on Falling Edge // Timer Period: 1 s // Timer1 Overflow Interrupt: On TCCR1A=(0<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (0<<COM1B0) | (0<<WGM11) | (0<<WGM10); TCCR1B=(1<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (0<<WGM12) | (0<<CS12) | (1<<CS11) | (1<<CS10); TCNT1H=0xC2; TCNT1L=0xF7; ICR1H=0x00; ICR1L=0x00; OCR1AH=0x00; OCR1AL=0x00; OCR1BH=0x00; OCR1BL=0x00; // Timer(s)/Counter(s) Interrupt(s) initialization TIMSK=(0<<OCIE2) | (0<<TOIE2) | (0<<TICIE1) | (0<<OCIE1A) | (0<<OCIE1B) | (1<<TOIE1) | (0<<TOIE0); // Global enable interrupts #asm("sei") lcd_init(16); while (1) { if(*sec==59)lcd_clear(); sprintf(buffer,"%d:%d:%d",*hour,*min,*sec); lcd_gotoxy(0,0); lcd_puts(buffer); } } |
اطلاعات برنامه بعد از کامپایل :
نتیجه هر دو پروژه :
توی یک پروژه ساده مثل هم اینقد نتایج با هم فرق دارد !!
برنامه یک ساعت با استفاده از پوینتر ها
عدد 0x60h از قسمت project > configure > c compiler > Advanced در بخش On-chip RAM قابل مشاهده و تنظیم است. از جدول زیرهم میتوانید محل قرار گیری داده ها را در RAM مشاهده کنید.
چون میکرو های AVR 8 بیتی هستند و char هم 8 بیت فضا اشغال میکند ادرس داده اول(sec) را 60 و 61 (min)و 62(hour) هگز قرار دادیم، در تابع main سه پوینتر ساختیم و ان ها را با ادرس های بالا مقدار دهی کردیم.
بعد از کامپایل برنامه بالا یک Warning مشاهد خواهید کرد
Warning: C:\Users\Milad-Pc\Documents\a\a.c(8): @ RAM location address is in the Data Stack area
که شما میگه محل آدرس متغییری که ایجاد کردید مالData Stack هست.
اگر به جدول ادرس های حافظه RAM نگاه کنید متوجه حافظه Heap میشوید این همان حافظه ای است که هنگام
اجرا برنامه اختصاص داده میشود و مقدار ان را خودمان میتوانیم تعیین کنیم از قسمت
project > configure > c compiler > Code Generation در قسمت RAM مقدار آن را تعیین کنیم . با این حافظه میتوان در حین کار میکرو متغییر ایجاد کرد و پس از اتمام کار با آن فضای گرفته شده توسط ان را آزاد کرد. با کد نمونه توجه کنید .
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#include <mega8.h> #define xtal 1000000 #include <stdlib.h> #include <stdio.h> #include <alcd.h> void main(void) { char *buffer_lcd ,n = 16; lcd_init(16); do buffer_lcd = (char *) malloc(sizeof(char)*n); while(*buffer_lcd!=0); sprintf(buffer_lcd,"this is array"); lcd_puts(buffer_lcd); free(buffer_lcd); } |
در این برنامه بافری که برای lcd بکار میرود را به صورت دینامیک ساخته ایم ابتدا پوینتری از نوع char ساختیم و سپس توسط تابع (void *malloc(unsigned int size به مقدار متغییر n ارایه 16 تایی ایجاد کردیم و بعد از اتمام کار مقدار حافظه گرفته شده را آزاد کردیم توسط تابع (void free(void *ptr که این توابع در کتاب خانه stdio.h تعریف شده است.
مهمان
اون پوینتر ها اصلا فرقی تو حافظه شما ایجاد نکرد. شما تو برنامه اول متغیر هاتو به صورت گلوبال تعریف کردی و بخشی از رم که مربوط به متغیر های گلوبال هست رو اشغال کردی اما تو برنامه دوم رفتی تو تابع main اون ها رو تعریف کردی و بخشی از حافظه stack رو اشغال کردی! اگه دقت هم کنی حافظه استک رو بایت بیشتر شده
مدیر سایت
تو خط 12-14 یه متغییر از نوع آرایه با اندازه مد نظر ایجاد میکردی و بعد آدرسش رو میدادی به اشاره گر بهتر نبود؟
مهمان
سلام عالی بود و خیلی حرفه ایی و ارزشمند اان شاء الله موفق و پیروز باشید