اطلاعیه

Collapse
No announcement yet.

[آموزش] آموزش کامپایلر CCS از صفر

Collapse
این موضوع برجسته شده است.
X
X
 
  • فیلتر
  • زمان
  • Show
Clear All
new posts

    [آموزش] آموزش کامپایلر CCS از صفر

    با سلام به همه ی دوستان
    توی این تاپیک قصد داریم آموزش کاربردی کامپایلر CCS که به زبان C و یکی از بهترین کامپایلر ها برای میکرو کنترل PIC هستش رو از صفر آغاز کنیم و اون رو تا جایی که علم و زمان اجازه بده ادامه بدیم.
    در بینا بین صحبت ها ممکن است قسمتی هم به آموزش سطحی میکرو کنترل و حتی آموزش سطحی نرم افزارهایی مثل پروتئوس که در آموزش مبحث اصلی به ما کمک میکنند انجام گیرد.

    سعی میشه برنامه ها با فایل شبیه سازی شده در پروتئوس ارائه بشه آموزش راحت تر باشه.

    لطفا دوستان نظرات خودشون رو بیان و اشتباهات بنده رو گوشزد کنند.

    کامپایلر CCS رو میتونید از آدرس زیر دانلود کنید که روش نصب رو هم توضیح دادم




    اضافه شده در تاریخ :
    خب اول باید نرم افزار ccs رو تهیه و نصب کنید. برنامه ccs رو که نصب کردید باید یه پروژه ایجاد کنید.برای این کار از سربرگ Project گزینه Create رو انتخاب کنید. اسم پروژه رو تایپ کنید و ok رو بزنید تا پروژه شما ایجاد بشه. حالا بریم سراغ کد نویسی.
    ساده ترین برنامه ای که باهاش میشه شروع به آموزش یک کامپایلر کرد برنامه led چشمک زن هستش.
    میخوایم توی اولین قسمت آموزش این برنامه رو بنویسیم :nerd:

    اولین خطی که توی هر کامپایلر و هر برنامه ای وجود داره دستور مربوط به معرفی میکرو کنترل هستش. پس قبل از هرچیزی باید میکرو رو معرفی کنیم. اینکار رو با دستور زیر انجام میدیم
    کد:
    #include <نوع میکرو.h>
    مثلا اگه بخوایم میکروکنترل 16F877A رو معرفی کنیم به شکل زیر این کار رو انجام میدیم
    کد:
    #include <16F877a.h>
    در خط بعدی باید مقدار کریستال رو تعیین کنیم. که این کار رو با دستور زیر انجام میدیم.
    کد:
    #use delay(xtal=20Mhz)
    در دستور بالا مقدار کریستال 20 مگا هرتز معرفی شده است.
    دقت کنید که این فرکانس کرستال خارجی است و و برای بدست آوردن فرکانس کاری میکرو باید اون رو تقسیم بر 4 کنیم پس سرعت ( فرکانس کاری میکرو) 5 مگاهرتز است.

    پس از این باید وارد تابع اصلی برنامه شد تا بتونیم عمل چشمک زدن رو انجام بدیم.
    برای روشن و خاموش کردن یک LED توسط پورت میکرو نیاز است تا بتونیم یک پایه از میکرو رو صفر و یک کنیم.
    برای 1 کردن هر پایه از میکرو از دستور زیر استفاده میکنیم:
    کد:
    output_high(pin_X);
    برای 0 کردن هر پایه از میکرو از دستور زیر استفاده میکنیم:
    کد:
    output_low(pin_X);
    که X میتونه هر یک از پین های میکروکنترل مورد استفاده شما باشه که قابلیت ورودی و خروجی کردن رو داره.

    مثلا دستور زیر پایه b5 رو از پورت b یک میکنه.
    کد:
    output_high(pin_b5);
    دقت کنید که دو دستور بالا ، خود هم عمل خروجی کردن پایه و هم 0 یا 1 کردن پایه را انجام میده.

    تنها کار دیگه ای که در این برنامه باید بکنیم اینه که بتونیم تاخیر در برنامه ایجاد کنیم تا بشه به مدت زمان دلخواه LED رو روشن یا خاموش نگه داشت.
    ایجا تاخیر در برنامه رو با دستورات زیر انجام میدیم.
    کد:
    delay_ms(x);
    کد:
    delay_us(x);
    دستور اول به اندازه x میلی ثانیه تاخیر ایجاد میکند و دستور دوم به اندازه x میکروثانیه.

    خب حالا بریم سراغ برنامه کامل
    کد:
    #include <16F877a.h>
    #use delay(xtal=4Mhz)
    
    void main()
    {
    
     while(true)
     {
     output_high(pin_b5);
    
     delay_ms(200);
    
     output_low(pin_b5);
    
     delay_ms(200);
     }
    
    }
    نکته مهم:
    در کامپایلر ccs حلقه بی نهایت باید به شکل (while(true نوشته شود نه (while(1

    بعد از نوشتن برنامه برای کامپایل اون از سربرگ Compile گزینه Compile رو انتخاب کنید تا برنامه کامپایل بشه و کد هگز (کدی که باید روی میکرو بریزید) تولید بشه. وقتی اینکار رو انجام میدید خطاهای دستوری رو هم بهتون نشون میده.

    بعد در نرم افزار پروتئوس فایل هگز رو روی میکرو میریزید و دکمه play رو میزنید تا برنامه اجرا بشه( اگه کسی توی این قسمت مشکل داره بگه تا یه آ�وزسی هم در این مورد بذارم)



    این هم فایل برنامه و فایل شبیه سازی شده در پروتئوس:
    جدیدترین ویرایش توسط شاهرخ مستقیمی; ۱۸:۴۷ ۱۳۹۵/۰۵/۱۷.
    AYRIC

    #2
    پاسخ : آموزش کامپایلر CCS از صفر

    در تکمیل فرمایشات دوست عزیزمون، میشه از این دستور هم استفاده کرد:

    کد:
    output_toggle(PIN_B5);
    که مشابه همون علامت تعجب ( ! ) برای Not کردن خروجی هست.

    راستی این عکس بالایی از محیط پروتئوس واسه ورژن چنده؟

    دیدگاه


      #3
      پاسخ : آموزش کامپایلر CCS از صفر

      نوشته اصلی توسط شاهرخ
      راستی این عکس بالایی از محیط پروتئوس واسه ورژن چنده؟
      ورژن 7.8 هستش خودم آبیش کردم :mrgreen:
      AYRIC

      دیدگاه


        #4
        پاسخ : آموزش کامپایلر CCS از صفر

        خب توی آموزش قبلی تعریف کردن میکرو و کریستال و خروجی کردن یک پایه از میکرو و 0 و 1 کردن اون رو یاد گرفتیم.
        حالا میخوایم نحوه ی ورودی کردن و خوندن مقدار پورت ( 0 یا 1 بودن ) رو یاد بگیریم.
        برای ورودی کردن و خوندن مقدار یه پایه از میکرو از دستور زیر استفاده میکنیم

        input(pin_X)

        که X اسم پایه ای هستش که شما میخواید مقدارش رو بخونید

        حال باید نحوه تعریف متغیر رو یاد بگیریم چون از اینجا به بعد با متغییر کار داریم.
        دو نمونه از متغیر های عددی رو اینجا میگم تا بعدا در صورت نیاز ازشون استفاده کنیم.
        اولین نوع Integer است که اعداد صحیح را اختیار میکنند و با ظرفیت های مختلف مورد استفاده قرار میگرند:
        1- int1 که فضایی معادل 1 بیت را اشغال میکند و تنها دو مقدار 0 و 1 را میتواند اختیار کند
        2- int8 که فضایی معادل 8 بیت را اشغال میکند و مقادیر از 0 تا 255 را میتواند اختیار کند
        3- int16 که فضایی معادل 16 بیت را اشغال میکند و مقادیر از 0 تا 65536 را میتواند اختیار کند
        3- int32 که فضایی معادل 16 بیت را اشغال میکند و مقادیر از 0 تا 4294967295 را میتواند اختیار کند
        در کامپایلر ccs با تعریف کردن متغیر های بالا به صورت دیفالت Unsigned ( بدون علامت)در نظر گرفته میشوند و اگر میخواهی مقادیر منفی را در این متغیرها ذخیره کنید باید عبارت Signed را قبل از آنها بنویسید. به صورت زیر
        1- Signed int8 که مقادیری از 128- تا 127+ میتواند اختیار کند.
        2- Signed int16 که مقادیر از 32768- تا 32767+ را میتواند اختیار کند
        3- Signed int32 که مقادیر از 2147483648- تا 2147483647+ را میتواند اختیار کند

        دومین نوع هم متغیر float هستش که اعداد اعشاری رو اختیار میکنه

        حالا اگر بخواهیم یک متغیر در برنامه تعریف کنیم باید نوع متغیر مورد نظرمون رو بنویسیم و جلوی اون اسمی که برای متغییر میخواهیم رو بنویسیم. مثلا:
        int8 x=0;

        متغیر x از نوع 8 بیتی و بدون علامت تعریف شده است
        signed int16 x=0,y=0;

        متغیر x و y نوع 16 بیتی و علامت دار تعریف شده است
        float z=2.36;

        متغیر z از نوع اعشاری تعریف شده و مقدار اولیه ان 2.36 در نظر گرفته شده

        این هم یک نمونه کد از دو مبحث بالا
        int1 x=0;
        float z=2.36;

        void main()
        {

        while(true)
        {

        if(input(pin_b1)==1) z+=0.1;

        else x=input(pin_b3);
        }
        }

        در نمونه بالا گفته شده اگر مقدار پایه ی b1 برابر 1 بود به متغیر z مقدار 0.1 رو اضافه کن و اگر نه ( مقدار پایه ی b1 برابر 0 بود) مقدار پایه b3 رو در متغییر x بریز

        انشاالله در قسمت بعدی نحوه راه اندازی pwm رو آموزش میدیم.
        جدیدترین ویرایش توسط شاهرخ مستقیمی; ۱۷:۰۱ ۱۳۹۵/۰۳/۲۰.
        AYRIC

        دیدگاه


          #5
          پاسخ : آموزش کامپایلر CCS از صفر

          خب قرار شد در این قسمت نحوه راه اندازی pwm رو توضیح بدم

          دو راه برای راه اندازی pwm در کامپایلر ccs وجود داره یکی استفاده از فرمول های موجود برای بدست آوردن فرکانس و پریود تا اونها رو در دستورات کانفیگ pwm قرار بدیم که برای این روش میتونید به این تاپیک مراجعه کنید:
          http://www.eca.ir/forum2/index.php?topic=82583.msg503696#new
          توی تاپیک بالا دوست عزیزمون محمد حسین فایلی رو قرار داده که توضیحات خوبی درش ارائه شده.
          حتی اگر اطلاعاتی در مورد pwm ندارید میتونید از فایلی که توی این تاپیک قرار داده شده استفاده کنید

          راه دیگه برای راه اندازی pwm در کامپایلر CCS استفاده از WIZARD هستش که شما فرکانس دلخواهتون رو به اون میدید و اون دستورات کانفیگ PWM رو برای شما مینویسه. که در ادامه مطلب این روش رو آموزش میدیم

          برای اینکار در محیط کامپایلر وارد NEW و از اونجا گزینه Project Wizard را بزنید


          بعد از ذخیره فایل پنجره زیر باز میشه


          جلوی عبارت device میکرو کنترل خودتون رو انتخواب میکنید (البته این ویزارد برای میکرو های 8 بیتی هستش) که در اینجا 16f877a هستش
          و جلوی عبارت ocillator type نوع اسیلاتور رو مشخص میکنید که در اینجا چون از کریستال خارجی استفاده شده گزینه کریستال رو انتخواب میکنیم

          حالا از سربرگ های سمت چپ صفحه گزینه ccp & comparator رو انتخواب کنید( مثل عکس زیر)
          همچنین گزینه pwm رو انتخواب کنید تا تنظیمات pwm ظاهر شود
          حال در قسمت set pwm frequency فرکانس دلخواهتان رو انتخواب کنید (البته این مقدار نباید از 1220.7 هرتز کمتر و از 5mhz بیشتر باشه). که بنده فرکانس 50khz رو انتخواب کردم
          و قسمت duty cycle هم که مشخصه duty cycle مورد نظرتون رو انتخواب کنید و چون دیوتی سایکل از 0 تا 100 درصد است مقداری که میدید نمیتواند خارج از این بازه باشه. در اینجا من 100 رو انتخواب کردم تا حداکثر عددی که میتونم به دستور دیوتی سایکل بدم مشخص بشه


          بعد از این کارها روی کلید create project کلیک کنید تا دستورات کانفیگ نمایش داده بشن. همانند عکس زیر:


          خط 5 دستور کانفیگ timer2 که مخصوص pwm هستش رو کانفیگ میکنه و خط 7 هم کانال ccp رو در حالت pwm قرار میدهد
          خط 8 هم همان خطی است که در طول برنامه ممکن است باهاش کار داشته باشید.این دستور همان دستوری است که دیوتی سایکل pwm خروجی رو مشخص میکنه. همانطور که میبینید (عکس بالا) در حال حاضر عدد 397 را گرفته. این عددی است که ویزارد داده و ما در ویزارد درصد دیوتی سایکل رو 100 داده بودیم پس این مقدار 397 حداکثر مقداری است که دستور set_pwm1_dut میتواند بپذیرد. پس شما در طول برنامه میتوانید عددی بین 0 تا 397 رو در این دستور قرار بدید و دیوتی سایکل pwm خودتون رو مشخص کنید.

          حالا یه برنامه کامل برای دو pwm1 و pwm2 مینویسیم

          [code=c]#include <16f877a.h>
          #use delay(xtal=20Mhz)
          #fuses HS,NOWDT

          #define sw_1 input(pin_b0)
          #define sw_2 input(pin_b1)

          int16 i=0,j=0;

          void main()
          {
          setup_timer_2(T2_DIV_BY_1,99,1); //20.0 us overflow, 20.0 us interrupt

          setup_ccp1(CCP_PWM);

          setup_ccp2(CCP_PWM);

          while(TRUE)
          {
          set_pwm2_duty((int16)198);

          if( (sw_1) && (i<397) ) i++;

          if( (sw_2) && (i!=0) ) i--;

          while( (sw_1==1) && (sw_2==1) ) {}

          set_pwm1_duty((int16)i);

          set_pwm2_duty((int16)j);

          }
          }[/code]

          توی این برنامه کانال ccp1 و کانال ccp2 بر روی pwm با فرکانس 50 کیلو هرتز تنظیم شده اند.

          به کانال 2 دیوتی سایکل ثابت 50 درصد (198 نصف 397 است) داده شده است.

          اگر کلید متصل به پین b0 را فشار دهید یک واحد به i اضافه میشود و اگر کلید متصل به پین b1 رو فشار دهید یه واحد از i کم میشود. سپس در یک while منتظر میماند ( اگر ای while نباشد بخاطر سرعت زیاد میکرو کنترل با یکم فشار دادن کلید عدد به سرعت کم و زیاد میشه) این while را گذاشتم تا برای هر واحد اضافه یا کم کردن i مجبور باشیم یک بار کلید رو فشار بدیم

          و در نهایت مقدار i در دستور دیوتی سایکل pwm 1 قرار میگیرد

          این هم فایل پروتئوس و کد c مربوط به برنامه بالا
          http://s2.picofile.com/file/7917913117/pwm.rar.html
          AYRIC

          دیدگاه


            #6
            پاسخ : آموزش کامپایلر CCS از صفر

            جهت اطلاع از اپدیت شدن تاپیک

            دیدگاه


              #7
              پاسخ : آموزش کامپایلر CCS از صفر

              سلام
              ببخشید یه مدت افتاد توی کارای یه مسابقه و کارای دانشگاه نتونستم پست جدید بذارم

              خب توی این پست میخوام کار با LCD کارکتری رو آموزش بدم.
              نمایشگرهای کارکتری قادر به نمایش حروف و اعداد هستند.
              کامپایلر ccs دو کتابخانه با نام های LCD.C و LCD420.C داره که اولی برای LCD های 16*2 و کوچکتره و دومی برای LCD های 20*4 و کوچکتر هستش.

              این LCD ها سه تا پایه با نام های RS و RW و ENABLE دارند که پایه های کنترلی هستند. و 8 پایه دیگر که 4 تای آن (D0/D1/D2/D3) برای خواندن از روی LCD و 4 تای دیگر (D4/D5/D6/D7 که به پایه های خط دیتای نمایشگر معروفند) برای نوشتن بر روی LCD هستند.

              ما میخواهیم فقط روی LCD اطلاعاتی رو نمایش بدیم پس با 4 پایه دوم کار داریم.
              اگه با کتابخانه اولی کار میکنید میتونید این 7 پایه رو (3 پایه کنترلی و 4 پایه خط دیتای نمایشگر) به هر پایه از میکرو که قابلیت IO داشته باشه وصل کنید. چون در این کتابخانه دستوراتی هستند که شما میتونید مشخص کنید هر پایه رو به کدام پایه از مکرو وصل کرده اید.

              کل پایه های LCD به ترتیب به صورت زیر هستند:


              کنتراست صفحه روشنایی کارکتر ها هستش که با یه پتانسیومتر قابلیت کم و زیاد شدن داره. طریقه اتصال توی فایل شماتیک که در پیوست قرار داده شده مشخصه. وقتی LCD بسته شد و برنامه رو نوشتید باید این پتانسیومتر رو اونقدر بچرخونید تا وضوح نوشته به حداکثر خودش برسه.

              بعد از اینکه LCD رو وصل کردید باید بریم سراغ برنامه :nerd:
              بعد از دستورات تعریف میکرو و کریستال باید پایه های LCD رو مشخص کنیم. به صورت زیر:

              [code=c]
              #define LCD_RS_PIN PIN_b0
              #define LCD_RW_PIN PIN_b1
              #define LCD_ENABLE_PIN PIN_b2
              #define LCD_DATA4 PIN_b3
              #define LCD_DATA5 PIN_b4
              #define LCD_DATA6 PIN_b5
              #define LCD_DATA7 PIN_b6
              [/code]

              پایه های RS و RW و ENABLE به ترتیب به پایه های b0 و b1 و b2 متصل شدند و پایه های دیتا (D4 تا D7) به ترتیب به پایه های b3 تا b6 متصل شده اند. شما میتونید بر حسب نیاز پایه هارو تغییر بدید.

              و در خط بعدی باید کتابخانه LCD.C رو صدا بزنید. به این صورت:
              [code=c]#include <LCD.c>[/code]

              حالا برای کار با LCD و نوشتن بر روی آن باید حتما دستور زیر نوشته شود:
              [code=c] lcd_init();[/code]
              با نوشتن این دستور LCD پاک شده و آماده به کار میشود.

              یکی از توابعی که در این کتابخانه تعریف شده تابع lcd_putc هستش. که به صورت زیر تعریف شده:
              [code=c]Void lcd_putc(char c); [/code]

              به این معنی که این تابع یک کارکتر را به عنوان آرگومان گرفته و هیچ مقداری را بر نمیگرداند.
              مثلا دستور زیر حرف Q را بر روی LCD مینویسد:
              [code=c]Lcd_putc(“Q”[/code]

              توسط دستور printf نیز میتوانیم این کار رو انجام بدیم. به صورت زیر:
              [code=c]Printf(lcd_putc,”#test#”[/code]
              که دستور بالا رشته ی #test# رو بر روی LCD نمایش میده.

              با دستور printf عدد هم میتونید نشون بدید. به صورت زیر
              [code=c]
              Unsigned int8 i=80;

              Printf(lcd_putc,”\f\variable is %u”,i);
              [/code]
              دستور بالا نوشته روبرو رو چاپ میکنه: variable is 80
              که قسمت variable is که قبل از u% نوشته شده به عنوان رشته هستش و i به عنوان یک عدد متغیر هستش که هر مقداری رو در برنامه بگیره روی lcd چاپ میشه که اینجا 80 هستش
              بخش \f\ باعث پاک شدن LCD ( نه رفلش شدن آن) میشه. شما اگه نمیخواید LCD پاک بشه میتونید این رو ننویسید

              دومین تابع در این کتابخانه تابع lcd_gotoxy هستش. به صورت زیر:
              [code=c]Void lcd_gotoxy(BYTE x, BYTE y);[/code]

              که x شماره ستون و y شماره سطر هستش. و خانه ای که از سمت چپ در اولین ستون و در سطر بالا هستش دارای شماره ی 1و1 میباشد پس خانه ستون 5 ام و سطر دوم به صورت زیر مشخص میشه:
              [code=c]Lcd_gotoxy(5,2); [/code]

              خب حالا میریم سراغ برنامه کامل:
              [code=c]#include <16f877a.h>
              #use delay(xtal=20Mhz)
              #fuses HS,NOWDT

              #define LCD_RS_PIN PIN_b0
              #define LCD_RW_PIN PIN_b1
              #define LCD_ENABLE_PIN PIN_b2
              #define LCD_DATA4 PIN_b3
              #define LCD_DATA5 PIN_b4
              #define LCD_DATA6 PIN_b5
              #define LCD_DATA7 PIN_b6
              #include <LCD.c>

              int i=0;

              void main()
              {
              lcd_init();

              lcd_gotoxy(6,1);
              printf(lcd_putc,"<<ECA>>"
              lcd_gotoxy(8,2);
              printf(lcd_putc,"PIC"

              delay_ms(700);

              lcd_init();

              while(true)
              {
              lcd_gotoxy(1,1);
              printf(lcd_putc, "I=%u", i);

              i++;

              delay_ms(100);
              }
              }[/code]

              این برنامه ابتدا کارکتر هایی رو روی lcd نمایش میده سپس اون رو رفلش میکنه و مقدار یه متغیر به نام i که مدام در حال افزایش هست رو نشون میده.


              اینم فایل برنامه به اضافه فایل پروتئوس:
              http://s3.picofile.com/file/7963502254/lcd.rar.html
              AYRIC

              دیدگاه


                #8
                پاسخ : آموزش کامپایلر CCS از صفر

                من شروع کردم فعلا اولی رو دارم تمرین میکنم!!


                دیگه تصویر جا نشد 8 تا LED پشت سر هم روشن و خاموش میشن جالبه!!
                اینم کدش
                کد:
                #include <16f877a.h>
                #use delay(xtal=20Mhz)
                
                void main()
                {
                
                while(true)
                {
                output_high(pin_b0);
                
                delay_ms(100);
                
                output_low(pin_b0);
                
                delay_ms(100);
                
                output_high(pin_b1);
                
                delay_ms(100);
                
                output_low(pin_b1);
                
                delay_ms(100);
                
                output_high(pin_b2);
                
                delay_ms(100);
                
                output_low(pin_b2);
                
                delay_ms(100);
                
                output_high(pin_b3);
                
                delay_ms(100);
                
                output_low(pin_b3);
                
                delay_ms(100);
                
                output_high(pin_b4);
                
                delay_ms(100);
                
                output_low(pin_b4);
                
                delay_ms(100);
                
                output_high(pin_b5);
                
                delay_ms(100);
                
                output_low(pin_b5);
                
                delay_ms(100);
                
                output_high(pin_b6);
                
                delay_ms(100);
                
                output_low(pin_b6);
                
                delay_ms(100);
                
                output_high(pin_b7);
                
                delay_ms(100);
                
                output_low(pin_b7);
                }
                
                }

                دیدگاه


                  #9
                  پاسخ : آموزش کامپایلر CCS از صفر

                  سلام آموزشت برای شروع خیلی عالیه
                  یه سوال داشتم
                  شما نوشتید که فرکانسی که به میکرو میدیم تقسیم بر 4 میشه و فرکانس اصلی میکرو تقسیم شدشه مثلآ اگر نوشتیم xtal=20mhz فرکانس واقعی میکرو 5 مگاهرتزه پس این 20 مگاهرتز برای چیه؟
                  باید تو خروجی کریستال 20 مگاهرتز قرار بدیم؟
                  [آموزشی] کنترل رله با پیامک توسط sim800l
                  [آموزشی] راه اندازی سنسورهای DHT11 و DHT22 با کدویژن
                  [آموزشی] مدار عملی اتصال میکروفن خازنی به میکروکنترلر
                  [آموزشی] آموزش نحوه راه اندازی میکروهای fmd
                  صفحه اینستاگرام : ecdco_ir

                  دیدگاه


                    #10
                    پاسخ : آموزش کامپایلر CCS از صفر

                    شما وقتی با دستور xtal=20M قرار می دید یعنی به کامپایلر اعلان می کنید که یک کریستال 20 مگاهرتزی به دو پایه osc1 و osc2 وصل کردید بعدش خود کامپایلر فیوز بیت های داخلی شو مناسب با 20M قرار می ده... ولی کلاکی که cpu با اون عمل پردازش رو انجام می ده میشه مقدار کریستالی که به دو پایه osc1 و osc2 وصل شده تقسیم بر 4 = 5Mhz ....

                    دیدگاه


                      #11
                      پاسخ : آموزش کامپایلر CCS از صفر

                      ممنون از آقای Meysamhl
                      اگه اشتباه نکنم بقیه کلاک برای آدرس دهی رم و راماستفاده میشه
                      اما در عوض دسترسی مستقیم به رم و رام میکرو باعث افزایش سرعت انجام عملیات میشه.

                      اگر هم میکرو کریستال داخلی داشته باشه میتونید با دستور زیر از اون استفاده کنید:
                      کد:
                      #use delay(internal=16000000)
                      این مثلا برای یه میکرو هست که کریستال داخلی 16 مگاهرتز داره
                      AYRIC

                      دیدگاه


                        #12
                        پاسخ : آموزش کامپایلر CCS از صفر

                        خوب خیلی سرم شلوغ شده و کمتر وقت میکنم که داخل فاروم پست بذارم
                        بریم سراغ آموزش استفاده از ADC:
                        ADC چیست: مخفف ANALOG TO DIGITAL CONVERTER که به معنای تبدیل کننده مقدار آنالوگ به دیجیتال هست.که روی بسیاری از مدل های میکروهای PIC موجوده.
                        رزولیشن در ADC: دقت تبدیل ولتاژ آنالوگ به مقدار دیجیتال رو رزولیشن میگن. مثلا اگر یک ADC رزولیشن 8 بیت داشته باشه به این معناست که مقدار 5 ولت (یا حداکثر مقدار قابل اندازه گیری حالا هرچی که باشه) تقسیم بر 255 (مقدار کامل دسیمال 8 بیت) میشه. که اگر این تقسیم رو انجام بدیم 5/255=0.0196 یعنی این ADC میتونه ولتاژ مثلا 0 تا 5 ولت رو با دقت 0.196 ولت اندازه گیری کنه و به صورت یه عدد بین 0 تا 255 به ما برگردونه که 0 یعنی 0ولت و 255 یعنی 5 ولت (پس مشخصا اگر ADC مقدار 127 رو برگردونه ولتاژ 2.5 ولته)


                        در خانواده های PIC در سری 12F و 16F ماژول های ADC 8 یا 10 بیتی موجود داره. در یک سری از مدل های 18F ها یا مدلهای بالاتر ADC 12 و 16 بیتی هم هست

                        ما با میکروی 18F452 میخوایم ADC رو راه اندازی کنیم. و این میکرو روی 8 تا از پین هاش قابلیت ADC رو داره
                        در عکس زیر میتونیم این پایه هارو ببینیم:


                        کنار بعضی از پایه ها نوشته شده AN. این پایه ها میتونن ADC باشن.
                        این پایه ها بوسیله یک شماره از هم متمایز میشن که به اون کانال میگن. مثلا پایه شماره 8 میکرو که پین E0 هستش کنارش نوشته شده AN5 یعنی کانال 5 از ماژول ADC (دقت کنید که در این میکرو تنها یه ماژول ADC وجود داره و این 8 کانال روی همین ماژول مالتی پلکس میشه پس در عین واحد فقط از یکی از این پایه ها میشه به عنوان ADC استفاده کرد)

                        دقت کنید که پایه شماره 6 adc نیست!!

                        خب حالا ما در محیط پروتئوس میخوایم یک ولتاژ به یکی از این پایه ها بدیم و اون رو اندازه گیری کنیم و روی lcd نمایش بدیم:


                        حالا باید بریم سراغ کامپایلر ccs و اینکه توی کامپایلر باید چکار کنیم

                        با استفاده از دستور زیر میتوانیم رزولیشن adc را انتخاب کنیم:
                        [code=c]#device ADC=10[/code]

                        در دستور بالا adc در حالت 10 بیتی قرار گرفت. برای این میکرو میتونید از عدد 8 هم استفاده کنید و در این صورت adc میکرو در حالت 8 بیتی قرار میگیرد که دقت کمتری نسبت به 10 بیتی داره

                        حالا باید داخل برنامه و قبل از اینکه از adc استفاده کنید کلاک اون و پورت هایی که میخواید از اونا به عنوان adc استفاده کنید رو انتخاب کنیم

                        بوسیله تابع زیر میتونید کلاک adc رو مشخص کنید:
                        [code=c]
                        setup_adc( ADC_CLOCK_INTERNAL );
                        [/code]

                        که در اینجا بجای آرگومان تابع عبارت ADC_CLOCK_INTERNAL قرار گرفته.
                        کلا این کلاک زمان نمونه برداری adc رو مشخص میکنه که اینجا چون زیاد نرخ نمونه برداری مهم نیست از گزینه ADC_CLOCK_INTERNAL استفاده کردیم.
                        کمی پایین تر مشخص میشه که چه گزینه های دیگه ای وجود داره برای این تابع

                        بوسیله دستور زیر میتونیم کانال های adc که مورد استفاده قرار میگیرن رو تعریف کنیم:
                        [code=c]
                        setup_adc_ports(AN0);
                        [/code]

                        که اینجا در آرگومان تابع عبارت AN0 قرار گرفته چون در این مثال فقط از این کانال استفاده میکنیم. در میکروهای قدیمی انتخاب های محدودی برای این قسمت وجود داره مثلا نمیتونید فقط از AN0 و AN1 به عنوان آنالوگ استفاده کنید و مجبورید کانال AN3 رو هم ADC بکنید!
                        اما در میکرو های جدید مثلا 16F1829 یا 18F46K80 هر پایه رو که بخواید میتونید استفاده کنید
                        برای این که گزینه های قابل انتخاب رو ببینیم به ویزار CCS میریم

                        ویزار رو که باز کردید از منوی سمت چپ به بخش ANALOG برید

                        (این ویزارد مال CCS ورژن 5 هستش)

                        در قسمت 1 میتونید رزولیشن رو انتخاب کنید
                        در قسمت 2 میتونید کلاک ADC رو انتخاب کنید
                        در قسمت 3 هم اون انتخاب هایی که گفتم رو میتونید ببینید. مثلا در گزینه 7 میتونید یه ولتاژ به پایه A3 بدید که این ولتاژ به عنوان ولتاژ رفرنس منظور میشه. ابن کار برای زمانی استفاده میشه که ولتاژی که میخواید اندازه بگیرید بیشتر از مثلا 2 ولت نیست. در این حالت میتونید با انتخاب این گزینه و اعمال ولتاژ 2 ولت به پایه A3 ماکزیمم مقدار قابل اندازه گیری توسط ADC رو روی 2 ولت تنظیم کنید و دقت کار رو بالاتر ببرید. با انتخاب گزینه هفتم پایه های A0 و A1 به عنوان پایه های ADC در نظر گرفته میشن.

                        بعد از دستورات مربوط به تنظیمات باید ببینیم با چه توابعی میتونیم از ADC مقدار رو بگیریم.
                        قبل از گرفتن مقدار از ADC باید اول مشخص کنیم که از کدوم کانال میخوایم مقدار رو بگیریم که چون ما فقط کانال AN0 رو به عنوان ورودی ADC تنظیم کردیم خود میکرو مقدار رو از پایه A0 میخونه اما اگر چند پایه رو به عنوان ورودی در نظر بگیریم حتما باید کانال مورد نظر رو قبل از قرائت مقدار مشخص کنیم

                        با دستور زیر میتونیم کانال ADC رو مشخص کنیم:
                        [code=c]
                        set_adc_channel(7);
                        delay_us(10);
                        [/code]

                        مثلا اینجا کانال 7 انتخاب شده
                        اون تاخیر 10 میکرو ثانیه هم برای اینه که مالتی پلکسری که قراره بین کانال های مختلف سوئیچ کنه فرصت این کار رو داشته باشه

                        حالا دیگه میتونیم با دستور زیر مقدار ADC رو بخونیم:
                        [code=c]
                        adc_value = read_adc();
                        [/code]

                        در اینجا مقدار ADC رو خوندیم و توی متغیر adc_value قرارش دادیم

                        حالا اگر رزولیشن رو روی 8 بیتی تنظیم کرده باشیم مقدار adc_value مقداری بین 0 تا 255 و اگر 10 بیتی تنظیم کرده باشیم مقداری بین 0 تا 1023 رو داره
                        پس موقع تعریف متغیر (اینجا adc_value) حواستون به 8 یا 16 بیتی بودنش باشه

                        این مقداری که خونده شده یه مقدار دیجیتاله و دقیقا خود ولتاژ نیست. که خیلی راحت میشه اون رو به ولتاژ تبدیل کرد با فرمول زیر:
                        [code=c]
                        volts =adc_value * 5/1023.0; [/code]

                        5 بخاطر اینه که الان در مثال ما رفرس ADC روی 5 ولته و در واقع ماکزیمم مقدار قابل اندازه گیری 5 ولته. 1023 هم بخاطر اینه توی مثال ما رزولیشن 10 بیت انتخاب شده. و تقسیم این دو عدد بخاطر اینه که ببینیم هر بیتی که تابع read_adc برمیگردونه ارزشش چند ولته
                        volts هم یه متغیر اعشاریه

                        اینم فایل شامل سورس برنامه هگز و شماتیک :
                        http://s5.picofile.com/file/8151577892/ADC.rar.html

                        AYRIC

                        دیدگاه


                          #13
                          پاسخ : آموزش کامپایلر CCS از صفر

                          سلام
                          خوب در این قسمت میخوایم اینتراپت (interrupt) یا همون وقفه رو آموزش بدیم و با وقفه خارجی کار کنیم

                          وقفه چیست؟
                          همون طور که از اسمش پیداست یعنی ایجاد توقف در برنامه. که به منظور خاص صورت میگیره.مثلا "وقفه خارجی" باعث میشه که وقتی یه پایه از سطح منطقی 0 به 1 (یا برعکس) میره برنامه هرکاری که داره میکنه رو ول کنه و بره به تابع مربوط به "وقفه خارجی" تا دستوراتی که شما براش تعریف کردید رو انجام بده.

                          فرض کنید توی یک برنامه خیلی ساده مثل برنامه زیر:
                          [code=c]
                          while(true)
                          {
                          time=100;
                          output_high(pin_c0);
                          delay_ms(time);
                          output_high(pin_c1);
                          delay_ms(time);
                          output_high(pin_c2);
                          delay_ms(time);
                          output_low(pin_c0);
                          delay_ms(time);
                          output_low(pin_c1);
                          delay_ms(time);
                          output_low(pin_c2);
                          delay_ms(time);
                          }
                          [/code]

                          بخوایم به محض این که پایه B0 از 0 به 1 تغییر کرد (مثلا کلیدی که به پایه B0 زده شده رو فشار دادید) این برنامه که یه برنامه چشمک زنه مثلا سرعتش کمتربشه. که میتونیم برای کند تر شدن چشمک زن متغیر time رو بیشترش کنیم اما کی این کار رو انجام بدیم و چطور؟
                          اگر بیایم اول حلقه یه شرط بذاریم و بگیم مثلا :
                          [code=c]if(input(pin_b0)==1) time+=100;[/code]

                          اون موقع ممکنه هنگام زدن کلید برنامه وسط حلقه باشه و تا زمانی که حلقه تموم نشه زمان زیاد نمیشه!!
                          پس ممکنه برنامه ای که ما میخوایم با 100 تا 600 میلی ثانیه تاخیر اجرا بشه؟
                          خوب چکار میشه کرد؟ اینجا باید از قابلیت وقفه خارجی که یکی از انواع وقفه هستش استفاده کنیم
                          وقفه های خیلی متفاوتی وجود داره که من به چند تاش اشاره میکنم:
                          1- وقفه خارجی
                          2-وقفه سرریز تایمرها
                          3-وقفه تغییرات در پایه های b4 تا b7
                          4-وقفه ssp
                          5-وقفه rs232
                          6- تشخیص کاهش ولتاژ تغذیه
                          و .....

                          وقفه خارجی فقط روی بعضی از پایه ها موجوده.
                          باز عکس مربوط به پایه های میکروی 18f452 رو میذارم:


                          همین طور که میبینید کنار پین های B0 و B1 و B2 نوشته شده INT. که منظور همون INTERRUPT هستش. پس این میکرو 3 تا اینتراپت خارجی داره
                          برای فعال کردن این وقفه در CCS باید دستور زیر رو هرجا که خواستید وقفه فعال بشه بنویسید:
                          [code=c]
                          enable_interrupts(INT_EXT);
                          enable_interrupts(INT_EXT1);
                          enable_interrupts(INT_EXT2);[/code]
                          که به ترتیب وقفه مربوط به پایه های B0 و B1 و B2 رو فعال میکنه

                          همچنین برای غیرفعال کردنش از دستور زیر استفاده میکنیم:
                          [code=c]disable_interrupts(INT_EXT);
                          disable_interrupts(INT_EXT1);
                          disable_interrupts(INT_EXT2); [/code]

                          با فعال کردن وقفه خارجی به این شکل،وقفه خود به خود روی لبه بالا رونده تنظیم میشه. یعنی اینکه هر موقع وضعیت پایه 0 باشه و به 1 تغییر کنه وقفه اجرا میشه

                          اگر بخوایم وقفه روی لبه پایین رونده اتفاق بیوفته میتونیم از دستور زیر در کنار دستور بالا استفاده کنیم:
                          [code=c] EXT_INT_EDGE(H_TO_L);[/code]

                          دقت کنید که وقفه خارجی تنها یک قسمت از ماژول وقفه است و شما هنوز خود ماژول وقفه رو فعال نکردید.
                          برای فعال کردن وقفه سراسری از دستور زیر استفاده میشه:
                          [code=c]enable_interrupts(global); [/code]
                          و برای غیر فعال کردنش از دستور زیر:
                          [code=c]disable_interrupts(global); [/code]

                          دقت کنید که اگر دستور دوم رو به کار ببرید تمام وقفه هایی که فعال کردید غیر فعال میشن چون دارید وقفه سراسری رو غیر فعال میکنید. اما با فعال کردن وقفه سراسری تنها وقفه هایی فعال میشن که خودشون رو هم فعال کرده باشید (چقد فعال غیر فعال داشت :mrgreen

                          حالا میخوایم ببینیم وقتی وقفه خارجی اتفاق میافته برنامه به کجا میره ؟
                          برنامه به داخل هر تابعی که عبارت زیر دقیقا بالای سر اون نوشته شده باشه میره:
                          [code=c]#INT_EXT [/code]

                          مثال زیر رو ببینید:
                          [code=c]
                          #INT_EXT
                          void ext_isr()
                          {
                          time++;
                          }

                          #INT_EXT1
                          void ext_isr()
                          {
                          output_high(pin_c0);
                          time--;
                          }

                          #INT_EXT2
                          void ext_isr()
                          {
                          output_low(pin_c0);
                          }
                          [/code]

                          طبق مثال بالا اگه وقفه خارجی مربوط به پایه B0 اتفاق بیافته (یعنی INT0) یک واحد به time اضافه میشه
                          اگه INT1 اتفاق بیافته یک واحد از time کم میشه و پایه C0 هم 1 میشه
                          و اگه INT2 اتفاق بیافته پایه C0 صفر میشه

                          پس برنامه چشمک زن رو میتونید به صورت زیر بنویسید:

                          [code=c]
                          #INT_EXT
                          void ext_isr()
                          {
                          if(time<=900) time+=100;
                          }

                          #INT_EXT1
                          void ext_isr()
                          {
                          if(time>=100) time-=100;
                          }


                          void main()
                          {

                          enable_interrupts(int_ext);
                          enable_interrupts(int_ext1);
                          enable_interrupts(global);

                          time=100;
                          while(true)
                          {
                          output_high(pin_c0);
                          delay_ms(time);
                          output_high(pin_c1);
                          delay_ms(time);
                          output_high(pin_c2);
                          delay_ms(time);
                          output_low(pin_c0);
                          delay_ms(time);
                          output_low(pin_c1);
                          delay_ms(time);
                          output_low(pin_c2);
                          delay_ms(time);
                          }

                          }
                          [/code]

                          که با فشار دادن کلید متصل به B0 100 واحد به time اضافه میشه و با فشردن کلید متصل به پایه B1 100 واحد از time کم میشه که باعث کند شدن یا تند شدن چشمک زن میشه. اون شرط های داخل توابع وقفه هم برای خارج نشدن متغیر time از بازه 0 تا 1000 هستش

                          دستورات مربوط به تعریف میکرو و کریستال تکراری و خودتون بنویسیدش
                          این یه کاربرد خیلی ساده از وقفه خارجی بود و کارای زیادی با این نوع وقفه میشه انجام داد

                          موفق باشید
                          AYRIC

                          دیدگاه


                            #14
                            پاسخ : آموزش کامپایلر CCS از صفر

                            دوستان سوالات مربوط به برنامه نویسی رو تو تاپیک سوالات برنامه نویسی در کامپایلر CCS مطرح کنین و اجازه بدین دوست عزیزمون roboreza بدون ایجاد وقفه، آموزش ها رو ادامه بدن.
                            ممنونم.

                            دیدگاه


                              #15
                              پاسخ : آموزش کامپایلر CCS از صفر

                              سلام
                              خسته نباشید

                              خوب در این قسمت میخوایم تایمر رو بگیم و با تایمر 0 میکروکنترل 18f452 کار کنیم

                              فرض کنید که میخوایم یه کلاک خارجی رو بشمریم در حالی که میکرو داره کارای دیگه ای انجام میده مثلا خروجی چندتا سنسور دیگه رو میگیره و روی اونها پردازش انجام میده . مثلا پالس خروجی که یه سنسور انکودر میده رو میخوایم بشمریم(برای اطلاعات بیشتر راجع به انکودر عبارت rotary encoder یا shaft encoder رو جست و جو کنید)

                              خب تا اینجا ما وقفه رو گفتیم و ممکنه به ذهنتون برسه که از وقفه خارجی میشه استفاده کرد مثلا کد زیر:
                              [code=c]
                              #INT_EXT
                              void ext_isr()
                              {
                              encoder++;
                              }
                              [/code]

                              حالا اگه ما بیایم خروجی پالس انکودر رو به پایه مربوط به وقفه خارجی وصل کنیم هر بار که انکودر یه پالس میده برنامه وارد وقفه خارجی میشه و یک واحد به متغیر encoder اضافه میشه پس میتونیم بفهمیم که انکودر چقدر چرخیده

                              این راه در نگاه اول ممکنه خوب بنظر برسه. اما اگه فرکانس خروجی انکودر خیلی زیاد باشه چی؟ اون موقع میکرو همش باید وارد وقفه بشه و متغیر انکودر رو افزایش بده. یا حتی ممکنه فرکانس اینقدر زیاد بشه که دیگه میکرو نتونه از پس همین کار هم بر بیاد دیگه چه برسه بخواد کارای دیگه انجام بده. یا مثلا اگه شما داخل برنامتون از delay استفاده کنید یا روی lcd چیزی بنویسید این دو عمل باعث میشن تا وقفه اتفاق نیافته و اصلا میکرو شمارشی رو انجام نده.

                              حالا راه بهتری رو پیشنهاد میکنیم اونم استفاده از تایمرهای میکرو هستش
                              کلا تایمرها میتونن تعداد دفعات تحریک شدنشون رو بشمرن و توی یه متغیر 8 یا 16 یا 32 بیتی ذخیره کنن (این متغیر در واقع حجم یا بزرگی تایمر رو نشون میده مثلا میگن یه تایمر 16 بیتیه یعنی میتونه تا 65536 رو شمارش کنه)

                              اینکه هر میکرو چند تایمر داره رو میشه از صفحات اول دیتاشیت هر میکرو متوجه شد و اگر گوشیه شما اندرویده شما میتونید از برنامه جالب PICmicro Database این جور اطلاعات مربوط به هر میکرو PIC رو در بیارید. یا حتی بر اساس امکاناتی که نیاز دارید یک یا چند میکرو رو پیدا کنید. نمیدونم ولی احتمال زیاد برای ویندوز هم داره

                              میکروی ما 18F452 هست و این میکرو 4 تا تایمر داره که یکی از اونا 8 بیتی و بقیه 16 بیتی هستند
                              تایمر شماره 0 هم که توی این آموزش میخوایم باهاش کار کنیم 16 بیتیه. و همچنین این تایمر میتونه لبه بالا رونده یا پایین رونده یا حتی کلاک داخلی میکرو رو شمارش کنه.
                              حالا باید ببنیم چطور میشه تایمر 0 رو راه اندازی و تنظیم و از اون استفاده کرد

                              با نوشتن دستور زیر میتونید تایمر 0 رو فعال کنید:
                              [code=c]
                              setup_timer_0(RTCC_EXT_L_TO_H|RTCC_DIV_1|RTCC_8_bi t); [/code]

                              آرگومان اول منبع کلاک تایمر رو مشخص میکنه. که الان بجای اون عبارت RTCC_EXT_L_TO_H نوشته شده میتونه عبارت های RTCC_EXT_H_TO_L و همینطور INTERNAL رو هم بگیره.
                              بذارید تا اول فرق دو عبارت اول رو بگم .
                              اگر بجای آرگومان اول عبارت RTCC_EXT_L_TO_H رو بذاریم اولا داریم میگیم که منبع کلاک از خارج باشه (کنار پایه شماره 6 میکرو رو اگه نگاه کنید نوشته T0CKL این یعنی شما میتونید به این پایه یه کلاک بدید تا تایمر 0 اون رو برای شما شمارش کنه) و دوما دارید مشخص میکنید که تایمر لبه های بالا رونده (rising edge) کلاک رو بشمره. حالا اگه عبارت RTCC_EXT_H_TO_L رو قرار بدید دارید به تایمر میگید که لبه های پایین رونده (fulling edge) رو شمارش کنه. پس با تنظیم این گومان با عبارت های مذکور مقدار تایمر رو داخل برنامه به صورت زیر خواهید داشت:



                              همینطور که در قسمت بالایی میبینید با هر لبه بالا رونده یک واحد به مقدار تایمر اضافه شده و در قسمت پایینی با لبه پایین رونده یک واحد به مقدار تایمر اضافه شده. این تاثیر انتخاب عبارت های RTCC_EXT_L_TO_H و RTCC_EXT_H_TO_L در تابع setup_timer0 هستش

                              آرگومان دوم این تابع مشخص کننده prescale تایمر هستش (داخل ویزارد ccs با کلمه resolation مشخص شده) این آرگومان در واقع مشخص میکنه که تایمر با گرفتن چند کلاک؟ یک واحد به مقدار تایمر اضافه کنه
                              مثلا prescale=2 مشخص میکنه که تایمر با گرفتن 2 کلاک یک واحد به مقدار خودش اضافه کنه. شکل زیر رو برای prescale های 2 و 4 ببینید:


                              با گذاشتن عبارت RTCC_DIV_1 در واقع ما presclae رو روی 1 تنظیم کردیم یعنی با هر کلاک یک واحد به مقدار تایمر اضافه بشه که به جای عدد 1 شما میتونید عدد های 1,2,4,8,16,32,64,128,256 رو بذارید.

                              عبارت آخر در تابع setup_timer0 رو هم میتونید بذارید میتونید نذارید. که اگر بذارید تایمر به صورت 8 بیتی و اگر نذارید تایمر به صورت 16 بیتی پیکر بندی میشه (یعنی در حالت اول تا 255 و در حالت دوم تا 65535 رو میتونه بشمره)

                              برای دادن یک مقدار به تایمر میتونیم از تابع set_timer استفاده کنیم :
                              [code=c]
                              set_timer0(56);[/code]
                              که در مثال بالا به تایمر 0 مقدار 56 رو دادیم. در واقع داریم به تایمر میگیم که از عدد 56 شروع به شمارش کنه

                              و برای گرفتن مقدار تایمر از تابع get_timer استفاده میکنیم:
                              [code=c]
                              t0=get_timer0();[/code]

                              در اینجا مقدار تایمر 0 رو گرفتیم و داخل متغیر t0 ذخیره کردیم.

                              در برنامه زیر سنسور LM35 که سنسور اندازه گیری دما با خروجی آنالوگ هست رو راه اندازی کردیم و همچنین توسط تایمر 0 تعداد دفعات فشرده شدن یک کلید رو شمارش کردیم. و هر دو رو روی یک LCD کارکتری نمایش دادیم:



                              فایل شامل برنامه،هگز و شماتیک: http://s5.picofile.com/file/8152907268/timer0.rar.html
                              AYRIC

                              دیدگاه

                              لطفا صبر کنید...
                              X