اطلاعیه

Collapse
No announcement yet.

نکته ای در کدنویسی

Collapse
X
 
  • فیلتر
  • زمان
  • Show
Clear All
new posts

    #16
    پاسخ : نکته ای در کدنویسی

    با سلام خدمت استاد کی نژاد عزیز و دوستان محترم
    مطلبی که به ذهن بنده میرسد این است:
    با توجه به اینکه متغیر delay از نوع unsigned int تعریف شده و دو بایت از حافظه را اشغال میکند فلذا در زمان مقایسه با مقدار صفر ((while(delay) عملا مقدار low byte در یکی از رجیسترهای R0 الی R31 لود میشود و سپس مقدار high byte در یکی دیگر از رجیسترهای مذکور(به انتخاب کامپایلر) و سپس برای مقایسه با عدد ثابت صفر ابتدا مقدار رجیستر مربوط به low byte با عدد صفر مقایسه می شوذ و در کلاک بعدی مقدار رجیستر مربوط به high byte با عدد صفر مقایسه می شود و سپس با یک دستور branch , بسته به نتیجه مقایسه قبلی که نتیجه آن فلگهای مشخصی را تحت تاثیر قرار میدهد , دستور branch اجرا می گردد یا نمیگردد.
    حال فرض کنیم program counter بر روی دستور while(delay مانده و وقفه مربوطه نیز یکی پس از دیگری رخ میدهد و باعث کاهش مقدار متغییر delay می گردد و در آخرین وقفه مقدار delay صفر شده است و در حین اجرای دستور while ( پس از اجرای دستور اسمبلی مربوط به لود کردن رجیستر مربوط به low byte ) دوباره وقفه رخ دهد , چون قبلا مقدار متغیر صفر بوده است فلذا با کاهش یک واحدی دوباره مقدار متغیر, عملا مقدار آن به ماکزیمم مقدار خود یعنی 65535 تغییر حالت میدهد و پس از خاتمه وقفه, عملا program counter به آخرین محلی که قبلا بوده بر میگردد و به اجرای دستور اسمبلی مربوط به لود کردن رجیستر مربوط به high byte می پردازد و با توجه به اینکه مقدار محتوای متغیر قبلا در روتین وقفه دستکاری شده بود , عملا دوباره اجرای برنامه بر روی دستور while(delay می ماند .
    برای چلوگیری از این مشکل هم میتوان قبل از دستور while(delay وقفه ها را غیر فعال کرد و بعد از آن دوباره فعال کرد و یا شرط مقایسه با مقدار غیر صفر را در داخل خود وقفه قرار داد و پس از صفر شدن آن با ست کردن یک فلگ به حلقه اصلی برنامه فهماند که تاخیر مورد نظر سپری شده است
    مشخصات من در لینک زیر
    http://www.eca.ir/forum2/index.php?topic=1721.msg698645#msg698645

    www.********

    دیدگاه


      #17
      پاسخ : نکته ای در کدنویسی

      دوستان گرامی کاملا درست تشخیص دادند. اولین مورد برای عدم دقت، همزمان نبودن مقداردهی به متغیر با ابتدای سیکل شمارش تایمر است که می تواند تا حد یک سیکل تایمر خطا ایجاد کند. مثلا اگر در هنگام مقداردهی به متغیر، از 1 میلی ثانیه زمان تایمر 0.6 میلی ثانیه آن سپری شده باشد، در این حالت بجای 1 میلی ثانیه تنها حدود 0.4 میلی ثانیه زمان لازم است تا وقفه تایمر ایجاد می شود که باعث ایجاد خطا می شود.
      اما مورد اساسی تر که می تواند خطاهای بسیار بزرگتری را ایجاد کند ناشی از 16 بیتی بودن مقدار متغیر است. در صورت مسئله مطرح شده، این نوع خطا در دو مرحله ممکن است ایجاد شود. مرحله اول مقداردهی به متغیر delay است. با مراجعه به کدهای اسمبلی معادل مشاهده می شود که مقداردهی ابتدا به بایت با ارزش کمتر و بعد به بایت با ارزش بیشتر انجام می شود. ایجاد وقفه در بین مقداردهی این دو بایت می تواند اولین نوع خطا را ایجاد کند. به عنوان مثال فرض کنیم که مقدار فعلی delay برابر 0x123 باشد و قرار باشد به 0x200 تغییر کند. اگر در بین مقداردهی و بعد از نسبت دادن 0x00 به بایت پائین وقفه ای ایجاد شود، مقدار بایت پائین در وقفه به 0xff و بایت بالا به 0x00 تغییر خواهد کرد و بعد از بازگشت از وقفه، مقدار 0x02 در بایت بالا قرار خواهد گرفت. بنابراین در نهایت در delay بجای 0x200 مقدار 0x2ff قرار خواهد گرفت که خطای زیادی را در زمان گیری ایجاد می کند.
      مورد بعدی برای ایجاد خطا، نحوه قضاوت در while و ایجاد وقفه در بین آن است که باز می تواند منجربه خطا شود. با مراجعه به کدهای اسمبلی معادل قابل مشاهده است که قضاوت ابتدا روی بایت پائین و بعد بایت بالا انجام می شود. در همین رابطه یکی از دوستان مثالی را در پست های قبل مطرح کردند که آن را تکرار می کنم. اگر فرض کنیم مقدار delay برابر با 0x100 باشد و قضاوت روی بایت پائین که 0x00 است انجام شده باشد، اگر وقفه ای ایجاد شود و بایت بالا در وقفه صفر شود، در بازگشت از وقفه قضاوت روی بایت بالا (که اکنون صفر شده) باعث برآورده شدن شرط while به صورت غلط و ایجاد نتیجه اشتباه در زمان گیری خواهد شد.
      برای جلوگیری از ایجاد اشکالات فوق می توان اولا در هنگام مقدار دهی به متغیرهای 16 بیتی یا بزرگتر، وقفه مربوطه را بصورت موقت غیرفعال و بعد از مقداردهی مجددا فعال کرد که نمونه کد آن در پست های قبلی قرار داده شده است. برای قضاوت روی مقدار متغیر هم می توان از یک متغیر کمکی مانند مثال زیر استفاده کرد:

      [code=c]do{
      cli(); // WINAVR
      temp=delay;
      sei();
      }
      while(temp);[/code]

      بطور کلی وجود دید اسمبلی در برنامه نویس سطح بالا می تواند تا حد زیادی مانع از بوجود آمدن چنین مشکلاتی در برنامه نویسی شود. با توجه به اینکه به نظر می رسد صورت مسئله مطرح شده برای برخی دوستان مفید واقع شده باشد، در فرصت های دیگری احتمالا موارد مشابهی را در همین تاپیک مطرح خواهم کرد.
      اوژن: به معنای افکننده و شکست دهنده است
      دانایی، توانایی است-Knowledge is POWER
      برای حرفه ای شدن در الکترونیک باید با آن زندگی کرد
      وضعمان بهتر می شود، اگر همه نسبت به جامعه و اطراف خود مسوول باشیم و نگوئیم به ما چه
      قوی شدن و خوب ماندن - خوبی کردن به دیگران یک لذت ماندگار است
      اگر قرار باشد نفت و منابع خام را بدهیم و چرخ بگیریم، بهتر است چرخ را از نو اختراع کنیم
      ساعت کار بدن اکثر انسان ها کمتر از 800000 ساعت است و بعد از آن از کار می افتد

      دیدگاه


        #18
        پاسخ : نکته ای در کدنویسی

        آقای کی نژاد ممکنه در مورد علت درست کار کردن این کد اولی هم یه توضیح بدین


        نوشته اصلی توسط mahdi421
        [code=c] delay=500;
        while(delay)
        PORTE_OUTSET=255;

        delay=500;
        while(delay)
        PORTE_OUTCLR=255;[/code]

        [code=c] delay=500;
        while(delay);
        PORTE_OUTSET=255;


        delay=500;
        while(delay);
        PORTE_OUTCLR=255;[/code]

        دیدگاه


          #19
          پاسخ : نکته ای در کدنویسی

          در کد اول تا زمانی که delay غیر صفر باشد، به رجیستر دائما مقدار 255 نسبت داده می شود که اگر منظور فقط ایجاد تاخیر باشد، تکرار این مقداردهی کار غیرلازمی است. در کد دوم ابتدا برای صفر شدن delay انتظار ایجاد می شود و بعد یک بار در هر مرحله به رجیستر مقداردهی می شود.
          اوژن: به معنای افکننده و شکست دهنده است
          دانایی، توانایی است-Knowledge is POWER
          برای حرفه ای شدن در الکترونیک باید با آن زندگی کرد
          وضعمان بهتر می شود، اگر همه نسبت به جامعه و اطراف خود مسوول باشیم و نگوئیم به ما چه
          قوی شدن و خوب ماندن - خوبی کردن به دیگران یک لذت ماندگار است
          اگر قرار باشد نفت و منابع خام را بدهیم و چرخ بگیریم، بهتر است چرخ را از نو اختراع کنیم
          ساعت کار بدن اکثر انسان ها کمتر از 800000 ساعت است و بعد از آن از کار می افتد

          دیدگاه


            #20
            پاسخ : نکته ای در کدنویسی

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

            در حالی که اگر جلوی عبارت while از ; استفاده کنیم مقدار تاخیر همان طور که در پست اول اشاره کردین بعضی مواقع نادرست اعمال میشود

            [code=c]
            # define F_CPU 2000000UL

            #include <avr/io.h>
            #include <util/delay.h>


            #include <avr/io.h>
            #include <avr/interrupt.h>




            volatile unsigned long delay;


            int main()
            {


            TCC0.PER = 1;
            TCC0.INTCTRLA = TC_OVFINTLVL_HI_gc;
            TCC0.CTRLA = TC_CLKSEL_DIV1024_gc;


            PMIC.CTRL |= PMIC_HILVLEN_bm | PMIC_LOLVLEN_bm | PMIC_MEDLVLEN_bm;
            sei();


            PORTE_DIR=255;


            while(1){


            delay=500;
            while(delay)
            PORTE_OUTSET=255;


            delay=500;
            while(delay)
            PORTE_OUTCLR=255;
            }


            return 0;
            }


            ISR (TCC0_OVF_vect)
            {
            if(delay) delay--;

            }

            [/code]

            اضافه شده در تاریخ :
            مشکل از طرف برنامه ای بود که من تست کردام ( برای نشون دادن مقدار delay از lcd هم استفاده کرده بودام )
            در هر صورت چه مقابل عبارت while در کد بالا ; باشه یا نه برنامه تاخیر یکنواختی ایجاد نمیکنه :redface:

            دیدگاه

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