ايران ويج

نسخه‌ی کامل: آموزش کار با ATMEL STUDIO و AVR-GCC
شما در حال مشاهده‌ی نسخه‌ی متنی این صفحه می‌باشید. مشاهده‌ی نسخه‌ی کامل با قالب بندی مناسب.
صفحه‌ها: 1 2 3 4
سلام اینجا یکسری آموزش های جامع و مختصر درباره این موارد می دهم
پیش فرض من این است که با خود زبان C آشنایی کامل دارید.
(ATMEL STUDIO با همون AVRSTUDIO خدمون)
پیش نیاز
ATMEL STUDIO 6
-
لینک های مفید در زمینه آموزش AVR-GCC
-توضیح کتابخانه ها و توابع موجود
______________
اینم لینک کتابخونه کامل
چیزی که هست اینه که همه رو ATMELSTUDIO دارهBiggrin بیشتر مال WINAVR هست
______________
تمامی کتابخانه های پر کاربرد رو توضیحش رو همین جا میزارم
و نکات مهم منابع بالا رو ذکر می کنم اون هارو گفتم اگه خیلی عجله دارید یا می خواید بیشتر یاد بگیرید ببینید
_____________
اصولا تنظیم ریجیستر ها کار سختی هست هم اسمشون یادمون نمی مونه هم نحوه مقدار دهیش! برای همین من توصیه می کنم CODEVISION نسخه رایگانش رو بگیرید (رایگان برای این که 1- کار مارو راه میندازه 2- اون دنیا ...)
البته خیلی هم روش حساب نکنید بعضی مواقع سوتی میده (خودم سر سرعت دو سیمه یک هفته الاف شدم تا فهمیدم اشتباه مقدار دهی کرده!)
____________
اینشاالله آشنایی با محیط نرم افزار رو اول شروع می کنم.
____________
ادامه دارد ...
نقل قول: پیش فرض من این است که با خود زبان C آشنایی کامل دارید.
دستت درد نکنه
ولی کاش قبلش این زبان c رو کاما کار میکردیم و مشکلاتمون برطرف میشد و بعد gcc رو شروع می کردیم
من که اصلا نمی دونم این gcc چیهSad
(۰۲-بهمن-۱۳۹۱, ۱۸:۰۴:۴۷)r0b0 نوشته است: [ -> ]
نقل قول: پیش فرض من این است که با خود زبان C آشنایی کامل دارید.
دستت درد نکنه
ولی کاش قبلش این زبان c رو کاما کار میکردیم و مشکلاتمون برطرف میشد و بعد gcc رو شروع می کردیم
من که اصلا نمی دونم این gcc چیهSad
GCC که همون C هست اسم کامپایلرش GCC هست.
آموزش برای خود C زیاد هست به نظرم اومد کار اضافه ای هست که دوباره آموزش بدم.
یه بار کامل نوشتم پاک شد حالم گرفته شد! خداااااااااااا!!!AngryAngryAngryConfusedSadSad

بعد از نصب برنامه و اجرای اون با صفحه ی اصلی موتجه میشید (نه بابا !)
img
خیلی شبیه برادرش visual studio هست برای همین کار باهاش رو خیلی راحت می کنه!
اولین چیزی که به چشم می خوره (نخوره من میدونم و شما بهتره بخورهBiggrin)
New Example From ASF
هست اما ASF؟!!
ASF:ATMEL SOFTWARE FRAMEWORK
اما به چه دردی می خوره؟ به همون دردی که برادرش می خوره!
یکسری توابعی اماده هستن که برنامه نویسی رو ساده تر(اینو جدی نگیریدBiggrin)
می کنن البته نه برای مگا چون چیزی نداره بیشتر برای AVR32 - ARM
خوب میریم سراغ کار خودمون
New Project
و این صفحه میاد!
img
در سمت چپ یکسری پیش فرض هایی هست که پروژه رو بر اساس اون ها بسازید که مال برد های مختلف هست که شما نداریدBiggrin
یکی از قسمت هاش اسمبلر معروف هستBiggrin
اما توی همین قسمت که می بینید 4 گزینه داره واین هنگام هست که شاخ در میارید و می گید C++ و من میگم بلهBiggrin
خوب ما همون سی خودمون رو انتخاب می کنیم و اطلاعات پروژه خودتون رو بنویسید و کلیک ...
این صفحه میاد
img
بیشتر میکرو های اتمل تشریف دارندBiggrin
میکرو ی مورد نظر رو انتخاب کنید (mega16)
در سمت چپ یکسری اطلاعات در موردش میاد حافظه و ...
سخت افزار هایی که می تونن باهاش کار کنن
دیتاشیت و ...
کلیک
و صفحه ی زیر
img
به محیط خوش آمدید (مگه الان تو کجا بودیم؟Biggrin)
اون قسمت سمت چپ برای شما جزو گروه راست هست که اگر میخواید درگ انجام بدید و بیاریدش اینجا اما این VA چی هست؟
VA:VAssistansX
این کد نویسی رو راحت می کنه یکی از قسمت هاش همین outline هست که میبینید و همه ی توابع و متغییر ها و ... رو نشون میده تا سریع به اون جا برید!
نشون دادن خطا ها و تکمیل کردن نوشته هم از کار هاش هست
برای تکمیل کردن یه کار جالبی هم میشه کرد مثلا دستور if رو بنویسید و بعدش TAB رو بزنید! آزمایش کردید منظورم رو متوجه می شید!
img
اما برای تنظیم کامپابلر برای پروژه خودتون در منوی پروژه به پروپرتیز برید و در این قسمت
img
می تونید تنظیمات رو انجام بدید شرح کامل در آینده!
اما حالا برای خالی از لطف نبودن این آموزش یه برنامه هم می نویسیم!
img
برای کسایی که C بلدن که توضیح نمیخواد!
با کلید F7 کامپایل میشه و اطلاعات کامگایلر نوشته میشه

اگه یه کمی بالا تر برید اطلاعات دیگه ای هم نوشته شده
img
فایل کامپایل شده در پوشه دیباگ ایجاد میشه جون برنامه توی این مد هست
اگه می خواید تغییرش بدید از منوی اون وسط که دیباگ زار میزنه ریلیز رو انتخاب کنید
در اخر
یه همچین چیزی از آب در میاد
img
اینو گذاشتم فقط ذوق کنید بعدا در موردش صحبت میکنیم.
این یه توضیح مختصری از محیط این برنامه بود بقیه قابلیت ها رو حین آموزش میگم در آخر هم کار با شبیه سازیش می مونه که طلبتون برای آخرین پست!
شما که میگین توابعش از کد ویژن بیشتره باز یه جا میگین کم تره حالا بیشتره یا کمتره ؟ ساده است یا پر درد سر؟
(۰۲-بهمن-۱۳۹۱, ۲۲:۵۷:۵۱)abbasalifix نوشته است: [ -> ]شما که میگین توابعش از کد ویژن بیشتره باز یه جا میگین کم تره حالا بیشتره یا کمتره ؟ ساده است یا پر درد سر؟
تعداد کتابخانه های آماده برای کار با سخت افزار های جانبی کمتر هست برای مثال برای این موارد کتابخانه ای به صورت پیش فرض نیست ولی توی اینترنت می تونید پیدا کنید ولی من این قول رو میدم هیچ مشکلی پیدا نکنید!
کار با LCD
I2C نرم افزاری
MMC/SD
1Wire
...
یکی از اولین نیاز های برنامه نویسی با C اشنایی با ریجیستر های مختلف هست
و در صورت امکان آشنایی با دستورات اسمبلی.
هر دوتای این هارو در آخر دیتاشیت کامل میکرو ها به صورت خلاصه نوشته.
احتمالا همه ی شما کار دو ریجیستر DDRX و PORTX رو میدونید ولی در اکثر موارد به دسترسی بیتی به این ها نیاز داریم!
مثلا میخوایم بیت دوم از فلان ریجیستر رو یک کنیم یا مقدارش رو بخونیم.
اینجا کلا در مورد توابع بیتی توضیح میدم.
این توابع در "AVR/SRF_Defs.h" هستند که به صورت پیش فرض فراخوانی میشند!
اولین تابع
کد:
bit_is_clear(sfr, bit)
هست این تابع در ابتدا آدرس ریجیستر را می خواهد(می توانید از نام آن ها هم استفاده کنید) مثلا (PORTC,TCNT0,0x33) و در قسمت دوم شماره بیت مورد نظر در صورت صفر بودن ان بیت مقداری نا صفر و در صورت یک بودن بیت مقدار صفر برگردانده میشود
-
تابع بعدی
کد:
bit_is_set(sfr, bit)
مانند بالایی با این تفاوت که در صورت صفر بودن بیت مقدار صفر و درصورت یک بودن آن مقداری ناصفر را باز میگرداند
-
تابع بعدی
کد:
loop_until_bit_is_set(sfr, bit)
مانند بالایی ها مقدار دهی می شود و تا یک شدن بیت مورد نظر منتظر می ماند.
-
تابع بعدی
کد:
loop_until_bit_is_clear(sfr, bit)
برعکس تابع قبلی منتظر صفر شدن بیت مورد نظر می ماند.
-
این تابع ارزش مکانی بیت در مبنی 10 را باز می گرداند.
کد:
_BV(bit)
در واقع 1 به اندازه ی مقدار داده شده به سمت چپ شیفت داده میشود.
-
اما ما برای یک یا صفر کردن ریجیستر ها نیز نیاز به توابعی داریم
برای این کار از این توابع نوشته شده (از یه بنده خدایی یاد گرفتم) استفاده کنید این هارو باید در پروژه خودتون بنویسید.
کد:
#define BIT(x) (1 << (x))
#define SETBITS(x,y) ((x) |= (y))
#define CLEARBITS(x,y) ((x) &= (~(y)))
#define SETBIT(x,y) SETBITS((x), (BIT((y))))
#define CLEARBIT(x,y) CLEARBITS((x), (BIT((y))))
#define BITSET(x,y) ((x) & (BIT(y)))
#define BITCLEAR(x,y) !BITSET((x), (y))
#define BITSSET(x,y) (((x) & (y)) == (y))
#define BITSCLEAR(x,y) (((x) & (y)) == 0)
#define BITVAL(x,y) (((x)>>(y)) & 1)
این توابع در اصل سه تابع هستند که بقیه از یکدیگر استفاده می کنند.
در واقع کار برخی از توابع قبلی رو انجام میدهند.
-
اولی BITVAL که مانند توابع قبلی اول ادرس و بعد شماره یه بیت را می گیرد و در صورت یک بودن بیت مقدار 1 و در صورت صفر بودن بیت 0 را باز میگرداند
-
SETBIT که مانند قبلی ها مقدار دهی میشود و بیت متناظر را یک می کند.
-
CLEARBIT نیز به هم چنین بیت متناظر را صفر می کند.
-
برای تغییر وضعیت یک بیت هم میتوانید این گونه عمل کنید
کد:
X^=_BV(Y)
که اگر می خواهید به صورت تابع استفاده کنید این کد رو اضافه کنید
کد:
#define TOG(x,y) (x)^_BV(y)
و مساوی پورت مورد نظر قرار دهید یعنی اینجوری استفاده کنید برای مثال
کد:
PORTC=TOG(PORTC,0)
-
برای پورت ها هم مقدار هایی شبیه PORTC0 و PORTD5 تعریف شده اند که اینها صرفا 1 که به اندازه ی عدد پورت شیفت داده شده هستند ، هستند اشتباه نگیرید.
-
خوب دیگه مرحله بعد توابع تاخیر و watch-dog
-
ادامه دارد ...
خوب برای ایجاد تاخیر دو کتابخانه جود دارد
-
(میکرو یه دستوری به نام nop داره که توی C میتونید اینجوری استفاده ازش بکنید
کد:
asm("nop")
و کارش اینه که یک کلاک رو بدون انجام هیچ کاری سپری میکنه تلاش کنید از این دستور برای ایجاد تاخییر استفاده نکنید!)
-
این دو کتابخانه عبارت اند از
کد:
<util/delay.h>
<util/delay_basic.h>
(این دقیقا چیز هایی هست که باید اینکلود کنید
اولین چیزی که باید انجام بدید تعیین سرعت Clock هست که اینجوری تعیین میشه
کد:
#define F_CPU 8000000UL
مثلا الان من کلاک 8 مگا رو تعریف کردم.
توجه کنید که قبل از فراخوانی کتابخانه این رو تعریف کرده باشید
اولیم کتابخانه
کد:
#define F_CPU 1000000UL  // 1 MHz
    #include <util/delay.h>
توی این کتابخانه این دو تابع وجود دارد
1-
کد:
void     _delay_ms (double __ms)
میزان تاخییر به میلی ثانیه توجه کنید که یک متغییر رو نمیشه به این توابه ارسال کرد! باید عدد در Flash ذخیره شده باشه
برای حفظ دقت باید اپتیمایز کردن کد رو فعال کنید
حداکثر تاخیر با دقیق حداکثر این است
کد:
262.14 ms / F_CPU in MHz
که اگه یه مقداری بیشتر به تابع بدید دقت به مرور کم میشود
و این حداکثر مقداری هست که میشه به تابع داد وبیشتر از این اورفیلو میشه
کد:
4294967.295 ms/ F_CPU
2-
کد:
void     _delay_us (double __us)
این درحد نانو ثانیه تاخیر ایجاد می کنه
حداکثر عدد برای بیشترین دقت
کد:
void     _delay_us (double __us)
و بیشترین عددی که به تابع میشه داد
کد:
4294967.295 us/ F_CPU
__________________________________
کتاب خانه ی بعدی
کد:
#include <util/delay_basic.h>
کتابخانه ی قبلی هم از همین استفاده می کنه با این تفاوت که محاسبات رو خودش انجام میده
-
1-
کد:
void _delay_loop_1     (     uint8_t      __count    )
ایجاد یک تاخیر با کانتر 8 بیتی
به تابع حداکثر 255 میشه ورودی داد
در فرکانس 1 مگ حداکثر 768 میکرو ثانیه میشه تاخیر ایجاد کرد
2-
کد:
void _delay_loop_2     (     uint16_t      __count    )
ایجاد تاخیر با کانتر 16 بیتی
به تابع حداکثر 65535 میشه داد
در فرکانس 1 مگ حداکثر تاخیر 262 میلی ثانیه
-
پیشنهاد میکنم از همون کتابخونه ی قبلی استفاده کنید که این مشکلات رو نداشته باشید.
_______________________________
استفاده از Watchdog
کد:
#include <avr/wdt.h>
این توابع داخلش هست که خوب نیازی به توضیح ندارهBiggrin
کد:
wdt_disable()
wdt_reset()
wdt_enable(value)
برای مقدار آخرین تابع که زمان تایمر رو تنظیم می کنه این مقادیر قابل قبول هست
کد:
WDTO_15MS
WDTO_30MS
WDTO_60MS
WDTO_120MS
WDTO_250MS
WDTO_500MS
WDTO_1S
WDTO_2S
WDTO_4S
WDTO_8S
از اینکه میکرو یه شما اون مقدار خاص رو پشتیبانی میکنه اطمینان حاصل کیند
___________________
همین جوری که می بینید
هنوظ به CodeVision نیاز پیدا نشدهBiggrinHappyHappy
__________________
از ماشین حساب ویندوز در حالت پروگرامر هم می تونید استفاده کنید
_________________
در ادامه کار با UART
فعال کردن Printf
و....
_
ادامه دارد ....
برای کار با UART سه راه دارید که ریجیستر هارو تنظیم کنید!
1- استفاده از کتابخانه ی خود نرم افزار
2- کدویزارد کرویژن
3- فشار به مغزBiggrin
دو روش دیگه با خودتون اولی رو من میگمBiggrin
برای این کار از کتابخانه ی "setbaud" استفاده می کنیم
برای این کار این سه خط رو اضافه کنید
کد:
#define F_CPU 8000000
#define BAUD 9600
#include <util/setbaud.h>
طبق معمول نیاز به توضیحی که نداره:d!
فقط میزان خطا رو حواستون رو جمع کنید زیاد نشه!
بعد این قسمت رو اضافه کنید تا ریجیستر ها مقدار دهی بشن
کد:
UBRRH = UBRRH_VALUE;
UBRRL = UBRRL_VALUE;
#if USE_2X
UCSRA |= (1 << U2X);
#else
UCSRA &= ~(1 << U2X);
#endif
برای وقفه و اینا دیگه باید برید سراغ دیتاشیت یا کدویزارد:d!
اما با تنظیم این ها شما باید ریجیستر "UDR" رو مقدار دهی بکنید تا نوشته بشه یا بخونید! که این چیزی نیست که شما دنبالش باشید!
اصولا از دستور PRTINTF استفاده می کنیم اما این دستور هیچ چیزی رو ارسال نمی کنه! چرا؟ چون خروجی اون تعیین نشده و باید مشخص بکنید که خروجی اون باید به کجا بره برای انی کار از این کد استفاده می کنیم
کد:
extern FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);
extern int uart_putchar(char c, FILE *stream);
و این یکی رو توی برنامه بنویسید که یک بار اجرا بشه
کد:
stdout = &mystdout;
حالا خروجی تابع printf به تابع زیر میره که باید به برنامه اضافش کنید!
کد:
extern int uart_putchar(char c, FILE *stream)
{
    if (c == '\n') uart_putchar('\r', stream);
    loop_until_bit_is_set(UCSRA, UDRE);
    UDR = c;
    return 0;
}
دقیقا منم نگرفتم که اون دو خط اولی چه کاری میکنن! به هر حال مارو به خواستمون میرسونن! شما میتونید برای کار های دیگه هم ازش استفاده کنید مثلا جای ارسال به UART توی یک رشته ذخیره کنید! کار جالبی میشه نه!
_
توابع مدیریت توان!
برای این کار این کتابخونه رو اضافه کنید!
کد:
#include <avr/sleep.h>
این کتابخونه شمال این توابع است
کد:
void     sleep_enable (void)
void     sleep_disable (void)
void     sleep_cpu (void)
ابتدا فعال میکنید بعد سی پی یو رو به اسلیپ می برید و بلافاصله بعد از بیدار شدن غیر فعال کنید تا دباره به خواب نرود!
البته اگر قبل از ان وقفه ای رو فعال نکرده باشید یا وقفه سراسری غیر فعال باشه اون وقت هست که دیگه میکرو به کما میرهBiggrin تا شما ریستش کنیدBiggrin
برخی میکرو ها این قابلیت رو دارد که قبل از به خواب رفتن brown down رو هم خاموش کنن برای این کار قبل از به خواب بردن میکرو این رو اضافه بکنید
کد:
sleep_bod_disable();
اما قبل از همه ی این ها نیاز هست مد خواب رو تعیین کنید: 1- زمستانی 2- عصرانه 3- اقما و ...
برای این کار قبل از فرا خوانی هر کدام از توابع بالا این کد رو اضافه کنید
کد:
set_sleep_mode(<mode>);
که به جای "<mode>" این ها رو می تونید بزارید
کد:
SLEEP_MODE_IDLE
SLEEP_MODE_PWR_DOWN
SLEEP_MODE_PWR_SAVE
SLEEP_MODE_ADC          
SLEEP_MODE_STANDBY      
SLEEP_MODE_EXT_STANDBY  
SLEEP_MODE_PWR_OFF
البته باید این قابلیت رو میکرو داشته باشه وگرنه کامپایلر خطا میده پس هر میکرویی همه ی حالات بالا رو نداره!
اینم یه نمونه کد
کد:
set_sleep_mode(SLEEP_MODE_ADC);
sleep_enable();
asm("sei");
sleep_cpu();
sleep_disable();
فقط یک بار که نوع اسلیپ رو مشخص کنید کافی هست مگر اینکه بخواید تغییرش بدید و نیازی نیست هر دفعه قبل از به خواب رفتن مشخصش کنید.
اگر احیانا یکی از حالاتی رو می خواستید که اون بالا من ننوشته بودم و میکرو ی شما قابلیتش رو داشت می تونید عدد مربوط به ریجیستری که اسلیپ رو مشخص می کنه رو به تابع بدید.

ادامه دارد ...
یه زنگ تفریح می خوام نکاتی در مورد برنامه نویسی با C بگم بدرد بقیه هم می خورهBiggrin
توی میکرو اگه تابع رو به این صورت تعریف کنیم
کد:
;void (*function)(void) = 0x0000
میکرو به اون آدرسی که نوشته شده پرش می کنه! مثلا با کد بالا میکرو تقریبا ریست میشه می تونید ادرس رو تغییر بدید و به بوت لودر پرش کنید و ...
____________________
اگه یه متغییری دارید که هم در توابع تغییر پیدا می کنن هم توی روتین وقفه باید اونو از نوع "volataile" تعریف کنید!
کد:
volataile int iranled=0xFFFF;
__________________
سعی کنید متغییر هایی که فقط توی یه تابع استفاده میشن رو محلی تعریف کنید تا حجم کمتری اشغال بشه اینجوری ممکن هست متغییر توی ریجیستر های عمومی یا استک قرار بگیره ولی در حالت عمومی یه آدرس بهش توی اسرم تعلق می گیره!
_________________
سعی کنید حلقه های خودتون رو به صورت کاهشی بنویسید!
چرا؟ چون در حالت افزایشی باید مدام با مقدار مشخص شده مقایسه بشه ولی در حالت کاهشی وقتی مقدار به صفر رسید فلگ Z فعال میشه!
کد:
unsigned int iranvig = 100
do
}
;PORTB ^= 0x01
;--iranvig
;(while (iranvig {
________________
بعضی وقت ها چیز پیچ می شیم چون توی بررسی تساوی به جای استفاده از "==" از "=" استفاده می کنیم حالا خر بیار باقالی بار کن! تو هزار خط کد مشکل رو پیدا کن!
________________
یادتون باشه که مقداری که تابع بر میگردونه یه متغییر محلی نباشه چون در این صورت مقدار پاک میشه و یه چیز بی خودی برگشت داده میشه!
اگه محلی بود استتیک باشه که مقدار از بین نره!
_______________
وقتی اشاره گر تعریف می کنید
کد:
int* p, q, r;
الان فقط اولی اشاره گر هست اگه خواستید همه اشاره گر باشن باید این جوری بنویسید!
کد:
int *p, *q, *r;
______________

ادامه ندارد ...Biggrin
حافظی EEPROM که در این پست قصد استفاده از آن را داریم یکی از قسمت هایی است که نسبت به کدویژن دارای پیچیدگی بیشتری است!
___________
ابتدا فایل مربوط به این حافظه را به برنامه اضافه می کنیم
کد:
#include <avr/eeprom.h>
یه ذره توابع موجود و اینا زیاد هست برای همین تو این لینک می تونید کامل ببینید ولی من اون هایی که نیاز دارم رو توضیح میدم.
اما قبل از هر چیز یه سری متغییر استفاده شده اند که لازم هست توضیح بدم اون هارو!
زیاد پیش میاد که توی برنامه هایی که می بینید از متغییر هایی از نوع "uint8_t" و اینا استفاده شده باشند!
این ها فرقی با قبلی ها ندارن ولی برای اینکه هر کامپایلری بتونه با برنامه کار کنه از این ها استفاده می کنن
توی این فایل که باید به برنامه اضافه کنید
کد:
#include <stdint.h>
لیست کاملی از این ها اضافه میشه و برای مثال توی C ما از "unsigned char" استفاده می کنیم پس "uint8_t" به اون ترجمه می شه ممکن هست فلان کامپایلر "un ch" باشه پس "uint8_t" به اون تبدیل میشه!
کلا این ها توی این فایل سرامد تعریف شدن!
کد:
Integer types having exactly the specified width
typedef signed char
int8_t
typedef unsigned char
uint8_t
typedef signed int
int16_t
typedef unsigned int
uint16_t
typedef signed long int
int32_t
typedef unsigned long int
uint32_t
typedef signed long long int
int64_t
typedef unsigned long long int
uint64_t
چیز های دیگه ای هم توی این فایل هست که فعلا زیاد کاری باهاشون نداریم ولی توی این لینک می تونید ببینید
اولین قدم می خوایم از آدرس 60 حافظه یه داده ای رو بخونیم!
کد:
# include <avr / eeprom .h>
void main ( void )
{
uint8_t ByteOfData ;
ByteOfData = eeprom_read_byte (( uint8_t *) 60) ;
}
برای خوندن دو بایت از حافظه یا به عبارتی متغییر int این گونه عمل می کنیم
کد:
uint16_t WordOfData ;
WordOfData = eeprom_read_word (( uint16_t *) 46) ;
این دستور از 46 و 47 داده رو می خونه و توی متغییر ذخیره می کنه
برای متغییر های بزرگ از
کد:
eeprom_read_dword()
و برای اعداد اعشاری از
کد:
eeprom_read_float()
استفاده می کنیم
برای نوشتن یک بایت در حافظه این گونه عمل می کنیم
کد:
uint8_t ByteOfData ;
ByteOfData = 0 x12 ;
eeprom_update_byte (( uint8_t *) 46, ByteOfData );
حالا متغییر ما رو توی قسمت 46 حافظه ذخیره کرد.
و همانطوری که انتظار دارید برای متغییر های 2 بایتی از
کد:
uint16_t WordOfData ;
WordOfData = 0 x1232 ;
eeprom_update_word (( uint16_t *) 46, WordOfData );
و دو باره برای متغییر های 4 بایتی از
کد:
eeprom_update_dword()
و اعشاری ها
کد:
eeprom_update_float()
حالا ما می تونیم دونه دونه بنویسیم یا بخونیم ولی نیاز هست گاهی که چند تا رو بخونیم مثلا ارایه ها یا یک رشته متنی که ذخیره شده!
برای این کار از این تابع استفاده می کنیم
کد:
void eeprom_read_block ( void * pointer_ram , const void * pointer_eeprom , size_t n)
شاید تعجب کنید که هیچ مقداری رو بر نمی گردونه !
این مقدار در متغییری که ادرسش رو به عنوان اولین ورودی به تابع دادید ذخیره میشه!
برای مثال ما از این برای خواندن 10 بایت پشت سر هم از ادرس 12 رو می بینیم
کد:
uint8_t StringOfData [10];
eeprom_read_block (( void *) StringOfData , ( const void *) 12, 10) ;
حالا شاید از من بپرسید این void این وسط چه فایده ای داره؟!
در جواب می گم در مثال های قبل با اندازه ما مثلا یک متغییر دو بایتی رو خوندیم که ممکن بود که علامت دار باشد یا نباشد و نوع آن را مشخص می کردیم در واقع برای تابع اهمیت داشت که چه مقداری رو می خواند!
اما گاهی ما نمی دانیم که داده ای که درحال خواندن آن هستیم چه نوع داده ای است! شاید هم اصلا مهم نباشد! برای همین از void استفاده می کنیم با این کار تابع فقط مغدار را می خواند و دیگر کاری به نوع داده ی خوانده شده (متن - اعشاری - صحیح - منفی و...) ندارد و عین آن را در خروجی ظاهر می کند در مثال بالا 10 بایت پشت سر هم خوانده شده و در 10 عضو ارایه نوشته می شود.
برای نوشتن در حافظه هم این گونه عمل میشود
کد:
uint8_t StringOfData [10] = " TEST ";
eeprom_update_block (( const void *) StringOfData , ( void *) 12, 10);
اولین ورودی از کلمه ی const استفاده شده است چون دیگر نیازی نیست که تغییری در آن در تابع ایجاد شود و فقط قرار است مقدار آن خوانده شود.
حال از خانه 12 به صورت متوالی برای 10 بایت در حافظه نوشته میشود که 5 تای آن مقداری که در متغییر ما موجود است نوشته میشود و بقیه مقدار 0 می گیرند
_________
حالا ما کار با این حافظه رو یاد گرفتیم ولی حتما این چیزی نیست که ما بخوایم چون وقتی کمی تعداد متغییر ها زیاد میشن دیگه به خاطر سپردن آدرس ها کار ما نیست برای همین نیاز میشه که مثل بقیه متغییر ها ، متغییری برای حافظه تعیین بکنیم تا کار را برای ما ساده تر بکند!
برای این کار مانند تعریف متغییر ها عمل می کنیم با این تفاوت که "EEMEM" را به قبل آن ها اضافه می کنیم که به کامپایلر می گوید متغییر ها در حافظه EEPROM تعریف شوند
برای مثال
کد:
uint8_t EEMEM NonVolatileChar ;
uint16_t EEMEM NonVolatileInt ;
uint8_t EEMEM NonVolatileString [10];
اما با این حال این به این معنی نیست که مانند متغییر های معمولی به طور مستقیم به آن ها دسترسی داشته باشیم! برای مثال این کد کار نمی کند!
کد:
uint8_t EEMEM NonVolatileChar ;
uint16_t EEMEM NonVolatileInt ;
uint8_t EEMEM NonVolatileString [10];
int main ( void )
{
uint8_t SRAMchar ;
SRAMchar = NonVolatileChar ;
}
این ها صرفا یک ادرس هستند برای کار با ان ها باید مثل قبل عمل کنید
کد:
# include <avr / eeprom .h>
uint8_t EEMEM NonVolatileChar ;
uint16_t EEMEM NonVolatileInt ;
uint8_t EEMEM NonVolatileString [10];
int main ( void )
{
uint8_t SRAMchar ;
uint16_t SRAMint ;
uint8_t SRAMstring [10];
SRAMchar = eeprom_read_byte (& NonVolatileChar );
SRAMint = eeprom_read_word (& NonVolatileInt );
eeprom_read_block (( void *) SRAMstring , ( const void *) NonVolatileString , 10);
}
_________
کلا کامپایلر سه خروجی کامپایل شده به شما میده فایل هگز - فایل مربوط به EEPROM با نام EEP و ELF
در ELF هم اطلاعات مربوط به قسمت فلش هم EEPROM هم اطلاعات فیوزبیت ها ذخیره می شوند
اما در کل شاید ما بخواهیم مقدار پیش فرضی به متغییر خود بدهیم که در این صورت لازم است ما ان را پروگرام کنیم تا برای بار اول داخل EEPROM نوشته شود!
برای این کار کافی است که هنگام تعریف مقداری به آن نسبت دهیم!
کد:
uint8_t EEMEM SomeVariable = 12;
تغییر رو می تونید داخل فایل خروجی مربوط به حافظه مشاهده کنید
دقت کنید که پس از پروگرام کردن اگر مقدار در برنامه تغییر کرد با شروع مجدد میکرو این مقدار ها برای بار جدیدی نوشته نمی شوند و مقدار های قبلی خود را می گیرند!
____________
نمی دونم شاید ادامه داشته باشد! شاید:d

این فایل فشرده هم مجموعه ای از چند آموزش است به زبان شرین انگلیسی حال کردید بخونید!
کد:
EEPROM.pdf
Interrupts.pdf
InterruptUSART.pdf
ManagingLargeProjects.pdf
Progmem.pdf
ProgrammingMethods.pdf
Timers.pdf
USART.pdf
عجله هم نداشتید همه رو خودم هم میگم
صفحه‌ها: 1 2 3 4