اطلاعیه

Collapse
No announcement yet.

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

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

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

    سلام
    از درسام خسته شدم اومدم یه پست بذارم

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

    وقفه تایمر:
    قبلا وقفه رو گفتیم چیه. و با وقفه خارجی هم کار کردیم.
    هر کدوم از تایمرها هم برای خودشون یه وقفه دارن. که زمانی اتفاق میافته که تایمر سرریز (overflow) بشه برای همین به این وقفه، وقفه سرریز تایمر هم میگن. مثلا یه تایمر 8 بیتی رو فرض کنید که میتونه از 0 تا 255 رو بشمره و مثلا مقدار فعلی تایمر روی 255 هستش. حالا اگه تایمر فقط یک بار دیگه شمارش کنه چون پر شده و بیشتر 255 رو نمیتونه بشمره سرریز میشه و مقدارش 0 میشه. حالا همزمان با این سرریز یه وقفه هم توی برنامه میتونه اتفاق بیافته که شما باید اون رو فعال کرده باشین

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

    که بجای x در عبارت بالا باید شماره تایمر رو قرار بدید. مثلا برای فعال کردن وقفه تایمر 0 از عبارت زیر استفاده میکنیم :
    [code=c]enable_interrupts(int_timer0);[/code]

    یادتون باشه که وقفه global رو هم فعال کرده باشید.

    حالا وقتی وقفه تایمر اتفاق میافته برنامه به تابع نوشته شده در پایین عبارت زیر میره:
    [code=c]#INT_TIMERx[/code]

    باز هم در عبارت بالا به جای x شماره تایمر باید نوشته بشه

    مثلا میخوایم با میکروی 18f452 یه برنامه بنویسیم که با هربار سرریز تایمر مقدار یه متغیر 1 واحد زیاد بشه. کد زیر رو ببینید:
    [code=c,15]#Include <18f452.h>
    #fuses NOWDT,HS
    #use delay(xtal=20mhz)

    int16 overflow;

    #INT_TIMER0
    void count_overflow()
    {
    overflow++;
    }

    void main()
    {
    Setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
    enable_interrupts(int_timer0);
    enable_interrupts(global);

    while(true);

    }[/code]

    به خط 15 که هایلایت شده دقت کنید. شما در پست قبلی با این دستور کار کرده بودید فقط بجای عبارت RTCC_INTERNAL از عبارت RTCC_EXT_L_TO_H استفاده کردید. دلیلش واضحه که چرا اینجا اینطوری نوشته شده. چون میخواستیم تایمر به صورت داخلی فعال بشه و از کلاک خود میکرو شمارش رو انجام بده. همچنین عبارت RTCC_DIV_1 در تابع setup_timer0 مشخص کننده prescale تایمر هستش (یعنی به ازای هر کلاک یک واحد به تایمر اضافه بشه)

    حالا با توجه به برنامه بالا فکر میکنید چقدر وقت یکبار به متغیر overflow یک واحد اضافه میشه؟
    برای اینکه زمان سرریز تایمر رو مشخص کنیم قبلش باید چندتا چیز رو مشخص کنیم:
    1- حجم تایمر 0 در میکروی 18f452 چقدره؟ که مطابق دیتاشیت 16 بیتی هستش پس تا عدد 65535 رو میتونه شمارش کنه
    2- فاصله زمانی بین 2 کلاکی که به تایمر داده میشه چقدره؟ با توجه به این که کلاک در میکروهای 8 بیتی pic 1 به 4 است (یعنی 1/4 کل کلاک به cpu و واحدهای دیگه میرسه) پس با توجه به فرکانس 20 مگاهرتزی که ما مشخص کرده ایم فرکانس 5 مگاهرتز به تایمر میرسد (20 تقسیم بر 4 مساوی 5)
    حالا از رابطه f=1/t میشه فاصله زمانی بین هر دو کلاک رو مشخص کرد که 1/5000000=0.2us پس فاصله زمانی بین دو کلاک برابر 0.2 میکروثانیه هستش.
    3- بعد از چه مدت زمانی یک واحد به مقدار تایمر اضافه میشه؟ با توجه به این که prescale رو روی 1 تنظیم کردیم پس با هر کلاک یک واحد تایمر زیاد میشه پس زیاد شدن یک واحدی تایمر هم 0.2 میکروثانیه طول میکشه. این در حالیه که اگه prescale رو روی 2 تنظیم میکردیم افزایش هر واحد تایمر پس از 0.4 میکرو ثانیه رخ میداد

    حالا با اطلاعات بالا میشه فهمید وقفه تایمر پس از چه مدتی رخ میده:
    حجم تایمر 65536 واحد. هر واحد 0.2 طول میکشه پس کلا 65536*0.2=13107.2us طول میکشه تا وقفه اتفاق بیافته (حدود 13 میلی ثانیه)

    برنامه بالا برای این بود که با نحوه محاسبه زمان و دستورات تایمر و وقفه اون بهتر آشنا بشید.
    از برنامه بالا میتونید موقعی استفاده کنید که مثلا میخواید هر 13 میلی ثانیه داخل برنامتون یه اتفاقی بیافته (مثلا از adc یه نمونه برداری کنید)
    یا میتونه موقعی مورد استفاده قرار بگیره که میخواید زمان های بیشتر از 13 میلی ثانیه رو اندازه گیری کنید. به این شکل که هر واحد متغیر overflow نشان دهنده یک سرریز هست و مقدار خود تایمر هم که موجوده پس با فرمول زیر میشه زمان های بزرگتری رو هم اندازه گیری کرد:
    [code=c]time=(overflow*65536)+get_timer0();[/code]

    در پست بعدی با چگونگی تولید فرکانس پایین با این تایمر ها آشنا میشید
    AYRIC

    دیدگاه


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

      در این پست میخوایم ببینیم چطور میتونیم یه فرکانس مثلا 100 هرتز رو روی یک پایه دلخواه میکرو ایجاد کنیم؟

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

      همونطور که گفته شد برای فرکانس 100 هرتز نیاز داریم که هر 10 میلی ثانیه یکبار یک پایه رو 1 کنیم.
      در پست قبلی دیدم که چطور میشه توسط تایمر 0 هر 13 میلی ثانیه یکبار وقفه ایجاد کرد.
      خوب پس اگه بتونیم بجای 13 میلی ثانیه هر 10 میلی ثانیه یک وقفه داشته باشیم میتونیم فرکانس رو تولید کنیم.
      با مشخص کردن مقدار تایمر در ابتدای تابع وقفه تایمر میشه این کار رو انجام داد. به صورت زیر:
      [code=c]
      #Include <18f452.h>
      #fuses NOWDT,HS
      #use delay(xtal=20mhz)

      #INT_TIMER0
      void count_overflow()
      {
      set_timer0(15536);

      output_high(pin_b0);
      delay_ms(2);
      output_low(pin_b0);
      }
      [/code]

      با استفاده از دستور set_timer در ابتدای تابع سرریز تایمر و و قرار دادن مقدار 15536 در اون در واقع داریم مقدار اضافه ی زمان رو کم میکنیم.
      حالا چرا 15536؟
      ما میخواستیم هر 10 میلی ثانیه وقفه اتفاق بیافته اما هر 13107.2 میکرو ثانیه اتفاق میفتاد پس زمان اضافه میشه 3107.2 میکرو ثانیه. باید حساب کنیم این زمان اضافه چند واحد تایمر میشه که طبق چیزی که قبلا گفتیم هر واحد تایمر 0.2 میکرو ثانیه هست پس 3107.2/0.2=15536

      حالا که فهمیدیم زمان اضافه چند واحد تایمر میشه باید اون رو از مقدار تایمر کم کنیم. که با نوشتن دستور set_timer0(15536) داریم به تایمر میگیم از عدد 15536 شروع به شمارش کن. که با این کار تایمر بعد از شمارش 50000 کلاک سرریز میشه و وقفه ایحاد میشه. 50000 کلاک میشه دقیقا همون 10 میلی ثانیه که میخواستیم.

      یه چیزی رو اینجا یادآور بشم که چون ممکنه این مطالب یکم گیج کننده باشه مخصوصا برای افراد تازه کار اگر برای کسی جای ابهام وجود داره در تاپیک سوالات برنامه نویسی در کامپایلر ccs سوالات خودشون رو بپرسن تا ابهامات برطرف بشه

      برنامه بالا میتونه هر 10 میلی ثانیه یکبار پایه مثلا B0 رو 1 کنه و بعد از یک تاخیر 2 میلی ثانیه (Ton یا زمان روشن بودن پالس) دوباره پایه رو 0 کنه. که در این صورت شما یک فرکانس 100 هرتز رو روی پایه B0 میکرو ایجاد کرده اید. زمان روشن بودن رو هم که با تغییر اون عدد 2 بین مقادیر 0 تا 10 میتونید تغییر بدید

      اگر بخواید حرفه ای تر برنامه بالا رو بنویسید باید تاخیر مربوط به Ton رو هم با تایمر ایجاد کنید که میکرو درگیر دستور delay نشه. به برنامه زیر نگاه کنید:

      [code=c]#Include <18f452.h>
      #fuses NOWDT,HS
      #use delay(xtal=20mhz)

      int1 flag;

      #INT_TIMER0
      void count_overflow()
      {
      if(flag)
      {
      set_timer0(55536);
      output_high(pin_b0);
      }
      else
      {
      set_timer0(25536);
      output_low(pin_b0);
      }

      flag=!flag;

      }


      void main()
      {
      Setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
      enable_interrupts(int_timer0);
      enable_interrupts(global);

      flag=0;

      while(true);
      }[/code]

      در این برنامه از یک متغیر به اسم flag هم استفاده شده. به این صورت که اولین باری که برنامه وارد وقفه میشه flag برابر 0 است پس طبق شرطها مقدار اولیه تایمر رو 55536 میکنه و پایه B0 رو هم 1 میکنه (55536 برای اینکه میخواهیم پس از 2 میلی ثانیه دوباره وقفه اجرا بشه و پایه 0 بشه پس مقدار تایمر رو 55536 میکنیم تا 10000 واحد دیگر از تایمر باقی بمونه که برابر 2 میلی ثانیه هستش) در آخر تابع وقفه هم متغیر flag معکوس میشه (اینجا چون 0 بوده 1 میشه).
      با گذشت 2 میلی ثانیه مقدار تایمر دوباره به 65536 میرسه و سرریز میشه و برنامه وارد وقفه میشه. اینبار متغیر flag برابر 1 هستش پس پایه B0 رو 0 میکنه و مقدار تایمر رو هم 25536 میکنه تا پس از 8 میلی ثانیه دوباره همین اتفاقات بیافته
      میتونید مدار ساده ای برای برنامه بالا داخل پروتئوس ببنید و یه اسیلوسکوپ سر پایه B0 بذارید و اون رو تست کنید

      ما با این روش یه فرکانس تولید کردیم اما شما میتونید با این روش کارهایی که نیاز دارید در یه زمان مشخص در برنامه انجام بشه رو اجرا کنید. مثلا مثلا هر 10 میلی ثانیه یه نمونه از adc بگیرید یا هر کار دیگه ای.
      انشاالله در پست بعدی نحوه اندازه گیری فرکانس توسط میکرو رو میگم
      AYRIC

      دیدگاه


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

        سلام

        امروز میخوایم راه اندازی تایمر 1 رو کار کنیم.
        با دستور زیر میتونیم تایمر 1 رو در حالت کلاک از داخل با prescale 1 تنظیم کنیم :
        [code=c]
        setup_timer_1(T1_INTERNAL | T1_DIV_BY_1 ); [/code]

        اگر بجای عبارت T1_INTERNAL از عبارت T1_EXTERNAL استفاده کنیم، تایمر کلاک خودش رو از خارج و از پایه ای که با T1CKI مشخص شده میگیره. (در میکروی 18F452 پایه RC0 شماره 15)

        همچین prescale که در تنظیم تایمر 0 تشریح شد رو میتونید با عبارت T1_DIV_BY_x مشخص کنید که به جای x میتونه مقادیر 1,2,4,8 قرار بگیره .دقت کنید این که این قسمت با تایمر 0 متفاوته. presclae در تایمر 0 یک 8 بیتی بود اما در تایمر 1 فقط این 4 مقدار رو میتونید در نظر بگیرید. البته این ها برای میکروی 18f452 هستن و توی اکثر میکروهای هم رده یا پایین تر به همین شکله اما ممکنه در میکروی دیگه ای متفاوت باشه (میتونید از دیتاشیت کمک بگیرید)



        برای مقداردهی و گرفتن مقدار تایمر 1 هم از توابع زیر استفاده میشه:
        [code=c]
        set_timer1(0);
        i=get_timer1();[/code]

        همچنین برای فعال کردن وقفه سرریز تایمر 1 باید عبارت INT_TIMER1 رو در تابع فعال سازی وقفه قرار بدید:
        [code=c]
        enable_interrupts(INT_TIME1);
        [/code]

        برنامه زیر هر لحظه مقدار تایمر 1 که کلاک خودش رو از پایه T1CKI میگیره رو روی lcd نشون میده و با هر بار سرریز تایمر متغیر overflow اضافه میشه:
        [code=c]
        #include <18f452.h>
        #use delay(xtal=4mhz)

        #define LCD_RS_PIN PIN_d0
        #define LCD_RW_PIN PIN_d1
        #define LCD_ENABLE_PIN PIN_d2
        #define LCD_DATA4 PIN_d3
        #define LCD_DATA5 PIN_d4
        #define LCD_DATA6 PIN_d5
        #define LCD_DATA7 PIN_d6
        #include <LCD.c>

        int8 overflow=0;

        #INT_TIMER1
        void timer1_interr()
        {
        overflow++;
        }

        void main()
        {
        setup_timer_1(T1_EXTERNAL | T1_DIV_BY_2 );
        enable_interrupts(INT_TIMER1);
        enable_interrupts(GLOBAL);

        lcd_init();

        while(true)
        {
        lcd_gotoxy(1,1);
        printf(lcd_putc,"T1=%lu \nOVERFLOW=%u ",get_timer1(),overflow);
        }
        }

        [/code]

        دقت کنید که تایمر 1 در این میکرو 16 بیتیه (0-65535)
        اینم فایل برنامه و هگز و شماتیک
        AYRIC

        دیدگاه


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

          با سلام
          این جلسه راه اندازی ماژول UART رو میگم.
          این پست و چند تا پست دیگه مربوطه به نحوه استفاده و راه اندازی ماژولهای ارتباطی میکرو. که بهمون کمک میکنن تا بتونیم ارتباط میکرو و یک تجهیز دیگه (که اونم میتونه یک میکرو یا یک سنسور یا آیسی خاصی باشه) رو ایجاد کنیم و داده انتقال بدیم.
          ارتباط بین تجهیزات الکترونیکی به دو شکل آنالوگ و دیجیتال اتفاق میافته.
          ارتباط دیجیتال به 2 دسته تقسیم میشه. یکی ارتباط موازی و یکی هم ارتباط سریال.
          ارتباط موازی : بیت ها به صورت همزمان از طریق چند خط (مثلا 4 یا 8 خط) از فرستنده به گیرنده ارسال میشن.
          ارتباط سریال: بیت ها به صورت یکی یکی و پشت سر هم از طریق 1 خط ارسال میشن. ممکنه توی پروتکل های مختلف برای دریافت اطلاعات از خط دیگری استفاده بشه یا از یک خط هم برای ارسال و هم برای دریافت استفاده بشه.

          در ارتباط سریال باید فرستده و گیرنده با هم هماهنگ بشن. که با گذاشتن هر بیت روی خط دیتا توسط فرستنده، گیرنده بیاد اون بیت رو بخونه. این هماهنگی میتونه به صورت های زیر اتفاق بیافته:
          1- به این صورت که فرستنده با گذاشتن هر بیت روی خط دیتا یک کلاک به گیرنده بده. به این شکل هر موقع که گیرنده کلاک رو دریافت کرد میفهمه که بیت جدید اومده و اونو از خط دیتا میخونه.
          2- دومین روش اینه که فرستنده و گیرنده زمان بندی هاشون با هم یکی بشه و سر یه تایم مشخصی فرستنده بیت جدید رو بذاره روی خط. گیرنده هم بر اساس زمان بندی خودش که قاعدتا باید با فرستنده یکی باشه میدونه که چه موقع باید بیت جدید رو بخونه. مثلا اگر سرعت انتقال رو 1 بیت در هر ثانیه تعریف کنیم. 4 بیت 1001 به این صورت انتقال داده میشن که : در ثانیه اول خط دیتا 1، در ثانیه دوم 0، در ثانیه سوم 0، و در ثانیه چهارم خط 1 میشه. گیرنده هم اگر هر یک ثانیه یکبار خط رو بررسی کنه و وضعیت خط رو به جای بیت ها قرار بده 1001 رو دریافت میکنه.

          به روش 1 میگن ارتباط همگام یا synchronous و به روش دوم میگن ناهمگام یا asynchronous

          از انواع روش های انتقال اطلاعات به صورت دیجیتال میشه uart,i2c,spi,usb و .... را نام برد. که توی اینایی که گفتم uart ناهمگام و بقیه همگام هستن.

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

          اول باید چند تا چیز رو در مورد UART بدونید.
          1- همون طور که گفتم در UART ارتباط به صورت آسنکرون هست. پس باید سرعت ارسال اطلاعات در دو طرف فرستنده و گیرنده میشخص باشه. که به این سرعت میگن baud rate و واحدش bps هست. مخفف عبارت bit per second. مثلا میتونیم مقدار baud rate رو 9600 انتخاب کنیم که یعنی 9600 بیت در ثانیه انتقال داده میشه.
          2- این UART ای که ما باهاش کار میکنیم UART TTL هست که ولتاژ 5 رو پشتیبانی میکنه.
          3- UART برای ارسال و دریافت از 2 خط جداگانه استفاده میکنه. اسم پایه ارسال TX و اسم پایه دریافت RX هست. پس برای ارتباط بین دو تجهیز با استفاده از این روش باید پایه فرستنده یکی به پایه گیرنده دیگری وصل بشه و برعکس:

          همون طور که توی عکس مشخصه باید زمین هاشون هم به هم متصل باشه.

          در مورد برنامه و راه اندازی UART :

          برای راه اندازی UART در کامپایلر باید عبارت زیر نوشته بشه.

          [code=c]#use rs232(baud=9600, xmit=PIN_A2,rcv=PIN_A3)[/code]

          baud همون baudrate هست که توضیحش داده شد و مقدارش اینجا 9600 انتخاب شده.
          xmit کلمه ای هست که پایه TX رو مشخص میکنه. اینجا پایه A2 به عنوان TX بوده.
          rcv کلمه ای هست که پایه RX رو مشخص میکنه. اینجا پایه A3 به عنوان RX بوده.
          دقت کنید که اگر پایه های اصلی که در دیتاشیت میکروکنترلر با کلمات RX و TX مشخص شده اند در این عبارت انتخاب شوند، UART به صورت سخت افزاری پیکر بندی میشه و اگر همون پایه ها نباشن و پایه های دیگه ای رو انتخاب کنید UART به صورت نرم افزاری پیکر بندی میشه و ممکنه جواب کارتون رو بده اما خیلی جاها در این حالت مشکلاتی پیدا میکنه. پس بهتره به صورت سخت افزاری باشه و از همون پایه های گفته شده در دیتاشیت استفاده کنید.

          در برنامه برای انتقال مقادیر و داده دستورات مختلفی وجود داره.
          اگر بخواهید یک مقدار 8 بیتی یا یک کارکتر رو ارسال کنید دستور زیر میتونه این کار رو انجام بده:
          [code=c]putc(i);
          putc('F'
          [/code]
          در برنامه بالا مقدار i که یک متغیر 8 بیتی هست و بعدش کارکتر F ارسال شده.

          برای دریافت یک کارکتر میتونید از تابع getc به صورت زیر استفاده کنید:
          [code=c]x=getc();[/code]
          مقدار از فرستنده دریافت شده و داخل x ریخته شده.


          کد ساده زیر رو برای فرستنده و گیرنده به صورت جداگانه ببینید:

          کد فرستنده:
          [code=c]
          #include <18f452.h>
          #use delay(xtal=4mhz)

          #use rs232(baud=9600,xmit=pin_c6,rcv=pin_c7)

          int segment[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6 F};
          int i=0;

          void main()
          {

          while(true)
          {
          delay_ms(500);

          output_d(segment[i]);

          putc(i);

          i++;
          if(i>9) i=0;
          }
          }
          [/code]


          کد گیرنده:
          [code=c]
          #include <18f452.h>
          #use delay(xtal=4mhz)

          #use rs232(baud=9600,xmit=pin_c6,rcv=pin_c7)

          int segment[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6 F};
          int i=0;

          void main()
          {

          while(true)
          {
          i=getc();
          output_b(segment[i]);
          }
          }
          [/code]


          در این برنامه ها baudrate برابر 9600 هست و پایه های فرستنده و گیرنده همون پایه هایی که با TX و RX داخل پروتئوس مشخص شده.
          مقدار i در برنامه فرستنده زیاد شده و توسط دستور putc ارسال شده و روی 7segment هم نشون داده شده. گیرنده هم با دستور getc مقدار رو دریافت کرده و روی 7segment خودش نشون داده.
          چند نکته:
          1- شاید بپرسید آرایه segment برای چیه و چطوری عدد نشون داده میشه. اول باید بگم که یه سری توابع داره ccs که برای دستور دهی بایتی یا به عبارتی دستور دهی کلی به پورت هست. یعنی مقدار رو میگیره و بیت های مقدار دریافت کرده رو به جای پایه های اون پورت قرار میده. تابع همون طور که توی برنامه میبینید به صورت OUTPUT_X هست که X اسم پورته مثلا اگر مقدار 01001111 رو به تابع OUTPUT_D بدیم پایه های D0 تا D3 و D6 رو روشن میکنه و پایه های D4 و D5 و D7 خاموش هستند چون بیت معادلشون 0 هست.
          مقدار باینری که گفته شد (01001111) برابر 4F در مبنای 16 هست. و وقتی به شکلی که گفته شد پایه های پورت d تغییر وضعیت بدن عدد 3 روی سگمنت میکروی فرستنده نمایش داده میشه. (این وضعیت رو میتونید توی عکسی که گذاشته شده ببینید) . پس توی خونه شماره 3 آرایه مقدار 4F در مبنای 16 نمایش داده شده. (لزومی به نمایش در مبنای 16 نیست و میتونه در مبنای 2 یا 10 هم نمایش داده بشه)
          حالا وقتی خونه شماره 3 آرایه segment صدا زده میشه این آرایه مقداری 8 بیتی 4F رو به ما برمیگردونه که بیت های اون پورت d رو در وضعیتی قرار میدن که عدد 3 روی سگمنت نمایش داده بشه

          2- اگر این برنامه رو بنویسید و تست کنید می بینید که 500 میلی ثانیه اول از زمان استارت هیچ کدوم از سگمنت ها عددی رو نشون نمیدن. در برنامه فرستنده که این موضوع طبیعیه اما در برنامه گیرنده به این دلیل برنامه توقف میکنه که طرف فرستنده ارسالی رو انجام نمیده. یعنی دستور getc منتظر رسیدن کارکتر از فرستنده میمونه و تا زمانی که کارکتری رو دریافت نکنه بیرون نمیاد.

          3- چون انتقال اطلاعات ما یکطرفه انجام میشه نیازی به اتصال پایه TX از گیرنده به RX از فرستنده نبود.


          در قسمت بعد مابقی دستورات برای ارسال و دریافت اطلاعات و همچنین وقفه UART رو میگم
          AYRIC

          دیدگاه


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

            با سلام.
            بعضی مواقع نیاز داریم که بیش از یک کارکتر رو از طریق UART انتقال بدیم. که در این صورت باید اون رو به صورت رشته در بیاریم.
            برای ارسال داده به صورت رشته از طریق UART میتونیم از دستور زیر استفاده کنیم.

            [code=c] puts("PIC CCS"[/code]

            ارسال توسط تابع puts انجام شده. رشته PIC CCS هست. که از 7 کارکتر تشکیل شده. (کارکتر جای خالی رو هم حساب کنید)

            میتونیم همون کار بالا را به صورت زیر انجام بدیم:

            [code=c]
            char st[7];
            st="PIC CCS";
            puts(st);[/code]

            از طریق تابع printf هم میشه یک رشته رو ارسال کرد. به صورت زیر:
            [code=c]printf("PICC CCS"[/code]

            یا دوباره به یه شکل دیگه میشه رشته ای که در یک آرایه قرار گرفته رو به صورت زیر ارسال کرد:
            [code=c] char st[7];
            st="PIC CCS";
            printf("%s",st);[/code]

            2 نکته راجع به تابع printf:
            1- همون طور که میبینید این تابع دقیقا همون تابعی است که برای نوشتن روی lcd کارکتری استفاده میکردیم! تفاوت در اینه که دیگه در آرگومان اول تابع، تابع lcd_putc نوشته نمیشه. یعنی هر موقع در آرگومان اول چیزی نوشته نشه تابع printf خودش رشته ایجاد شده رو به سریال میفرسته.
            2- تابع printf کارش اینه که فرمت های مشخص در رشته داده شده رو به صورت یک رشته یک پارچه در بیاره و تک تک کارکتر های اون رشته رو به تابع مورد نظر بده. مثلا در lcd کارکتری، رشته ایجاد شده رو به تابع lcd_putc میداد یا در اینجا کارکترهارو به تابع putc میده.

            یک نکته هم در مورد تابع puts که این تابع در آخر رشته خودش \r\n رو میزنه.

            پس میشه با تابع printf هر جور رشته ای رو انقال داد. مثال زیر رو ببینید:
            [code=c] char name[11];
            int16 v=340;
            float acc=2.9;
            name="FERRARI-458";

            printf("Name:%s Speed:%lu km/h Acceleratio:%f 0-100km",name,v,acc);[/code]

            رشته ای که ارسال میشه اینه:
            کد:
            Name:FERRARI-458  Speed:340 km/h   Acceleratio:2.9 0-100km
            این ها برای ارسال بود. حالا برای دریافت میتونید علاوه بر تابع getc که یک کارکتر رو دریافت میکرد از تابع gets به صورت زیر استفاده کنید:
            [code=c] char st[10];
            gets(st);[/code]

            st یک آرایه هست که تابع gets بعد از گرفتن رشته اون رو در آرایه st قرار میده.



            در برنامه آموزش قبل که یک عدد انتقال داده می شد دیدید که به نحوی باید منتظر اومدن کارکتر از فرستنده میموندیم. حالا میخوام وقفه UART رو بگم که بهمون این کمک رو میکنه که دیگه منتظر اومدن کارکتر نمونیم و هر موقع که یک کارکتر اومد برنامه وارد وقفه میشه.
            کلمه کارکتر رو قرمز کردم چون نکته اینجاست که با هر کارکتر برنامه یکبار وارد وقفه میشه. مثلا برای یک رشته که 30 تا کارکتر داره برنامه 30 بار وارد وقفه میشه.

            وقفه UART رو میشه به صورت زیر فعال کرد:
            [code=c]enable_interrupts(int_rda);[/code]

            rda مخفف receive data available هست.
            یادتون نره که وقفه gloabal رو فعال کنید.

            خود وقفه هم به صورت زیر هستش:
            [code=c]#INT_RDA
            void rda_interr()
            {


            }[/code]

            وقتی برنامه وارد این وقفه بشه یعنی یک کارکتر جدید اومده. پس باید داخلش از تابع دریافت کارکتر (getc) استفاده کنیم. پس برنامه گیرنده در آموزش قبل به صورت زیر در میاد:
            [code=c]#include <18f452.h>
            #use delay(xtal=4mhz)

            #use rs232(baud=9600,xmit=pin_c6,rcv=pin_c7)

            int segment[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6 F};
            int i=0;

            #INT_RDA
            void rda_interr()
            {
            i=getc();
            }

            void main()
            {
            enable_interrupts(int_rda);
            enable_interrupts(global);

            while(true)
            {
            output_b(segment[i]);
            }
            }[/code]

            حالا اگه بخوایم یک رشته رو دریافت کنیم خیلی راحت میتونیم با استفاده از یک آرایه و یک شمارنده این کار رو انجام بدیم.به کد زیر نگاه کنید:
            [code=c]int t=0,buffer[15];

            #INT_RDA
            void rda_interr()
            {
            buffer[t]=getc();
            t++;
            if(t>=15) t=0;
            }[/code]
            در اینجا آرایه مورد نظر ما buffer و شمارنده t هست. آرایه 15 خونه ای هست.
            هر بار که کارکتری دریافت بشه برنامه وارد وقفه میشه و اون کارکتر در خونه t ام آرایه ریخته میشه. و t یک واحد زیاد میشه تا کارکتر بعدی در خونه بعدی ریخته بشه. و چک شده که اگر t بزرگتر از 14 شد اون رو 0 کنه تا t از تعداد خونه های آرایه بیشتر نشه.

            در برنامه بالا طول جمله 15 کارکتر در نظر گرفته شده. فرض کنید طول رشته ای که ارسال میشه 14 کارکتر باشه. در اینصورت خونه آخر از آرایه خالی میمونه و شمارنده t مقدار 14 رو داره پس 0 نمیشه. حالا با ارسال رشته بعدی که مثلا طولش 5 کارکتره. گیرنده کارکتر اول رو در خونه 15 ام آرایه قرار میده (در همین زمان t برابر 0 میشه) و 4 کاکتر دیگه در 4 خونه اول آرایه قرار میگیرن. پس نظم رشته هنگامی که در آرایه ذخیره میشه به هم میخوره.
            برای جلوگیری از این اتفاق باید آخر رشته رو با علامت خاصی که قرار نیست وسط رشته از اون استفاده بشه مشخص کنیم.
            مثلا به طور قرار داد آخر تمام رشته ها در سمت فرستنده علامت "!" رو قرار میدیم. و در گیرنده هنگامی که در کارکترهای دریافتی به این علامت رسیدیم t رو 0 می کنیم تا نظم رشته های دریافتی به هم نخوره. به برنامه زیر برای گیرنده دقت کنید:
            [code=c]int t=0,buffer[15];

            #INT_RDA
            void rda_interr()
            {
            buffer[t]=getc();

            if(buffer[t]=='!&#039 t=0;
            else
            {
            t++;
            if(t>=15) t=0;
            }
            }[/code]


            مثال زیر دو میکرو هستن که هر کدوم یک lcd دارن و میکروی اول مقدار یک پتانسیومتر رو توسط adc میخونه و برای دومی میفرسته و میکروی دوم هم تعداد دفعات فشرده شدن کلید خودش رو برای اولی ارسال میکنه. هر کدوم از میکروها هر دو مقدار یعنی مقدار adc و شمارنده رو روی lcd های خودشون مینویسن.

            برنامه میکروی اول:
            [code=c]#include <18f452.h>
            #use delay(xtal=4mhz)

            #use rs232(baud=9600,xmit=pin_c6,rcv=pin_c7)

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

            int adc_value;

            int t=0,buffer[15];

            #INT_RDA
            void rda_interr()
            {
            buffer[t]=getc();

            if(buffer[t]=='!&#039 t=0;
            else
            {
            t++;
            if(t>=15) t=0;
            }
            }


            void main()
            {
            enable_interrupts(int_rda);
            enable_interrupts(global);
            setup_adc_ports(AN0);
            setup_adc( ADC_CLOCK_INTERNAL );
            set_adc_channel(0);

            lcd_init();

            while(true)
            {
            adc_value = read_adc();

            lcd_gotoxy(1,1);
            printf(lcd_putc, "ADC= %u ", adc_value);
            lcd_gotoxy(1,2);
            printf(lcd_putc, "UART: %s", buffer);

            printf("ADC=%u!",adc_value);
            }
            }[/code]

            برنامه میکروی دوم:
            [code=c]#include <18f452.h>
            #use delay(xtal=4mhz)

            #use rs232(baud=9600,xmit=pin_c6,rcv=pin_c7)

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

            int i;

            int t=0,buffer[15];

            #INT_RDA
            void rda_interr()
            {
            buffer[t]=getc();

            if(buffer[t]=='!&#039 t=0;
            else
            {
            t++;
            if(t>=15) t=0;
            }
            }


            void main()
            {
            enable_interrupts(int_rda);
            enable_interrupts(global);

            lcd_init();

            while(true)
            {
            if(input(pin_c0))
            {
            i++;
            while(input(pin_c0));
            }

            lcd_gotoxy(1,1);
            printf(lcd_putc, "KEY= %u ", i);
            lcd_gotoxy(1,2);
            printf(lcd_putc, "UART: %s", buffer);

            printf("KEY=%u!",i);
            }
            }[/code]


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

            ورژن ccs 5.51 و ورژن پروتئوس 8.1 هست.
            AYRIC

            دیدگاه


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

              سلام
              اگه میشه یکمی هم درباره ی خود میکروکنترلر های pic توضیح بدید .
              معماری و ساختار pic
              واحد های میکرو کنترلر ها
              سری های pic
              نام گذاری pic

              ممنون
              /SAM/

              دیدگاه


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

                سلام دوستان خخسته نباشید من یه پروژه دارم که میخوام با میکروکنترلر PIC از sd card یه موزیکی پخش کنم با کامپایلر ccs کسی اینکارو کرده؟ یا حداقل کسی با این ;کامپایلر sd csrd رو راه اندازی کرده؟

                دیدگاه


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

                  با عرض سلام و خسته نباشد میشه بگین مشکل این برنامه ای که بنده نوشتم چی هستش ؟ این برنامه مربوط به برقراری ارتباط سریال بین میکرو و ماژول بلوتوث HC05 وگوشی موبایل هست. تو این برنامه می خوام با برنامه ای که تو گوشیم هستش ، نوشته ای را که ارسال میکنم میکرو همون را توسط ماژول بلوتوث به من برگردونه ....اما اصلا هیچ اتفاقی نمی افته ....ماژول بلوتوث را هم توسط hyper terminal پیکره بندیشم کردم ....با تشکر
                  #include <18f4520.h>
                  #use delay(clock=8000000)
                  #use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7)
                  #fuses INTRC_IO,nowdt,NOPROTECT,NOPUT


                  void main()
                  {
                  int8 a=0;
                  setup_oscillator(OSC_8MHZ|OSC_INTRC);
                  while(true){
                  a=getc();
                  putc(a);
                  }
                  }

                  دیدگاه


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

                    ,واقعا ممنون بابت آموزشاتون ...دمتون گرم ....هرچی تشکر کنم کم کردم ...چون آموزش کامپایلر ccs خیلی کم پیدا میشه و اگههم پیدا بشه ناقصه....ممنون

                    دیدگاه


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

                      تشکر از آموزش های عالی تون آقای roboreza

                      دیدگاه


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

                        ساخت فایل رجیستر در CCS
                        سلام به همه ی دوستان
                        من یه مدتی با ccs کار می کنم و دوستان گفته بودند که این کامپایلر رجیستر ها رو نمیشناسه و برای این کار باید از دستور #bit و#byte استفاده کنیم که وقت گیره.
                        ولی من دیدم که این کامپایلر یه ابزاری داره که میتونه فایل مربوط به شناسایی رجیستر ها رو بسازه و گفتم بزارم ، شاید بدرد خورد
                        حالت استفاده از رجیستر ها هم به صورت کامپایلر XC8 هست
                        برای استفده از این فایل ، باید اینکلودش کنین و #case رو تو برنامتون بنویسین
                        حتما #case رو قبل اینکلود کردن بنویسین
                        یک نمونه:
                        #case
                        #include <YourRegisterFileName.h>

                        void main() {
                        PORTB = 0;
                        PORTBbits.RB0 = 1;
                        }

                        برای درست کردن فایل:
                        1_برای این کار روی تب view کلیک میکنیم
                        2_بعد در قسمت Chip Information روی گزینه ی Register کلیک می کنیم
                        3_در قست چپ پنجره ی باز شده میکروی مورد نظر رو انتخاب می کنیم
                        4_بعد روی گزینه ی make include file در بالای همون صفحه کلیک می کنیم
                        5_حالا یه پنجره ی جدید باز میشه ، در قسمت output file می تونیم اسم فایل خروجی مون رو بنویسیم . من نوشتم 18F4520REG.h
                        6_بعد روی گزینه ی pack into struct's کلید می کنیم
                        Byte Prefix_6 رو پاک میکنیم
                        7_در Byte Sufix عبارت bits رو می نویسیم
                        عبارت Make upper case struct names رو تیک می زنیم
                        تیک عبارت Combine Low/High byte register into one int16 رو برمی دارید
                        در آخر هم روی Generate کلیک می کنیم.

                        به همین راحتی می تونید از رجیستر ها استفاده کنین

                        امید وارم بدرد تون بخوره

                        دیدگاه


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

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

                          دیدگاه


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

                            سلام
                            برین به سایت https://simple-circuit.com/
                            تمام پروژه هاش با CCS C هست
                            من خودم هم با همین کامپایلر کار می کنم. اگر کمک نیاز داشتید در خدمتم.

                            دیدگاه


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

                              سلام
                              من جدید ترین نسخه CCS C Compiler کرک شده رو میخام ولی خب تو اینترنت نیست و تو خود سایت CCS هم قیمت PCWHD خیلی بالاست(600 دلار). اگر کسی لینکی داره لطفا در اختیار بزاره . من خودم 5.049 رو دارم. تو سایتش زده 5.1 اومده.
                              کرک ها بیاین وسط

                              دیدگاه


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

                                نوشته اصلی توسط Matin_Mirzadeh نمایش پست ها
                                سلام
                                من جدید ترین نسخه CCS C Compiler کرک شده رو میخام ولی خب تو اینترنت نیست و تو خود سایت CCS هم قیمت PCWHD خیلی بالاست(600 دلار). اگر کسی لینکی داره لطفا در اختیار بزاره . من خودم 5.049 رو دارم. تو سایتش زده 5.1 اومده.
                                کرک ها بیاین وسط
                                با سلام. 5.093 را میتوانید از لینک زیر بگیرید. ( البته من خودم تستش نکردم.)

                                دیدگاه

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